@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
|
@@ -0,0 +1,1438 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
import { dehydrateArrowTable, hydrateArrowTable, IndexedArrowTable } from '@loaders.gl/arrow';
|
|
5
|
+
import { BlobFile, DataSource, createScanQueryMetadata, emitScanExecutionTelemetry, explainTableQuery, isBrowser, makeTableScanBatch, validateTableQueryLimit } from '@loaders.gl/loader-utils';
|
|
6
|
+
import { convertTable } from '@loaders.gl/schema-utils';
|
|
7
|
+
import { getGeoMetadata } from '@loaders.gl/gis';
|
|
8
|
+
import { getSchemaFromParquetReader } from "./lib/parsers/get-parquet-schema.js";
|
|
9
|
+
import { canGeoParquetRowGroupMatch, combineParquetPredicates, createGeoParquetBoundingBoxPredicate } from "./lib/geo/geoparquet-covering.js";
|
|
10
|
+
import { decodeParquetSplitBlockBloomFilter, encodeParquetBloomFilterValue, hashParquetBloomFilterValue, checkParquetSplitBlockBloomFilter } from "./lib/parquet-bloom-filter.js";
|
|
11
|
+
import { getParquetBloomFilterProbes } from "./lib/parquet-bloom-filter-planner.js";
|
|
12
|
+
import { canParquetRowGroupMatch, copyParquetPredicate, filterParquetRowIndices, gatherParquetColumns, getParquetPredicateColumns, validateParquetPredicate } from "./lib/parquet-predicate.js";
|
|
13
|
+
import { createParquetPagePruningPlan, getParquetPageReadRanges } from "./lib/parquet-page-index.js";
|
|
14
|
+
import { canDecodeParquetSourceOnWorker, decodeParquetSourceRowGroupOnWorker } from "./lib/parquet-source-worker-client.js";
|
|
15
|
+
import { sliceParquetBatch } from "./lib/slice-parquet-batch.js";
|
|
16
|
+
import { ParquetRangeFile } from "./lib/sources/parquet-range-file.js";
|
|
17
|
+
import { toPrimitive } from "./parquetjs/schema/types.js";
|
|
18
|
+
import { PARQUET_TABLE_QUERY_CAPABILITIES, PARQUET_SOURCE_CAPABILITIES } from "./parquet-source-capabilities.js";
|
|
19
|
+
import { ParquetSourceLoader as ParquetSourceLoaderMetadata } from "./parquet-source-loader-types.js";
|
|
20
|
+
export { PARQUET_TABLE_QUERY_CAPABILITIES, PARQUET_SOURCE_CAPABILITIES } from "./parquet-source-capabilities.js";
|
|
21
|
+
import { preloadCompressions } from "./parquetjs/compression.js";
|
|
22
|
+
import { CompressionCodec, Encoding } from "./parquetjs/parquet-thrift/index.js";
|
|
23
|
+
import { ParquetReader } from "./parquetjs/parser/parquet-reader.js";
|
|
24
|
+
import * as Types from "./parquetjs/schema/types.js";
|
|
25
|
+
import { copyUint8Array, readDoubleLE, readFloatLE, readInt32LE, readInt64LE, readUInt32LE, readUInt64LE, toUint8Array } from "./parquetjs/utils/binary-utils.js";
|
|
26
|
+
import { fieldIndexOf } from "./parquetjs/utils/read-utils.js";
|
|
27
|
+
const { preload: _preloadParquetSourceLoader, createDataSource: _createMetadataDataSource, ...ParquetSourceLoaderBase } = ParquetSourceLoaderMetadata;
|
|
28
|
+
/** Runtime source factory for reusable, range-backed Parquet access. */
|
|
29
|
+
export const ParquetSourceLoaderWithParser = {
|
|
30
|
+
...ParquetSourceLoaderBase,
|
|
31
|
+
createDataSource: (data, options, coreApi) => new ParquetSource(data, options, coreApi)
|
|
32
|
+
};
|
|
33
|
+
/** Runtime Parquet source loader exposed by the explicit package subpath. */
|
|
34
|
+
export { ParquetSourceLoaderWithParser as ParquetSourceLoader };
|
|
35
|
+
/** Reusable Parquet source that caches footer/schema state and selectively reads byte ranges. */
|
|
36
|
+
export class ParquetSource extends DataSource {
|
|
37
|
+
/** Common projection, predicate, limit, streaming, and cancellation capabilities. */
|
|
38
|
+
tableQueryCapabilities = PARQUET_TABLE_QUERY_CAPABILITIES;
|
|
39
|
+
/** Immutable feature support for the current range-backed source implementation. */
|
|
40
|
+
capabilities = PARQUET_SOURCE_CAPABILITIES;
|
|
41
|
+
/** Shared initialization for this source instance. */
|
|
42
|
+
initializationPromise = null;
|
|
43
|
+
/** File allocated during source initialization, including while it is opening. */
|
|
44
|
+
readableFile = null;
|
|
45
|
+
/** Whether this source has been permanently closed. */
|
|
46
|
+
closed = false;
|
|
47
|
+
/** Compression module preload shared by all selective reads. */
|
|
48
|
+
compressionPromise = null;
|
|
49
|
+
/** Read abort controllers used to cancel active iterators when the source closes. */
|
|
50
|
+
activeReadControllers = new Set();
|
|
51
|
+
/** Cumulative source telemetry counters. */
|
|
52
|
+
telemetry = createParquetTelemetry();
|
|
53
|
+
/** Creates a Parquet source backed by strict URL ranges or Blob slices. */
|
|
54
|
+
constructor(data, options, coreApi) {
|
|
55
|
+
const wasmUrl = options.parquet?.wasmUrl;
|
|
56
|
+
super(data, options, ParquetSourceLoaderWithParser.defaultOptions, coreApi);
|
|
57
|
+
if (wasmUrl !== undefined) {
|
|
58
|
+
this.options.parquet.wasmUrl = wasmUrl;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Returns the cached logical schema decoded from the Parquet footer. */
|
|
62
|
+
async getSchema(options = {}) {
|
|
63
|
+
const initialization = await this.getInitialization(options.signal);
|
|
64
|
+
return initialization.schema;
|
|
65
|
+
}
|
|
66
|
+
/** Returns normalized dataset, row-group, and column-chunk metadata. */
|
|
67
|
+
async getMetadata(options = {}) {
|
|
68
|
+
const initialization = await this.getInitialization(options.signal);
|
|
69
|
+
if (!options.formatSpecificMetadata) {
|
|
70
|
+
return initialization.metadata;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
...initialization.metadata,
|
|
74
|
+
formatSpecificMetadata: initialization.fileMetadata
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Discovers schema, capabilities, and footer statistics without decoding Parquet data pages. */
|
|
78
|
+
async getQueryMetadata(options = {}) {
|
|
79
|
+
const [schema, metadata] = await Promise.all([
|
|
80
|
+
this.getSchema({ signal: options.signal }),
|
|
81
|
+
this.getMetadata({ signal: options.signal })
|
|
82
|
+
]);
|
|
83
|
+
return createScanQueryMetadata({
|
|
84
|
+
sourceType: 'parquet',
|
|
85
|
+
queryType: 'table',
|
|
86
|
+
execution: { status: 'supported', method: 'read' },
|
|
87
|
+
name: metadata.name,
|
|
88
|
+
schema,
|
|
89
|
+
capabilities: { table: this.tableQueryCapabilities },
|
|
90
|
+
columnRoles: getParquetColumnRoles(schema.fields.map(field => field.name)),
|
|
91
|
+
statistics: { rowCount: metadata.rowCount, byteLength: metadata.fileByteLength }
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** Plans a portable query using Parquet metadata without decoding data pages. */
|
|
95
|
+
async getScanPlan(options = {}) {
|
|
96
|
+
const readOptions = this.getReadOptions(options);
|
|
97
|
+
const initialization = await this.getInitialization(readOptions.signal);
|
|
98
|
+
const sourceColumnNames = initialization.schema.fields.map(field => field.name);
|
|
99
|
+
const signal = readOptions.signal ?? new AbortController().signal;
|
|
100
|
+
const physicalPlan = await this.planRowGroups(initialization, readOptions, signal);
|
|
101
|
+
const pagePlans = await this.planPages(initialization, readOptions, physicalPlan, signal);
|
|
102
|
+
const explanation = explainTableQuery(sourceColumnNames, {
|
|
103
|
+
columns: readOptions.columns,
|
|
104
|
+
predicate: physicalPlan.predicate,
|
|
105
|
+
limit: readOptions.limit
|
|
106
|
+
}, PARQUET_TABLE_QUERY_CAPABILITIES);
|
|
107
|
+
return Object.freeze({
|
|
108
|
+
...explanation,
|
|
109
|
+
source: 'parquet',
|
|
110
|
+
rowGroups: Object.freeze({
|
|
111
|
+
indices: Object.freeze([...physicalPlan.rowGroupIndices]),
|
|
112
|
+
requested: physicalPlan.requested,
|
|
113
|
+
selected: physicalPlan.rowGroupIndices.length,
|
|
114
|
+
prunedByCallback: physicalPlan.prunedByCallback,
|
|
115
|
+
prunedBySpatial: physicalPlan.prunedBySpatial,
|
|
116
|
+
prunedByStatistics: physicalPlan.prunedByStatistics,
|
|
117
|
+
prunedByBloomFilter: physicalPlan.prunedByBloomFilter
|
|
118
|
+
}),
|
|
119
|
+
bloomFilters: Object.freeze({
|
|
120
|
+
read: physicalPlan.bloomFiltersRead,
|
|
121
|
+
bytesRead: physicalPlan.bloomFilterBytesRead
|
|
122
|
+
}),
|
|
123
|
+
pages: Object.freeze({
|
|
124
|
+
rowGroupsPlanned: new Set(pagePlans.map(plan => plan.rowGroupIndex)).size,
|
|
125
|
+
indexesRead: pagePlans.reduce((sum, plan) => sum + plan.indexesRead, 0),
|
|
126
|
+
total: pagePlans.reduce((sum, plan) => sum + plan.totalPages, 0),
|
|
127
|
+
selected: pagePlans.reduce((sum, plan) => sum + plan.selectedPages, 0),
|
|
128
|
+
rowsPruned: pagePlans.reduce((sum, plan) => sum + plan.rowsPruned, 0),
|
|
129
|
+
plans: Object.freeze(pagePlans)
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/** Explains the common logical query and Parquet-specific physical scan plan. */
|
|
134
|
+
async explain(options = {}) {
|
|
135
|
+
return await this.getScanPlan(options);
|
|
136
|
+
}
|
|
137
|
+
/** Executes a previously computed physical plan while preserving its row-group decisions. */
|
|
138
|
+
async *executeScanPlan(plan, options = {}) {
|
|
139
|
+
if (plan.source !== 'parquet') {
|
|
140
|
+
throw new Error('ParquetSource can only execute Parquet scan plans');
|
|
141
|
+
}
|
|
142
|
+
const predicateStep = plan.plan.find(step => step.kind === 'filter');
|
|
143
|
+
const limitStep = plan.plan.find(step => step.kind === 'limit');
|
|
144
|
+
yield* this.read({
|
|
145
|
+
...options,
|
|
146
|
+
columns: options.columns ?? plan.outputColumns,
|
|
147
|
+
predicate: options.predicate ??
|
|
148
|
+
(predicateStep?.kind === 'filter' ? predicateStep.predicate : undefined),
|
|
149
|
+
limit: options.limit ?? (limitStep?.kind === 'limit' ? limitStep.limit : undefined),
|
|
150
|
+
rowGroups: plan.rowGroups.indices
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/** Common scan-architecture alias for selective Parquet reads. */
|
|
154
|
+
scan(options = {}) {
|
|
155
|
+
return this.read(options);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Reads candidate encoded pages without decoding values or constructing Arrow arrays.
|
|
159
|
+
*
|
|
160
|
+
* Footer statistics and Bloom filters prune complete row groups. Any exact predicate or spatial
|
|
161
|
+
* filter is returned as residual work, and its hidden columns are included in the page batch.
|
|
162
|
+
*/
|
|
163
|
+
async *readPages(options = {}) {
|
|
164
|
+
const readOptions = this.getReadOptions({
|
|
165
|
+
rowGroups: options.rowGroups,
|
|
166
|
+
columns: options.columns,
|
|
167
|
+
rowGroupFilter: options.rowGroupFilter,
|
|
168
|
+
predicate: options.predicate,
|
|
169
|
+
bbox: options.bbox,
|
|
170
|
+
geometryColumn: options.geometryColumn,
|
|
171
|
+
signal: options.signal
|
|
172
|
+
});
|
|
173
|
+
const readContext = createReadAbortContext(readOptions.signal);
|
|
174
|
+
this.activeReadControllers.add(readContext.abortController);
|
|
175
|
+
try {
|
|
176
|
+
const initialization = await this.getInitialization(readContext.abortController.signal);
|
|
177
|
+
await this.getCompressionInitialization();
|
|
178
|
+
throwIfAborted(readContext.abortController.signal);
|
|
179
|
+
const physicalPlan = await this.planRowGroups(initialization, readOptions, readContext.abortController.signal);
|
|
180
|
+
const projectedColumns = normalizeColumns(readOptions.columns, initialization.schema);
|
|
181
|
+
const predicateColumns = physicalPlan.predicate
|
|
182
|
+
? getParquetPredicateColumns(physicalPlan.predicate)
|
|
183
|
+
: [];
|
|
184
|
+
const geoMetadata = readOptions.bbox
|
|
185
|
+
? getGeoMetadata(initialization.schema.metadata)
|
|
186
|
+
: undefined;
|
|
187
|
+
const geometryColumn = readOptions.bbox
|
|
188
|
+
? readOptions.geometryColumn || geoMetadata?.primary_column
|
|
189
|
+
: undefined;
|
|
190
|
+
const filterColumns = [
|
|
191
|
+
...new Set([...predicateColumns, ...(geometryColumn ? [geometryColumn] : [])])
|
|
192
|
+
];
|
|
193
|
+
const decodedColumns = projectedColumns.length === 0 ? [] : [...new Set([...projectedColumns, ...filterColumns])];
|
|
194
|
+
const columnList = decodedColumns.map(column => [column]);
|
|
195
|
+
const preserveCompression = new Set(options.preserveCompression ?? []);
|
|
196
|
+
const residualFilter = readOptions.predicate || readOptions.bbox
|
|
197
|
+
? Object.freeze({
|
|
198
|
+
predicate: readOptions.predicate,
|
|
199
|
+
bbox: readOptions.bbox,
|
|
200
|
+
geometryColumn
|
|
201
|
+
})
|
|
202
|
+
: undefined;
|
|
203
|
+
for (const rowGroupIndex of physicalPlan.rowGroupIndices) {
|
|
204
|
+
throwIfAborted(readContext.abortController.signal);
|
|
205
|
+
const columns = await initialization.reader.readRowGroupEncodedPages(initialization.parquetSchema, initialization.fileMetadata.row_groups[rowGroupIndex], columnList, preserveCompression, readContext.abortController.signal, rowGroupIndex);
|
|
206
|
+
yield Object.freeze({
|
|
207
|
+
shape: 'parquet-encoded-pages',
|
|
208
|
+
rowGroup: initialization.metadata.rowGroups[rowGroupIndex],
|
|
209
|
+
projectedColumns: Object.freeze([...projectedColumns]),
|
|
210
|
+
filterColumns: Object.freeze(filterColumns),
|
|
211
|
+
columns,
|
|
212
|
+
residualFilter
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
readContext.abortController.abort();
|
|
218
|
+
readContext.removeSignalListener();
|
|
219
|
+
this.activeReadControllers.delete(readContext.abortController);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/** Returns a copy of cumulative transport, decode, conversion, and pruning telemetry. */
|
|
223
|
+
getTelemetry() {
|
|
224
|
+
return Object.freeze({ ...this.telemetry });
|
|
225
|
+
}
|
|
226
|
+
/** Selectively fetches row groups and columns as ordered Arrow batches with source provenance. */
|
|
227
|
+
async *read(options = {}) {
|
|
228
|
+
const startedAt = Date.now();
|
|
229
|
+
const telemetryBefore = this.getTelemetry();
|
|
230
|
+
const readOptions = this.getReadOptions(options);
|
|
231
|
+
if (readOptions.limit === 0) {
|
|
232
|
+
emitScanExecutionTelemetry(options.onTelemetry, createParquetScanExecutionTelemetry(telemetryBefore, this.getTelemetry(), startedAt, 'early-terminated', 'limit'));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const readContext = createReadAbortContext(readOptions.signal);
|
|
236
|
+
const inFlightReads = new Set();
|
|
237
|
+
let completed = false;
|
|
238
|
+
let limitReached = false;
|
|
239
|
+
let readError;
|
|
240
|
+
this.activeReadControllers.add(readContext.abortController);
|
|
241
|
+
try {
|
|
242
|
+
const initialization = await this.getInitialization(readContext.abortController.signal);
|
|
243
|
+
await this.getCompressionInitialization();
|
|
244
|
+
throwIfAborted(readContext.abortController.signal);
|
|
245
|
+
const physicalPlan = await this.planRowGroups(initialization, readOptions, readContext.abortController.signal);
|
|
246
|
+
const { predicate, rowGroupIndices } = physicalPlan;
|
|
247
|
+
this.recordTelemetry('row-group-prune', {
|
|
248
|
+
rowGroupsRequested: physicalPlan.requested,
|
|
249
|
+
rowGroupsPruned: physicalPlan.requested - rowGroupIndices.length,
|
|
250
|
+
rowGroupsPrunedByStatistics: physicalPlan.prunedByStatistics,
|
|
251
|
+
rowGroupsPrunedByBloomFilter: physicalPlan.prunedByBloomFilter,
|
|
252
|
+
bloomFiltersRead: physicalPlan.bloomFiltersRead,
|
|
253
|
+
bloomFilterBytesRead: physicalPlan.bloomFilterBytesRead
|
|
254
|
+
}, {});
|
|
255
|
+
const columns = normalizeColumns(readOptions.columns, initialization.schema);
|
|
256
|
+
const predicateColumns = predicate ? getParquetPredicateColumns(predicate) : [];
|
|
257
|
+
const decodedColumns = columns.length === 0 ? [] : [...new Set([...columns, ...predicateColumns])];
|
|
258
|
+
const columnList = decodedColumns.map(column => [column]);
|
|
259
|
+
const batchSize = normalizeBatchSize(readOptions.batchSize);
|
|
260
|
+
const concurrency = normalizeConcurrency(readOptions.concurrency);
|
|
261
|
+
const projectedSchema = projectSchema(initialization.schema, columns);
|
|
262
|
+
const projectedColumnNames = columns.length ? new Set(columns) : undefined;
|
|
263
|
+
const workerOptions = this.getWorkerOptions(concurrency, readContext.abortController.signal);
|
|
264
|
+
const decodeOnWorker = canDecodeParquetSourceOnWorker(workerOptions) &&
|
|
265
|
+
(!initialization.reader.encrypted || Boolean(this.options.parquet?.keyRetriever));
|
|
266
|
+
const scheduledReads = new Map();
|
|
267
|
+
let nextPositionToSchedule = 0;
|
|
268
|
+
let remainingRows = readOptions.limit ?? Number.POSITIVE_INFINITY;
|
|
269
|
+
const scheduleReads = () => {
|
|
270
|
+
while (nextPositionToSchedule < rowGroupIndices.length &&
|
|
271
|
+
scheduledReads.size < concurrency) {
|
|
272
|
+
const position = nextPositionToSchedule++;
|
|
273
|
+
const rowGroupIndex = rowGroupIndices[position];
|
|
274
|
+
const read = this.readRowGroup(initialization, rowGroupIndex, columnList, projectedSchema, batchSize, predicate, projectedColumnNames, decodeOnWorker ? workerOptions : undefined, readContext.abortController.signal).then(result => ({ result }), error => ({ error }));
|
|
275
|
+
scheduledReads.set(position, read);
|
|
276
|
+
inFlightReads.add(read);
|
|
277
|
+
void read.then(() => inFlightReads.delete(read));
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
scheduleReads();
|
|
281
|
+
for (let position = 0; position < rowGroupIndices.length; position++) {
|
|
282
|
+
const settledRead = await scheduledReads.get(position);
|
|
283
|
+
scheduledReads.delete(position);
|
|
284
|
+
scheduleReads();
|
|
285
|
+
if ('error' in settledRead) {
|
|
286
|
+
throw settledRead.error;
|
|
287
|
+
}
|
|
288
|
+
const { rowGroupIndex, columns: materializedColumns, rowCount, rowIndices, workerResult } = settledRead.result;
|
|
289
|
+
if (workerResult) {
|
|
290
|
+
for (const workerBatch of workerResult.batches) {
|
|
291
|
+
throwIfAborted(readContext.abortController.signal);
|
|
292
|
+
const deserializationStartTime = getCurrentTime();
|
|
293
|
+
const arrowTable = hydrateArrowTable(workerBatch.arrowTable);
|
|
294
|
+
const deserializationDurationMs = getCurrentTime() - deserializationStartTime;
|
|
295
|
+
this.recordTelemetry('arrow-conversion', { arrowConversionDurationMs: deserializationDurationMs }, { rowGroupIndex, durationMs: deserializationDurationMs });
|
|
296
|
+
const batch = sliceParquetBatch(createParquetBatchFromArrow(initialization.metadata, projectedSchema, rowGroupIndex, workerBatch.rowGroupRowOffset, arrowTable, workerBatch.rowCount, workerBatch.rowGroupRowIndices), Math.min(workerBatch.rowCount, remainingRows));
|
|
297
|
+
this.recordTelemetry('batch', { batchesEmitted: 1, rowsEmitted: batch.length }, { rowGroupIndex, rowCount: batch.length });
|
|
298
|
+
yield batch;
|
|
299
|
+
remainingRows -= batch.length;
|
|
300
|
+
if (remainingRows === 0) {
|
|
301
|
+
limitReached = true;
|
|
302
|
+
completed = true;
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const outputRowCount = rowCount;
|
|
309
|
+
const outputBatchSize = batchSize || Math.max(outputRowCount, 1);
|
|
310
|
+
for (let outputRowOffset = 0; outputRowOffset < outputRowCount; outputRowOffset += outputBatchSize) {
|
|
311
|
+
throwIfAborted(readContext.abortController.signal);
|
|
312
|
+
const batchRowCount = Math.min(outputBatchSize, outputRowCount - outputRowOffset, remainingRows);
|
|
313
|
+
const batchRowIndices = rowIndices
|
|
314
|
+
? rowIndices.slice(outputRowOffset, outputRowOffset + batchRowCount)
|
|
315
|
+
: undefined;
|
|
316
|
+
const rowGroupRowOffset = batchRowIndices?.[0] ?? outputRowOffset;
|
|
317
|
+
const batchColumns = sliceColumns(materializedColumns, outputRowOffset, outputRowOffset + batchRowCount);
|
|
318
|
+
const conversionStartTime = getCurrentTime();
|
|
319
|
+
const batch = createParquetBatch(initialization.metadata, projectedSchema, rowGroupIndex, rowGroupRowOffset, batchColumns, batchRowCount, batchRowIndices);
|
|
320
|
+
const conversionDurationMs = getCurrentTime() - conversionStartTime;
|
|
321
|
+
this.recordTelemetry('arrow-conversion', { arrowConversionDurationMs: conversionDurationMs }, { rowGroupIndex, durationMs: conversionDurationMs });
|
|
322
|
+
this.recordTelemetry('batch', { batchesEmitted: 1, rowsEmitted: batchRowCount }, { rowGroupIndex, rowCount: batchRowCount });
|
|
323
|
+
yield batch;
|
|
324
|
+
remainingRows -= batch.length;
|
|
325
|
+
if (remainingRows === 0) {
|
|
326
|
+
limitReached = true;
|
|
327
|
+
completed = true;
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
completed = true;
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
readError = error;
|
|
336
|
+
if (readContext.abortController.signal.aborted) {
|
|
337
|
+
this.recordTelemetry('cancel', { cancellationCount: 1 }, { error });
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
this.recordTelemetry('read-error', { failedReadCount: 1 }, { error });
|
|
341
|
+
}
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
finally {
|
|
345
|
+
if (!completed && readError === undefined) {
|
|
346
|
+
this.recordTelemetry('cancel', { cancellationCount: 1 }, {});
|
|
347
|
+
}
|
|
348
|
+
const cancelled = readContext.abortController.signal.aborted || readOptions.signal?.aborted;
|
|
349
|
+
readContext.abortController.abort();
|
|
350
|
+
readContext.removeSignalListener();
|
|
351
|
+
this.activeReadControllers.delete(readContext.abortController);
|
|
352
|
+
await Promise.allSettled([...inFlightReads]);
|
|
353
|
+
const status = readError
|
|
354
|
+
? cancelled
|
|
355
|
+
? 'cancelled'
|
|
356
|
+
: 'failed'
|
|
357
|
+
: limitReached || !completed
|
|
358
|
+
? 'early-terminated'
|
|
359
|
+
: 'completed';
|
|
360
|
+
emitScanExecutionTelemetry(options.onTelemetry, createParquetScanExecutionTelemetry(telemetryBefore, this.getTelemetry(), startedAt, status, limitReached
|
|
361
|
+
? 'limit'
|
|
362
|
+
: !completed && readError === undefined
|
|
363
|
+
? 'consumer-return'
|
|
364
|
+
: undefined, readError));
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/** Produces the physical row-group plan shared by explain and execution. */
|
|
368
|
+
async planRowGroups(initialization, readOptions, signal) {
|
|
369
|
+
throwIfAborted(signal);
|
|
370
|
+
const candidateRowGroupIndices = normalizeRowGroupIndices(readOptions.rowGroups, initialization.fileMetadata.row_groups.length);
|
|
371
|
+
const callbackFilteredRowGroupIndices = readOptions.rowGroupFilter
|
|
372
|
+
? candidateRowGroupIndices.filter(rowGroupIndex => readOptions.rowGroupFilter(initialization.metadata.rowGroups[rowGroupIndex]))
|
|
373
|
+
: candidateRowGroupIndices;
|
|
374
|
+
const spatiallyFilteredRowGroupIndices = readOptions.bbox
|
|
375
|
+
? callbackFilteredRowGroupIndices.filter(rowGroupIndex => canGeoParquetRowGroupMatch(initialization.metadata, initialization.metadata.rowGroups[rowGroupIndex], readOptions.bbox, readOptions.geometryColumn))
|
|
376
|
+
: callbackFilteredRowGroupIndices;
|
|
377
|
+
const spatialPredicate = readOptions.bbox
|
|
378
|
+
? createGeoParquetBoundingBoxPredicate(initialization.metadata, readOptions.bbox, readOptions.geometryColumn)
|
|
379
|
+
: undefined;
|
|
380
|
+
const predicate = combineParquetPredicates(readOptions.predicate, spatialPredicate);
|
|
381
|
+
if (predicate) {
|
|
382
|
+
validateParquetPredicate(predicate, new Set(initialization.schema.fields.map(field => field.name)));
|
|
383
|
+
}
|
|
384
|
+
const statisticsRowGroupIndices = predicate
|
|
385
|
+
? spatiallyFilteredRowGroupIndices.filter(rowGroupIndex => canParquetRowGroupMatch(predicate, initialization.metadata.rowGroups[rowGroupIndex]))
|
|
386
|
+
: spatiallyFilteredRowGroupIndices;
|
|
387
|
+
const bloomFilterResult = predicate
|
|
388
|
+
? await filterParquetRowGroupsWithBloomFilters(initialization, statisticsRowGroupIndices, predicate, signal)
|
|
389
|
+
: { rowGroupIndices: statisticsRowGroupIndices, filtersRead: 0, bytesRead: 0 };
|
|
390
|
+
return {
|
|
391
|
+
predicate,
|
|
392
|
+
rowGroupIndices: bloomFilterResult.rowGroupIndices,
|
|
393
|
+
requested: candidateRowGroupIndices.length,
|
|
394
|
+
prunedByCallback: candidateRowGroupIndices.length - callbackFilteredRowGroupIndices.length,
|
|
395
|
+
prunedBySpatial: callbackFilteredRowGroupIndices.length - spatiallyFilteredRowGroupIndices.length,
|
|
396
|
+
prunedByStatistics: spatiallyFilteredRowGroupIndices.length - statisticsRowGroupIndices.length,
|
|
397
|
+
prunedByBloomFilter: statisticsRowGroupIndices.length - bloomFilterResult.rowGroupIndices.length,
|
|
398
|
+
bloomFiltersRead: bloomFilterResult.filtersRead,
|
|
399
|
+
bloomFilterBytesRead: bloomFilterResult.bytesRead
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/** Produces explainable page-index and byte-range plans for retained row groups. */
|
|
403
|
+
async planPages(initialization, readOptions, rowGroupPlan, signal) {
|
|
404
|
+
if (!rowGroupPlan.predicate)
|
|
405
|
+
return [];
|
|
406
|
+
const columns = normalizeColumns(readOptions.columns, initialization.schema);
|
|
407
|
+
const predicateColumns = getParquetPredicateColumns(rowGroupPlan.predicate);
|
|
408
|
+
const decodedColumns = columns.length === 0 ? [] : [...new Set([...columns, ...predicateColumns])];
|
|
409
|
+
const hasHiddenPredicateColumns = columns.length > 0 && predicateColumns.some(column => !columns.includes(column));
|
|
410
|
+
const phases = hasHiddenPredicateColumns
|
|
411
|
+
? [
|
|
412
|
+
{
|
|
413
|
+
phase: 'predicate',
|
|
414
|
+
columns: predicateColumns.map(column => [column]),
|
|
415
|
+
predicate: rowGroupPlan.predicate
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
phase: 'projection',
|
|
419
|
+
columns: columns.map(column => [column]),
|
|
420
|
+
predicate: undefined
|
|
421
|
+
}
|
|
422
|
+
]
|
|
423
|
+
: [
|
|
424
|
+
{
|
|
425
|
+
phase: 'combined',
|
|
426
|
+
columns: decodedColumns.map(column => [column]),
|
|
427
|
+
predicate: rowGroupPlan.predicate
|
|
428
|
+
}
|
|
429
|
+
];
|
|
430
|
+
const plans = [];
|
|
431
|
+
for (const rowGroupIndex of rowGroupPlan.rowGroupIndices) {
|
|
432
|
+
const rowGroup = initialization.fileMetadata.row_groups[rowGroupIndex];
|
|
433
|
+
let predicateProvedEmpty = false;
|
|
434
|
+
for (const phase of phases) {
|
|
435
|
+
throwIfAborted(signal);
|
|
436
|
+
if (phase.phase === 'projection' && predicateProvedEmpty) {
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
await initialization.reader.resolveColumnMetadata(rowGroup, rowGroupIndex, phase.columns);
|
|
440
|
+
const pagePlan = phase.predicate
|
|
441
|
+
? await createParquetPagePruningPlan(initialization.file, rowGroup, initialization.parquetSchema, phase.columns, phase.predicate, signal, {
|
|
442
|
+
rowGroupOrdinal: rowGroupIndex,
|
|
443
|
+
int96AsTimestamp: Boolean(this.options.parquet?.int96AsTimestamp),
|
|
444
|
+
decryptModule: (bytes, module, rowGroupOrdinal, columnOrdinal, columnChunk) => initialization.reader.decryptIndexModule(bytes, module, rowGroupOrdinal, columnOrdinal, columnChunk)
|
|
445
|
+
})
|
|
446
|
+
: undefined;
|
|
447
|
+
plans.push(pagePlan
|
|
448
|
+
? Object.freeze({
|
|
449
|
+
rowGroupIndex,
|
|
450
|
+
phase: phase.phase,
|
|
451
|
+
columns: Object.freeze(phase.columns.map(column => Object.freeze([...column]))),
|
|
452
|
+
rowRanges: Object.freeze(pagePlan.rowRanges.map(rowRange => Object.freeze({ ...rowRange }))),
|
|
453
|
+
indexesRead: pagePlan.indexCount,
|
|
454
|
+
totalPages: pagePlan.totalPageCount,
|
|
455
|
+
selectedPages: pagePlan.selectedPageCount,
|
|
456
|
+
rowsPruned: pagePlan.prunedRowCount,
|
|
457
|
+
ranges: Object.freeze(getParquetPageReadRanges(rowGroup, phase.columns, pagePlan, initialization.parquetSchema).map(range => Object.freeze({ ...range })))
|
|
458
|
+
})
|
|
459
|
+
: createFullColumnScanPlan(rowGroup, rowGroupIndex, phase.phase, phase.columns));
|
|
460
|
+
if (phase.phase === 'predicate' && pagePlan?.rowRanges.length === 0) {
|
|
461
|
+
predicateProvedEmpty = true;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return plans;
|
|
466
|
+
}
|
|
467
|
+
/** Closes the underlying readable file and aborts active remote requests. */
|
|
468
|
+
async close() {
|
|
469
|
+
if (this.closed) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
this.closed = true;
|
|
473
|
+
for (const abortController of this.activeReadControllers) {
|
|
474
|
+
abortController.abort();
|
|
475
|
+
}
|
|
476
|
+
await this.readableFile?.close();
|
|
477
|
+
const initialization = await this.initializationPromise?.catch(() => null);
|
|
478
|
+
initialization?.reader.close();
|
|
479
|
+
if (initialization?.file !== this.readableFile) {
|
|
480
|
+
await initialization?.file.close();
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/** Returns cached initialization, resetting the cache when initialization fails. */
|
|
484
|
+
getInitialization(signal) {
|
|
485
|
+
if (this.closed) {
|
|
486
|
+
return Promise.reject(new Error('ParquetSource is closed'));
|
|
487
|
+
}
|
|
488
|
+
if (!this.initializationPromise) {
|
|
489
|
+
this.initializationPromise = this.initialize(signal).catch(error => {
|
|
490
|
+
this.initializationPromise = null;
|
|
491
|
+
throw error;
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return this.initializationPromise;
|
|
495
|
+
}
|
|
496
|
+
/** Preloads TypeScript decoder compression modules once and permits retry after failure. */
|
|
497
|
+
getCompressionInitialization() {
|
|
498
|
+
if (!this.compressionPromise) {
|
|
499
|
+
this.compressionPromise = preloadCompressions()
|
|
500
|
+
.then(() => undefined)
|
|
501
|
+
.catch(error => {
|
|
502
|
+
this.compressionPromise = null;
|
|
503
|
+
throw error;
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
return this.compressionPromise;
|
|
507
|
+
}
|
|
508
|
+
/** Snapshots source defaults and per-read overrides before asynchronous iteration begins. */
|
|
509
|
+
getReadOptions(options) {
|
|
510
|
+
const rowGroups = options.rowGroups ?? this.options.parquet?.rowGroups;
|
|
511
|
+
const columns = options.columns ?? this.options.parquet?.columns;
|
|
512
|
+
const predicate = options.predicate ?? this.options.parquet?.predicate;
|
|
513
|
+
const bbox = options.bbox ?? this.options.parquet?.bbox;
|
|
514
|
+
const limit = options.limit ?? this.options.parquet?.limit;
|
|
515
|
+
validateTableQueryLimit(limit);
|
|
516
|
+
return {
|
|
517
|
+
rowGroups: rowGroups && [...rowGroups],
|
|
518
|
+
columns: columns && [...columns],
|
|
519
|
+
rowGroupFilter: options.rowGroupFilter ?? this.options.parquet?.rowGroupFilter,
|
|
520
|
+
predicate: predicate ? copyParquetPredicate(predicate) : undefined,
|
|
521
|
+
limit,
|
|
522
|
+
bbox: bbox ? [...bbox] : undefined,
|
|
523
|
+
geometryColumn: options.geometryColumn ?? this.options.parquet?.geometryColumn,
|
|
524
|
+
batchSize: options.batchSize ?? this.options.parquet?.batchSize,
|
|
525
|
+
concurrency: options.concurrency ?? this.options.parquet?.concurrency,
|
|
526
|
+
signal: options.signal
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
/** Creates loader-utils worker options for one selective source read. */
|
|
530
|
+
getWorkerOptions(concurrency, signal) {
|
|
531
|
+
return {
|
|
532
|
+
core: {
|
|
533
|
+
worker: this.options.core?.worker ?? true,
|
|
534
|
+
maxConcurrency: concurrency,
|
|
535
|
+
maxMobileConcurrency: this.options.core?.maxMobileConcurrency ?? concurrency,
|
|
536
|
+
reuseWorkers: this.options.core?.reuseWorkers ?? isBrowser,
|
|
537
|
+
_workerType: this.options.core?._workerType
|
|
538
|
+
},
|
|
539
|
+
'parquet-source': {
|
|
540
|
+
workerUrl: this.options.parquet?.workerUrl
|
|
541
|
+
},
|
|
542
|
+
parquet: {
|
|
543
|
+
signal
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
/** Fetches and decodes one selected row group using the cached footer and schema. */
|
|
548
|
+
async readRowGroup(initialization, rowGroupIndex, columnList, projectedSchema, batchSize, predicate, projectedColumnNames, workerOptions, signal) {
|
|
549
|
+
if (predicate &&
|
|
550
|
+
projectedColumnNames &&
|
|
551
|
+
getParquetPredicateColumns(predicate).some(column => !projectedColumnNames.has(column))) {
|
|
552
|
+
return await this.readRowGroupWithLateMaterialization(initialization, rowGroupIndex, columnList, projectedSchema, batchSize, predicate, projectedColumnNames, workerOptions, signal);
|
|
553
|
+
}
|
|
554
|
+
const rowGroup = initialization.fileMetadata.row_groups[rowGroupIndex];
|
|
555
|
+
await initialization.reader.resolveColumnMetadata(rowGroup, rowGroupIndex, columnList);
|
|
556
|
+
const pagePlan = predicate
|
|
557
|
+
? await createParquetPagePruningPlan(initialization.file, rowGroup, initialization.parquetSchema, columnList, predicate, signal, {
|
|
558
|
+
rowGroupOrdinal: rowGroupIndex,
|
|
559
|
+
int96AsTimestamp: Boolean(this.options.parquet?.int96AsTimestamp),
|
|
560
|
+
decryptModule: (bytes, module, rowGroupOrdinal, columnOrdinal, columnChunk) => initialization.reader.decryptIndexModule(bytes, module, rowGroupOrdinal, columnOrdinal, columnChunk)
|
|
561
|
+
})
|
|
562
|
+
: undefined;
|
|
563
|
+
if (pagePlan) {
|
|
564
|
+
this.recordPagePruningTelemetry(rowGroupIndex, pagePlan);
|
|
565
|
+
if (pagePlan.rowRanges.length === 0) {
|
|
566
|
+
return { rowGroupIndex, columns: {}, rowCount: 0, rowIndices: [] };
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (workerOptions) {
|
|
570
|
+
return await this.readRowGroupOnWorker(initialization, rowGroupIndex, columnList, projectedSchema, batchSize, predicate, pagePlan, workerOptions, signal);
|
|
571
|
+
}
|
|
572
|
+
const decodeStartTime = getCurrentTime();
|
|
573
|
+
const decodedRowGroups = pagePlan
|
|
574
|
+
? await Promise.all(pagePlan.rowRanges.map(rowRange => initialization.reader.readRowGroupRange(initialization.parquetSchema, rowGroup, columnList, rowRange, pagePlan.pageLocations, signal, rowGroupIndex)))
|
|
575
|
+
: [
|
|
576
|
+
await initialization.reader.readRowGroup(initialization.parquetSchema, rowGroup, columnList, signal, rowGroupIndex)
|
|
577
|
+
];
|
|
578
|
+
throwIfAborted(signal);
|
|
579
|
+
const columns = concatenateMaterializedColumns(decodedRowGroups.map(decodedRowGroup => initialization.parquetSchema.materializeColumns(decodedRowGroup)));
|
|
580
|
+
const sourceRowIndices = pagePlan
|
|
581
|
+
? pagePlan.rowRanges.flatMap(rowRange => Array.from({ length: rowRange.end - rowRange.start }, (_, index) => rowRange.start + index))
|
|
582
|
+
: undefined;
|
|
583
|
+
const localRowCount = sourceRowIndices?.length ?? Number(rowGroup.num_rows);
|
|
584
|
+
const localRowIndices = predicate
|
|
585
|
+
? filterParquetRowIndices(predicate, columns, localRowCount)
|
|
586
|
+
: undefined;
|
|
587
|
+
const rowIndices = localRowIndices?.map(rowIndex => sourceRowIndices?.[rowIndex] ?? rowIndex);
|
|
588
|
+
const outputColumns = localRowIndices
|
|
589
|
+
? gatherParquetColumns(columns, localRowIndices, projectedColumnNames)
|
|
590
|
+
: columns;
|
|
591
|
+
const decodeDurationMs = getCurrentTime() - decodeStartTime;
|
|
592
|
+
this.recordTelemetry('decode', { decodeDurationMs, rowGroupsDecoded: 1 }, { rowGroupIndex, durationMs: decodeDurationMs });
|
|
593
|
+
if (predicate) {
|
|
594
|
+
this.recordTelemetry('predicate-filter', {
|
|
595
|
+
predicateRowsTested: localRowCount,
|
|
596
|
+
predicateRowsMatched: rowIndices.length
|
|
597
|
+
}, { rowGroupIndex, rowCount: rowIndices.length });
|
|
598
|
+
}
|
|
599
|
+
return {
|
|
600
|
+
rowGroupIndex,
|
|
601
|
+
columns: outputColumns,
|
|
602
|
+
rowCount: rowIndices?.length ?? localRowCount,
|
|
603
|
+
rowIndices
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
/** Fetches selected chunks and transfers their decompression and Arrow conversion to a worker. */
|
|
607
|
+
async readRowGroupOnWorker(initialization, rowGroupIndex, columnList, projectedSchema, batchSize, predicate, pagePlan, workerOptions, signal) {
|
|
608
|
+
const rowGroup = initialization.fileMetadata.row_groups[rowGroupIndex];
|
|
609
|
+
const selectedColumnChunks = rowGroup.columns.filter(columnChunk => {
|
|
610
|
+
const path = columnChunk.meta_data?.path_in_schema;
|
|
611
|
+
return Boolean(path && (columnList.length === 0 || fieldIndexOf(columnList, path) >= 0));
|
|
612
|
+
});
|
|
613
|
+
const rangeDescriptors = pagePlan
|
|
614
|
+
? getParquetPageReadRanges(rowGroup, columnList, pagePlan, initialization.parquetSchema)
|
|
615
|
+
: selectedColumnChunks.map(getColumnChunkRange);
|
|
616
|
+
const ranges = await Promise.all(rangeDescriptors.map(async ({ offset, length }) => {
|
|
617
|
+
return { offset, data: await initialization.file.read(offset, length, signal) };
|
|
618
|
+
}));
|
|
619
|
+
throwIfAborted(signal);
|
|
620
|
+
const workerColumnChunks = await Promise.all(selectedColumnChunks.map(async (columnChunk) => {
|
|
621
|
+
const descriptor = createParquetSourceWorkerColumnChunk(columnChunk);
|
|
622
|
+
descriptor.columnOrdinal = rowGroup.columns.indexOf(columnChunk);
|
|
623
|
+
if (columnChunk.crypto_metadata) {
|
|
624
|
+
const columnOrdinal = rowGroup.columns.indexOf(columnChunk);
|
|
625
|
+
const key = await initialization.reader.getColumnKeyForWorker(columnChunk, rowGroupIndex, columnOrdinal);
|
|
626
|
+
descriptor.encrypted = true;
|
|
627
|
+
descriptor.keyMetadata = key.keyMetadata?.slice().buffer;
|
|
628
|
+
descriptor.keyMaterial = key.keyMaterial.slice().buffer;
|
|
629
|
+
}
|
|
630
|
+
return descriptor;
|
|
631
|
+
}));
|
|
632
|
+
const encryptionContext = initialization.reader.getEncryptionContextForWorker();
|
|
633
|
+
let workerResult;
|
|
634
|
+
try {
|
|
635
|
+
workerResult = await decodeParquetSourceRowGroupOnWorker({
|
|
636
|
+
fileByteLength: initialization.file.size,
|
|
637
|
+
rowCount: Number(rowGroup.num_rows),
|
|
638
|
+
uncompressedByteLength: Number(rowGroup.total_byte_size),
|
|
639
|
+
schemaDefinition: initialization.parquetSchema.schema,
|
|
640
|
+
projectedSchema,
|
|
641
|
+
columnChunks: workerColumnChunks,
|
|
642
|
+
ranges,
|
|
643
|
+
batchSize: batchSize || Math.max(Number(rowGroup.num_rows), 1),
|
|
644
|
+
predicate: predicate ? copyParquetPredicate(predicate) : undefined,
|
|
645
|
+
pagePlan,
|
|
646
|
+
encryption: encryptionContext
|
|
647
|
+
? {
|
|
648
|
+
algorithm: encryptionContext.algorithm,
|
|
649
|
+
aadPrefix: encryptionContext.aadPrefix?.slice().buffer,
|
|
650
|
+
fileUnique: encryptionContext.fileUnique.slice().buffer
|
|
651
|
+
}
|
|
652
|
+
: undefined,
|
|
653
|
+
preserveBinary: Boolean(this.options.parquet?.preserveBinary),
|
|
654
|
+
int96AsTimestamp: Boolean(this.options.parquet?.int96AsTimestamp),
|
|
655
|
+
verifyPageChecksums: Boolean(this.options.parquet?.verifyPageChecksums)
|
|
656
|
+
}, workerOptions);
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
throwIfAborted(signal);
|
|
660
|
+
throw error;
|
|
661
|
+
}
|
|
662
|
+
throwIfAborted(signal);
|
|
663
|
+
this.recordTelemetry('decode', { decodeDurationMs: workerResult.decodeDurationMs, rowGroupsDecoded: 1 }, { rowGroupIndex, durationMs: workerResult.decodeDurationMs });
|
|
664
|
+
this.recordTelemetry('arrow-conversion', { arrowConversionDurationMs: workerResult.arrowConversionDurationMs }, { rowGroupIndex, durationMs: workerResult.arrowConversionDurationMs });
|
|
665
|
+
if (predicate) {
|
|
666
|
+
this.recordTelemetry('predicate-filter', {
|
|
667
|
+
predicateRowsTested: workerResult.sourceRowCount,
|
|
668
|
+
predicateRowsMatched: workerResult.rowCount
|
|
669
|
+
}, { rowGroupIndex, rowCount: workerResult.rowCount });
|
|
670
|
+
}
|
|
671
|
+
return { rowGroupIndex, rowCount: workerResult.rowCount, workerResult };
|
|
672
|
+
}
|
|
673
|
+
/** Decodes predicate columns first, avoiding projected-column decoding for empty matches. */
|
|
674
|
+
async readRowGroupWithLateMaterialization(initialization, rowGroupIndex, columnList, projectedSchema, batchSize, predicate, projectedColumnNames, workerOptions, signal) {
|
|
675
|
+
const predicateColumns = getParquetPredicateColumns(predicate);
|
|
676
|
+
const predicateColumnList = predicateColumns.map(column => [column]);
|
|
677
|
+
const filterResult = await this.readRowGroup(initialization, rowGroupIndex, predicateColumnList, projectSchema(initialization.schema, predicateColumns), batchSize, predicate, new Set(predicateColumns), workerOptions, signal);
|
|
678
|
+
const rowIndices = filterResult.rowIndices;
|
|
679
|
+
const selectedRowIndices = rowIndices || getWorkerRowIndices(filterResult.workerResult);
|
|
680
|
+
if (!selectedRowIndices || selectedRowIndices.length === 0) {
|
|
681
|
+
return { rowGroupIndex, rowCount: 0, columns: {}, rowIndices: [] };
|
|
682
|
+
}
|
|
683
|
+
const projectedColumnList = columnList.filter(columnPath => projectedColumnNames.has(columnPath[0]));
|
|
684
|
+
const projectedResult = await this.readRowGroup(initialization, rowGroupIndex, projectedColumnList, projectedSchema, batchSize, undefined, projectedColumnNames, workerOptions, signal);
|
|
685
|
+
if (workerOptions && projectedResult.workerResult) {
|
|
686
|
+
return {
|
|
687
|
+
rowGroupIndex,
|
|
688
|
+
rowCount: selectedRowIndices.length,
|
|
689
|
+
rowIndices: selectedRowIndices,
|
|
690
|
+
workerResult: gatherWorkerProjectedRows(projectedResult.workerResult, selectedRowIndices, batchSize)
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
return {
|
|
694
|
+
rowGroupIndex,
|
|
695
|
+
rowCount: selectedRowIndices.length,
|
|
696
|
+
rowIndices: selectedRowIndices,
|
|
697
|
+
columns: projectedResult.columns
|
|
698
|
+
? gatherParquetColumns(projectedResult.columns, selectedRowIndices, projectedColumnNames)
|
|
699
|
+
: {}
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
/** Records the rows and pages avoided by one conservative page-index plan. */
|
|
703
|
+
recordPagePruningTelemetry(rowGroupIndex, plan) {
|
|
704
|
+
this.recordTelemetry('page-index-prune', {
|
|
705
|
+
pageIndexesRead: plan.indexCount,
|
|
706
|
+
pagesRead: plan.selectedPageCount,
|
|
707
|
+
pagesPruned: plan.totalPageCount - plan.selectedPageCount,
|
|
708
|
+
rowsPrunedByPageIndex: plan.prunedRowCount,
|
|
709
|
+
rowGroupsPrunedByPageIndex: plan.rowRanges.length === 0 ? 1 : 0,
|
|
710
|
+
rowGroupsPruned: plan.rowRanges.length === 0 ? 1 : 0
|
|
711
|
+
}, { rowGroupIndex, rowCount: plan.prunedRowCount });
|
|
712
|
+
}
|
|
713
|
+
/** Opens the readable file and decodes its footer and schema once. */
|
|
714
|
+
async initialize(signal) {
|
|
715
|
+
const file = await this.openFile(signal);
|
|
716
|
+
try {
|
|
717
|
+
const reader = new ParquetReader(file, {
|
|
718
|
+
preserveBinary: this.options.parquet?.preserveBinary,
|
|
719
|
+
int96AsTimestamp: this.options.parquet?.int96AsTimestamp,
|
|
720
|
+
verifyPageChecksums: this.options.parquet?.verifyPageChecksums,
|
|
721
|
+
verifyFooterSignature: this.options.parquet?.verifyFooterSignature,
|
|
722
|
+
keyRetriever: this.options.parquet?.keyRetriever,
|
|
723
|
+
aadPrefix: this.options.parquet?.aadPrefix,
|
|
724
|
+
signal
|
|
725
|
+
});
|
|
726
|
+
const fileMetadata = await reader.getFileMetadata();
|
|
727
|
+
const parquetSchema = await reader.getSchema();
|
|
728
|
+
const schema = deepFreeze(await getSchemaFromParquetReader(reader));
|
|
729
|
+
const metadata = createParquetSourceMetadata(this.data, this.url, file, fileMetadata, schema, parquetSchema, file instanceof ParquetRangeFile ? file.objectVersion : undefined);
|
|
730
|
+
reader.props.signal = undefined;
|
|
731
|
+
return { file, reader, schema, parquetSchema, fileMetadata, metadata };
|
|
732
|
+
}
|
|
733
|
+
catch (error) {
|
|
734
|
+
await file.close();
|
|
735
|
+
throw error;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
/** Opens a Blob file or probes a remote object with one bounded range request. */
|
|
739
|
+
async openFile(signal) {
|
|
740
|
+
if (typeof this.data !== 'string') {
|
|
741
|
+
this.readableFile = new BlobFile(this.data);
|
|
742
|
+
return this.readableFile;
|
|
743
|
+
}
|
|
744
|
+
const file = new ParquetRangeFile(this.url, {
|
|
745
|
+
fetch: this.fetch,
|
|
746
|
+
headers: this.options.parquet?.headers,
|
|
747
|
+
rangeRequests: this.options.rangeRequests,
|
|
748
|
+
onTelemetry: event => this.recordTelemetry(event.type, {
|
|
749
|
+
rangeRequestCount: event.rangeRequestCount,
|
|
750
|
+
requestedBytes: event.requestedBytes,
|
|
751
|
+
downloadedBytes: event.downloadedBytes,
|
|
752
|
+
cacheHits: event.cacheHits,
|
|
753
|
+
networkDurationMs: event.networkDurationMs,
|
|
754
|
+
failedRangeRequestCount: event.failedRangeRequestCount,
|
|
755
|
+
abortedRangeRequestCount: event.abortedRangeRequestCount
|
|
756
|
+
}, { durationMs: event.networkDurationMs, error: event.error })
|
|
757
|
+
});
|
|
758
|
+
this.readableFile = file;
|
|
759
|
+
return await file.open(signal);
|
|
760
|
+
}
|
|
761
|
+
/** Applies telemetry deltas and emits a callback with the resulting cumulative snapshot. */
|
|
762
|
+
recordTelemetry(type, delta, details) {
|
|
763
|
+
for (const [key, value] of Object.entries(delta)) {
|
|
764
|
+
if (value !== undefined) {
|
|
765
|
+
this.telemetry[key] += value;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
try {
|
|
769
|
+
this.options.parquet?.onTelemetry?.({ type, telemetry: this.getTelemetry(), ...details });
|
|
770
|
+
}
|
|
771
|
+
catch {
|
|
772
|
+
// Telemetry must never change source read behavior.
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
function getParquetColumnRoles(columnNames) {
|
|
777
|
+
const roles = {};
|
|
778
|
+
for (const columnName of columnNames) {
|
|
779
|
+
const normalizedName = columnName.toLowerCase();
|
|
780
|
+
if (normalizedName === 'geometry' || normalizedName === 'geom' || normalizedName === 'shape') {
|
|
781
|
+
roles[columnName] = 'geometry';
|
|
782
|
+
}
|
|
783
|
+
else if (normalizedName === 'longitude' ||
|
|
784
|
+
normalizedName === 'lon' ||
|
|
785
|
+
normalizedName === 'x') {
|
|
786
|
+
roles[columnName] = 'longitude';
|
|
787
|
+
}
|
|
788
|
+
else if (normalizedName === 'latitude' ||
|
|
789
|
+
normalizedName === 'lat' ||
|
|
790
|
+
normalizedName === 'y') {
|
|
791
|
+
roles[columnName] = 'latitude';
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return roles;
|
|
795
|
+
}
|
|
796
|
+
/** Normalizes a decoded Parquet footer into source metadata. */
|
|
797
|
+
function createParquetSourceMetadata(data, url, file, fileMetadata, schema, parquetSchema, objectVersion) {
|
|
798
|
+
let rowOffset = 0;
|
|
799
|
+
const rowGroups = fileMetadata.row_groups.map((rowGroup, index) => {
|
|
800
|
+
const columns = rowGroup.columns
|
|
801
|
+
.filter(columnChunk => Boolean(columnChunk.meta_data))
|
|
802
|
+
.map(columnChunk => createColumnChunkMetadata(columnChunk, parquetSchema));
|
|
803
|
+
const normalizedRowGroup = createRowGroupMetadata(index, rowOffset, Number(rowGroup.num_rows), Number(rowGroup.total_byte_size), columns, rowGroup.sorting_columns);
|
|
804
|
+
rowOffset += normalizedRowGroup.rowCount;
|
|
805
|
+
return normalizedRowGroup;
|
|
806
|
+
});
|
|
807
|
+
return Object.freeze({
|
|
808
|
+
schema,
|
|
809
|
+
name: getSourceName(data, url),
|
|
810
|
+
url: url || undefined,
|
|
811
|
+
fileByteLength: file.size,
|
|
812
|
+
version: fileMetadata.version,
|
|
813
|
+
formatVersion: fileMetadata.version,
|
|
814
|
+
createdBy: fileMetadata.created_by,
|
|
815
|
+
rowCount: Number(fileMetadata.num_rows),
|
|
816
|
+
rowGroupCount: rowGroups.length,
|
|
817
|
+
keyValueMetadata: Object.freeze(getKeyValueMetadata(fileMetadata)),
|
|
818
|
+
rowGroups: Object.freeze(rowGroups),
|
|
819
|
+
objectVersion: hasObjectVersion(objectVersion) ? Object.freeze({ ...objectVersion }) : undefined
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
/** Normalizes a decoded Parquet column chunk. */
|
|
823
|
+
function createColumnChunkMetadata(columnChunk, parquetSchema) {
|
|
824
|
+
const columnMetadata = columnChunk.meta_data;
|
|
825
|
+
const dataPageOffset = Number(columnMetadata.data_page_offset);
|
|
826
|
+
const dictionaryPageOffset = columnMetadata.dictionary_page_offset === undefined
|
|
827
|
+
? undefined
|
|
828
|
+
: Number(columnMetadata.dictionary_page_offset);
|
|
829
|
+
const statistics = createColumnChunkStatistics(columnMetadata.statistics, parquetSchema.findField(columnMetadata.path_in_schema));
|
|
830
|
+
const geospatialStatistics = createGeospatialStatistics(columnMetadata.geospatial_statistics);
|
|
831
|
+
const sizeStatistics = createSizeStatistics(columnMetadata.size_statistics);
|
|
832
|
+
const compressedByteLength = Number(columnMetadata.total_compressed_size);
|
|
833
|
+
const uncompressedByteLength = Number(columnMetadata.total_uncompressed_size);
|
|
834
|
+
return Object.freeze({
|
|
835
|
+
path: Object.freeze([...columnMetadata.path_in_schema]),
|
|
836
|
+
filePath: columnChunk.file_path || undefined,
|
|
837
|
+
compression: CompressionCodec[columnMetadata.codec] || String(columnMetadata.codec),
|
|
838
|
+
encodings: Object.freeze(columnMetadata.encodings.map(encoding => Encoding[encoding] || String(encoding))),
|
|
839
|
+
valueCount: Number(columnMetadata.num_values),
|
|
840
|
+
fileOffset: Math.min(dataPageOffset, dictionaryPageOffset && dictionaryPageOffset > 0 ? dictionaryPageOffset : dataPageOffset),
|
|
841
|
+
compressedByteLength,
|
|
842
|
+
compressedSize: compressedByteLength,
|
|
843
|
+
uncompressedByteLength,
|
|
844
|
+
uncompressedSize: uncompressedByteLength,
|
|
845
|
+
dataPageOffset,
|
|
846
|
+
dictionaryPageOffset,
|
|
847
|
+
columnIndexOffset: columnChunk.column_index_offset === undefined
|
|
848
|
+
? undefined
|
|
849
|
+
: Number(columnChunk.column_index_offset),
|
|
850
|
+
columnIndexByteLength: columnChunk.column_index_length,
|
|
851
|
+
offsetIndexOffset: columnChunk.offset_index_offset === undefined
|
|
852
|
+
? undefined
|
|
853
|
+
: Number(columnChunk.offset_index_offset),
|
|
854
|
+
offsetIndexByteLength: columnChunk.offset_index_length,
|
|
855
|
+
bloomFilterOffset: columnMetadata.bloom_filter_offset === undefined
|
|
856
|
+
? undefined
|
|
857
|
+
: Number(columnMetadata.bloom_filter_offset),
|
|
858
|
+
bloomFilterByteLength: columnMetadata.bloom_filter_length,
|
|
859
|
+
statistics,
|
|
860
|
+
sizeStatistics,
|
|
861
|
+
geospatialStatistics
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
/** Normalizes optional Parquet size statistics without inventing missing counts. */
|
|
865
|
+
function createSizeStatistics(statistics) {
|
|
866
|
+
if (!statistics)
|
|
867
|
+
return undefined;
|
|
868
|
+
const result = {
|
|
869
|
+
unencodedByteArrayDataBytes: statistics.unencoded_byte_array_data_bytes === undefined
|
|
870
|
+
? undefined
|
|
871
|
+
: toSafeNumber(statistics.unencoded_byte_array_data_bytes),
|
|
872
|
+
repetitionLevelHistogram: normalizeSizeStatisticsList(statistics.repetition_level_histogram),
|
|
873
|
+
definitionLevelHistogram: normalizeSizeStatisticsList(statistics.definition_level_histogram)
|
|
874
|
+
};
|
|
875
|
+
if (result.unencodedByteArrayDataBytes === undefined &&
|
|
876
|
+
result.repetitionLevelHistogram === undefined &&
|
|
877
|
+
result.definitionLevelHistogram === undefined) {
|
|
878
|
+
return undefined;
|
|
879
|
+
}
|
|
880
|
+
return Object.freeze({
|
|
881
|
+
...result,
|
|
882
|
+
repetitionLevelHistogram: result.repetitionLevelHistogram
|
|
883
|
+
? Object.freeze(result.repetitionLevelHistogram)
|
|
884
|
+
: undefined,
|
|
885
|
+
definitionLevelHistogram: result.definitionLevelHistogram
|
|
886
|
+
? Object.freeze(result.definitionLevelHistogram)
|
|
887
|
+
: undefined
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
function toSafeNumber(value) {
|
|
891
|
+
const numberValue = typeof value === 'number' ? value : value.toNumber?.();
|
|
892
|
+
return numberValue !== undefined && Number.isSafeInteger(numberValue) && numberValue >= 0
|
|
893
|
+
? numberValue
|
|
894
|
+
: undefined;
|
|
895
|
+
}
|
|
896
|
+
/** Converts a Thrift int64 histogram only when every entry is a safe non-negative integer. */
|
|
897
|
+
function normalizeSizeStatisticsList(values) {
|
|
898
|
+
if (!values)
|
|
899
|
+
return undefined;
|
|
900
|
+
const normalized = values.map(toSafeNumber);
|
|
901
|
+
return normalized.every((value) => value !== undefined) ? normalized : undefined;
|
|
902
|
+
}
|
|
903
|
+
/** Normalizes native Parquet geospatial statistics from the decoded footer. */
|
|
904
|
+
function createGeospatialStatistics(statistics) {
|
|
905
|
+
if (!statistics)
|
|
906
|
+
return undefined;
|
|
907
|
+
const bbox = statistics.bbox
|
|
908
|
+
? Object.freeze({
|
|
909
|
+
xmin: statistics.bbox.xmin,
|
|
910
|
+
xmax: statistics.bbox.xmax,
|
|
911
|
+
ymin: statistics.bbox.ymin,
|
|
912
|
+
ymax: statistics.bbox.ymax,
|
|
913
|
+
zmin: statistics.bbox.zmin,
|
|
914
|
+
zmax: statistics.bbox.zmax,
|
|
915
|
+
mmin: statistics.bbox.mmin,
|
|
916
|
+
mmax: statistics.bbox.mmax
|
|
917
|
+
})
|
|
918
|
+
: undefined;
|
|
919
|
+
return Object.freeze({
|
|
920
|
+
bbox,
|
|
921
|
+
geometryTypes: statistics.geospatial_types
|
|
922
|
+
? Object.freeze([...statistics.geospatial_types])
|
|
923
|
+
: undefined
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
/** Decodes optional footer statistics into the column's logical value representation. */
|
|
927
|
+
function createColumnChunkStatistics(statistics, field) {
|
|
928
|
+
if (!statistics) {
|
|
929
|
+
return undefined;
|
|
930
|
+
}
|
|
931
|
+
const minBytes = statistics.min_value ?? statistics.min;
|
|
932
|
+
const maxBytes = statistics.max_value ?? statistics.max;
|
|
933
|
+
const result = {
|
|
934
|
+
nullCount: statistics.null_count === undefined ? undefined : Number(statistics.null_count),
|
|
935
|
+
distinctCount: statistics.distinct_count === undefined ? undefined : Number(statistics.distinct_count),
|
|
936
|
+
minIsExact: statistics.is_min_value_exact,
|
|
937
|
+
maxIsExact: statistics.is_max_value_exact
|
|
938
|
+
};
|
|
939
|
+
if (minBytes) {
|
|
940
|
+
result.min = decodeStatisticsValueSafely(toUint8Array(minBytes), field);
|
|
941
|
+
}
|
|
942
|
+
if (maxBytes) {
|
|
943
|
+
result.max = decodeStatisticsValueSafely(toUint8Array(maxBytes), field);
|
|
944
|
+
}
|
|
945
|
+
if (result.min === undefined &&
|
|
946
|
+
result.max === undefined &&
|
|
947
|
+
result.nullCount === undefined &&
|
|
948
|
+
result.distinctCount === undefined &&
|
|
949
|
+
result.minIsExact === undefined &&
|
|
950
|
+
result.maxIsExact === undefined) {
|
|
951
|
+
return undefined;
|
|
952
|
+
}
|
|
953
|
+
return Object.freeze(result);
|
|
954
|
+
}
|
|
955
|
+
/** Decodes one footer statistic and returns undefined for malformed or unsupported values. */
|
|
956
|
+
function decodeStatisticsValueSafely(bytes, field) {
|
|
957
|
+
try {
|
|
958
|
+
let primitiveValue;
|
|
959
|
+
switch (field.primitiveType) {
|
|
960
|
+
case 'BOOLEAN':
|
|
961
|
+
primitiveValue = Boolean(bytes[0]);
|
|
962
|
+
break;
|
|
963
|
+
case 'INT32':
|
|
964
|
+
primitiveValue =
|
|
965
|
+
field.originalType === 'UINT_32' ? readUInt32LE(bytes, 0) : readInt32LE(bytes, 0);
|
|
966
|
+
break;
|
|
967
|
+
case 'INT64':
|
|
968
|
+
primitiveValue =
|
|
969
|
+
field.originalType === 'UINT_64' ? readUInt64LE(bytes, 0) : readInt64LE(bytes, 0);
|
|
970
|
+
break;
|
|
971
|
+
case 'FLOAT':
|
|
972
|
+
primitiveValue = readFloatLE(bytes, 0);
|
|
973
|
+
break;
|
|
974
|
+
case 'DOUBLE':
|
|
975
|
+
primitiveValue = readDoubleLE(bytes, 0);
|
|
976
|
+
break;
|
|
977
|
+
case 'INT96':
|
|
978
|
+
case 'BYTE_ARRAY':
|
|
979
|
+
case 'FIXED_LEN_BYTE_ARRAY':
|
|
980
|
+
primitiveValue = copyUint8Array(bytes);
|
|
981
|
+
break;
|
|
982
|
+
default:
|
|
983
|
+
return undefined;
|
|
984
|
+
}
|
|
985
|
+
return Types.fromPrimitive(field.originalType || field.primitiveType, primitiveValue, field);
|
|
986
|
+
}
|
|
987
|
+
catch {
|
|
988
|
+
return undefined;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
/** Normalizes one decoded row group and derives its compressed byte length. */
|
|
992
|
+
function createRowGroupMetadata(index, rowOffset, rowCount, uncompressedByteLength, columns, sortingColumns) {
|
|
993
|
+
const compressedByteLength = columns.reduce((sum, column) => sum + column.compressedByteLength, 0);
|
|
994
|
+
return Object.freeze({
|
|
995
|
+
index,
|
|
996
|
+
rowOffset,
|
|
997
|
+
rowCount,
|
|
998
|
+
uncompressedByteLength,
|
|
999
|
+
uncompressedSize: uncompressedByteLength,
|
|
1000
|
+
compressedByteLength,
|
|
1001
|
+
compressedSize: compressedByteLength,
|
|
1002
|
+
columns: Object.freeze(columns),
|
|
1003
|
+
sortingColumns: Object.freeze((sortingColumns || []).map(sortingColumn => Object.freeze({
|
|
1004
|
+
columnIndex: sortingColumn.column_idx,
|
|
1005
|
+
descending: sortingColumn.descending,
|
|
1006
|
+
nullsFirst: sortingColumn.nulls_first
|
|
1007
|
+
})))
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
/** Describes a phase that reads complete column chunks because no page index is available. */
|
|
1011
|
+
function createFullColumnScanPlan(rowGroup, rowGroupIndex, phase, columns) {
|
|
1012
|
+
const selectedColumnChunks = rowGroup.columns.filter(columnChunk => {
|
|
1013
|
+
const path = columnChunk.meta_data?.path_in_schema;
|
|
1014
|
+
return Boolean(path && (columns.length === 0 || columns.some(column => pathMatchesSelection(column, path))));
|
|
1015
|
+
});
|
|
1016
|
+
const rowCount = Number(rowGroup.num_rows);
|
|
1017
|
+
return Object.freeze({
|
|
1018
|
+
rowGroupIndex,
|
|
1019
|
+
phase,
|
|
1020
|
+
columns: Object.freeze(columns.map(column => Object.freeze([...column]))),
|
|
1021
|
+
rowRanges: Object.freeze([Object.freeze({ start: 0, end: rowCount })]),
|
|
1022
|
+
indexesRead: 0,
|
|
1023
|
+
totalPages: 0,
|
|
1024
|
+
selectedPages: 0,
|
|
1025
|
+
rowsPruned: 0,
|
|
1026
|
+
ranges: Object.freeze(selectedColumnChunks.map(columnChunk => Object.freeze(getColumnChunkRange(columnChunk))))
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
/** Returns whether a requested path selects a footer leaf or one of its nested children. */
|
|
1030
|
+
function pathMatchesSelection(selection, path) {
|
|
1031
|
+
return selection.length <= path.length && selection.every((part, index) => part === path[index]);
|
|
1032
|
+
}
|
|
1033
|
+
/** Returns the complete contiguous byte range occupied by one Parquet column chunk. */
|
|
1034
|
+
function getColumnChunkRange(columnChunk) {
|
|
1035
|
+
if (columnChunk.file_path) {
|
|
1036
|
+
throw new Error('Parquet worker decoding does not support external column chunk files');
|
|
1037
|
+
}
|
|
1038
|
+
const columnMetadata = columnChunk.meta_data;
|
|
1039
|
+
if (!columnMetadata) {
|
|
1040
|
+
throw new Error('Parquet column chunk is missing metadata');
|
|
1041
|
+
}
|
|
1042
|
+
const dataPageOffset = Number(columnMetadata.data_page_offset);
|
|
1043
|
+
const dictionaryPageOffset = columnMetadata.dictionary_page_offset === undefined
|
|
1044
|
+
? undefined
|
|
1045
|
+
: Number(columnMetadata.dictionary_page_offset);
|
|
1046
|
+
const offset = Math.min(dataPageOffset, dictionaryPageOffset && dictionaryPageOffset > 0 ? dictionaryPageOffset : dataPageOffset);
|
|
1047
|
+
const length = Number(columnMetadata.total_compressed_size);
|
|
1048
|
+
if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || offset < 0 || length < 0) {
|
|
1049
|
+
throw new Error('Parquet column chunk range must use non-negative safe integers');
|
|
1050
|
+
}
|
|
1051
|
+
return { offset, length };
|
|
1052
|
+
}
|
|
1053
|
+
/** Copies one selected Thrift column chunk into a structured-cloneable worker descriptor. */
|
|
1054
|
+
function createParquetSourceWorkerColumnChunk(columnChunk) {
|
|
1055
|
+
const columnMetadata = columnChunk.meta_data;
|
|
1056
|
+
if (!columnMetadata) {
|
|
1057
|
+
throw new Error('Parquet column chunk is missing metadata');
|
|
1058
|
+
}
|
|
1059
|
+
return {
|
|
1060
|
+
filePath: columnChunk.file_path || undefined,
|
|
1061
|
+
physicalType: columnMetadata.type,
|
|
1062
|
+
compressionCodec: columnMetadata.codec,
|
|
1063
|
+
path: [...columnMetadata.path_in_schema],
|
|
1064
|
+
valueCount: Number(columnMetadata.num_values),
|
|
1065
|
+
compressedByteLength: Number(columnMetadata.total_compressed_size),
|
|
1066
|
+
uncompressedByteLength: Number(columnMetadata.total_uncompressed_size),
|
|
1067
|
+
dataPageOffset: Number(columnMetadata.data_page_offset),
|
|
1068
|
+
dictionaryPageOffset: columnMetadata.dictionary_page_offset === undefined
|
|
1069
|
+
? undefined
|
|
1070
|
+
: Number(columnMetadata.dictionary_page_offset)
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
/** Converts decoded columns into one Arrow batch and attaches stable source provenance. */
|
|
1074
|
+
function createParquetBatch(metadata, schema, rowGroupIndex, rowGroupRowOffset, columns, rowCount, rowGroupRowIndices) {
|
|
1075
|
+
const arrowTable = convertTable({ shape: 'columnar-table', schema, data: columns }, 'arrow-table');
|
|
1076
|
+
return createParquetBatchFromArrow(metadata, schema, rowGroupIndex, rowGroupRowOffset, arrowTable.data, rowCount, rowGroupRowIndices);
|
|
1077
|
+
}
|
|
1078
|
+
/** Wraps a worker-transferred or locally converted Arrow table with source provenance. */
|
|
1079
|
+
function createParquetBatchFromArrow(metadata, schema, rowGroupIndex, rowGroupRowOffset, data, rowCount, rowGroupRowIndices) {
|
|
1080
|
+
const rowGroup = metadata.rowGroups[rowGroupIndex];
|
|
1081
|
+
const sourceId = metadata.url || metadata.name;
|
|
1082
|
+
const provenance = Object.freeze({
|
|
1083
|
+
sourceId,
|
|
1084
|
+
sourceUrl: metadata.url,
|
|
1085
|
+
source: sourceId,
|
|
1086
|
+
rowGroupIndex,
|
|
1087
|
+
rowOffset: rowGroup.rowOffset + rowGroupRowOffset,
|
|
1088
|
+
rowGroupRowOffset,
|
|
1089
|
+
rowCount,
|
|
1090
|
+
rowGroupRowIndices: rowGroupRowIndices ? Object.freeze([...rowGroupRowIndices]) : undefined,
|
|
1091
|
+
rowIndices: rowGroupRowIndices
|
|
1092
|
+
? Object.freeze(rowGroupRowIndices.map(rowIndex => rowGroup.rowOffset + rowIndex))
|
|
1093
|
+
: undefined
|
|
1094
|
+
});
|
|
1095
|
+
return {
|
|
1096
|
+
...makeTableScanBatch({ shape: 'arrow-table', schema, data }),
|
|
1097
|
+
schemaType: 'explicit',
|
|
1098
|
+
length: rowCount,
|
|
1099
|
+
metadata: provenance,
|
|
1100
|
+
...provenance
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
/** Returns a contiguous row slice of every decoded column without constructing row objects. */
|
|
1104
|
+
function sliceColumns(columns, start, end) {
|
|
1105
|
+
const slicedColumns = {};
|
|
1106
|
+
for (const [name, column] of Object.entries(columns)) {
|
|
1107
|
+
const slice = column.slice;
|
|
1108
|
+
slicedColumns[name] = slice
|
|
1109
|
+
? slice.call(column, start, end)
|
|
1110
|
+
: Array.prototype.slice.call(column, start, end);
|
|
1111
|
+
}
|
|
1112
|
+
return slicedColumns;
|
|
1113
|
+
}
|
|
1114
|
+
/** Concatenates materialized page-range fragments without constructing row objects. */
|
|
1115
|
+
function concatenateMaterializedColumns(fragments) {
|
|
1116
|
+
const columns = {};
|
|
1117
|
+
for (const fragment of fragments) {
|
|
1118
|
+
for (const [name, values] of Object.entries(fragment)) {
|
|
1119
|
+
columns[name] ||= [];
|
|
1120
|
+
const destination = columns[name];
|
|
1121
|
+
for (let index = 0; index < values.length; index++) {
|
|
1122
|
+
destination.push(values[index]);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return columns;
|
|
1127
|
+
}
|
|
1128
|
+
/** Validates and normalizes requested row-group indexes. */
|
|
1129
|
+
function normalizeRowGroupIndices(rowGroups, rowGroupCount) {
|
|
1130
|
+
const rowGroupIndices = rowGroups || Array.from({ length: rowGroupCount }, (_, index) => index);
|
|
1131
|
+
const seenIndices = new Set();
|
|
1132
|
+
for (const rowGroupIndex of rowGroupIndices) {
|
|
1133
|
+
if (!Number.isInteger(rowGroupIndex) || rowGroupIndex < 0 || rowGroupIndex >= rowGroupCount) {
|
|
1134
|
+
throw new Error(`Invalid Parquet row-group index ${rowGroupIndex}`);
|
|
1135
|
+
}
|
|
1136
|
+
if (seenIndices.has(rowGroupIndex)) {
|
|
1137
|
+
throw new Error(`Duplicate Parquet row-group index ${rowGroupIndex}`);
|
|
1138
|
+
}
|
|
1139
|
+
seenIndices.add(rowGroupIndex);
|
|
1140
|
+
}
|
|
1141
|
+
return [...rowGroupIndices];
|
|
1142
|
+
}
|
|
1143
|
+
/** Validates selected top-level columns against the source schema. */
|
|
1144
|
+
function normalizeColumns(columns, schema) {
|
|
1145
|
+
if (!columns?.length) {
|
|
1146
|
+
return [];
|
|
1147
|
+
}
|
|
1148
|
+
const availableColumns = new Set(schema.fields.map(field => field.name));
|
|
1149
|
+
const normalizedColumns = [];
|
|
1150
|
+
for (const column of columns) {
|
|
1151
|
+
if (!availableColumns.has(column)) {
|
|
1152
|
+
throw new Error(`Parquet column not found: ${column}`);
|
|
1153
|
+
}
|
|
1154
|
+
if (!normalizedColumns.includes(column)) {
|
|
1155
|
+
normalizedColumns.push(column);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
return normalizedColumns;
|
|
1159
|
+
}
|
|
1160
|
+
/** Returns a schema containing only explicitly selected top-level fields. */
|
|
1161
|
+
function projectSchema(schema, columns) {
|
|
1162
|
+
if (columns.length === 0) {
|
|
1163
|
+
return schema;
|
|
1164
|
+
}
|
|
1165
|
+
const selectedColumns = new Set(columns);
|
|
1166
|
+
return { ...schema, fields: schema.fields.filter(field => selectedColumns.has(field.name)) };
|
|
1167
|
+
}
|
|
1168
|
+
/** Validates an optional output batch size. */
|
|
1169
|
+
function normalizeBatchSize(batchSize) {
|
|
1170
|
+
if (batchSize === undefined) {
|
|
1171
|
+
return undefined;
|
|
1172
|
+
}
|
|
1173
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
1174
|
+
throw new Error(`Invalid Parquet batch size ${batchSize}`);
|
|
1175
|
+
}
|
|
1176
|
+
return batchSize;
|
|
1177
|
+
}
|
|
1178
|
+
/** Validates the row-group decode concurrency limit. */
|
|
1179
|
+
function normalizeConcurrency(concurrency = 1) {
|
|
1180
|
+
if (!Number.isInteger(concurrency) || concurrency <= 0) {
|
|
1181
|
+
throw new Error(`Invalid Parquet concurrency ${concurrency}`);
|
|
1182
|
+
}
|
|
1183
|
+
return concurrency;
|
|
1184
|
+
}
|
|
1185
|
+
/** Creates a zero-filled telemetry snapshot for one Parquet source. */
|
|
1186
|
+
function createParquetTelemetry() {
|
|
1187
|
+
return {
|
|
1188
|
+
rangeRequestCount: 0,
|
|
1189
|
+
requestedBytes: 0,
|
|
1190
|
+
downloadedBytes: 0,
|
|
1191
|
+
cacheHits: 0,
|
|
1192
|
+
networkDurationMs: 0,
|
|
1193
|
+
failedRangeRequestCount: 0,
|
|
1194
|
+
abortedRangeRequestCount: 0,
|
|
1195
|
+
retryCount: 0,
|
|
1196
|
+
decodeDurationMs: 0,
|
|
1197
|
+
arrowConversionDurationMs: 0,
|
|
1198
|
+
rowGroupsRequested: 0,
|
|
1199
|
+
rowGroupsPruned: 0,
|
|
1200
|
+
rowGroupsPrunedByStatistics: 0,
|
|
1201
|
+
rowGroupsPrunedByBloomFilter: 0,
|
|
1202
|
+
bloomFiltersRead: 0,
|
|
1203
|
+
bloomFilterBytesRead: 0,
|
|
1204
|
+
rowGroupsPrunedByPageIndex: 0,
|
|
1205
|
+
pageIndexesRead: 0,
|
|
1206
|
+
pagesRead: 0,
|
|
1207
|
+
pagesPruned: 0,
|
|
1208
|
+
rowsPrunedByPageIndex: 0,
|
|
1209
|
+
rowGroupsDecoded: 0,
|
|
1210
|
+
batchesEmitted: 0,
|
|
1211
|
+
rowsEmitted: 0,
|
|
1212
|
+
predicateRowsTested: 0,
|
|
1213
|
+
predicateRowsMatched: 0,
|
|
1214
|
+
cancellationCount: 0,
|
|
1215
|
+
failedReadCount: 0
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
/** Converts cumulative Parquet counters into one portable read-scoped execution snapshot. */
|
|
1219
|
+
function createParquetScanExecutionTelemetry(before, after, startedAt, status, earlyTerminationReason, error) {
|
|
1220
|
+
const delta = Object.fromEntries(Object.keys(after).map(key => {
|
|
1221
|
+
const telemetryKey = key;
|
|
1222
|
+
return [key, after[telemetryKey] - before[telemetryKey]];
|
|
1223
|
+
}));
|
|
1224
|
+
const rowsRead = Math.max(delta.predicateRowsTested, delta.rowsEmitted);
|
|
1225
|
+
return Object.freeze({
|
|
1226
|
+
status,
|
|
1227
|
+
sourcesPlanned: 1,
|
|
1228
|
+
sourcesRead: status === 'early-terminated' && earlyTerminationReason === 'limit' && rowsRead === 0 ? 0 : 1,
|
|
1229
|
+
batchesRead: delta.batchesEmitted,
|
|
1230
|
+
batchesDecoded: delta.rowGroupsDecoded,
|
|
1231
|
+
rowsRead,
|
|
1232
|
+
rowsTested: delta.predicateRowsTested || undefined,
|
|
1233
|
+
rowsRetained: delta.predicateRowsMatched || undefined,
|
|
1234
|
+
rowsReturned: delta.rowsEmitted,
|
|
1235
|
+
bytesRead: delta.downloadedBytes,
|
|
1236
|
+
bytesFetched: delta.downloadedBytes,
|
|
1237
|
+
filesOpened: rowsRead || delta.downloadedBytes ? 1 : 0,
|
|
1238
|
+
tasksOpened: delta.rowGroupsDecoded,
|
|
1239
|
+
rowsPruned: delta.rowsPrunedByPageIndex,
|
|
1240
|
+
durationMilliseconds: Date.now() - startedAt,
|
|
1241
|
+
earlyTerminationReason,
|
|
1242
|
+
details: Object.freeze({ ...delta }),
|
|
1243
|
+
...(error === undefined ? {} : { error })
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
/** Returns a monotonic timestamp when available and falls back to wall-clock time. */
|
|
1247
|
+
function getCurrentTime() {
|
|
1248
|
+
return globalThis.performance?.now() ?? Date.now();
|
|
1249
|
+
}
|
|
1250
|
+
/** Creates a read-scoped abort controller linked to the caller signal. */
|
|
1251
|
+
function createReadAbortContext(signal) {
|
|
1252
|
+
const abortController = new AbortController();
|
|
1253
|
+
const abortRead = () => abortController.abort(signal?.reason);
|
|
1254
|
+
if (signal?.aborted) {
|
|
1255
|
+
abortRead();
|
|
1256
|
+
}
|
|
1257
|
+
else {
|
|
1258
|
+
signal?.addEventListener('abort', abortRead, { once: true });
|
|
1259
|
+
}
|
|
1260
|
+
return {
|
|
1261
|
+
abortController,
|
|
1262
|
+
removeSignalListener: () => signal?.removeEventListener('abort', abortRead)
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
/** Throws a cross-runtime AbortError when a signal has been aborted. */
|
|
1266
|
+
function throwIfAborted(signal) {
|
|
1267
|
+
if (!signal.aborted) {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
if (signal.reason !== undefined) {
|
|
1271
|
+
throw signal.reason;
|
|
1272
|
+
}
|
|
1273
|
+
const error = new Error('Parquet read aborted');
|
|
1274
|
+
error.name = 'AbortError';
|
|
1275
|
+
throw error;
|
|
1276
|
+
}
|
|
1277
|
+
/** Recursively freezes the plain schema tree cached by a source. */
|
|
1278
|
+
function deepFreeze(value) {
|
|
1279
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
|
|
1280
|
+
return value;
|
|
1281
|
+
}
|
|
1282
|
+
for (const nestedValue of Object.values(value)) {
|
|
1283
|
+
deepFreeze(nestedValue);
|
|
1284
|
+
}
|
|
1285
|
+
return Object.freeze(value);
|
|
1286
|
+
}
|
|
1287
|
+
/** Converts footer key/value pairs into an object. */
|
|
1288
|
+
function getKeyValueMetadata(fileMetadata) {
|
|
1289
|
+
const result = {};
|
|
1290
|
+
for (const entry of fileMetadata.key_value_metadata || []) {
|
|
1291
|
+
if (entry.value !== undefined) {
|
|
1292
|
+
result[entry.key] = entry.value;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
return result;
|
|
1296
|
+
}
|
|
1297
|
+
/** Infers a stable display name from URL or File input. */
|
|
1298
|
+
function getSourceName(data, url) {
|
|
1299
|
+
const sourceName = typeof data !== 'string' && 'name' in data && typeof data.name === 'string'
|
|
1300
|
+
? data.name
|
|
1301
|
+
: typeof data === 'string'
|
|
1302
|
+
? url.split(/[?#]/)[0].split('/').pop() || 'parquet'
|
|
1303
|
+
: 'parquet';
|
|
1304
|
+
return sourceName.replace(/\.parquet$/i, '') || 'parquet';
|
|
1305
|
+
}
|
|
1306
|
+
/** Reconstructs exact row-group indexes from worker predicate batches. */
|
|
1307
|
+
function getWorkerRowIndices(workerResult) {
|
|
1308
|
+
if (!workerResult)
|
|
1309
|
+
return [];
|
|
1310
|
+
return workerResult.batches.flatMap(batch => batch.rowGroupRowIndices
|
|
1311
|
+
? [...batch.rowGroupRowIndices]
|
|
1312
|
+
: Array.from({ length: batch.rowCount }, (_, index) => batch.rowGroupRowOffset + index));
|
|
1313
|
+
}
|
|
1314
|
+
/** Gathers projected worker Arrow batches through the shared indexed Arrow table utility. */
|
|
1315
|
+
function gatherWorkerProjectedRows(workerResult, rowIndices, batchSize) {
|
|
1316
|
+
const tables = workerResult.batches.map(batch => hydrateArrowTable(batch.arrowTable));
|
|
1317
|
+
if (tables.length === 0) {
|
|
1318
|
+
return { ...workerResult, rowCount: 0, batches: [] };
|
|
1319
|
+
}
|
|
1320
|
+
const table = tables.length === 1 ? tables[0] : tables[0].concat(...tables.slice(1));
|
|
1321
|
+
const indexedTable = new IndexedArrowTable(table, rowIndices);
|
|
1322
|
+
const outputBatchSize = batchSize || Math.max(rowIndices.length, 1);
|
|
1323
|
+
const batches = [];
|
|
1324
|
+
for (let offset = 0; offset < rowIndices.length; offset += outputBatchSize) {
|
|
1325
|
+
const end = Math.min(offset + outputBatchSize, rowIndices.length);
|
|
1326
|
+
const batchIndexes = rowIndices.slice(offset, end);
|
|
1327
|
+
const batchTable = indexedTable.slice(offset, end).materializeArrowTable();
|
|
1328
|
+
batches.push({
|
|
1329
|
+
rowGroupRowOffset: batchIndexes[0],
|
|
1330
|
+
rowCount: batchIndexes.length,
|
|
1331
|
+
rowGroupRowIndices: [...batchIndexes],
|
|
1332
|
+
arrowTable: dehydrateArrowTable(batchTable)
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
return {
|
|
1336
|
+
sourceRowCount: workerResult.sourceRowCount,
|
|
1337
|
+
rowCount: rowIndices.length,
|
|
1338
|
+
batches,
|
|
1339
|
+
decodeDurationMs: workerResult.decodeDurationMs,
|
|
1340
|
+
arrowConversionDurationMs: workerResult.arrowConversionDurationMs
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
/** Applies only proven-negative Bloom-filter checks to candidate row groups. */
|
|
1344
|
+
async function filterParquetRowGroupsWithBloomFilters(initialization, rowGroupIndices, predicate, signal) {
|
|
1345
|
+
const rowGroups = [];
|
|
1346
|
+
let filtersRead = 0;
|
|
1347
|
+
let bytesRead = 0;
|
|
1348
|
+
for (const rowGroupIndex of rowGroupIndices) {
|
|
1349
|
+
let rowGroup = initialization.metadata.rowGroups[rowGroupIndex];
|
|
1350
|
+
const rawRowGroup = initialization.fileMetadata.row_groups[rowGroupIndex];
|
|
1351
|
+
if (rawRowGroup.columns.some(columnChunk => columnChunk.encrypted_column_metadata)) {
|
|
1352
|
+
// The immutable source metadata predates selective column-metadata decryption. Resolve
|
|
1353
|
+
// predicate columns before probing, without changing the plaintext planning path.
|
|
1354
|
+
await initialization.reader.resolveColumnMetadata(rawRowGroup, rowGroupIndex, getParquetPredicateColumns(predicate).map(column => [column]));
|
|
1355
|
+
throwIfAborted(signal);
|
|
1356
|
+
rowGroup = {
|
|
1357
|
+
...rowGroup,
|
|
1358
|
+
columns: rawRowGroup.columns
|
|
1359
|
+
.filter(columnChunk => Boolean(columnChunk.meta_data))
|
|
1360
|
+
.map(columnChunk => createColumnChunkMetadata(columnChunk, initialization.parquetSchema))
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
const probes = getParquetBloomFilterProbes(predicate, rowGroup);
|
|
1364
|
+
let keepRowGroup = true;
|
|
1365
|
+
for (const probe of probes) {
|
|
1366
|
+
if (probe.column.bloomFilterOffset === undefined ||
|
|
1367
|
+
probe.column.bloomFilterByteLength === undefined) {
|
|
1368
|
+
continue;
|
|
1369
|
+
}
|
|
1370
|
+
let field;
|
|
1371
|
+
try {
|
|
1372
|
+
field = initialization.parquetSchema.findField([...probe.column.path]);
|
|
1373
|
+
}
|
|
1374
|
+
catch {
|
|
1375
|
+
throwIfAborted(signal);
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1378
|
+
if (!field.primitiveType)
|
|
1379
|
+
continue;
|
|
1380
|
+
let filter;
|
|
1381
|
+
try {
|
|
1382
|
+
const rawColumnOrdinal = initialization.fileMetadata.row_groups[rowGroupIndex].columns.findIndex(columnChunk => JSON.stringify(columnChunk.meta_data?.path_in_schema) ===
|
|
1383
|
+
JSON.stringify(probe.column.path));
|
|
1384
|
+
const rawColumnChunk = rawColumnOrdinal >= 0
|
|
1385
|
+
? initialization.fileMetadata.row_groups[rowGroupIndex].columns[rawColumnOrdinal]
|
|
1386
|
+
: undefined;
|
|
1387
|
+
const data = await initialization.file.read(probe.column.bloomFilterOffset, probe.column.bloomFilterByteLength, signal);
|
|
1388
|
+
const decodedBloomFilter = rawColumnChunk
|
|
1389
|
+
? await initialization.reader.decryptBloomFilter(toUint8Array(data), rowGroupIndex, rawColumnOrdinal, rawColumnChunk)
|
|
1390
|
+
: toUint8Array(data);
|
|
1391
|
+
filter = decodeParquetSplitBlockBloomFilter(decodedBloomFilter);
|
|
1392
|
+
filtersRead++;
|
|
1393
|
+
bytesRead += data.byteLength;
|
|
1394
|
+
}
|
|
1395
|
+
catch {
|
|
1396
|
+
throwIfAborted(signal);
|
|
1397
|
+
continue;
|
|
1398
|
+
}
|
|
1399
|
+
if (filter.algorithm !== 'BLOCK' ||
|
|
1400
|
+
filter.hash !== 'XXHASH' ||
|
|
1401
|
+
filter.compression !== 'UNCOMPRESSED') {
|
|
1402
|
+
continue;
|
|
1403
|
+
}
|
|
1404
|
+
const mayContainValue = probe.values.some(value => {
|
|
1405
|
+
try {
|
|
1406
|
+
if (value instanceof Date)
|
|
1407
|
+
return true;
|
|
1408
|
+
const physicalValue = getParquetBloomFilterPhysicalValue(value, field);
|
|
1409
|
+
const encoded = encodeParquetBloomFilterValue(physicalValue, field.primitiveType, field.typeLength);
|
|
1410
|
+
return checkParquetSplitBlockBloomFilter(filter.bitset, hashParquetBloomFilterValue(encoded));
|
|
1411
|
+
}
|
|
1412
|
+
catch {
|
|
1413
|
+
throwIfAborted(signal);
|
|
1414
|
+
return true;
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
if (!mayContainValue) {
|
|
1418
|
+
keepRowGroup = false;
|
|
1419
|
+
break;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
if (keepRowGroup)
|
|
1423
|
+
rowGroups.push(rowGroupIndex);
|
|
1424
|
+
}
|
|
1425
|
+
return { rowGroupIndices: rowGroups, filtersRead, bytesRead };
|
|
1426
|
+
}
|
|
1427
|
+
/** Converts logical predicate values into the physical values stored in Bloom filters. */
|
|
1428
|
+
function getParquetBloomFilterPhysicalValue(value, field) {
|
|
1429
|
+
if (field.originalType?.startsWith('DECIMAL_')) {
|
|
1430
|
+
return toPrimitive(field.originalType, value, field);
|
|
1431
|
+
}
|
|
1432
|
+
return value;
|
|
1433
|
+
}
|
|
1434
|
+
/** Returns true when at least one HTTP object validator was captured. */
|
|
1435
|
+
function hasObjectVersion(version) {
|
|
1436
|
+
return Boolean(version?.etag || version?.lastModified);
|
|
1437
|
+
}
|
|
1438
|
+
//# sourceMappingURL=parquet-source-loader.js.map
|