2024-01-07 04:27:18 +00:00
|
|
|
/**
|
|
|
|
|
* @typedef {import('./types.js').SchemaElement} SchemaElement
|
2024-01-20 02:51:16 +00:00
|
|
|
* @typedef {import('./types.js').SchemaTree} SchemaTree
|
2024-01-07 04:27:18 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build a tree from the schema elements.
|
|
|
|
|
*
|
|
|
|
|
* @param {SchemaElement[]} schema
|
2024-01-20 02:51:16 +00:00
|
|
|
* @param {number} rootIndex index of the root element
|
2024-01-07 04:27:18 +00:00
|
|
|
* @returns {SchemaTree} tree of schema elements
|
|
|
|
|
*/
|
2024-01-20 02:51:16 +00:00
|
|
|
export function schemaTree(schema, rootIndex) {
|
|
|
|
|
const root = schema[rootIndex]
|
2024-01-07 04:27:18 +00:00
|
|
|
const children = []
|
2024-01-20 02:51:16 +00:00
|
|
|
let count = 1
|
2024-01-07 04:27:18 +00:00
|
|
|
|
|
|
|
|
// Read the specified number of children
|
|
|
|
|
if (root.num_children) {
|
|
|
|
|
while (children.length < root.num_children) {
|
2024-01-20 02:51:16 +00:00
|
|
|
const child = schemaTree(schema, rootIndex + count)
|
|
|
|
|
count += child.count
|
2024-01-07 04:27:18 +00:00
|
|
|
children.push(child)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-20 02:51:16 +00:00
|
|
|
return { count, element: root, children }
|
2024-01-07 04:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the schema element with the given name.
|
|
|
|
|
*
|
|
|
|
|
* @param {SchemaElement[]} schema
|
|
|
|
|
* @param {string[]} name path to the element
|
|
|
|
|
* @returns {SchemaElement} schema element
|
|
|
|
|
*/
|
|
|
|
|
export function schemaElement(schema, name) {
|
|
|
|
|
let tree = schemaTree(schema, 0)
|
|
|
|
|
// traverse the tree to find the element
|
|
|
|
|
for (const part of name) {
|
|
|
|
|
const child = tree.children.find(child => child.element.name === part)
|
|
|
|
|
if (!child) {
|
2024-01-13 00:28:37 +00:00
|
|
|
throw new Error(`parquet schema element not found: ${name}`)
|
2024-01-07 04:27:18 +00:00
|
|
|
}
|
|
|
|
|
tree = child
|
|
|
|
|
}
|
|
|
|
|
return tree.element
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the schema element with the given name is required.
|
|
|
|
|
*
|
|
|
|
|
* @param {SchemaElement[]} schema
|
|
|
|
|
* @param {string[]} name path to the element
|
|
|
|
|
* @returns {boolean} true if the element is required
|
|
|
|
|
*/
|
|
|
|
|
export function isRequired(schema, name) {
|
2024-02-11 22:33:56 +00:00
|
|
|
return schemaElement(schema, name).repetition_type === 'REQUIRED'
|
2024-01-07 04:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the max repetition level for a given schema path.
|
|
|
|
|
*
|
|
|
|
|
* @param {SchemaElement[]} schema
|
|
|
|
|
* @param {string[]} parts path to the element
|
|
|
|
|
* @returns {number} max repetition level
|
|
|
|
|
*/
|
|
|
|
|
export function getMaxRepetitionLevel(schema, parts) {
|
|
|
|
|
let maxLevel = 0
|
|
|
|
|
parts.forEach((part, i) => {
|
|
|
|
|
const element = schemaElement(schema, parts.slice(0, i + 1))
|
2024-02-11 22:33:56 +00:00
|
|
|
if (element.repetition_type === 'REPEATED') {
|
2024-01-07 04:27:18 +00:00
|
|
|
maxLevel += 1
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return maxLevel
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the max definition level for a given schema path.
|
|
|
|
|
*
|
|
|
|
|
* @param {SchemaElement[]} schema
|
|
|
|
|
* @param {string[]} parts path to the element
|
|
|
|
|
* @returns {number} max definition level
|
|
|
|
|
*/
|
|
|
|
|
export function getMaxDefinitionLevel(schema, parts) {
|
|
|
|
|
let maxLevel = 0
|
|
|
|
|
parts.forEach((part, i) => {
|
|
|
|
|
const element = schemaElement(schema, parts.slice(0, i + 1))
|
2024-02-11 22:33:56 +00:00
|
|
|
if (element.repetition_type !== 'REQUIRED') {
|
2024-01-07 04:27:18 +00:00
|
|
|
maxLevel += 1
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return maxLevel
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the number of bytes to skip for definition levels.
|
|
|
|
|
*
|
|
|
|
|
* @param {number} num number of values
|
|
|
|
|
* @returns {number} number of bytes to skip
|
|
|
|
|
*/
|
|
|
|
|
export function skipDefinitionBytes(num) {
|
|
|
|
|
let byteLength = 6
|
|
|
|
|
let n = num >>> 8
|
|
|
|
|
while (n !== 0) {
|
|
|
|
|
byteLength += 1
|
|
|
|
|
n >>>= 7
|
|
|
|
|
}
|
|
|
|
|
return byteLength
|
|
|
|
|
}
|