@loaders.gl/parquet 4.5.3 → 5.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +14 -3
- package/dist/bundled.d.ts +9 -0
- package/dist/bundled.d.ts.map +1 -0
- package/dist/bundled.js +10 -0
- package/dist/bundled.js.map +1 -0
- package/dist/delta-format.d.ts +9 -0
- package/dist/delta-format.d.ts.map +1 -0
- package/dist/delta-format.js +12 -0
- package/dist/delta-format.js.map +1 -0
- package/dist/delta-source-loader-types.d.ts +27 -0
- package/dist/delta-source-loader-types.d.ts.map +1 -0
- package/dist/delta-source-loader-types.js +28 -0
- package/dist/delta-source-loader-types.js.map +1 -0
- package/dist/delta-source.d.ts +48 -0
- package/dist/delta-source.d.ts.map +1 -0
- package/dist/delta-source.js +222 -0
- package/dist/delta-source.js.map +1 -0
- package/dist/delta-types.d.ts +38 -0
- package/dist/delta-types.d.ts.map +1 -0
- package/dist/delta-types.js +5 -0
- package/dist/delta-types.js.map +1 -0
- package/dist/geoparquet-loader-with-parser.d.ts +33 -0
- package/dist/geoparquet-loader-with-parser.d.ts.map +1 -0
- package/dist/geoparquet-loader-with-parser.js +52 -0
- package/dist/geoparquet-loader-with-parser.js.map +1 -0
- package/dist/geoparquet-loader.d.ts +59 -0
- package/dist/geoparquet-loader.d.ts.map +1 -0
- package/dist/geoparquet-loader.js +30 -0
- package/dist/geoparquet-loader.js.map +1 -0
- package/dist/iceberg-rest-catalog.d.ts +49 -0
- package/dist/iceberg-rest-catalog.d.ts.map +1 -0
- package/dist/iceberg-rest-catalog.js +78 -0
- package/dist/iceberg-rest-catalog.js.map +1 -0
- package/dist/iceberg-table-source.d.ts +63 -0
- package/dist/iceberg-table-source.d.ts.map +1 -0
- package/dist/iceberg-table-source.js +797 -0
- package/dist/iceberg-table-source.js.map +1 -0
- package/dist/iceberg-types.d.ts +150 -0
- package/dist/iceberg-types.d.ts.map +1 -0
- package/dist/iceberg-types.js +5 -0
- package/dist/iceberg-types.js.map +1 -0
- package/dist/index.cjs +41568 -6781
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +15 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -12
- package/dist/index.js.map +1 -1
- package/dist/lib/arrow/convert-columns-to-row-group.js +3 -0
- package/dist/lib/arrow/convert-columns-to-row-group.js.map +1 -1
- package/dist/lib/arrow/convert-schema-from-parquet.d.ts +3 -1
- package/dist/lib/arrow/convert-schema-from-parquet.d.ts.map +1 -1
- package/dist/lib/arrow/convert-schema-from-parquet.js +164 -29
- package/dist/lib/arrow/convert-schema-from-parquet.js.map +1 -1
- package/dist/lib/arrow/convert-schema-to-parquet.d.ts.map +1 -1
- package/dist/lib/arrow/convert-schema-to-parquet.js +16 -7
- package/dist/lib/arrow/convert-schema-to-parquet.js.map +1 -1
- package/dist/lib/arrow/create-nested-arrow-vector.d.ts +8 -0
- package/dist/lib/arrow/create-nested-arrow-vector.d.ts.map +1 -0
- package/dist/lib/arrow/create-nested-arrow-vector.js +485 -0
- package/dist/lib/arrow/create-nested-arrow-vector.js.map +1 -0
- package/dist/lib/constants.d.ts +0 -1
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -2
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/encoders/encode-arrow-to-parquet.d.ts +2 -2
- package/dist/lib/encoders/encode-arrow-to-parquet.d.ts.map +1 -1
- package/dist/lib/encoders/encode-arrow-to-parquet.js +3 -10
- package/dist/lib/encoders/encode-arrow-to-parquet.js.map +1 -1
- package/dist/lib/encoders/encode-table-to-parquet-js.d.ts +5 -0
- package/dist/lib/encoders/encode-table-to-parquet-js.d.ts.map +1 -0
- package/dist/lib/encoders/encode-table-to-parquet-js.js +394 -0
- package/dist/lib/encoders/encode-table-to-parquet-js.js.map +1 -0
- package/dist/lib/geo/geoparquet-covering.d.ts +19 -0
- package/dist/lib/geo/geoparquet-covering.d.ts.map +1 -0
- package/dist/lib/geo/geoparquet-covering.js +137 -0
- package/dist/lib/geo/geoparquet-covering.js.map +1 -0
- package/dist/lib/geo/geospatial-metadata.d.ts +67 -0
- package/dist/lib/geo/geospatial-metadata.d.ts.map +1 -0
- package/dist/lib/geo/geospatial-metadata.js +412 -0
- package/dist/lib/geo/geospatial-metadata.js.map +1 -0
- package/dist/lib/parquet-bloom-filter-planner.d.ts +16 -0
- package/dist/lib/parquet-bloom-filter-planner.d.ts.map +1 -0
- package/dist/lib/parquet-bloom-filter-planner.js +57 -0
- package/dist/lib/parquet-bloom-filter-planner.js.map +1 -0
- package/dist/lib/parquet-bloom-filter.d.ts +30 -0
- package/dist/lib/parquet-bloom-filter.d.ts.map +1 -0
- package/dist/lib/parquet-bloom-filter.js +289 -0
- package/dist/lib/parquet-bloom-filter.js.map +1 -0
- package/dist/lib/parquet-encryption.d.ts +80 -0
- package/dist/lib/parquet-encryption.d.ts.map +1 -0
- package/dist/lib/parquet-encryption.js +190 -0
- package/dist/lib/parquet-encryption.js.map +1 -0
- package/dist/lib/parquet-page-index.d.ts +91 -0
- package/dist/lib/parquet-page-index.d.ts.map +1 -0
- package/dist/lib/parquet-page-index.js +463 -0
- package/dist/lib/parquet-page-index.js.map +1 -0
- package/dist/lib/parquet-predicate.d.ts +21 -0
- package/dist/lib/parquet-predicate.d.ts.map +1 -0
- package/dist/lib/parquet-predicate.js +328 -0
- package/dist/lib/parquet-predicate.js.map +1 -0
- package/dist/lib/parquet-source-worker-client.d.ts +6 -0
- package/dist/lib/parquet-source-worker-client.d.ts.map +1 -0
- package/dist/lib/parquet-source-worker-client.js +24 -0
- package/dist/lib/parquet-source-worker-client.js.map +1 -0
- package/dist/lib/parquet-source-worker-decoder.d.ts +7 -0
- package/dist/lib/parquet-source-worker-decoder.d.ts.map +1 -0
- package/dist/lib/parquet-source-worker-decoder.js +181 -0
- package/dist/lib/parquet-source-worker-decoder.js.map +1 -0
- package/dist/lib/parquet-source-worker-file.d.ts +24 -0
- package/dist/lib/parquet-source-worker-file.d.ts.map +1 -0
- package/dist/lib/parquet-source-worker-file.js +40 -0
- package/dist/lib/parquet-source-worker-file.js.map +1 -0
- package/dist/lib/parquet-source-worker-types.d.ts +121 -0
- package/dist/lib/parquet-source-worker-types.d.ts.map +1 -0
- package/dist/lib/parquet-source-worker-types.js +5 -0
- package/dist/lib/parquet-source-worker-types.js.map +1 -0
- package/dist/lib/parquet-worker-transport.d.ts +8 -0
- package/dist/lib/parquet-worker-transport.d.ts.map +1 -0
- package/dist/lib/parquet-worker-transport.js +40 -0
- package/dist/lib/parquet-worker-transport.js.map +1 -0
- package/dist/lib/parsers/convert-parquet-tables.d.ts +16 -0
- package/dist/lib/parsers/convert-parquet-tables.d.ts.map +1 -0
- package/dist/lib/parsers/convert-parquet-tables.js +30 -0
- package/dist/lib/parsers/convert-parquet-tables.js.map +1 -0
- package/dist/lib/parsers/get-parquet-schema.d.ts.map +1 -1
- package/dist/lib/parsers/get-parquet-schema.js +6 -2
- package/dist/lib/parsers/get-parquet-schema.js.map +1 -1
- package/dist/lib/parsers/parse-geoparquet-to-geojson.d.ts +4 -4
- package/dist/lib/parsers/parse-geoparquet-to-geojson.d.ts.map +1 -1
- package/dist/lib/parsers/parse-geoparquet-to-geojson.js +19 -6
- package/dist/lib/parsers/parse-geoparquet-to-geojson.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-tables.d.ts +37 -0
- package/dist/lib/parsers/parse-parquet-tables.d.ts.map +1 -0
- package/dist/lib/parsers/parse-parquet-tables.js +50 -0
- package/dist/lib/parsers/parse-parquet-tables.js.map +1 -0
- package/dist/lib/parsers/parse-parquet-to-arrow-js.d.ts +19 -0
- package/dist/lib/parsers/parse-parquet-to-arrow-js.d.ts.map +1 -0
- package/dist/lib/parsers/parse-parquet-to-arrow-js.js +921 -0
- package/dist/lib/parsers/parse-parquet-to-arrow-js.js.map +1 -0
- package/dist/lib/parsers/parse-parquet-to-arrow.d.ts +7 -7
- package/dist/lib/parsers/parse-parquet-to-arrow.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow.js +45 -32
- package/dist/lib/parsers/parse-parquet-to-arrow.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-columns.d.ts +3 -3
- package/dist/lib/parsers/parse-parquet-to-columns.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-columns.js +4 -5
- package/dist/lib/parsers/parse-parquet-to-columns.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-json.d.ts +3 -3
- package/dist/lib/parsers/parse-parquet-to-json.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-json.js +95 -28
- package/dist/lib/parsers/parse-parquet-to-json.js.map +1 -1
- package/dist/lib/slice-parquet-batch.d.ts +9 -0
- package/dist/lib/slice-parquet-batch.d.ts.map +1 -0
- package/dist/lib/slice-parquet-batch.js +28 -0
- package/dist/lib/slice-parquet-batch.js.map +1 -0
- package/dist/lib/sources/parquet-range-file.d.ts +80 -0
- package/dist/lib/sources/parquet-range-file.d.ts.map +1 -0
- package/dist/lib/sources/parquet-range-file.js +267 -0
- package/dist/lib/sources/parquet-range-file.js.map +1 -0
- package/dist/lib/sources/single-batch-queue.d.ts +24 -0
- package/dist/lib/sources/single-batch-queue.d.ts.map +1 -0
- package/dist/lib/sources/single-batch-queue.js +91 -0
- package/dist/lib/sources/single-batch-queue.js.map +1 -0
- package/dist/lib/utils/load-wasm-node.d.ts +3 -0
- package/dist/lib/utils/load-wasm-node.d.ts.map +1 -0
- package/dist/lib/utils/load-wasm-node.js +23 -0
- package/dist/lib/utils/load-wasm-node.js.map +1 -0
- package/dist/lib/utils/load-wasm.d.ts +2 -2
- package/dist/lib/utils/load-wasm.d.ts.map +1 -1
- package/dist/lib/utils/load-wasm.js +28 -12
- package/dist/lib/utils/load-wasm.js.map +1 -1
- package/dist/lib/utils/make-stream-iterator.d.ts +2 -0
- package/dist/lib/utils/make-stream-iterator.d.ts.map +1 -1
- package/dist/lib/utils/make-stream-iterator.js +123 -14
- package/dist/lib/utils/make-stream-iterator.js.map +1 -1
- package/dist/lib/utils/normalize-parquet-options.d.ts +5 -0
- package/dist/lib/utils/normalize-parquet-options.d.ts.map +1 -0
- package/dist/lib/utils/normalize-parquet-options.js +25 -0
- package/dist/lib/utils/normalize-parquet-options.js.map +1 -0
- package/dist/parquet-dataset-source.cjs +38974 -0
- package/dist/parquet-dataset-source.cjs.map +6 -0
- package/dist/parquet-dataset-source.d.ts +81 -0
- package/dist/parquet-dataset-source.d.ts.map +1 -0
- package/dist/parquet-dataset-source.js +602 -0
- package/dist/parquet-dataset-source.js.map +1 -0
- package/dist/parquet-encoded-page-types.d.ts +108 -0
- package/dist/parquet-encoded-page-types.d.ts.map +1 -0
- package/dist/parquet-encoded-page-types.js +5 -0
- package/dist/parquet-encoded-page-types.js.map +1 -0
- package/dist/parquet-format.d.ts +2 -0
- package/dist/parquet-format.d.ts.map +1 -1
- package/dist/parquet-format.js +2 -0
- package/dist/parquet-format.js.map +1 -1
- package/dist/parquet-js-loader-types.d.ts +59 -0
- package/dist/parquet-js-loader-types.d.ts.map +1 -0
- package/dist/parquet-js-loader-types.js +34 -0
- package/dist/parquet-js-loader-types.js.map +1 -0
- package/dist/parquet-js-loader.d.ts +18 -22
- package/dist/parquet-js-loader.d.ts.map +1 -1
- package/dist/parquet-js-loader.js +53 -14
- package/dist/parquet-js-loader.js.map +1 -1
- package/dist/parquet-js-writer.d.ts +65 -0
- package/dist/parquet-js-writer.d.ts.map +1 -0
- package/dist/parquet-js-writer.js +28 -0
- package/dist/parquet-js-writer.js.map +1 -0
- package/dist/parquet-loader-base.d.ts +25 -0
- package/dist/parquet-loader-base.d.ts.map +1 -0
- package/dist/parquet-loader-base.js +23 -0
- package/dist/parquet-loader-base.js.map +1 -0
- package/dist/parquet-loader-options.d.ts +55 -0
- package/dist/parquet-loader-options.d.ts.map +1 -0
- package/dist/parquet-loader-options.js +10 -0
- package/dist/parquet-loader-options.js.map +1 -0
- package/dist/parquet-loader-types.d.ts +61 -0
- package/dist/parquet-loader-types.d.ts.map +1 -0
- package/dist/parquet-loader-types.js +17 -0
- package/dist/parquet-loader-types.js.map +1 -0
- package/dist/parquet-loader.d.ts +42 -0
- package/dist/parquet-loader.d.ts.map +1 -0
- package/dist/parquet-loader.js +68 -0
- package/dist/parquet-loader.js.map +1 -0
- package/dist/parquet-source-capabilities.d.ts +43 -0
- package/dist/parquet-source-capabilities.d.ts.map +1 -0
- package/dist/parquet-source-capabilities.js +32 -0
- package/dist/parquet-source-capabilities.js.map +1 -0
- package/dist/parquet-source-loader-types.d.ts +82 -0
- package/dist/parquet-source-loader-types.d.ts.map +1 -0
- package/dist/parquet-source-loader-types.js +84 -0
- package/dist/parquet-source-loader-types.js.map +1 -0
- package/dist/parquet-source-loader.cjs +38261 -0
- package/dist/parquet-source-loader.cjs.map +6 -0
- package/dist/parquet-source-loader.d.ts +167 -0
- package/dist/parquet-source-loader.d.ts.map +1 -0
- package/dist/parquet-source-loader.js +1438 -0
- package/dist/parquet-source-loader.js.map +1 -0
- package/dist/parquet-source-types.d.ts +534 -0
- package/dist/parquet-source-types.d.ts.map +1 -0
- package/dist/parquet-source-types.js +5 -0
- package/dist/parquet-source-types.js.map +1 -0
- package/dist/parquet-source-worker-factory.d.ts +4 -0
- package/dist/parquet-source-worker-factory.d.ts.map +1 -0
- package/dist/parquet-source-worker-factory.js +6 -0
- package/dist/parquet-source-worker-factory.js.map +1 -0
- package/dist/parquet-source-worker-url.d.ts +3 -0
- package/dist/parquet-source-worker-url.d.ts.map +1 -0
- package/dist/parquet-source-worker-url.js +22 -0
- package/dist/parquet-source-worker-url.js.map +1 -0
- package/dist/parquet-source-worker.js +38871 -0
- package/dist/parquet-source-worker.js.map +7 -0
- package/dist/parquet-worker-node.cjs +78507 -0
- package/dist/parquet-worker-node.cjs.map +7 -0
- package/dist/parquet-worker-url.d.ts +3 -0
- package/dist/parquet-worker-url.d.ts.map +1 -0
- package/dist/parquet-worker-url.js +19 -0
- package/dist/parquet-worker-url.js.map +1 -0
- package/dist/parquet-worker.js +20094 -0
- package/dist/parquet-worker.js.map +7 -0
- package/dist/parquet-writer.d.ts +10 -0
- package/dist/parquet-writer.d.ts.map +1 -0
- package/dist/parquet-writer.js +27 -0
- package/dist/parquet-writer.js.map +1 -0
- package/dist/parquet_wasm_bg.wasm +0 -0
- package/dist/parquetjs/codecs/byte-stream-split.d.ts +9 -0
- package/dist/parquetjs/codecs/byte-stream-split.d.ts.map +1 -0
- package/dist/parquetjs/codecs/byte-stream-split.js +159 -0
- package/dist/parquetjs/codecs/byte-stream-split.js.map +1 -0
- package/dist/parquetjs/codecs/declare.d.ts +35 -3
- package/dist/parquetjs/codecs/declare.d.ts.map +1 -1
- package/dist/parquetjs/codecs/declare.js +17 -1
- package/dist/parquetjs/codecs/declare.js.map +1 -1
- package/dist/parquetjs/codecs/delta.d.ts +17 -0
- package/dist/parquetjs/codecs/delta.d.ts.map +1 -0
- package/dist/parquetjs/codecs/delta.js +788 -0
- package/dist/parquetjs/codecs/delta.js.map +1 -0
- package/dist/parquetjs/codecs/dictionary.d.ts +5 -2
- package/dist/parquetjs/codecs/dictionary.d.ts.map +1 -1
- package/dist/parquetjs/codecs/dictionary.js +16 -4
- package/dist/parquetjs/codecs/dictionary.js.map +1 -1
- package/dist/parquetjs/codecs/index.d.ts.map +1 -1
- package/dist/parquetjs/codecs/index.js +22 -0
- package/dist/parquetjs/codecs/index.js.map +1 -1
- package/dist/parquetjs/codecs/plain.d.ts +3 -3
- package/dist/parquetjs/codecs/plain.d.ts.map +1 -1
- package/dist/parquetjs/codecs/plain.js +231 -78
- package/dist/parquetjs/codecs/plain.js.map +1 -1
- package/dist/parquetjs/codecs/rle.d.ts +7 -3
- package/dist/parquetjs/codecs/rle.d.ts.map +1 -1
- package/dist/parquetjs/codecs/rle.js +613 -69
- package/dist/parquetjs/codecs/rle.js.map +1 -1
- package/dist/parquetjs/compression.d.ts +16 -8
- package/dist/parquetjs/compression.d.ts.map +1 -1
- package/dist/parquetjs/compression.js +114 -141
- package/dist/parquetjs/compression.js.map +1 -1
- package/dist/parquetjs/encoder/dictionary-planner.d.ts +17 -0
- package/dist/parquetjs/encoder/dictionary-planner.d.ts.map +1 -0
- package/dist/parquetjs/encoder/dictionary-planner.js +67 -0
- package/dist/parquetjs/encoder/dictionary-planner.js.map +1 -0
- package/dist/parquetjs/encoder/page-planner.d.ts +11 -0
- package/dist/parquetjs/encoder/page-planner.d.ts.map +1 -0
- package/dist/parquetjs/encoder/page-planner.js +60 -0
- package/dist/parquetjs/encoder/page-planner.js.map +1 -0
- package/dist/parquetjs/encoder/parquet-encoder.d.ts +54 -5
- package/dist/parquetjs/encoder/parquet-encoder.d.ts.map +1 -1
- package/dist/parquetjs/encoder/parquet-encoder.js +930 -66
- package/dist/parquetjs/encoder/parquet-encoder.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/BoundingBox.d.ts +29 -0
- package/dist/parquetjs/parquet-thrift/BoundingBox.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/BoundingBox.js +85 -0
- package/dist/parquetjs/parquet-thrift/BoundingBox.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/BsonType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/BsonType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/BsonType.js +1 -1
- package/dist/parquetjs/parquet-thrift/BsonType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnChunk.d.ts +7 -2
- package/dist/parquetjs/parquet-thrift/ColumnChunk.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnChunk.js +37 -2
- package/dist/parquetjs/parquet-thrift/ColumnChunk.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.d.ts +35 -0
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.js +135 -0
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/ColumnIndex.d.ts +6 -6
- package/dist/parquetjs/parquet-thrift/ColumnIndex.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnIndex.js +3 -3
- package/dist/parquetjs/parquet-thrift/ColumnIndex.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.d.ts +12 -2
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.js +75 -2
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnOrder.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnOrder.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnOrder.js +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnOrder.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeader.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeader.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeader.js +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeader.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeaderV2.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeaderV2.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeaderV2.js +1 -1
- package/dist/parquetjs/parquet-thrift/DataPageHeaderV2.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/DateType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/DateType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/DateType.js +1 -1
- package/dist/parquetjs/parquet-thrift/DateType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/DecimalType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/DecimalType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/DecimalType.js +1 -1
- package/dist/parquetjs/parquet-thrift/DecimalType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/DictionaryPageHeader.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/DictionaryPageHeader.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/DictionaryPageHeader.js +1 -1
- package/dist/parquetjs/parquet-thrift/DictionaryPageHeader.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/EdgeInterpolationAlgorithm.d.ts +8 -0
- package/dist/parquetjs/parquet-thrift/EdgeInterpolationAlgorithm.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/EdgeInterpolationAlgorithm.js +14 -0
- package/dist/parquetjs/parquet-thrift/EdgeInterpolationAlgorithm.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/Encoding.d.ts +2 -1
- package/dist/parquetjs/parquet-thrift/Encoding.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/Encoding.js +1 -0
- package/dist/parquetjs/parquet-thrift/Encoding.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.d.ts +22 -0
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.js +111 -0
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/EnumType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/EnumType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/EnumType.js +1 -1
- package/dist/parquetjs/parquet-thrift/EnumType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.d.ts +16 -0
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.js +57 -0
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/FileMetaData.d.ts +7 -2
- package/dist/parquetjs/parquet-thrift/FileMetaData.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/FileMetaData.js +37 -2
- package/dist/parquetjs/parquet-thrift/FileMetaData.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/Float16Type.d.ts +9 -0
- package/dist/parquetjs/parquet-thrift/Float16Type.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/Float16Type.js +27 -0
- package/dist/parquetjs/parquet-thrift/Float16Type.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/GeographyType.d.ts +14 -0
- package/dist/parquetjs/parquet-thrift/GeographyType.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/GeographyType.js +51 -0
- package/dist/parquetjs/parquet-thrift/GeographyType.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/GeometryType.d.ts +11 -0
- package/dist/parquetjs/parquet-thrift/GeometryType.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/GeometryType.js +41 -0
- package/dist/parquetjs/parquet-thrift/GeometryType.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.d.ts +18 -0
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.js +62 -0
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/IndexPageHeader.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/IndexPageHeader.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/IndexPageHeader.js +1 -1
- package/dist/parquetjs/parquet-thrift/IndexPageHeader.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/IntType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/IntType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/IntType.js +1 -1
- package/dist/parquetjs/parquet-thrift/IntType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/JsonType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/JsonType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/JsonType.js +1 -1
- package/dist/parquetjs/parquet-thrift/JsonType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/KeyValue.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/KeyValue.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/KeyValue.js +1 -1
- package/dist/parquetjs/parquet-thrift/KeyValue.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/ListType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/ListType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ListType.js +1 -1
- package/dist/parquetjs/parquet-thrift/ListType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/LogicalType.d.ts +17 -1
- package/dist/parquetjs/parquet-thrift/LogicalType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/LogicalType.js +97 -1
- package/dist/parquetjs/parquet-thrift/LogicalType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/MapType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/MapType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/MapType.js +1 -1
- package/dist/parquetjs/parquet-thrift/MapType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/MicroSeconds.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/MicroSeconds.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/MicroSeconds.js +1 -1
- package/dist/parquetjs/parquet-thrift/MicroSeconds.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/MilliSeconds.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/MilliSeconds.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/MilliSeconds.js +1 -1
- package/dist/parquetjs/parquet-thrift/MilliSeconds.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/NanoSeconds.d.ts +9 -0
- package/dist/parquetjs/parquet-thrift/NanoSeconds.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/NanoSeconds.js +27 -0
- package/dist/parquetjs/parquet-thrift/NanoSeconds.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/NullType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/NullType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/NullType.js +1 -1
- package/dist/parquetjs/parquet-thrift/NullType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/OffsetIndex.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/OffsetIndex.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/OffsetIndex.js +1 -1
- package/dist/parquetjs/parquet-thrift/OffsetIndex.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/PageEncodingStats.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/PageEncodingStats.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/PageEncodingStats.js +1 -1
- package/dist/parquetjs/parquet-thrift/PageEncodingStats.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/PageHeader.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/PageHeader.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/PageHeader.js +1 -1
- package/dist/parquetjs/parquet-thrift/PageHeader.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/PageLocation.d.ts +2 -2
- package/dist/parquetjs/parquet-thrift/PageLocation.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/PageLocation.js +2 -2
- package/dist/parquetjs/parquet-thrift/PageLocation.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/RowGroup.d.ts +2 -2
- package/dist/parquetjs/parquet-thrift/RowGroup.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/RowGroup.js +2 -2
- package/dist/parquetjs/parquet-thrift/RowGroup.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/SchemaElement.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/SchemaElement.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/SchemaElement.js +1 -1
- package/dist/parquetjs/parquet-thrift/SchemaElement.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/SizeStatistics.d.ts +26 -0
- package/dist/parquetjs/parquet-thrift/SizeStatistics.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/SizeStatistics.js +85 -0
- package/dist/parquetjs/parquet-thrift/SizeStatistics.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/SortingColumn.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/SortingColumn.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/SortingColumn.js +1 -1
- package/dist/parquetjs/parquet-thrift/SortingColumn.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/Statistics.d.ts +14 -10
- package/dist/parquetjs/parquet-thrift/Statistics.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/Statistics.js +38 -2
- package/dist/parquetjs/parquet-thrift/Statistics.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/StringType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/StringType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/StringType.js +1 -1
- package/dist/parquetjs/parquet-thrift/StringType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/TimeType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/TimeType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/TimeType.js +1 -1
- package/dist/parquetjs/parquet-thrift/TimeType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/TimeUnit.d.ts +5 -1
- package/dist/parquetjs/parquet-thrift/TimeUnit.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/TimeUnit.js +25 -1
- package/dist/parquetjs/parquet-thrift/TimeUnit.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/TimestampType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/TimestampType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/TimestampType.js +1 -1
- package/dist/parquetjs/parquet-thrift/TimestampType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/TypeDefinedOrder.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/TypeDefinedOrder.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/TypeDefinedOrder.js +1 -1
- package/dist/parquetjs/parquet-thrift/TypeDefinedOrder.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/UUIDType.d.ts +1 -1
- package/dist/parquetjs/parquet-thrift/UUIDType.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/UUIDType.js +1 -1
- package/dist/parquetjs/parquet-thrift/UUIDType.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/VariantType.d.ts +11 -0
- package/dist/parquetjs/parquet-thrift/VariantType.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/VariantType.js +41 -0
- package/dist/parquetjs/parquet-thrift/VariantType.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/index.d.ts +12 -2
- package/dist/parquetjs/parquet-thrift/index.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/index.js +12 -2
- package/dist/parquetjs/parquet-thrift/index.js.map +1 -1
- package/dist/parquetjs/parser/decoders.d.ts +23 -3
- package/dist/parquetjs/parser/decoders.d.ts.map +1 -1
- package/dist/parquetjs/parser/decoders.js +687 -119
- package/dist/parquetjs/parser/decoders.js.map +1 -1
- package/dist/parquetjs/parser/encoded-pages.d.ts +24 -0
- package/dist/parquetjs/parser/encoded-pages.d.ts.map +1 -0
- package/dist/parquetjs/parser/encoded-pages.js +206 -0
- package/dist/parquetjs/parser/encoded-pages.js.map +1 -0
- package/dist/parquetjs/parser/parquet-reader.d.ts +111 -10
- package/dist/parquetjs/parser/parquet-reader.d.ts.map +1 -1
- package/dist/parquetjs/parser/parquet-reader.js +836 -69
- package/dist/parquetjs/parser/parquet-reader.js.map +1 -1
- package/dist/parquetjs/schema/declare.d.ts +83 -10
- package/dist/parquetjs/schema/declare.d.ts.map +1 -1
- package/dist/parquetjs/schema/declare.js.map +1 -1
- package/dist/parquetjs/schema/schema.d.ts +3 -0
- package/dist/parquetjs/schema/schema.d.ts.map +1 -1
- package/dist/parquetjs/schema/schema.js +31 -3
- package/dist/parquetjs/schema/schema.js.map +1 -1
- package/dist/parquetjs/schema/shred.d.ts +2 -0
- package/dist/parquetjs/schema/shred.d.ts.map +1 -1
- package/dist/parquetjs/schema/shred.js +285 -29
- package/dist/parquetjs/schema/shred.js.map +1 -1
- package/dist/parquetjs/schema/types.d.ts.map +1 -1
- package/dist/parquetjs/schema/types.js +290 -71
- package/dist/parquetjs/schema/types.js.map +1 -1
- package/dist/parquetjs/schema/variant.d.ts +3 -0
- package/dist/parquetjs/schema/variant.d.ts.map +1 -0
- package/dist/parquetjs/schema/variant.js +248 -0
- package/dist/parquetjs/schema/variant.js.map +1 -0
- package/dist/parquetjs/utils/binary-utils.d.ts +41 -0
- package/dist/parquetjs/utils/binary-utils.d.ts.map +1 -0
- package/dist/parquetjs/utils/binary-utils.js +106 -0
- package/dist/parquetjs/utils/binary-utils.js.map +1 -0
- package/dist/parquetjs/utils/crc32.d.ts +3 -0
- package/dist/parquetjs/utils/crc32.d.ts.map +1 -0
- package/dist/parquetjs/utils/crc32.js +15 -0
- package/dist/parquetjs/utils/crc32.js.map +1 -0
- package/dist/parquetjs/utils/file-utils.d.ts +1 -1
- package/dist/parquetjs/utils/file-utils.d.ts.map +1 -1
- package/dist/parquetjs/utils/file-utils.js +3 -3
- package/dist/parquetjs/utils/file-utils.js.map +1 -1
- package/dist/parquetjs/utils/read-utils.d.ts +25 -7
- package/dist/parquetjs/utils/read-utils.d.ts.map +1 -1
- package/dist/parquetjs/utils/read-utils.js +66 -39
- package/dist/parquetjs/utils/read-utils.js.map +1 -1
- package/dist/parquetjs/utils/thrift-runtime.d.ts +106 -0
- package/dist/parquetjs/utils/thrift-runtime.d.ts.map +1 -0
- package/dist/parquetjs/utils/thrift-runtime.js +50 -0
- package/dist/parquetjs/utils/thrift-runtime.js.map +1 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol-writer.d.ts +78 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol-writer.d.ts.map +1 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol-writer.js +213 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol-writer.js.map +1 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol.d.ts +80 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol.d.ts.map +1 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol.js +276 -0
- package/dist/parquetjs/utils/uint8-array-compact-protocol.js.map +1 -0
- package/dist/parquetjs/utils/uint8-array-transport.d.ts +25 -0
- package/dist/parquetjs/utils/uint8-array-transport.d.ts.map +1 -0
- package/dist/parquetjs/utils/uint8-array-transport.js +62 -0
- package/dist/parquetjs/utils/uint8-array-transport.js.map +1 -0
- package/dist/polyfills/process.d.ts +12 -0
- package/dist/polyfills/process.d.ts.map +1 -0
- package/dist/polyfills/process.js +17 -0
- package/dist/polyfills/process.js.map +1 -0
- package/dist/unbundled.d.ts +10 -0
- package/dist/unbundled.d.ts.map +1 -0
- package/dist/unbundled.js +11 -0
- package/dist/unbundled.js.map +1 -0
- package/dist/wasm.d.ts +3 -0
- package/dist/wasm.d.ts.map +1 -0
- package/dist/wasm.js +6 -0
- package/dist/wasm.js.map +1 -0
- package/dist/workers/parquet-source-worker.d.ts +2 -0
- package/dist/workers/parquet-source-worker.d.ts.map +1 -0
- package/dist/workers/parquet-source-worker.js +17 -0
- package/dist/workers/parquet-source-worker.js.map +1 -0
- package/dist/workers/parquet-worker-node.d.ts +2 -0
- package/dist/workers/parquet-worker-node.d.ts.map +1 -0
- package/dist/workers/parquet-worker-node.js +5 -0
- package/dist/workers/parquet-worker-node.js.map +1 -0
- package/dist/workers/parquet-worker.d.ts +2 -0
- package/dist/workers/parquet-worker.d.ts.map +1 -0
- package/dist/workers/parquet-worker.js +27 -0
- package/dist/workers/parquet-worker.js.map +1 -0
- package/package.json +84 -40
- package/src/bundled.ts +43 -0
- package/src/delta-format.ts +12 -0
- package/src/delta-source-loader-types.ts +40 -0
- package/src/delta-source.ts +305 -0
- package/src/delta-types.ts +40 -0
- package/src/geoparquet-loader-with-parser.ts +95 -0
- package/src/geoparquet-loader.ts +54 -0
- package/src/iceberg-rest-catalog.ts +122 -0
- package/src/iceberg-table-source.ts +1037 -0
- package/src/iceberg-types.ts +165 -0
- package/src/index.ts +105 -26
- package/src/lib/arrow/convert-columns-to-row-group.ts +3 -0
- package/src/lib/arrow/convert-schema-from-parquet.ts +193 -32
- package/src/lib/arrow/convert-schema-to-parquet.ts +16 -7
- package/src/lib/arrow/create-nested-arrow-vector.ts +705 -0
- package/src/lib/constants.ts +0 -2
- package/src/lib/encoders/encode-arrow-to-parquet.ts +10 -16
- package/src/lib/encoders/encode-table-to-parquet-js.ts +526 -0
- package/src/lib/geo/geoparquet-covering.ts +201 -0
- package/src/lib/geo/geospatial-metadata.ts +547 -0
- package/src/lib/parquet-bloom-filter-planner.ts +86 -0
- package/src/lib/parquet-bloom-filter.ts +345 -0
- package/src/lib/parquet-encryption.ts +344 -0
- package/src/lib/parquet-page-index.ts +727 -0
- package/src/lib/parquet-predicate.ts +410 -0
- package/src/lib/parquet-source-worker-client.ts +41 -0
- package/src/lib/parquet-source-worker-decoder.ts +252 -0
- package/src/lib/parquet-source-worker-file.ts +56 -0
- package/src/lib/parquet-source-worker-types.ts +132 -0
- package/src/lib/parquet-worker-transport.ts +57 -0
- package/src/lib/parsers/convert-parquet-tables.ts +39 -0
- package/src/lib/parsers/get-parquet-schema.ts +6 -2
- package/src/lib/parsers/parse-geoparquet-to-geojson.ts +27 -14
- package/src/lib/parsers/parse-parquet-tables.ts +82 -0
- package/src/lib/parsers/parse-parquet-to-arrow-js.ts +1213 -0
- package/src/lib/parsers/parse-parquet-to-arrow.ts +62 -36
- package/src/lib/parsers/parse-parquet-to-columns.ts +9 -8
- package/src/lib/parsers/parse-parquet-to-json.ts +119 -35
- package/src/lib/slice-parquet-batch.ts +32 -0
- package/src/lib/sources/parquet-range-file.ts +365 -0
- package/src/lib/sources/single-batch-queue.ts +95 -0
- package/src/lib/utils/load-wasm-node.ts +25 -0
- package/src/lib/utils/load-wasm.ts +36 -13
- package/src/lib/utils/make-stream-iterator.ts +126 -14
- package/src/lib/utils/normalize-parquet-options.ts +30 -0
- package/src/parquet-dataset-source.ts +800 -0
- package/src/parquet-encoded-page-types.ts +122 -0
- package/src/parquet-format.ts +2 -0
- package/src/parquet-js-loader-types.ts +53 -0
- package/src/parquet-js-loader.ts +76 -19
- package/src/parquet-js-writer.ts +98 -0
- package/src/parquet-loader-base.ts +34 -0
- package/src/parquet-loader-options.ts +62 -0
- package/src/parquet-loader-types.ts +35 -0
- package/src/parquet-loader.ts +115 -0
- package/src/parquet-source-capabilities.ts +73 -0
- package/src/parquet-source-loader-types.ts +97 -0
- package/src/parquet-source-loader.ts +2254 -0
- package/src/parquet-source-types.ts +627 -0
- package/src/parquet-source-worker-factory.ts +8 -0
- package/src/parquet-source-worker-url.ts +23 -0
- package/src/parquet-worker-url.ts +23 -0
- package/src/parquet-writer.ts +42 -0
- package/src/parquetjs/LICENSE +23 -1
- package/src/parquetjs/codecs/byte-stream-split.ts +221 -0
- package/src/parquetjs/codecs/declare.ts +62 -3
- package/src/parquetjs/codecs/delta.ts +1047 -0
- package/src/parquetjs/codecs/dictionary.ts +22 -4
- package/src/parquetjs/codecs/index.ts +22 -0
- package/src/parquetjs/codecs/plain.ts +317 -89
- package/src/parquetjs/codecs/rle.ts +852 -82
- package/src/parquetjs/compression.ts +137 -156
- package/src/parquetjs/encoder/dictionary-planner.ts +104 -0
- package/src/parquetjs/encoder/page-planner.ts +83 -0
- package/src/parquetjs/encoder/parquet-encoder.ts +1374 -95
- package/src/parquetjs/parquet-thrift/BoundingBox.ts +108 -0
- package/src/parquetjs/parquet-thrift/BsonType.ts +1 -1
- package/src/parquetjs/parquet-thrift/ColumnChunk.ts +37 -2
- package/src/parquetjs/parquet-thrift/ColumnCryptoMetaData.ts +139 -0
- package/src/parquetjs/parquet-thrift/ColumnIndex.ts +13 -13
- package/src/parquetjs/parquet-thrift/ColumnMetaData.ts +75 -2
- package/src/parquetjs/parquet-thrift/ColumnOrder.ts +1 -1
- package/src/parquetjs/parquet-thrift/DataPageHeader.ts +1 -1
- package/src/parquetjs/parquet-thrift/DataPageHeaderV2.ts +1 -1
- package/src/parquetjs/parquet-thrift/DateType.ts +1 -1
- package/src/parquetjs/parquet-thrift/DecimalType.ts +1 -1
- package/src/parquetjs/parquet-thrift/DictionaryPageHeader.ts +1 -1
- package/src/parquetjs/parquet-thrift/EdgeInterpolationAlgorithm.ts +13 -0
- package/src/parquetjs/parquet-thrift/Encoding.ts +2 -1
- package/src/parquetjs/parquet-thrift/EncryptionAlgorithm.ts +127 -0
- package/src/parquetjs/parquet-thrift/EnumType.ts +1 -1
- package/src/parquetjs/parquet-thrift/FileCryptoMetaData.ts +60 -0
- package/src/parquetjs/parquet-thrift/FileMetaData.ts +37 -2
- package/src/parquetjs/parquet-thrift/Float16Type.ts +28 -0
- package/src/parquetjs/parquet-thrift/GeographyType.ts +54 -0
- package/src/parquetjs/parquet-thrift/GeometryType.ts +43 -0
- package/src/parquetjs/parquet-thrift/GeospatialStatistics.ts +68 -0
- package/src/parquetjs/parquet-thrift/IndexPageHeader.ts +1 -1
- package/src/parquetjs/parquet-thrift/IntType.ts +1 -1
- package/src/parquetjs/parquet-thrift/JsonType.ts +1 -1
- package/src/parquetjs/parquet-thrift/KeyValue.ts +1 -1
- package/src/parquetjs/parquet-thrift/ListType.ts +1 -1
- package/src/parquetjs/parquet-thrift/LogicalType.ts +97 -1
- package/src/parquetjs/parquet-thrift/MapType.ts +1 -1
- package/src/parquetjs/parquet-thrift/MicroSeconds.ts +1 -1
- package/src/parquetjs/parquet-thrift/MilliSeconds.ts +1 -1
- package/src/parquetjs/parquet-thrift/NanoSeconds.ts +28 -0
- package/src/parquetjs/parquet-thrift/NullType.ts +1 -1
- package/src/parquetjs/parquet-thrift/OffsetIndex.ts +1 -1
- package/src/parquetjs/parquet-thrift/PageEncodingStats.ts +1 -1
- package/src/parquetjs/parquet-thrift/PageHeader.ts +1 -1
- package/src/parquetjs/parquet-thrift/PageLocation.ts +2 -2
- package/src/parquetjs/parquet-thrift/RowGroup.ts +2 -2
- package/src/parquetjs/parquet-thrift/SchemaElement.ts +1 -1
- package/src/parquetjs/parquet-thrift/SizeStatistics.ts +98 -0
- package/src/parquetjs/parquet-thrift/SortingColumn.ts +1 -1
- package/src/parquetjs/parquet-thrift/Statistics.ts +50 -14
- package/src/parquetjs/parquet-thrift/StringType.ts +1 -1
- package/src/parquetjs/parquet-thrift/TimeType.ts +1 -1
- package/src/parquetjs/parquet-thrift/TimeUnit.ts +25 -1
- package/src/parquetjs/parquet-thrift/TimestampType.ts +1 -1
- package/src/parquetjs/parquet-thrift/TypeDefinedOrder.ts +1 -1
- package/src/parquetjs/parquet-thrift/UUIDType.ts +1 -1
- package/src/parquetjs/parquet-thrift/VariantType.ts +43 -0
- package/src/parquetjs/parquet-thrift/index.ts +12 -4
- package/src/parquetjs/parser/decoders.ts +922 -143
- package/src/parquetjs/parser/encoded-pages.ts +278 -0
- package/src/parquetjs/parser/parquet-reader.ts +1334 -83
- package/src/parquetjs/schema/declare.ts +121 -9
- package/src/parquetjs/schema/schema.ts +33 -3
- package/src/parquetjs/schema/shred.ts +345 -41
- package/src/parquetjs/schema/types.ts +308 -84
- package/src/parquetjs/schema/variant.ts +313 -0
- package/src/parquetjs/utils/binary-utils.ts +132 -0
- package/src/parquetjs/utils/crc32.ts +15 -0
- package/src/parquetjs/utils/file-utils.ts +4 -4
- package/src/parquetjs/utils/read-utils.ts +77 -51
- package/src/parquetjs/utils/thrift-runtime.ts +109 -0
- package/src/parquetjs/utils/uint8-array-compact-protocol-writer.ts +254 -0
- package/src/parquetjs/utils/uint8-array-compact-protocol.ts +322 -0
- package/src/parquetjs/utils/uint8-array-transport.ts +79 -0
- package/src/polyfills/process.ts +17 -0
- package/src/unbundled.ts +47 -0
- package/src/wasm.ts +6 -0
- package/src/workers/parquet-source-worker.ts +21 -0
- package/src/workers/parquet-worker-node.ts +5 -0
- package/src/workers/parquet-worker.ts +31 -0
- package/dist/parquet-arrow-loader.d.ts +0 -43
- package/dist/parquet-arrow-loader.d.ts.map +0 -1
- package/dist/parquet-arrow-loader.js +0 -49
- package/dist/parquet-arrow-loader.js.map +0 -1
- package/dist/parquet-arrow-writer.d.ts +0 -9
- package/dist/parquet-arrow-writer.d.ts.map +0 -1
- package/dist/parquet-arrow-writer.js +0 -23
- package/dist/parquet-arrow-writer.js.map +0 -1
- package/dist/parquet-json-loader.d.ts +0 -148
- package/dist/parquet-json-loader.d.ts.map +0 -1
- package/dist/parquet-json-loader.js +0 -106
- package/dist/parquet-json-loader.js.map +0 -1
- package/dist/parquet-json-writer.d.ts +0 -19
- package/dist/parquet-json-writer.d.ts.map +0 -1
- package/dist/parquet-json-writer.js +0 -20
- package/dist/parquet-json-writer.js.map +0 -1
- package/dist/polyfills/buffer/buffer-polyfill.browser.d.ts +0 -3
- package/dist/polyfills/buffer/buffer-polyfill.browser.d.ts.map +0 -1
- package/dist/polyfills/buffer/buffer-polyfill.browser.js +0 -12
- package/dist/polyfills/buffer/buffer-polyfill.browser.js.map +0 -1
- package/dist/polyfills/buffer/buffer-polyfill.node.d.ts +0 -3
- package/dist/polyfills/buffer/buffer-polyfill.node.d.ts.map +0 -1
- package/dist/polyfills/buffer/buffer-polyfill.node.js +0 -17
- package/dist/polyfills/buffer/buffer-polyfill.node.js.map +0 -1
- package/dist/polyfills/buffer/buffer.d.ts +0 -222
- package/dist/polyfills/buffer/buffer.d.ts.map +0 -1
- package/dist/polyfills/buffer/buffer.js +0 -1868
- package/dist/polyfills/buffer/buffer.js.map +0 -1
- package/dist/polyfills/buffer/index.d.ts +0 -4
- package/dist/polyfills/buffer/index.d.ts.map +0 -1
- package/dist/polyfills/buffer/index.js +0 -9
- package/dist/polyfills/buffer/index.js.map +0 -1
- package/dist/polyfills/buffer/install-buffer-polyfill.d.ts +0 -2
- package/dist/polyfills/buffer/install-buffer-polyfill.d.ts.map +0 -1
- package/dist/polyfills/buffer/install-buffer-polyfill.js +0 -10
- package/dist/polyfills/buffer/install-buffer-polyfill.js.map +0 -1
- package/dist/workers/parquet-json-worker.d.ts +0 -2
- package/dist/workers/parquet-json-worker.d.ts.map +0 -1
- package/dist/workers/parquet-json-worker.js +0 -7
- package/dist/workers/parquet-json-worker.js.map +0 -1
- package/src/parquet-arrow-loader.ts +0 -74
- package/src/parquet-arrow-writer.ts +0 -33
- package/src/parquet-json-loader.ts +0 -160
- package/src/parquet-json-writer.ts +0 -27
- package/src/parquetjs/modules.d.ts +0 -25
- package/src/polyfills/buffer/buffer-polyfill.browser.ts +0 -14
- package/src/polyfills/buffer/buffer-polyfill.node.ts +0 -19
- package/src/polyfills/buffer/buffer.ts +0 -2205
- package/src/polyfills/buffer/index.ts +0 -11
- package/src/polyfills/buffer/install-buffer-polyfill.ts +0 -12
- package/src/workers/parquet-json-worker.ts +0 -8
|
@@ -3,17 +3,31 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
// Copyright (c) 2017 ironSource Ltd.
|
|
5
5
|
// Forked from https://github.com/kbajalc/parquets under MIT license
|
|
6
|
+
import { getWKBGeometryStatistics } from '@loaders.gl/gis';
|
|
6
7
|
import { PARQUET_CODECS } from "../codecs/index.js";
|
|
7
8
|
import * as Compression from "../compression.js";
|
|
8
9
|
import * as Shred from "../schema/shred.js";
|
|
9
|
-
import { ColumnChunk, ColumnMetaData, CompressionCodec, ConvertedType, DataPageHeader, DataPageHeaderV2, Encoding, FieldRepetitionType, FileMetaData, KeyValue, PageHeader, PageType, RowGroup, SchemaElement, Type } from "../parquet-thrift/index.js";
|
|
10
|
+
import { BsonType, BoundingBox, ColumnChunk, ColumnCryptoMetaData, ColumnIndex, ColumnMetaData, SizeStatistics, Statistics, SortingColumn, CompressionCodec, ConvertedType, DataPageHeader, DataPageHeaderV2, DateType, DecimalType, DictionaryPageHeader, EdgeInterpolationAlgorithm, Encoding, EnumType, FieldRepetitionType, FileMetaData, Float16Type, GeographyType, GeospatialStatistics, GeometryType, IntType, JsonType, KeyValue, ListType, LogicalType, MapType, MicroSeconds, MilliSeconds, NanoSeconds, NullType, PageHeader, PageEncodingStats, PageType, PageLocation, RowGroup, SchemaElement, StringType, TimeType, TimeUnit, TimestampType, Type, UUIDType, VariantType, OffsetIndex } from "../parquet-thrift/index.js";
|
|
10
11
|
import { osopen, oswrite, osclose } from "../utils/file-utils.js";
|
|
11
12
|
import { getBitWidth, serializeThrift } from "../utils/read-utils.js";
|
|
12
|
-
import
|
|
13
|
+
import { concatUint8Arrays, encodeUtf8, writeUInt32LE } from "../utils/binary-utils.js";
|
|
14
|
+
import { crc32 } from "../utils/crc32.js";
|
|
15
|
+
import { CompactInt64 } from "../utils/uint8-array-compact-protocol.js";
|
|
16
|
+
import { planColumnPages } from "./page-planner.js";
|
|
17
|
+
import { planDictionary } from "./dictionary-planner.js";
|
|
18
|
+
import { decodeParquetSplitBlockBloomFilter, encodeParquetBloomFilterValue, encodeParquetSplitBlockBloomFilter } from "../../lib/parquet-bloom-filter.js";
|
|
19
|
+
import { BoundaryOrder } from "../parquet-thrift/BoundaryOrder.js";
|
|
20
|
+
import { EncryptionWithColumnKey, EncryptionWithFooterKey } from "../parquet-thrift/ColumnCryptoMetaData.js";
|
|
21
|
+
import { EncryptionAlgorithm } from "../parquet-thrift/EncryptionAlgorithm.js";
|
|
22
|
+
import { FileCryptoMetaData } from "../parquet-thrift/FileCryptoMetaData.js";
|
|
23
|
+
import { PARQUET_MAGIC_ENCRYPTED } from "../../lib/constants.js";
|
|
24
|
+
import { createParquetModuleAad, createParquetFooterSignature, encryptParquetModule } from "../../lib/parquet-encryption.js";
|
|
13
25
|
/**
|
|
14
26
|
* Parquet File Magic String
|
|
15
27
|
*/
|
|
16
28
|
const PARQUET_MAGIC = 'PAR1';
|
|
29
|
+
const PARQUET_MAGIC_BYTES = encodeUtf8(PARQUET_MAGIC);
|
|
30
|
+
const PARQUET_MAGIC_ENCRYPTED_BYTES = encodeUtf8(PARQUET_MAGIC_ENCRYPTED);
|
|
17
31
|
/**
|
|
18
32
|
* Parquet File Format Version
|
|
19
33
|
*/
|
|
@@ -63,8 +77,7 @@ export class ParquetEncoder {
|
|
|
63
77
|
constructor(schema, envelopeWriter, opts) {
|
|
64
78
|
this.schema = schema;
|
|
65
79
|
this.envelopeWriter = envelopeWriter;
|
|
66
|
-
|
|
67
|
-
this.rowBuffer = {};
|
|
80
|
+
this.rowBuffer = schema.rowGroup();
|
|
68
81
|
this.rowGroupSize = opts.rowGroupSize || PARQUET_DEFAULT_ROW_GROUP_SIZE;
|
|
69
82
|
this.closed = false;
|
|
70
83
|
this.userMetadata = {};
|
|
@@ -91,8 +104,8 @@ export class ParquetEncoder {
|
|
|
91
104
|
}
|
|
92
105
|
Shred.shredRecord(this.schema, row, this.rowBuffer);
|
|
93
106
|
if (this.rowBuffer.rowCount >= this.rowGroupSize) {
|
|
94
|
-
|
|
95
|
-
this.rowBuffer =
|
|
107
|
+
await this.envelopeWriter.writeRowGroup(this.rowBuffer);
|
|
108
|
+
this.rowBuffer = this.schema.rowGroup();
|
|
96
109
|
}
|
|
97
110
|
}
|
|
98
111
|
/**
|
|
@@ -107,8 +120,8 @@ export class ParquetEncoder {
|
|
|
107
120
|
}
|
|
108
121
|
this.closed = true;
|
|
109
122
|
if (this.rowBuffer.rowCount > 0 || this.rowBuffer.rowCount >= this.rowGroupSize) {
|
|
110
|
-
|
|
111
|
-
this.rowBuffer =
|
|
123
|
+
await this.envelopeWriter.writeRowGroup(this.rowBuffer);
|
|
124
|
+
this.rowBuffer = this.schema.rowGroup();
|
|
112
125
|
}
|
|
113
126
|
await this.envelopeWriter.writeFooter(this.userMetadata);
|
|
114
127
|
await this.envelopeWriter.close();
|
|
@@ -164,6 +177,21 @@ export class ParquetEnvelopeWriter {
|
|
|
164
177
|
rowGroups;
|
|
165
178
|
pageSize;
|
|
166
179
|
useDataPageV2;
|
|
180
|
+
dictionary;
|
|
181
|
+
columnDictionaries;
|
|
182
|
+
dictionaryPageSizeLimit;
|
|
183
|
+
bloomFilter;
|
|
184
|
+
pageIndex;
|
|
185
|
+
writePageChecksums;
|
|
186
|
+
writeSizeStatistics;
|
|
187
|
+
writeStatistics;
|
|
188
|
+
sortingColumns;
|
|
189
|
+
/** Optional modular-encryption configuration for the footer. */
|
|
190
|
+
encryption;
|
|
191
|
+
/** Optional plaintext-footer signature configuration. */
|
|
192
|
+
footerSignature;
|
|
193
|
+
/** File identifier used for encrypted column-module AAD. */
|
|
194
|
+
encryptionFileUnique;
|
|
167
195
|
constructor(schema, writeFn, closeFn, fileOffset, opts) {
|
|
168
196
|
this.schema = schema;
|
|
169
197
|
this.write = writeFn;
|
|
@@ -173,6 +201,43 @@ export class ParquetEnvelopeWriter {
|
|
|
173
201
|
this.rowGroups = [];
|
|
174
202
|
this.pageSize = opts.pageSize || PARQUET_DEFAULT_PAGE_SIZE;
|
|
175
203
|
this.useDataPageV2 = 'useDataPageV2' in opts ? Boolean(opts.useDataPageV2) : false;
|
|
204
|
+
this.dictionary = opts.dictionary ?? 'auto';
|
|
205
|
+
this.columnDictionaries = opts.columnDictionaries || {};
|
|
206
|
+
this.dictionaryPageSizeLimit = opts.dictionaryPageSizeLimit ?? 1024 * 1024;
|
|
207
|
+
this.bloomFilter = opts.bloomFilter;
|
|
208
|
+
this.pageIndex = opts.pageIndex;
|
|
209
|
+
this.writePageChecksums = Boolean(opts.writePageChecksums);
|
|
210
|
+
this.writeSizeStatistics = Boolean(opts.writeSizeStatistics);
|
|
211
|
+
this.writeStatistics = opts.writeStatistics;
|
|
212
|
+
this.sortingColumns = opts.sortingColumns;
|
|
213
|
+
const encryptionFileUnique = opts.encryption?.fileUnique
|
|
214
|
+
? new Uint8Array(opts.encryption.fileUnique)
|
|
215
|
+
: undefined;
|
|
216
|
+
const footerSignatureFileUnique = opts.footerSignature?.fileUnique
|
|
217
|
+
? new Uint8Array(opts.footerSignature.fileUnique)
|
|
218
|
+
: undefined;
|
|
219
|
+
if (encryptionFileUnique &&
|
|
220
|
+
footerSignatureFileUnique &&
|
|
221
|
+
!encryptionFileUnique.every((value, index) => value === footerSignatureFileUnique[index])) {
|
|
222
|
+
throw new Error('Parquet encryption and footer signature file_unique values must match');
|
|
223
|
+
}
|
|
224
|
+
const sharedFileUnique = encryptionFileUnique ??
|
|
225
|
+
footerSignatureFileUnique ??
|
|
226
|
+
(opts.encryption || opts.footerSignature ? createFileUnique() : undefined);
|
|
227
|
+
this.encryption = opts.encryption
|
|
228
|
+
? { ...opts.encryption, fileUnique: new Uint8Array(sharedFileUnique) }
|
|
229
|
+
: undefined;
|
|
230
|
+
this.footerSignature = opts.footerSignature
|
|
231
|
+
? {
|
|
232
|
+
...opts.footerSignature,
|
|
233
|
+
keyMetadata: new Uint8Array(opts.footerSignature.keyMetadata),
|
|
234
|
+
aadPrefix: opts.footerSignature.aadPrefix
|
|
235
|
+
? new Uint8Array(opts.footerSignature.aadPrefix)
|
|
236
|
+
: undefined,
|
|
237
|
+
fileUnique: new Uint8Array(sharedFileUnique)
|
|
238
|
+
}
|
|
239
|
+
: undefined;
|
|
240
|
+
this.encryptionFileUnique = sharedFileUnique;
|
|
176
241
|
}
|
|
177
242
|
writeSection(buf) {
|
|
178
243
|
this.offset += buf.length;
|
|
@@ -182,7 +247,7 @@ export class ParquetEnvelopeWriter {
|
|
|
182
247
|
* Encode the parquet file header
|
|
183
248
|
*/
|
|
184
249
|
writeHeader() {
|
|
185
|
-
return this.writeSection(
|
|
250
|
+
return this.writeSection(this.encryption && !this.footerSignature ? PARQUET_MAGIC_ENCRYPTED_BYTES : PARQUET_MAGIC_BYTES);
|
|
186
251
|
}
|
|
187
252
|
/**
|
|
188
253
|
* Encode a parquet row group. The records object should be created using the
|
|
@@ -192,7 +257,19 @@ export class ParquetEnvelopeWriter {
|
|
|
192
257
|
const rgroup = await encodeRowGroup(this.schema, records, {
|
|
193
258
|
baseOffset: this.offset,
|
|
194
259
|
pageSize: this.pageSize,
|
|
195
|
-
useDataPageV2: this.useDataPageV2
|
|
260
|
+
useDataPageV2: this.useDataPageV2,
|
|
261
|
+
dictionary: this.dictionary,
|
|
262
|
+
columnDictionaries: this.columnDictionaries,
|
|
263
|
+
dictionaryPageSizeLimit: this.dictionaryPageSizeLimit,
|
|
264
|
+
bloomFilter: this.bloomFilter,
|
|
265
|
+
pageIndex: this.pageIndex,
|
|
266
|
+
writePageChecksums: this.writePageChecksums,
|
|
267
|
+
writeSizeStatistics: this.writeSizeStatistics,
|
|
268
|
+
writeStatistics: this.writeStatistics,
|
|
269
|
+
sortingColumns: this.sortingColumns,
|
|
270
|
+
encryption: this.encryption,
|
|
271
|
+
encryptionFileUnique: this.encryptionFileUnique,
|
|
272
|
+
rowGroupOrdinal: this.rowGroups.length
|
|
196
273
|
});
|
|
197
274
|
this.rowCount += records.rowCount;
|
|
198
275
|
this.rowGroups.push(rgroup.metadata);
|
|
@@ -201,12 +278,21 @@ export class ParquetEnvelopeWriter {
|
|
|
201
278
|
/**
|
|
202
279
|
* Write the parquet file footer
|
|
203
280
|
*/
|
|
204
|
-
writeFooter(userMetadata) {
|
|
281
|
+
async writeFooter(userMetadata) {
|
|
205
282
|
if (!userMetadata) {
|
|
206
283
|
// tslint:disable-next-line:no-parameter-reassignment
|
|
207
284
|
userMetadata = {};
|
|
208
285
|
}
|
|
209
|
-
|
|
286
|
+
if (this.footerSignature) {
|
|
287
|
+
await this.writeSection(await encodeSignedFooter(this.schema, this.rowCount, this.rowGroups, userMetadata, this.footerSignature));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const footer = encodeFooter(this.schema, this.rowCount, this.rowGroups, userMetadata);
|
|
291
|
+
if (!this.encryption) {
|
|
292
|
+
await this.writeSection(footer);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
await this.writeSection(await encodeEncryptedFooter(footer, this.encryption));
|
|
210
296
|
}
|
|
211
297
|
/**
|
|
212
298
|
* Set the parquet data page size. The data page size controls the maximum
|
|
@@ -264,16 +350,16 @@ function encodeValues(type, encoding, values, opts) {
|
|
|
264
350
|
/**
|
|
265
351
|
* Encode a parquet data page
|
|
266
352
|
*/
|
|
267
|
-
async function encodeDataPage(column, data) {
|
|
353
|
+
async function encodeDataPage(column, data, valueEncoding = column.encoding, valueBitWidth, writePageChecksums = false, statistics, int96AsTimestamp = false) {
|
|
268
354
|
/* encode repetition and definition levels */
|
|
269
|
-
let rLevelsBuf =
|
|
355
|
+
let rLevelsBuf = new Uint8Array(0);
|
|
270
356
|
if (column.rLevelMax > 0) {
|
|
271
357
|
rLevelsBuf = encodeValues(PARQUET_RDLVL_TYPE, PARQUET_RDLVL_ENCODING, data.rlevels, {
|
|
272
358
|
bitWidth: getBitWidth(column.rLevelMax)
|
|
273
359
|
// disableEnvelope: false
|
|
274
360
|
});
|
|
275
361
|
}
|
|
276
|
-
let dLevelsBuf =
|
|
362
|
+
let dLevelsBuf = new Uint8Array(0);
|
|
277
363
|
if (column.dLevelMax > 0) {
|
|
278
364
|
dLevelsBuf = encodeValues(PARQUET_RDLVL_TYPE, PARQUET_RDLVL_ENCODING, data.dlevels, {
|
|
279
365
|
bitWidth: getBitWidth(column.dLevelMax)
|
|
@@ -281,11 +367,12 @@ async function encodeDataPage(column, data) {
|
|
|
281
367
|
});
|
|
282
368
|
}
|
|
283
369
|
/* encode values */
|
|
284
|
-
const valuesBuf = encodeValues(column.primitiveType,
|
|
370
|
+
const valuesBuf = encodeValues(column.primitiveType, valueEncoding, data.values, {
|
|
285
371
|
typeLength: column.typeLength,
|
|
286
|
-
bitWidth: column.typeLength
|
|
372
|
+
bitWidth: valueBitWidth ?? column.typeLength,
|
|
373
|
+
int96AsTimestamp
|
|
287
374
|
});
|
|
288
|
-
const dataBuf =
|
|
375
|
+
const dataBuf = concatUint8Arrays([rLevelsBuf, dLevelsBuf, valuesBuf]);
|
|
289
376
|
// compression = column.compression === 'UNCOMPRESSED' ? (compression || 'UNCOMPRESSED') : column.compression;
|
|
290
377
|
const compressedBuf = await Compression.deflate(column.compression, dataBuf);
|
|
291
378
|
/* build page header */
|
|
@@ -293,38 +380,41 @@ async function encodeDataPage(column, data) {
|
|
|
293
380
|
type: PageType.DATA_PAGE,
|
|
294
381
|
data_page_header: new DataPageHeader({
|
|
295
382
|
num_values: data.count,
|
|
296
|
-
encoding: Encoding[
|
|
383
|
+
encoding: Encoding[valueEncoding],
|
|
297
384
|
definition_level_encoding: Encoding[PARQUET_RDLVL_ENCODING], // [PARQUET_RDLVL_ENCODING],
|
|
298
|
-
repetition_level_encoding: Encoding[PARQUET_RDLVL_ENCODING] // [PARQUET_RDLVL_ENCODING]
|
|
385
|
+
repetition_level_encoding: Encoding[PARQUET_RDLVL_ENCODING], // [PARQUET_RDLVL_ENCODING]
|
|
386
|
+
statistics
|
|
299
387
|
}),
|
|
300
388
|
uncompressed_page_size: dataBuf.length,
|
|
301
|
-
compressed_page_size: compressedBuf.length
|
|
389
|
+
compressed_page_size: compressedBuf.length,
|
|
390
|
+
crc: writePageChecksums ? crc32(compressedBuf) : undefined
|
|
302
391
|
});
|
|
303
392
|
/* concat page header, repetition and definition levels and values */
|
|
304
393
|
const headerBuf = serializeThrift(header);
|
|
305
|
-
const page =
|
|
394
|
+
const page = concatUint8Arrays([headerBuf, compressedBuf]);
|
|
306
395
|
return { header, headerSize: headerBuf.length, page };
|
|
307
396
|
}
|
|
308
397
|
/**
|
|
309
398
|
* Encode a parquet data page (v2)
|
|
310
399
|
*/
|
|
311
|
-
async function encodeDataPageV2(column, data, rowCount) {
|
|
400
|
+
async function encodeDataPageV2(column, data, rowCount, valueEncoding = column.encoding, valueBitWidth, writePageChecksums = false, statistics, int96AsTimestamp = false) {
|
|
312
401
|
/* encode values */
|
|
313
|
-
const valuesBuf = encodeValues(column.primitiveType,
|
|
402
|
+
const valuesBuf = encodeValues(column.primitiveType, valueEncoding, data.values, {
|
|
314
403
|
typeLength: column.typeLength,
|
|
315
|
-
bitWidth: column.typeLength
|
|
404
|
+
bitWidth: valueBitWidth ?? column.typeLength,
|
|
405
|
+
int96AsTimestamp
|
|
316
406
|
});
|
|
317
407
|
// compression = column.compression === 'UNCOMPRESSED' ? (compression || 'UNCOMPRESSED') : column.compression;
|
|
318
408
|
const compressedBuf = await Compression.deflate(column.compression, valuesBuf);
|
|
319
409
|
/* encode repetition and definition levels */
|
|
320
|
-
let rLevelsBuf =
|
|
410
|
+
let rLevelsBuf = new Uint8Array(0);
|
|
321
411
|
if (column.rLevelMax > 0) {
|
|
322
412
|
rLevelsBuf = encodeValues(PARQUET_RDLVL_TYPE, PARQUET_RDLVL_ENCODING, data.rlevels, {
|
|
323
413
|
bitWidth: getBitWidth(column.rLevelMax),
|
|
324
414
|
disableEnvelope: true
|
|
325
415
|
});
|
|
326
416
|
}
|
|
327
|
-
let dLevelsBuf =
|
|
417
|
+
let dLevelsBuf = new Uint8Array(0);
|
|
328
418
|
if (column.dLevelMax > 0) {
|
|
329
419
|
dLevelsBuf = encodeValues(PARQUET_RDLVL_TYPE, PARQUET_RDLVL_ENCODING, data.dlevels, {
|
|
330
420
|
bitWidth: getBitWidth(column.dLevelMax),
|
|
@@ -338,98 +428,677 @@ async function encodeDataPageV2(column, data, rowCount) {
|
|
|
338
428
|
num_values: data.count,
|
|
339
429
|
num_nulls: data.count - data.values.length,
|
|
340
430
|
num_rows: rowCount,
|
|
341
|
-
encoding: Encoding[
|
|
431
|
+
encoding: Encoding[valueEncoding],
|
|
342
432
|
definition_levels_byte_length: dLevelsBuf.length,
|
|
343
433
|
repetition_levels_byte_length: rLevelsBuf.length,
|
|
344
|
-
is_compressed: column.compression !== 'UNCOMPRESSED'
|
|
434
|
+
is_compressed: column.compression !== 'UNCOMPRESSED',
|
|
435
|
+
statistics
|
|
345
436
|
}),
|
|
346
437
|
uncompressed_page_size: rLevelsBuf.length + dLevelsBuf.length + valuesBuf.length,
|
|
347
|
-
compressed_page_size: rLevelsBuf.length + dLevelsBuf.length + compressedBuf.length
|
|
438
|
+
compressed_page_size: rLevelsBuf.length + dLevelsBuf.length + compressedBuf.length,
|
|
439
|
+
crc: writePageChecksums
|
|
440
|
+
? crc32(concatUint8Arrays([rLevelsBuf, dLevelsBuf, compressedBuf]))
|
|
441
|
+
: undefined
|
|
348
442
|
});
|
|
349
443
|
/* concat page header, repetition and definition levels and values */
|
|
350
444
|
const headerBuf = serializeThrift(header);
|
|
351
|
-
const page =
|
|
445
|
+
const page = concatUint8Arrays([headerBuf, rLevelsBuf, dLevelsBuf, compressedBuf]);
|
|
352
446
|
return { header, headerSize: headerBuf.length, page };
|
|
353
447
|
}
|
|
448
|
+
/** Encodes one chunk-wide PLAIN dictionary page. */
|
|
449
|
+
async function encodeDictionaryPage(column, dictionaryValues, writePageChecksums = false, int96AsTimestamp = false) {
|
|
450
|
+
const valuesBuffer = encodeValues(column.primitiveType, 'PLAIN', dictionaryValues, {
|
|
451
|
+
typeLength: column.typeLength,
|
|
452
|
+
int96AsTimestamp
|
|
453
|
+
});
|
|
454
|
+
const compressedBuffer = await Compression.deflate(column.compression, valuesBuffer);
|
|
455
|
+
const header = new PageHeader({
|
|
456
|
+
type: PageType.DICTIONARY_PAGE,
|
|
457
|
+
dictionary_page_header: new DictionaryPageHeader({
|
|
458
|
+
num_values: dictionaryValues.length,
|
|
459
|
+
encoding: Encoding.PLAIN
|
|
460
|
+
}),
|
|
461
|
+
uncompressed_page_size: valuesBuffer.length,
|
|
462
|
+
compressed_page_size: compressedBuffer.length,
|
|
463
|
+
crc: writePageChecksums ? crc32(compressedBuffer) : undefined
|
|
464
|
+
});
|
|
465
|
+
const headerBuffer = serializeThrift(header);
|
|
466
|
+
return {
|
|
467
|
+
header,
|
|
468
|
+
headerSize: headerBuffer.length,
|
|
469
|
+
page: concatUint8Arrays([headerBuffer, compressedBuffer])
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
/** Computes native Parquet geospatial statistics for a GEOMETRY or GEOGRAPHY column chunk. */
|
|
473
|
+
function createGeospatialStatistics(column, values) {
|
|
474
|
+
const logicalType = column.logicalType?.type || column.originalType;
|
|
475
|
+
if (logicalType !== 'GEOMETRY' && logicalType !== 'GEOGRAPHY')
|
|
476
|
+
return undefined;
|
|
477
|
+
const geometryTypes = new Set();
|
|
478
|
+
let bbox;
|
|
479
|
+
// Vertex bounds are not conservative for GEOGRAPHY: non-linear edge algorithms can reach
|
|
480
|
+
// extrema between vertices. Until edge-aware geodesic bounds are available, omit the bbox while
|
|
481
|
+
// retaining the useful geometry-type statistics.
|
|
482
|
+
const canWriteBoundingBox = logicalType === 'GEOMETRY';
|
|
483
|
+
for (const value of values) {
|
|
484
|
+
if (!(value instanceof ArrayBuffer) && !ArrayBuffer.isView(value)) {
|
|
485
|
+
throw new Error(`${logicalType} columns must contain WKB binary values`);
|
|
486
|
+
}
|
|
487
|
+
const statistics = getWKBGeometryStatistics(value);
|
|
488
|
+
geometryTypes.add(statistics.geometryType);
|
|
489
|
+
if (canWriteBoundingBox) {
|
|
490
|
+
bbox = mergeGeometryBoundingBoxes(bbox, statistics.bbox);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return new GeospatialStatistics({
|
|
494
|
+
bbox: bbox ? new BoundingBox(bbox) : undefined,
|
|
495
|
+
geospatial_types: [...geometryTypes].sort((left, right) => left - right)
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
/** Merges finite per-dimension bounds without inventing absent Z or M dimensions. */
|
|
499
|
+
function mergeGeometryBoundingBoxes(target, source) {
|
|
500
|
+
if (!source)
|
|
501
|
+
return target;
|
|
502
|
+
if (!target)
|
|
503
|
+
return { ...source };
|
|
504
|
+
target.xmin = Math.min(target.xmin, source.xmin);
|
|
505
|
+
target.xmax = Math.max(target.xmax, source.xmax);
|
|
506
|
+
target.ymin = Math.min(target.ymin, source.ymin);
|
|
507
|
+
target.ymax = Math.max(target.ymax, source.ymax);
|
|
508
|
+
mergeOptionalBounds(target, source, 'zmin', Math.min);
|
|
509
|
+
mergeOptionalBounds(target, source, 'zmax', Math.max);
|
|
510
|
+
mergeOptionalBounds(target, source, 'mmin', Math.min);
|
|
511
|
+
mergeOptionalBounds(target, source, 'mmax', Math.max);
|
|
512
|
+
return target;
|
|
513
|
+
}
|
|
514
|
+
/** Merges one optional bound while preserving a dimension absent from every value. */
|
|
515
|
+
function mergeOptionalBounds(target, source, key, merge) {
|
|
516
|
+
const sourceValue = source[key];
|
|
517
|
+
if (sourceValue === undefined)
|
|
518
|
+
return;
|
|
519
|
+
target[key] = target[key] === undefined ? sourceValue : merge(target[key], sourceValue);
|
|
520
|
+
}
|
|
354
521
|
/**
|
|
355
522
|
* Encode an array of values into a parquet column chunk
|
|
356
523
|
*/
|
|
357
|
-
async function encodeColumnChunk(column, buffer, offset, opts) {
|
|
524
|
+
async function encodeColumnChunk(column, buffer, offset, opts, rowGroupOrdinal, columnOrdinal) {
|
|
358
525
|
const data = buffer.columnData[column.path.join()];
|
|
359
526
|
const baseOffset = (opts.baseOffset || 0) + offset;
|
|
360
527
|
/* encode data page(s) */
|
|
361
|
-
|
|
362
|
-
|
|
528
|
+
const pageRecords = [];
|
|
529
|
+
const pageLocations = [];
|
|
363
530
|
// tslint:disable-next-line:variable-name
|
|
364
531
|
let total_uncompressed_size = 0;
|
|
365
532
|
// tslint:disable-next-line:variable-name
|
|
366
533
|
let total_compressed_size = 0;
|
|
367
|
-
|
|
534
|
+
const plannedPages = planColumnPages(column, data, buffer.rowCount, opts.pageSize || PARQUET_DEFAULT_PAGE_SIZE);
|
|
535
|
+
const dictionaryPolicy = opts.columnDictionaries?.[column.path[0]] ?? opts.dictionary ?? 'auto';
|
|
536
|
+
const dictionaryPlan = planDictionary(column, Array.from(data.values), dictionaryPolicy, opts.dictionaryPageSizeLimit ?? 1024 * 1024);
|
|
537
|
+
if (dictionaryPlan) {
|
|
538
|
+
const result = await encodeDictionaryPage(column, dictionaryPlan.values, opts.writePageChecksums, opts.int96AsTimestamp);
|
|
539
|
+
pageRecords.push({ page: result.page, headerSize: result.headerSize, dictionary: true });
|
|
540
|
+
total_uncompressed_size += result.header.uncompressed_page_size + result.headerSize;
|
|
541
|
+
total_compressed_size += result.header.compressed_page_size + result.headerSize;
|
|
542
|
+
}
|
|
543
|
+
const valueEncoding = dictionaryPlan
|
|
544
|
+
? column.encoding === 'PLAIN_DICTIONARY'
|
|
545
|
+
? 'PLAIN_DICTIONARY'
|
|
546
|
+
: 'RLE_DICTIONARY'
|
|
547
|
+
: column.encoding === 'PLAIN_DICTIONARY' || column.encoding === 'RLE_DICTIONARY'
|
|
548
|
+
? 'PLAIN'
|
|
549
|
+
: column.encoding;
|
|
550
|
+
let dictionaryIndexOffset = 0;
|
|
551
|
+
for (const plannedPage of plannedPages) {
|
|
552
|
+
const pageData = dictionaryPlan
|
|
553
|
+
? {
|
|
554
|
+
...plannedPage.data,
|
|
555
|
+
values: dictionaryPlan.indices.slice(dictionaryIndexOffset, dictionaryIndexOffset + plannedPage.data.values.length)
|
|
556
|
+
}
|
|
557
|
+
: plannedPage.data;
|
|
558
|
+
dictionaryIndexOffset += plannedPage.data.values.length;
|
|
368
559
|
const result = opts.useDataPageV2
|
|
369
|
-
? await encodeDataPageV2(column,
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
560
|
+
? await encodeDataPageV2(column, pageData, plannedPage.rowCount, valueEncoding, dictionaryPlan?.bitWidth, opts.writePageChecksums, isStatisticsEnabled(opts.writeStatistics, column)
|
|
561
|
+
? createColumnStatistics(column, plannedPage.data)
|
|
562
|
+
: undefined, opts.int96AsTimestamp)
|
|
563
|
+
: await encodeDataPage(column, pageData, valueEncoding, dictionaryPlan?.bitWidth, opts.writePageChecksums, isStatisticsEnabled(opts.writeStatistics, column)
|
|
564
|
+
? createColumnStatistics(column, plannedPage.data)
|
|
565
|
+
: undefined, opts.int96AsTimestamp);
|
|
566
|
+
pageRecords.push({ page: result.page, headerSize: result.headerSize, dictionary: false });
|
|
373
567
|
total_uncompressed_size += result.header.uncompressed_page_size + result.headerSize;
|
|
374
568
|
total_compressed_size += result.header.compressed_page_size + result.headerSize;
|
|
375
569
|
}
|
|
376
|
-
|
|
570
|
+
const encryption = opts.encryption;
|
|
571
|
+
const encryptedColumn = Boolean(encryption && shouldEncryptColumn(encryption, column));
|
|
572
|
+
const columnKeyMetadata = encryption ? getColumnKeyMetadata(encryption, column) : undefined;
|
|
573
|
+
const pages = encryptedColumn
|
|
574
|
+
? await encryptParquetColumnPages(pageRecords, encryption, opts.encryptionFileUnique, opts.rowGroupOrdinal ?? 0, columnOrdinal, columnKeyMetadata)
|
|
575
|
+
: pageRecords.map(record => record.page);
|
|
576
|
+
let pageOffset = 0;
|
|
577
|
+
let dataPageIndex = 0;
|
|
578
|
+
let firstRowIndex = 0;
|
|
579
|
+
for (const [pageIndex, page] of pages.entries()) {
|
|
580
|
+
if (!pageRecords[pageIndex].dictionary) {
|
|
581
|
+
pageLocations.push(new PageLocation({
|
|
582
|
+
offset: baseOffset + pageOffset,
|
|
583
|
+
compressed_page_size: page.length,
|
|
584
|
+
first_row_index: firstRowIndex
|
|
585
|
+
}));
|
|
586
|
+
firstRowIndex += plannedPages[dataPageIndex++].rowCount;
|
|
587
|
+
}
|
|
588
|
+
pageOffset += page.length;
|
|
589
|
+
}
|
|
590
|
+
total_compressed_size = pages.reduce((total, page) => total + page.length, 0);
|
|
591
|
+
const pagesBuf = concatUint8Arrays(pages);
|
|
377
592
|
// const compression = column.compression === 'UNCOMPRESSED' ? (opts.compression || 'UNCOMPRESSED') : column.compression;
|
|
593
|
+
const bloomFilterEnabled = opts.bloomFilter === true || opts.bloomFilter?.[column.path[0]] === true;
|
|
594
|
+
const bloomFilter = bloomFilterEnabled ? createColumnBloomFilter(column, data.values) : undefined;
|
|
595
|
+
const encodedBloomFilter = bloomFilter && encryptedColumn
|
|
596
|
+
? await encryptParquetBloomFilter(bloomFilter, encryption, opts.encryptionFileUnique, opts.rowGroupOrdinal ?? 0, columnOrdinal, columnKeyMetadata)
|
|
597
|
+
: bloomFilter;
|
|
598
|
+
const pageIndexEnabled = opts.pageIndex === true || opts.pageIndex?.[column.path[0]] === true;
|
|
599
|
+
const pageIndexes = pageIndexEnabled
|
|
600
|
+
? createColumnPageIndexes(column, plannedPages, pageLocations, opts.int96AsTimestamp)
|
|
601
|
+
: undefined;
|
|
602
|
+
const encodedPageIndexes = pageIndexes && encryptedColumn
|
|
603
|
+
? await encryptParquetPageIndexes(pageIndexes, encryption, opts.encryptionFileUnique, opts.rowGroupOrdinal ?? 0, columnOrdinal, columnKeyMetadata)
|
|
604
|
+
: pageIndexes;
|
|
378
605
|
/* prepare metadata header */
|
|
379
606
|
const metadata = new ColumnMetaData({
|
|
380
607
|
path_in_schema: column.path,
|
|
381
|
-
num_values: data.count,
|
|
382
|
-
data_page_offset: baseOffset,
|
|
608
|
+
num_values: int64(data.count),
|
|
609
|
+
data_page_offset: int64(baseOffset + (dictionaryPlan ? pages[0].length : 0)),
|
|
610
|
+
dictionary_page_offset: dictionaryPlan ? int64(baseOffset) : undefined,
|
|
383
611
|
encodings: [],
|
|
384
|
-
|
|
385
|
-
|
|
612
|
+
encoding_stats: [
|
|
613
|
+
...(dictionaryPlan
|
|
614
|
+
? [
|
|
615
|
+
new PageEncodingStats({
|
|
616
|
+
page_type: PageType.DICTIONARY_PAGE,
|
|
617
|
+
encoding: Encoding.PLAIN,
|
|
618
|
+
count: 1
|
|
619
|
+
})
|
|
620
|
+
]
|
|
621
|
+
: []),
|
|
622
|
+
new PageEncodingStats({
|
|
623
|
+
page_type: opts.useDataPageV2 ? PageType.DATA_PAGE_V2 : PageType.DATA_PAGE,
|
|
624
|
+
encoding: Encoding[valueEncoding],
|
|
625
|
+
count: plannedPages.length
|
|
626
|
+
})
|
|
627
|
+
],
|
|
628
|
+
total_uncompressed_size: int64(total_uncompressed_size), // : pagesBuf.length,
|
|
629
|
+
total_compressed_size: int64(total_compressed_size),
|
|
386
630
|
type: Type[column.primitiveType],
|
|
387
|
-
codec: CompressionCodec[column.compression]
|
|
631
|
+
codec: CompressionCodec[column.compression],
|
|
632
|
+
bloom_filter_offset: encodedBloomFilter ? int64(baseOffset + pagesBuf.length) : undefined,
|
|
633
|
+
bloom_filter_length: encodedBloomFilter?.length,
|
|
634
|
+
geospatial_statistics: createGeospatialStatistics(column, data.values),
|
|
635
|
+
size_statistics: opts.writeSizeStatistics ? createSizeStatistics(column, data) : undefined,
|
|
636
|
+
statistics: isStatisticsEnabled(opts.writeStatistics, column)
|
|
637
|
+
? createColumnStatistics(column, data)
|
|
638
|
+
: undefined
|
|
388
639
|
});
|
|
389
640
|
/* list encodings */
|
|
390
641
|
metadata.encodings.push(Encoding[PARQUET_RDLVL_ENCODING]);
|
|
391
|
-
|
|
642
|
+
if (dictionaryPlan)
|
|
643
|
+
metadata.encodings.push(Encoding.PLAIN);
|
|
644
|
+
metadata.encodings.push(Encoding[valueEncoding]);
|
|
392
645
|
/* concat metadata header and data pages */
|
|
393
|
-
const
|
|
394
|
-
const
|
|
395
|
-
|
|
646
|
+
const metadataEncoded = serializeThrift(metadata);
|
|
647
|
+
const metadataSection = encryptedColumn ? undefined : metadataEncoded;
|
|
648
|
+
const metadataOffset = baseOffset + pagesBuf.length + (encodedBloomFilter?.length || 0);
|
|
649
|
+
const offsetIndexOffset = encodedPageIndexes
|
|
650
|
+
? metadataOffset + (metadataSection?.length || 0)
|
|
651
|
+
: undefined;
|
|
652
|
+
const columnIndexOffset = encodedPageIndexes?.columnIndex
|
|
653
|
+
? metadataOffset + (metadataSection?.length || 0) + encodedPageIndexes.offsetIndex.length
|
|
654
|
+
: undefined;
|
|
655
|
+
const body = concatUint8Arrays([
|
|
656
|
+
pagesBuf,
|
|
657
|
+
...(encodedBloomFilter ? [encodedBloomFilter] : []),
|
|
658
|
+
...(metadataSection ? [metadataSection] : []),
|
|
659
|
+
...(encodedPageIndexes
|
|
660
|
+
? [
|
|
661
|
+
encodedPageIndexes.offsetIndex,
|
|
662
|
+
...(encodedPageIndexes.columnIndex ? [encodedPageIndexes.columnIndex] : [])
|
|
663
|
+
]
|
|
664
|
+
: [])
|
|
665
|
+
]);
|
|
666
|
+
return {
|
|
667
|
+
body,
|
|
668
|
+
metadata,
|
|
669
|
+
metadataOffset,
|
|
670
|
+
offsetIndexOffset,
|
|
671
|
+
offsetIndexLength: encodedPageIndexes?.offsetIndex.length,
|
|
672
|
+
columnIndexOffset,
|
|
673
|
+
columnIndexLength: encodedPageIndexes?.columnIndex?.length,
|
|
674
|
+
...(encryptedColumn
|
|
675
|
+
? {
|
|
676
|
+
encryptedColumnMetadata: await encryptParquetModule(metadataEncoded, {
|
|
677
|
+
algorithm: encryption.algorithm ?? 'AES_GCM_V1',
|
|
678
|
+
aad: createParquetModuleAad(encryption.aadPrefix, opts.encryptionFileUnique, 'column-metadata', opts.rowGroupOrdinal ?? 0, columnOrdinal),
|
|
679
|
+
keyMetadata: columnKeyMetadata ?? encryption.keyMetadata,
|
|
680
|
+
keyRetriever: encryption.keyRetriever
|
|
681
|
+
}),
|
|
682
|
+
cryptoMetadata: new ColumnCryptoMetaData({
|
|
683
|
+
...(columnKeyMetadata
|
|
684
|
+
? {
|
|
685
|
+
ENCRYPTION_WITH_COLUMN_KEY: new EncryptionWithColumnKey({
|
|
686
|
+
path_in_schema: [...column.path],
|
|
687
|
+
key_metadata: new Uint8Array(columnKeyMetadata)
|
|
688
|
+
})
|
|
689
|
+
}
|
|
690
|
+
: { ENCRYPTION_WITH_FOOTER_KEY: new EncryptionWithFooterKey() })
|
|
691
|
+
})
|
|
692
|
+
}
|
|
693
|
+
: {})
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
/** Returns whether a writer column should use modular encryption. */
|
|
697
|
+
function shouldEncryptColumn(options, column) {
|
|
698
|
+
return Boolean(options.columnKeyMetadata?.[column.path[0]] ||
|
|
699
|
+
options.encryptColumns === true ||
|
|
700
|
+
options.encryptColumns?.[column.path[0]] === true);
|
|
701
|
+
}
|
|
702
|
+
/** Returns a defensive copy of the key metadata assigned to one top-level column. */
|
|
703
|
+
function getColumnKeyMetadata(options, column) {
|
|
704
|
+
const keyMetadata = options.columnKeyMetadata?.[column.path[0]];
|
|
705
|
+
return keyMetadata ? new Uint8Array(keyMetadata) : undefined;
|
|
706
|
+
}
|
|
707
|
+
/** Adds the four-byte module length required by encrypted page and Bloom-filter modules. */
|
|
708
|
+
function prefixEncryptedModule(module) {
|
|
709
|
+
const prefixed = new Uint8Array(module.byteLength + 4);
|
|
710
|
+
writeUInt32LE(prefixed, module.byteLength, 0);
|
|
711
|
+
prefixed.set(module, 4);
|
|
712
|
+
return prefixed;
|
|
713
|
+
}
|
|
714
|
+
/** Encrypts one column's dictionary and data pages using the Parquet module AAD rules. */
|
|
715
|
+
async function encryptParquetColumnPages(pageRecords, options, fileUnique, rowGroupOrdinal, columnOrdinal, keyMetadata) {
|
|
716
|
+
const encryptedPages = [];
|
|
717
|
+
let dataPageOrdinal = 0;
|
|
718
|
+
const algorithm = options.algorithm ?? 'AES_GCM_V1';
|
|
719
|
+
for (const pageRecord of pageRecords) {
|
|
720
|
+
const moduleType = pageRecord.dictionary ? 'dictionary-page' : 'data-page';
|
|
721
|
+
const headerModuleType = pageRecord.dictionary ? 'dictionary-page-header' : 'data-page-header';
|
|
722
|
+
const header = await encryptParquetModule(pageRecord.page.subarray(0, pageRecord.headerSize), {
|
|
723
|
+
algorithm,
|
|
724
|
+
aad: createParquetModuleAad(options.aadPrefix, fileUnique, headerModuleType, rowGroupOrdinal, columnOrdinal, pageRecord.dictionary ? undefined : dataPageOrdinal),
|
|
725
|
+
keyMetadata: keyMetadata ?? options.keyMetadata,
|
|
726
|
+
keyRetriever: options.keyRetriever
|
|
727
|
+
});
|
|
728
|
+
const body = await encryptParquetModule(pageRecord.page.subarray(pageRecord.headerSize), {
|
|
729
|
+
algorithm,
|
|
730
|
+
aad: createParquetModuleAad(options.aadPrefix, fileUnique, moduleType, rowGroupOrdinal, columnOrdinal, pageRecord.dictionary ? undefined : dataPageOrdinal),
|
|
731
|
+
keyMetadata: keyMetadata ?? options.keyMetadata,
|
|
732
|
+
keyRetriever: options.keyRetriever,
|
|
733
|
+
page: true
|
|
734
|
+
});
|
|
735
|
+
encryptedPages.push(concatUint8Arrays([prefixEncryptedModule(header), prefixEncryptedModule(body)]));
|
|
736
|
+
if (!pageRecord.dictionary)
|
|
737
|
+
dataPageOrdinal++;
|
|
738
|
+
}
|
|
739
|
+
return encryptedPages;
|
|
740
|
+
}
|
|
741
|
+
/** Encrypts a split-block Bloom filter header and bitset as independent Parquet modules. */
|
|
742
|
+
async function encryptParquetBloomFilter(bloomFilter, options, fileUnique, rowGroupOrdinal, columnOrdinal, keyMetadata) {
|
|
743
|
+
const parsed = decodeParquetSplitBlockBloomFilter(bloomFilter);
|
|
744
|
+
const algorithm = options.algorithm ?? 'AES_GCM_V1';
|
|
745
|
+
const keyOptions = {
|
|
746
|
+
algorithm,
|
|
747
|
+
keyMetadata: keyMetadata ?? options.keyMetadata,
|
|
748
|
+
keyRetriever: options.keyRetriever
|
|
749
|
+
};
|
|
750
|
+
const header = await encryptParquetModule(bloomFilter.subarray(0, parsed.headerByteLength), {
|
|
751
|
+
...keyOptions,
|
|
752
|
+
aad: createParquetModuleAad(options.aadPrefix, fileUnique, 'bloom-filter-header', rowGroupOrdinal, columnOrdinal)
|
|
753
|
+
});
|
|
754
|
+
const bitset = await encryptParquetModule(parsed.bitset, {
|
|
755
|
+
...keyOptions,
|
|
756
|
+
aad: createParquetModuleAad(options.aadPrefix, fileUnique, 'bloom-filter-bitset', rowGroupOrdinal, columnOrdinal)
|
|
757
|
+
});
|
|
758
|
+
return concatUint8Arrays([prefixEncryptedModule(header), prefixEncryptedModule(bitset)]);
|
|
759
|
+
}
|
|
760
|
+
/** Encrypts column and offset indexes independently while preserving their footer offsets. */
|
|
761
|
+
async function encryptParquetPageIndexes(pageIndexes, options, fileUnique, rowGroupOrdinal, columnOrdinal, keyMetadata) {
|
|
762
|
+
const algorithm = options.algorithm ?? 'AES_GCM_V1';
|
|
763
|
+
const encryptIndex = (bytes, module) => encryptParquetModule(bytes, {
|
|
764
|
+
algorithm,
|
|
765
|
+
aad: createParquetModuleAad(options.aadPrefix, fileUnique, module, rowGroupOrdinal, columnOrdinal),
|
|
766
|
+
keyMetadata: keyMetadata ?? options.keyMetadata,
|
|
767
|
+
keyRetriever: options.keyRetriever
|
|
768
|
+
});
|
|
769
|
+
return {
|
|
770
|
+
offsetIndex: await encryptIndex(pageIndexes.offsetIndex, 'offset-index'),
|
|
771
|
+
columnIndex: pageIndexes.columnIndex
|
|
772
|
+
? await encryptIndex(pageIndexes.columnIndex, 'column-index')
|
|
773
|
+
: undefined
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
/** Builds page indexes for primitive leaves, including nested and repeated leaves. */
|
|
777
|
+
function createColumnPageIndexes(column, plannedPages, pageLocations, int96AsTimestamp = false) {
|
|
778
|
+
if (!column.primitiveType ||
|
|
779
|
+
!isPageIndexPhysicalType(column.primitiveType) ||
|
|
780
|
+
plannedPages.length !== pageLocations.length ||
|
|
781
|
+
plannedPages.length === 0) {
|
|
782
|
+
return undefined;
|
|
783
|
+
}
|
|
784
|
+
const offsetIndex = serializeThrift(new OffsetIndex({ page_locations: pageLocations }));
|
|
785
|
+
if (!supportsStatisticsSortOrder(column)) {
|
|
786
|
+
return { offsetIndex };
|
|
787
|
+
}
|
|
788
|
+
const nullPages = [];
|
|
789
|
+
const minValues = [];
|
|
790
|
+
const maxValues = [];
|
|
791
|
+
// A repeated leaf's definition-level count is not a row-level null count.
|
|
792
|
+
// Omit null_counts for those leaves so readers do not interpret entry counts
|
|
793
|
+
// as null counts while still benefiting from min/max page pruning.
|
|
794
|
+
const nullCounts = column.rLevelMax === 0 ? [] : undefined;
|
|
795
|
+
for (const plannedPage of plannedPages) {
|
|
796
|
+
const values = plannedPage.data.values;
|
|
797
|
+
const nullCount = plannedPage.data.count - values.length;
|
|
798
|
+
nullCounts?.push(nullCount);
|
|
799
|
+
if (values.length === 0) {
|
|
800
|
+
nullPages.push(true);
|
|
801
|
+
minValues.push(new Uint8Array(0));
|
|
802
|
+
maxValues.push(new Uint8Array(0));
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
const bounds = getPageBounds(values, column.primitiveType, column.typeLength, int96AsTimestamp);
|
|
806
|
+
if (!bounds)
|
|
807
|
+
return undefined;
|
|
808
|
+
nullPages.push(false);
|
|
809
|
+
minValues.push(bounds.min);
|
|
810
|
+
maxValues.push(bounds.max);
|
|
811
|
+
}
|
|
812
|
+
return {
|
|
813
|
+
offsetIndex,
|
|
814
|
+
columnIndex: serializeThrift(new ColumnIndex({
|
|
815
|
+
null_pages: nullPages,
|
|
816
|
+
min_values: minValues,
|
|
817
|
+
max_values: maxValues,
|
|
818
|
+
boundary_order: BoundaryOrder.UNORDERED,
|
|
819
|
+
null_counts: nullCounts
|
|
820
|
+
}))
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
function isPageIndexPhysicalType(physicalType) {
|
|
824
|
+
return (physicalType === 'BOOLEAN' ||
|
|
825
|
+
physicalType === 'INT32' ||
|
|
826
|
+
physicalType === 'INT64' ||
|
|
827
|
+
physicalType === 'INT96' ||
|
|
828
|
+
physicalType === 'FLOAT' ||
|
|
829
|
+
physicalType === 'DOUBLE' ||
|
|
830
|
+
physicalType === 'BYTE_ARRAY' ||
|
|
831
|
+
physicalType === 'FIXED_LEN_BYTE_ARRAY');
|
|
832
|
+
}
|
|
833
|
+
function getPageBounds(values, physicalType, typeLength, int96AsTimestamp = false) {
|
|
834
|
+
if (physicalType === 'INT96' && !int96AsTimestamp)
|
|
835
|
+
return undefined;
|
|
836
|
+
const normalizedValues = Array.from(values, value => normalizePageIndexValue(value, physicalType));
|
|
837
|
+
if (normalizedValues.some(value => value === undefined))
|
|
838
|
+
return undefined;
|
|
839
|
+
const comparableValues = normalizedValues;
|
|
840
|
+
let min = comparableValues[0];
|
|
841
|
+
let max = comparableValues[0];
|
|
842
|
+
for (const value of comparableValues.slice(1)) {
|
|
843
|
+
if (comparePageIndexValues(value, min, physicalType) < 0)
|
|
844
|
+
min = value;
|
|
845
|
+
if (comparePageIndexValues(value, max, physicalType) > 0)
|
|
846
|
+
max = value;
|
|
847
|
+
}
|
|
848
|
+
try {
|
|
849
|
+
return {
|
|
850
|
+
min: encodePageIndexValue(min, physicalType, typeLength, int96AsTimestamp),
|
|
851
|
+
max: encodePageIndexValue(max, physicalType, typeLength, int96AsTimestamp)
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
catch {
|
|
855
|
+
return undefined;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function encodePageIndexValue(value, physicalType, typeLength, int96AsTimestamp) {
|
|
859
|
+
if (physicalType === 'INT96') {
|
|
860
|
+
if (!int96AsTimestamp) {
|
|
861
|
+
throw new Error('INT96 page indexes require timestamp mode');
|
|
862
|
+
}
|
|
863
|
+
return PARQUET_CODECS.PLAIN.encodeValues('INT96', [value], { int96AsTimestamp });
|
|
864
|
+
}
|
|
865
|
+
return encodeParquetBloomFilterValue(value, physicalType, typeLength);
|
|
866
|
+
}
|
|
867
|
+
function normalizePageIndexValue(value, physicalType) {
|
|
868
|
+
if (physicalType === 'BYTE_ARRAY' || physicalType === 'FIXED_LEN_BYTE_ARRAY') {
|
|
869
|
+
if (typeof value === 'string')
|
|
870
|
+
return new TextEncoder().encode(value);
|
|
871
|
+
if (value instanceof ArrayBuffer)
|
|
872
|
+
return new Uint8Array(value);
|
|
873
|
+
if (ArrayBuffer.isView(value)) {
|
|
874
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength).slice();
|
|
875
|
+
}
|
|
876
|
+
return undefined;
|
|
877
|
+
}
|
|
878
|
+
if (typeof value === 'boolean' ||
|
|
879
|
+
typeof value === 'number' ||
|
|
880
|
+
typeof value === 'bigint' ||
|
|
881
|
+
typeof value === 'string') {
|
|
882
|
+
return value;
|
|
883
|
+
}
|
|
884
|
+
return undefined;
|
|
885
|
+
}
|
|
886
|
+
function comparePageIndexValues(left, right, physicalType) {
|
|
887
|
+
if (physicalType === 'BYTE_ARRAY' || physicalType === 'FIXED_LEN_BYTE_ARRAY') {
|
|
888
|
+
const leftBytes = typeof left === 'string' ? new TextEncoder().encode(left) : left;
|
|
889
|
+
const rightBytes = typeof right === 'string' ? new TextEncoder().encode(right) : right;
|
|
890
|
+
if (!(leftBytes instanceof Uint8Array) || !(rightBytes instanceof Uint8Array))
|
|
891
|
+
return 0;
|
|
892
|
+
const length = Math.min(leftBytes.length, rightBytes.length);
|
|
893
|
+
for (let index = 0; index < length; index++) {
|
|
894
|
+
if (leftBytes[index] !== rightBytes[index]) {
|
|
895
|
+
return leftBytes[index] < rightBytes[index] ? -1 : 1;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return leftBytes.length - rightBytes.length;
|
|
899
|
+
}
|
|
900
|
+
if (typeof left === 'boolean' && typeof right === 'boolean')
|
|
901
|
+
return Number(left) - Number(right);
|
|
902
|
+
if (physicalType !== 'INT64' && physicalType !== 'INT96') {
|
|
903
|
+
const leftNumber = Number(left);
|
|
904
|
+
const rightNumber = Number(right);
|
|
905
|
+
return leftNumber < rightNumber ? -1 : leftNumber > rightNumber ? 1 : 0;
|
|
906
|
+
}
|
|
907
|
+
try {
|
|
908
|
+
const leftNumber = BigInt(left);
|
|
909
|
+
const rightNumber = BigInt(right);
|
|
910
|
+
return leftNumber < rightNumber ? -1 : leftNumber > rightNumber ? 1 : 0;
|
|
911
|
+
}
|
|
912
|
+
catch {
|
|
913
|
+
const leftNumber = Number(left);
|
|
914
|
+
const rightNumber = Number(right);
|
|
915
|
+
return leftNumber < rightNumber ? -1 : leftNumber > rightNumber ? 1 : 0;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
/** Builds a Bloom filter for writer-supported physical scalar columns. */
|
|
919
|
+
function createColumnBloomFilter(column, values) {
|
|
920
|
+
const physicalType = column.primitiveType;
|
|
921
|
+
if (physicalType !== 'BOOLEAN' &&
|
|
922
|
+
physicalType !== 'INT32' &&
|
|
923
|
+
physicalType !== 'INT64' &&
|
|
924
|
+
physicalType !== 'FLOAT' &&
|
|
925
|
+
physicalType !== 'DOUBLE' &&
|
|
926
|
+
physicalType !== 'BYTE_ARRAY' &&
|
|
927
|
+
physicalType !== 'FIXED_LEN_BYTE_ARRAY') {
|
|
928
|
+
return undefined;
|
|
929
|
+
}
|
|
930
|
+
const bloomValues = values.map(value => {
|
|
931
|
+
if (value instanceof ArrayBuffer)
|
|
932
|
+
return new Uint8Array(value);
|
|
933
|
+
if (ArrayBuffer.isView(value)) {
|
|
934
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength).slice();
|
|
935
|
+
}
|
|
936
|
+
return value;
|
|
937
|
+
});
|
|
938
|
+
return encodeParquetSplitBlockBloomFilter(bloomValues, physicalType, column.typeLength);
|
|
939
|
+
}
|
|
940
|
+
/** Builds optional size statistics from one shredded column chunk. */
|
|
941
|
+
function createSizeStatistics(column, data) {
|
|
942
|
+
const repetitionLevelHistogram = createLevelHistogram(data.rlevels, column.rLevelMax);
|
|
943
|
+
const definitionLevelHistogram = createLevelHistogram(data.dlevels, column.dLevelMax);
|
|
944
|
+
let unencodedByteArrayDataBytes = 0;
|
|
945
|
+
if (column.primitiveType === 'BYTE_ARRAY') {
|
|
946
|
+
for (const value of data.values) {
|
|
947
|
+
if (typeof value === 'string') {
|
|
948
|
+
unencodedByteArrayDataBytes += encodeUtf8(value).byteLength;
|
|
949
|
+
}
|
|
950
|
+
else if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
951
|
+
unencodedByteArrayDataBytes += value.byteLength;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return new SizeStatistics({
|
|
956
|
+
unencoded_byte_array_data_bytes: column.primitiveType === 'BYTE_ARRAY' ? unencodedByteArrayDataBytes : undefined,
|
|
957
|
+
repetition_level_histogram: repetitionLevelHistogram,
|
|
958
|
+
definition_level_histogram: definitionLevelHistogram
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
/** Returns whether standard column statistics are enabled for one top-level field. */
|
|
962
|
+
function isStatisticsEnabled(option, column) {
|
|
963
|
+
return option === true || option?.[column.path[0]] === true;
|
|
964
|
+
}
|
|
965
|
+
/** Builds conservative standard min/max/null-count statistics for one column chunk. */
|
|
966
|
+
function createColumnStatistics(column, data) {
|
|
967
|
+
if (!column.primitiveType ||
|
|
968
|
+
!isPageIndexPhysicalType(column.primitiveType) ||
|
|
969
|
+
!supportsStatisticsSortOrder(column)) {
|
|
970
|
+
return undefined;
|
|
971
|
+
}
|
|
972
|
+
const statistics = new Statistics({
|
|
973
|
+
null_count: column.rLevelMax === 0 ? data.count - data.values.length : undefined,
|
|
974
|
+
is_min_value_exact: true,
|
|
975
|
+
is_max_value_exact: true
|
|
976
|
+
});
|
|
977
|
+
if (data.values.length === 0)
|
|
978
|
+
return statistics;
|
|
979
|
+
const bounds = getPageBounds(data.values, column.primitiveType, column.typeLength);
|
|
980
|
+
if (!bounds)
|
|
981
|
+
return undefined;
|
|
982
|
+
statistics.min_value = bounds.min;
|
|
983
|
+
statistics.max_value = bounds.max;
|
|
984
|
+
return statistics;
|
|
985
|
+
}
|
|
986
|
+
/** Returns whether the physical representation preserves the logical sort order. */
|
|
987
|
+
function supportsStatisticsSortOrder(column) {
|
|
988
|
+
const logicalType = column.logicalType?.type || column.originalType;
|
|
989
|
+
if (logicalType === 'FLOAT16')
|
|
990
|
+
return false;
|
|
991
|
+
if (logicalType === 'DECIMAL' || logicalType?.startsWith('DECIMAL_')) {
|
|
992
|
+
return column.primitiveType !== 'BYTE_ARRAY' && column.primitiveType !== 'FIXED_LEN_BYTE_ARRAY';
|
|
993
|
+
}
|
|
994
|
+
if (logicalType === 'INTEGER' || logicalType?.startsWith('UINT_')) {
|
|
995
|
+
return column.logicalType?.isSigned !== false && !logicalType.startsWith('UINT_');
|
|
996
|
+
}
|
|
997
|
+
return true;
|
|
998
|
+
}
|
|
999
|
+
/** Counts the occurrences of each definition or repetition level. */
|
|
1000
|
+
function createLevelHistogram(levels, maximumLevel) {
|
|
1001
|
+
const histogram = new Array(maximumLevel + 1).fill(0);
|
|
1002
|
+
for (const level of levels) {
|
|
1003
|
+
if (level >= 0 && level <= maximumLevel)
|
|
1004
|
+
histogram[level]++;
|
|
1005
|
+
}
|
|
1006
|
+
return histogram;
|
|
1007
|
+
}
|
|
1008
|
+
/** Converts writer-facing sort keys into Parquet leaf-column indexes. */
|
|
1009
|
+
function createSortingColumns(schema, sortingColumns) {
|
|
1010
|
+
if (!sortingColumns?.length)
|
|
1011
|
+
return undefined;
|
|
1012
|
+
const leafFields = schema.fieldList.filter(field => !field.isNested);
|
|
1013
|
+
const usedColumnIndexes = new Set();
|
|
1014
|
+
return sortingColumns.map(sortKey => {
|
|
1015
|
+
const columnIndex = leafFields.findIndex(field => (field.path.length === 1 && field.name === sortKey.column) ||
|
|
1016
|
+
(field.path.length > 1 && field.path.join('.') === sortKey.column));
|
|
1017
|
+
if (columnIndex < 0) {
|
|
1018
|
+
throw new Error(`Unknown Parquet sorting column ${sortKey.column}`);
|
|
1019
|
+
}
|
|
1020
|
+
if (usedColumnIndexes.has(columnIndex)) {
|
|
1021
|
+
throw new Error(`Duplicate Parquet sorting column ${sortKey.column}`);
|
|
1022
|
+
}
|
|
1023
|
+
usedColumnIndexes.add(columnIndex);
|
|
1024
|
+
return new SortingColumn({
|
|
1025
|
+
column_idx: columnIndex,
|
|
1026
|
+
descending: Boolean(sortKey.descending),
|
|
1027
|
+
nulls_first: Boolean(sortKey.nullsFirst)
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
396
1030
|
}
|
|
397
1031
|
/**
|
|
398
1032
|
* Encode a list of column values into a parquet row group
|
|
399
1033
|
*/
|
|
400
1034
|
async function encodeRowGroup(schema, data, opts) {
|
|
401
1035
|
const metadata = new RowGroup({
|
|
402
|
-
num_rows: data.rowCount,
|
|
1036
|
+
num_rows: int64(data.rowCount),
|
|
403
1037
|
columns: [],
|
|
404
|
-
total_byte_size: 0
|
|
1038
|
+
total_byte_size: int64(0),
|
|
1039
|
+
sorting_columns: createSortingColumns(schema, opts.sortingColumns)
|
|
405
1040
|
});
|
|
406
|
-
let body =
|
|
1041
|
+
let body = new Uint8Array(0);
|
|
407
1042
|
for (const field of schema.fieldList) {
|
|
408
1043
|
if (field.isNested) {
|
|
409
1044
|
continue; // eslint-disable-line no-continue
|
|
410
1045
|
}
|
|
411
|
-
const cchunkData = await encodeColumnChunk(field, data, body.length, opts);
|
|
1046
|
+
const cchunkData = await encodeColumnChunk(field, data, body.length, opts, opts.rowGroupOrdinal ?? 0, metadata.columns.length);
|
|
412
1047
|
const cchunk = new ColumnChunk({
|
|
413
|
-
file_offset: cchunkData.metadataOffset,
|
|
414
|
-
meta_data: cchunkData.metadata
|
|
1048
|
+
file_offset: int64(cchunkData.metadataOffset),
|
|
1049
|
+
meta_data: cchunkData.encryptedColumnMetadata ? undefined : cchunkData.metadata,
|
|
1050
|
+
offset_index_offset: cchunkData.offsetIndexOffset === undefined
|
|
1051
|
+
? undefined
|
|
1052
|
+
: int64(cchunkData.offsetIndexOffset),
|
|
1053
|
+
offset_index_length: cchunkData.offsetIndexLength,
|
|
1054
|
+
column_index_offset: cchunkData.columnIndexOffset === undefined
|
|
1055
|
+
? undefined
|
|
1056
|
+
: int64(cchunkData.columnIndexOffset),
|
|
1057
|
+
column_index_length: cchunkData.columnIndexLength,
|
|
1058
|
+
crypto_metadata: cchunkData.cryptoMetadata,
|
|
1059
|
+
encrypted_column_metadata: cchunkData.encryptedColumnMetadata
|
|
415
1060
|
});
|
|
416
1061
|
metadata.columns.push(cchunk);
|
|
417
|
-
metadata.total_byte_size =
|
|
418
|
-
body =
|
|
1062
|
+
metadata.total_byte_size = int64(Number(metadata.total_byte_size) + cchunkData.body.length);
|
|
1063
|
+
body = concatUint8Arrays([body, cchunkData.body]);
|
|
419
1064
|
}
|
|
420
1065
|
return { body, metadata };
|
|
421
1066
|
}
|
|
422
1067
|
/**
|
|
423
1068
|
* Encode a parquet file metadata footer
|
|
424
1069
|
*/
|
|
425
|
-
function
|
|
1070
|
+
function encodeFooterMetadata(schema, rowCount, rowGroups, userMetadata, footerSignature) {
|
|
1071
|
+
const signatureAlgorithm = footerSignature?.algorithm ?? 'AES_GCM_V1';
|
|
1072
|
+
const signatureFileUnique = footerSignature?.fileUnique
|
|
1073
|
+
? new Uint8Array(footerSignature.fileUnique)
|
|
1074
|
+
: undefined;
|
|
426
1075
|
const metadata = new FileMetaData({
|
|
427
1076
|
version: PARQUET_VERSION,
|
|
428
1077
|
created_by: 'parquets',
|
|
429
|
-
num_rows: rowCount,
|
|
1078
|
+
num_rows: int64(rowCount),
|
|
430
1079
|
row_groups: rowGroups,
|
|
431
1080
|
schema: [],
|
|
432
|
-
key_value_metadata: []
|
|
1081
|
+
key_value_metadata: [],
|
|
1082
|
+
encryption_algorithm: footerSignature
|
|
1083
|
+
? new EncryptionAlgorithm({
|
|
1084
|
+
...(signatureAlgorithm === 'AES_GCM_CTR_V1'
|
|
1085
|
+
? {
|
|
1086
|
+
AES_GCM_CTR_V1: {
|
|
1087
|
+
aad_prefix: footerSignature.aadPrefix,
|
|
1088
|
+
aad_file_unique: signatureFileUnique
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
: {
|
|
1092
|
+
AES_GCM_V1: {
|
|
1093
|
+
aad_prefix: footerSignature.aadPrefix,
|
|
1094
|
+
aad_file_unique: signatureFileUnique
|
|
1095
|
+
}
|
|
1096
|
+
})
|
|
1097
|
+
})
|
|
1098
|
+
: undefined,
|
|
1099
|
+
footer_signing_key_metadata: footerSignature
|
|
1100
|
+
? new Uint8Array(footerSignature.keyMetadata)
|
|
1101
|
+
: undefined
|
|
433
1102
|
});
|
|
434
1103
|
for (const key in userMetadata) {
|
|
435
1104
|
const kv = new KeyValue({
|
|
@@ -458,16 +1127,211 @@ function encodeFooter(schema, rowCount, rowGroups, userMetadata) {
|
|
|
458
1127
|
schemaElem.type = Type[field.primitiveType];
|
|
459
1128
|
}
|
|
460
1129
|
if (field.originalType) {
|
|
461
|
-
|
|
1130
|
+
const convertedType = ConvertedType[field.originalType];
|
|
1131
|
+
if (typeof convertedType === 'number') {
|
|
1132
|
+
schemaElem.converted_type = convertedType;
|
|
1133
|
+
}
|
|
462
1134
|
}
|
|
463
1135
|
schemaElem.type_length = field.typeLength;
|
|
1136
|
+
schemaElem.precision = field.precision ?? field.presision;
|
|
1137
|
+
schemaElem.scale = field.scale;
|
|
1138
|
+
schemaElem.field_id = field.fieldId;
|
|
1139
|
+
const logicalType = getFieldLogicalType(field);
|
|
1140
|
+
if (logicalType) {
|
|
1141
|
+
schemaElem.logicalType = encodeParquetLogicalType(logicalType);
|
|
1142
|
+
}
|
|
464
1143
|
metadata.schema.push(schemaElem);
|
|
465
1144
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
1145
|
+
return serializeThrift(metadata);
|
|
1146
|
+
}
|
|
1147
|
+
/** Encodes an unsigned plaintext footer with its standard Parquet trailer. */
|
|
1148
|
+
function encodeFooter(schema, rowCount, rowGroups, userMetadata) {
|
|
1149
|
+
const metadataEncoded = encodeFooterMetadata(schema, rowCount, rowGroups, userMetadata);
|
|
1150
|
+
const footerEncoded = new Uint8Array(metadataEncoded.length + 8);
|
|
1151
|
+
footerEncoded.set(metadataEncoded);
|
|
1152
|
+
writeUInt32LE(footerEncoded, metadataEncoded.length, metadataEncoded.length);
|
|
1153
|
+
footerEncoded.set(PARQUET_MAGIC_BYTES, metadataEncoded.length + 4);
|
|
471
1154
|
return footerEncoded;
|
|
472
1155
|
}
|
|
1156
|
+
/** Encodes a plaintext footer with its trailing 28-byte authenticated signature. */
|
|
1157
|
+
async function encodeSignedFooter(schema, rowCount, rowGroups, userMetadata, options) {
|
|
1158
|
+
const metadata = encodeFooterMetadata(schema, rowCount, rowGroups, userMetadata, options);
|
|
1159
|
+
const signature = await createParquetFooterSignature(metadata, options);
|
|
1160
|
+
const footerEncoded = new Uint8Array(metadata.length + signature.length + 8);
|
|
1161
|
+
footerEncoded.set(metadata);
|
|
1162
|
+
footerEncoded.set(signature, metadata.length);
|
|
1163
|
+
writeUInt32LE(footerEncoded, metadata.length + signature.length, metadata.length + signature.length);
|
|
1164
|
+
footerEncoded.set(PARQUET_MAGIC_BYTES, metadata.length + signature.length + 4);
|
|
1165
|
+
return footerEncoded;
|
|
1166
|
+
}
|
|
1167
|
+
/** Wraps a serialized footer in Parquet modular-encryption metadata and AES-GCM. */
|
|
1168
|
+
async function encodeEncryptedFooter(footer, options) {
|
|
1169
|
+
const algorithm = options.algorithm ?? 'AES_GCM_V1';
|
|
1170
|
+
const fileUnique = options.fileUnique ? new Uint8Array(options.fileUnique) : createFileUnique();
|
|
1171
|
+
if (fileUnique.byteLength !== 8) {
|
|
1172
|
+
throw new Error(`Parquet encrypted footer file_unique must be 8 bytes`);
|
|
1173
|
+
}
|
|
1174
|
+
const algorithmParameters = {
|
|
1175
|
+
aad_prefix: options.aadPrefix && new Uint8Array(options.aadPrefix),
|
|
1176
|
+
aad_file_unique: fileUnique,
|
|
1177
|
+
supply_aad_prefix: undefined
|
|
1178
|
+
};
|
|
1179
|
+
const encryptionAlgorithm = algorithm === 'AES_GCM_CTR_V1'
|
|
1180
|
+
? new EncryptionAlgorithm({ AES_GCM_CTR_V1: algorithmParameters })
|
|
1181
|
+
: new EncryptionAlgorithm({ AES_GCM_V1: algorithmParameters });
|
|
1182
|
+
const cryptoMetadata = serializeThrift(new FileCryptoMetaData({
|
|
1183
|
+
encryption_algorithm: encryptionAlgorithm,
|
|
1184
|
+
key_metadata: options.keyMetadata && new Uint8Array(options.keyMetadata)
|
|
1185
|
+
}));
|
|
1186
|
+
const footerMetadata = footer.subarray(0, footer.byteLength - 8);
|
|
1187
|
+
const encryptedFooter = await encryptParquetModule(footerMetadata, {
|
|
1188
|
+
algorithm,
|
|
1189
|
+
aad: createParquetModuleAad(options.aadPrefix, fileUnique, 'footer'),
|
|
1190
|
+
keyMetadata: options.keyMetadata,
|
|
1191
|
+
keyRetriever: options.keyRetriever
|
|
1192
|
+
});
|
|
1193
|
+
const metadataSize = cryptoMetadata.byteLength + encryptedFooter.byteLength;
|
|
1194
|
+
const trailer = new Uint8Array(8);
|
|
1195
|
+
writeUInt32LE(trailer, metadataSize, 0);
|
|
1196
|
+
trailer.set(encodeUtf8(PARQUET_MAGIC_ENCRYPTED), 4);
|
|
1197
|
+
return concatUint8Arrays([cryptoMetadata, encryptedFooter, trailer]);
|
|
1198
|
+
}
|
|
1199
|
+
/** Generates the eight-byte file identifier required by Parquet module AAD. */
|
|
1200
|
+
function createFileUnique() {
|
|
1201
|
+
const fileUnique = new Uint8Array(8);
|
|
1202
|
+
const cryptoProvider = globalThis.crypto;
|
|
1203
|
+
if (!cryptoProvider?.getRandomValues) {
|
|
1204
|
+
throw new Error('Parquet encrypted footer requires Web Crypto random values');
|
|
1205
|
+
}
|
|
1206
|
+
cryptoProvider.getRandomValues(fileUnique);
|
|
1207
|
+
return fileUnique;
|
|
1208
|
+
}
|
|
1209
|
+
/** Returns an explicit or inferred modern logical annotation for a writer field. */
|
|
1210
|
+
function getFieldLogicalType(field) {
|
|
1211
|
+
if (field.logicalType)
|
|
1212
|
+
return field.logicalType;
|
|
1213
|
+
const originalType = field.originalType;
|
|
1214
|
+
if (!originalType)
|
|
1215
|
+
return undefined;
|
|
1216
|
+
if (originalType === 'UTF8')
|
|
1217
|
+
return { type: 'STRING' };
|
|
1218
|
+
if (originalType === 'ENUM')
|
|
1219
|
+
return { type: 'ENUM' };
|
|
1220
|
+
if (originalType.startsWith('DECIMAL_')) {
|
|
1221
|
+
return {
|
|
1222
|
+
type: 'DECIMAL',
|
|
1223
|
+
precision: field.precision ?? field.presision,
|
|
1224
|
+
scale: field.scale
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
if (originalType === 'DATE')
|
|
1228
|
+
return { type: 'DATE' };
|
|
1229
|
+
if (originalType.startsWith('TIME_')) {
|
|
1230
|
+
return {
|
|
1231
|
+
type: 'TIME',
|
|
1232
|
+
unit: originalType.slice(5),
|
|
1233
|
+
isAdjustedToUTC: true
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
if (originalType.startsWith('TIMESTAMP_')) {
|
|
1237
|
+
return {
|
|
1238
|
+
type: 'TIMESTAMP',
|
|
1239
|
+
unit: originalType.slice(10),
|
|
1240
|
+
isAdjustedToUTC: true
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
if (originalType.startsWith('UINT_') || originalType.startsWith('INT_')) {
|
|
1244
|
+
return {
|
|
1245
|
+
type: 'INTEGER',
|
|
1246
|
+
bitWidth: Number(originalType.slice(originalType.indexOf('_') + 1)),
|
|
1247
|
+
isSigned: originalType.startsWith('INT_')
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
if (originalType === 'JSON' || originalType === 'BSON')
|
|
1251
|
+
return { type: originalType };
|
|
1252
|
+
if (originalType === 'UUID' ||
|
|
1253
|
+
originalType === 'FLOAT16' ||
|
|
1254
|
+
originalType === 'UNKNOWN' ||
|
|
1255
|
+
originalType === 'VARIANT' ||
|
|
1256
|
+
originalType === 'GEOMETRY' ||
|
|
1257
|
+
originalType === 'GEOGRAPHY') {
|
|
1258
|
+
return { type: originalType };
|
|
1259
|
+
}
|
|
1260
|
+
return undefined;
|
|
1261
|
+
}
|
|
1262
|
+
/** Converts the internal logical annotation into the Parquet 2.13 Thrift union. */
|
|
1263
|
+
function encodeParquetLogicalType(logicalType) {
|
|
1264
|
+
switch (logicalType.type) {
|
|
1265
|
+
case 'STRING':
|
|
1266
|
+
return LogicalType.fromSTRING(new StringType());
|
|
1267
|
+
case 'MAP':
|
|
1268
|
+
return LogicalType.fromMAP(new MapType());
|
|
1269
|
+
case 'LIST':
|
|
1270
|
+
return LogicalType.fromLIST(new ListType());
|
|
1271
|
+
case 'ENUM':
|
|
1272
|
+
return LogicalType.fromENUM(new EnumType());
|
|
1273
|
+
case 'DECIMAL':
|
|
1274
|
+
if (logicalType.precision === undefined || logicalType.scale === undefined) {
|
|
1275
|
+
throw new Error('Parquet DECIMAL requires precision and scale');
|
|
1276
|
+
}
|
|
1277
|
+
return LogicalType.fromDECIMAL(new DecimalType({ precision: logicalType.precision, scale: logicalType.scale }));
|
|
1278
|
+
case 'DATE':
|
|
1279
|
+
return LogicalType.fromDATE(new DateType());
|
|
1280
|
+
case 'TIME':
|
|
1281
|
+
return LogicalType.fromTIME(new TimeType({
|
|
1282
|
+
isAdjustedToUTC: logicalType.isAdjustedToUTC ?? false,
|
|
1283
|
+
unit: encodeParquetTimeUnit(logicalType.unit)
|
|
1284
|
+
}));
|
|
1285
|
+
case 'TIMESTAMP':
|
|
1286
|
+
return LogicalType.fromTIMESTAMP(new TimestampType({
|
|
1287
|
+
isAdjustedToUTC: logicalType.isAdjustedToUTC ?? false,
|
|
1288
|
+
unit: encodeParquetTimeUnit(logicalType.unit)
|
|
1289
|
+
}));
|
|
1290
|
+
case 'INTEGER':
|
|
1291
|
+
if (logicalType.bitWidth === undefined || logicalType.isSigned === undefined) {
|
|
1292
|
+
throw new Error('Parquet INTEGER requires bitWidth and isSigned');
|
|
1293
|
+
}
|
|
1294
|
+
return LogicalType.fromINTEGER(new IntType({ bitWidth: logicalType.bitWidth, isSigned: logicalType.isSigned }));
|
|
1295
|
+
case 'UNKNOWN':
|
|
1296
|
+
return LogicalType.fromUNKNOWN(new NullType());
|
|
1297
|
+
case 'JSON':
|
|
1298
|
+
return LogicalType.fromJSON(new JsonType());
|
|
1299
|
+
case 'BSON':
|
|
1300
|
+
return LogicalType.fromBSON(new BsonType());
|
|
1301
|
+
case 'UUID':
|
|
1302
|
+
return LogicalType.fromUUID(new UUIDType());
|
|
1303
|
+
case 'FLOAT16':
|
|
1304
|
+
return LogicalType.fromFLOAT16(new Float16Type());
|
|
1305
|
+
case 'VARIANT':
|
|
1306
|
+
return LogicalType.fromVARIANT(new VariantType({ specification_version: logicalType.specificationVersion }));
|
|
1307
|
+
case 'GEOMETRY':
|
|
1308
|
+
return LogicalType.fromGEOMETRY(new GeometryType({ crs: logicalType.crs }));
|
|
1309
|
+
case 'GEOGRAPHY':
|
|
1310
|
+
return LogicalType.fromGEOGRAPHY(new GeographyType({
|
|
1311
|
+
crs: logicalType.crs,
|
|
1312
|
+
algorithm: logicalType.algorithm === undefined
|
|
1313
|
+
? undefined
|
|
1314
|
+
: EdgeInterpolationAlgorithm[logicalType.algorithm]
|
|
1315
|
+
}));
|
|
1316
|
+
default:
|
|
1317
|
+
throw new Error(`Unsupported Parquet logical type ${logicalType.type}`);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
/** Encodes one Parquet logical time unit. */
|
|
1321
|
+
function encodeParquetTimeUnit(unit) {
|
|
1322
|
+
switch (unit) {
|
|
1323
|
+
case 'MILLIS':
|
|
1324
|
+
return TimeUnit.fromMILLIS(new MilliSeconds());
|
|
1325
|
+
case 'MICROS':
|
|
1326
|
+
return TimeUnit.fromMICROS(new MicroSeconds());
|
|
1327
|
+
case 'NANOS':
|
|
1328
|
+
return TimeUnit.fromNANOS(new NanoSeconds());
|
|
1329
|
+
default:
|
|
1330
|
+
throw new Error('Parquet TIME and TIMESTAMP require a unit');
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
/** Wrap a writer metadata number in the thrift int64 compatibility object. */
|
|
1334
|
+
function int64(value) {
|
|
1335
|
+
return new CompactInt64(BigInt(value));
|
|
1336
|
+
}
|
|
473
1337
|
//# sourceMappingURL=parquet-encoder.js.map
|