@loaders.gl/parquet 5.0.0-alpha.2 → 5.0.0-alpha.3
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 +1 -1
- package/dist/bundled.d.ts +1 -1
- package/dist/bundled.d.ts.map +1 -1
- package/dist/bundled.js.map +1 -1
- 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.js +1 -1
- 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 +15005 -3143
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.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 +94 -19
- package/dist/lib/arrow/convert-schema-from-parquet.js.map +1 -1
- package/dist/lib/arrow/create-nested-arrow-vector.js +89 -0
- package/dist/lib/arrow/create-nested-arrow-vector.js.map +1 -1
- package/dist/lib/constants.js +1 -1
- package/dist/lib/encoders/encode-table-to-parquet-js.d.ts.map +1 -1
- package/dist/lib/encoders/encode-table-to-parquet-js.js +202 -7
- package/dist/lib/encoders/encode-table-to-parquet-js.js.map +1 -1
- 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.map +1 -1
- package/dist/lib/geo/geospatial-metadata.js +39 -13
- package/dist/lib/geo/geospatial-metadata.js.map +1 -1
- 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 +34 -5
- package/dist/lib/parquet-page-index.d.ts.map +1 -1
- package/dist/lib/parquet-page-index.js +114 -28
- package/dist/lib/parquet-page-index.js.map +1 -1
- package/dist/lib/parquet-predicate.d.ts +5 -1
- package/dist/lib/parquet-predicate.d.ts.map +1 -1
- package/dist/lib/parquet-predicate.js +42 -14
- package/dist/lib/parquet-predicate.js.map +1 -1
- package/dist/lib/parquet-source-worker-decoder.d.ts +4 -1
- package/dist/lib/parquet-source-worker-decoder.d.ts.map +1 -1
- package/dist/lib/parquet-source-worker-decoder.js +83 -17
- package/dist/lib/parquet-source-worker-decoder.js.map +1 -1
- package/dist/lib/parquet-source-worker-types.d.ts +24 -0
- package/dist/lib/parquet-source-worker-types.d.ts.map +1 -1
- package/dist/lib/parsers/get-parquet-schema.d.ts.map +1 -1
- package/dist/lib/parsers/get-parquet-schema.js +3 -1
- package/dist/lib/parsers/get-parquet-schema.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow-js.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow-js.js +327 -18
- package/dist/lib/parsers/parse-parquet-to-arrow-js.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow.js +5 -5
- package/dist/lib/parsers/parse-parquet-to-arrow.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-columns.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-columns.js +3 -1
- package/dist/lib/parsers/parse-parquet-to-columns.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-json.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-json.js +18 -2
- 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 +1 -1
- package/dist/lib/sources/parquet-range-file.d.ts.map +1 -1
- package/dist/lib/sources/parquet-range-file.js +28 -22
- package/dist/lib/sources/parquet-range-file.js.map +1 -1
- package/dist/lib/utils/normalize-parquet-options.d.ts.map +1 -1
- package/dist/lib/utils/normalize-parquet-options.js +15 -1
- package/dist/lib/utils/normalize-parquet-options.js.map +1 -1
- package/dist/parquet-dataset-source.cjs +15766 -4896
- package/dist/parquet-dataset-source.cjs.map +3 -3
- package/dist/parquet-dataset-source.d.ts +31 -4
- package/dist/parquet-dataset-source.d.ts.map +1 -1
- package/dist/parquet-dataset-source.js +296 -74
- package/dist/parquet-dataset-source.js.map +1 -1
- package/dist/parquet-js-loader-types.d.ts +2 -0
- package/dist/parquet-js-loader-types.d.ts.map +1 -1
- package/dist/parquet-js-loader-types.js +2 -1
- package/dist/parquet-js-loader-types.js.map +1 -1
- package/dist/parquet-js-loader.d.ts +1 -0
- package/dist/parquet-js-loader.d.ts.map +1 -1
- package/dist/parquet-js-loader.js +2 -1
- package/dist/parquet-js-loader.js.map +1 -1
- package/dist/parquet-js-writer.d.ts +23 -2
- package/dist/parquet-js-writer.d.ts.map +1 -1
- package/dist/parquet-js-writer.js +1 -1
- package/dist/parquet-js-writer.js.map +1 -1
- package/dist/parquet-loader-base.js +1 -1
- package/dist/parquet-loader-options.d.ts +11 -0
- package/dist/parquet-loader-options.d.ts.map +1 -1
- package/dist/parquet-loader-options.js.map +1 -1
- package/dist/parquet-source-capabilities.d.ts +8 -1
- package/dist/parquet-source-capabilities.d.ts.map +1 -1
- package/dist/parquet-source-capabilities.js +10 -0
- package/dist/parquet-source-capabilities.js.map +1 -1
- package/dist/parquet-source-loader-types.d.ts +10 -0
- package/dist/parquet-source-loader-types.d.ts.map +1 -1
- package/dist/parquet-source-loader-types.js +11 -1
- package/dist/parquet-source-loader-types.js.map +1 -1
- package/dist/parquet-source-loader.cjs +14911 -4316
- package/dist/parquet-source-loader.cjs.map +3 -3
- package/dist/parquet-source-loader.d.ts +42 -4
- package/dist/parquet-source-loader.d.ts.map +1 -1
- package/dist/parquet-source-loader.js +585 -38
- package/dist/parquet-source-loader.js.map +1 -1
- package/dist/parquet-source-types.d.ts +180 -30
- package/dist/parquet-source-types.d.ts.map +1 -1
- package/dist/parquet-source-worker.js +7055 -6989
- package/dist/parquet-source-worker.js.map +4 -4
- package/dist/parquet-worker-node.cjs +8505 -1041
- package/dist/parquet-worker-node.cjs.map +4 -4
- package/dist/parquet-worker-url.js +5 -1
- package/dist/parquet-worker-url.js.map +1 -1
- package/dist/parquet-worker.js +289 -218
- package/dist/parquet-worker.js.map +4 -4
- package/dist/parquetjs/codecs/declare.d.ts +15 -0
- package/dist/parquetjs/codecs/declare.d.ts.map +1 -1
- package/dist/parquetjs/codecs/declare.js +10 -0
- package/dist/parquetjs/codecs/declare.js.map +1 -1
- package/dist/parquetjs/codecs/delta.d.ts.map +1 -1
- package/dist/parquetjs/codecs/delta.js +356 -7
- package/dist/parquetjs/codecs/delta.js.map +1 -1
- package/dist/parquetjs/codecs/index.d.ts.map +1 -1
- package/dist/parquetjs/codecs/index.js +4 -0
- package/dist/parquetjs/codecs/index.js.map +1 -1
- package/dist/parquetjs/codecs/plain.d.ts +1 -1
- package/dist/parquetjs/codecs/plain.d.ts.map +1 -1
- package/dist/parquetjs/codecs/plain.js +153 -12
- package/dist/parquetjs/codecs/plain.js.map +1 -1
- package/dist/parquetjs/codecs/rle.d.ts +4 -0
- package/dist/parquetjs/codecs/rle.d.ts.map +1 -1
- package/dist/parquetjs/codecs/rle.js +406 -3
- package/dist/parquetjs/codecs/rle.js.map +1 -1
- package/dist/parquetjs/compression.d.ts +9 -0
- package/dist/parquetjs/compression.d.ts.map +1 -1
- package/dist/parquetjs/compression.js +86 -67
- package/dist/parquetjs/compression.js.map +1 -1
- package/dist/parquetjs/encoder/dictionary-planner.d.ts.map +1 -1
- package/dist/parquetjs/encoder/dictionary-planner.js +5 -2
- package/dist/parquetjs/encoder/dictionary-planner.js.map +1 -1
- package/dist/parquetjs/encoder/parquet-encoder.d.ts +43 -1
- package/dist/parquetjs/encoder/parquet-encoder.d.ts.map +1 -1
- package/dist/parquetjs/encoder/parquet-encoder.js +691 -34
- 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/ColumnChunk.d.ts +5 -0
- package/dist/parquetjs/parquet-thrift/ColumnChunk.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnChunk.js +35 -0
- 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/ColumnMetaData.d.ts +10 -0
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.js +73 -0
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.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/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 +5 -0
- package/dist/parquetjs/parquet-thrift/FileMetaData.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/FileMetaData.js +35 -0
- package/dist/parquetjs/parquet-thrift/FileMetaData.js.map +1 -1
- 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/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/index.d.ts +6 -0
- package/dist/parquetjs/parquet-thrift/index.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/index.js +6 -0
- package/dist/parquetjs/parquet-thrift/index.js.map +1 -1
- package/dist/parquetjs/parser/decoders.d.ts +10 -1
- package/dist/parquetjs/parser/decoders.d.ts.map +1 -1
- package/dist/parquetjs/parser/decoders.js +318 -14
- package/dist/parquetjs/parser/decoders.js.map +1 -1
- package/dist/parquetjs/parser/parquet-reader.d.ts +78 -12
- package/dist/parquetjs/parser/parquet-reader.d.ts.map +1 -1
- package/dist/parquetjs/parser/parquet-reader.js +605 -66
- package/dist/parquetjs/parser/parquet-reader.js.map +1 -1
- package/dist/parquetjs/schema/declare.d.ts +22 -3
- 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.map +1 -1
- package/dist/parquetjs/schema/schema.js +10 -0
- package/dist/parquetjs/schema/schema.js.map +1 -1
- package/dist/parquetjs/schema/shred.d.ts.map +1 -1
- package/dist/parquetjs/schema/shred.js +219 -11
- package/dist/parquetjs/schema/shred.js.map +1 -1
- package/dist/parquetjs/schema/types.js +19 -21
- 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/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/read-utils.d.ts +11 -1
- package/dist/parquetjs/utils/read-utils.d.ts.map +1 -1
- package/dist/parquetjs/utils/read-utils.js +21 -1
- package/dist/parquetjs/utils/read-utils.js.map +1 -1
- package/dist/unbundled.d.ts +2 -1
- package/dist/unbundled.d.ts.map +1 -1
- package/dist/unbundled.js +1 -0
- package/dist/unbundled.js.map +1 -1
- package/package.json +36 -11
- package/src/bundled.ts +3 -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/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 +50 -1
- package/src/lib/arrow/convert-schema-from-parquet.ts +113 -19
- package/src/lib/arrow/create-nested-arrow-vector.ts +116 -0
- package/src/lib/encoders/encode-table-to-parquet-js.ts +268 -7
- package/src/lib/geo/geoparquet-covering.ts +201 -0
- package/src/lib/geo/geospatial-metadata.ts +42 -15
- 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 +180 -34
- package/src/lib/parquet-predicate.ts +52 -16
- package/src/lib/parquet-source-worker-decoder.ts +116 -20
- package/src/lib/parquet-source-worker-types.ts +25 -0
- package/src/lib/parsers/get-parquet-schema.ts +3 -1
- package/src/lib/parsers/parse-parquet-to-arrow-js.ts +397 -17
- package/src/lib/parsers/parse-parquet-to-arrow.ts +4 -5
- package/src/lib/parsers/parse-parquet-to-columns.ts +3 -1
- package/src/lib/parsers/parse-parquet-to-json.ts +18 -2
- package/src/lib/slice-parquet-batch.ts +32 -0
- package/src/lib/sources/parquet-range-file.ts +35 -29
- package/src/lib/utils/normalize-parquet-options.ts +17 -1
- package/src/parquet-dataset-source.ts +397 -85
- package/src/parquet-js-loader-types.ts +1 -0
- package/src/parquet-js-loader.ts +2 -1
- package/src/parquet-js-writer.ts +30 -0
- package/src/parquet-loader-options.ts +11 -0
- package/src/parquet-source-capabilities.ts +18 -1
- package/src/parquet-source-loader-types.ts +10 -0
- package/src/parquet-source-loader.ts +929 -52
- package/src/parquet-source-types.ts +197 -28
- package/src/parquet-worker-url.ts +6 -1
- package/src/parquetjs/codecs/declare.ts +27 -0
- package/src/parquetjs/codecs/delta.ts +466 -6
- package/src/parquetjs/codecs/index.ts +4 -0
- package/src/parquetjs/codecs/plain.ts +177 -11
- package/src/parquetjs/codecs/rle.ts +573 -3
- package/src/parquetjs/compression.ts +102 -76
- package/src/parquetjs/encoder/dictionary-planner.ts +7 -2
- package/src/parquetjs/encoder/parquet-encoder.ts +1016 -38
- package/src/parquetjs/parquet-thrift/BoundingBox.ts +108 -0
- package/src/parquetjs/parquet-thrift/ColumnChunk.ts +35 -0
- package/src/parquetjs/parquet-thrift/ColumnCryptoMetaData.ts +139 -0
- package/src/parquetjs/parquet-thrift/ColumnMetaData.ts +73 -0
- package/src/parquetjs/parquet-thrift/EncryptionAlgorithm.ts +127 -0
- package/src/parquetjs/parquet-thrift/FileCryptoMetaData.ts +60 -0
- package/src/parquetjs/parquet-thrift/FileMetaData.ts +35 -0
- package/src/parquetjs/parquet-thrift/GeospatialStatistics.ts +68 -0
- package/src/parquetjs/parquet-thrift/SizeStatistics.ts +98 -0
- package/src/parquetjs/parquet-thrift/index.ts +6 -0
- package/src/parquetjs/parser/decoders.ts +451 -26
- package/src/parquetjs/parser/parquet-reader.ts +935 -87
- package/src/parquetjs/schema/declare.ts +22 -2
- package/src/parquetjs/schema/schema.ts +10 -0
- package/src/parquetjs/schema/shred.ts +238 -11
- package/src/parquetjs/schema/types.ts +16 -25
- package/src/parquetjs/schema/variant.ts +313 -0
- package/src/parquetjs/utils/crc32.ts +15 -0
- package/src/parquetjs/utils/read-utils.ts +26 -1
- package/src/unbundled.ts +14 -0
|
@@ -32,7 +32,11 @@ import {
|
|
|
32
32
|
} from '../parquetjs/utils/binary-utils';
|
|
33
33
|
import {Uint8ArrayCompactProtocol} from '../parquetjs/utils/uint8-array-compact-protocol';
|
|
34
34
|
import {Uint8ArrayTransport} from '../parquetjs/utils/uint8-array-transport';
|
|
35
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
canParquetStatisticsMatch,
|
|
37
|
+
getParquetPredicatePath,
|
|
38
|
+
getParquetPredicatePaths
|
|
39
|
+
} from './parquet-predicate';
|
|
36
40
|
|
|
37
41
|
/** Half-open logical row range relative to one Parquet row group. */
|
|
38
42
|
export type ParquetRowRange = {
|
|
@@ -73,7 +77,27 @@ export type ParquetPagePruningPlan = {
|
|
|
73
77
|
prunedRowCount: number;
|
|
74
78
|
};
|
|
75
79
|
|
|
76
|
-
|
|
80
|
+
/** Decrypts an encrypted page-index module before Thrift decoding. */
|
|
81
|
+
export type ParquetPageIndexDecryptor = (
|
|
82
|
+
bytes: Uint8Array,
|
|
83
|
+
module: 'column-index' | 'offset-index',
|
|
84
|
+
rowGroupOrdinal: number,
|
|
85
|
+
columnOrdinal: number,
|
|
86
|
+
columnChunk: ColumnChunk
|
|
87
|
+
) => Promise<Uint8Array>;
|
|
88
|
+
|
|
89
|
+
/** Optional controls for reading page indexes from a Parquet source. */
|
|
90
|
+
export type ParquetPagePruningOptions = {
|
|
91
|
+
/** Row-group ordinal used when constructing encrypted-module AAD. */
|
|
92
|
+
rowGroupOrdinal?: number;
|
|
93
|
+
/** Decode legacy INT96 page statistics as epoch nanoseconds. */
|
|
94
|
+
int96AsTimestamp?: boolean;
|
|
95
|
+
/** Decrypts encrypted index modules; omitted for plaintext files. */
|
|
96
|
+
decryptModule?: ParquetPageIndexDecryptor;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/** Logical statistics attached to one data page. */
|
|
100
|
+
export type ParquetPageStatistics = {
|
|
77
101
|
min?: unknown;
|
|
78
102
|
max?: unknown;
|
|
79
103
|
nullCount?: number;
|
|
@@ -89,8 +113,10 @@ type ParquetColumnPageStatistics = {
|
|
|
89
113
|
/**
|
|
90
114
|
* Builds a conservative selective-page plan from Parquet column and offset indexes.
|
|
91
115
|
*
|
|
92
|
-
* Returns `undefined` when indexes or the
|
|
93
|
-
*
|
|
116
|
+
* Returns `undefined` when indexes or the selected decoder cannot safely avoid full column-chunk
|
|
117
|
+
* reads. Repeated leaves are selected only when every decoded column uses the same page row
|
|
118
|
+
* boundaries, so ranges begin and end on complete logical rows. An empty `rowRanges` array means
|
|
119
|
+
* the indexes prove the predicate cannot match.
|
|
94
120
|
*/
|
|
95
121
|
export async function createParquetPagePruningPlan(
|
|
96
122
|
file: ReadableFile,
|
|
@@ -98,23 +124,27 @@ export async function createParquetPagePruningPlan(
|
|
|
98
124
|
schema: ParquetSchema,
|
|
99
125
|
selectedColumnPaths: readonly string[][],
|
|
100
126
|
predicate: ParquetPredicate,
|
|
101
|
-
signal?: AbortSignal
|
|
127
|
+
signal?: AbortSignal,
|
|
128
|
+
options?: ParquetPagePruningOptions
|
|
102
129
|
): Promise<ParquetPagePruningPlan | undefined> {
|
|
103
130
|
const rowCount = Number(rowGroup.num_rows);
|
|
104
131
|
const selectedColumnChunks = getSelectedColumnChunks(rowGroup, selectedColumnPaths);
|
|
105
|
-
if (!
|
|
132
|
+
if (!isSafePageSelection(schema, selectedColumnChunks) || rowCount <= 0) {
|
|
106
133
|
return undefined;
|
|
107
134
|
}
|
|
108
135
|
|
|
109
136
|
const pageLocations: ParquetPageLocations = {};
|
|
110
137
|
const pageStatistics: Record<string, ParquetColumnPageStatistics> = {};
|
|
111
|
-
const
|
|
138
|
+
const predicatePaths = new Set(
|
|
139
|
+
getParquetPredicatePaths(predicate).map(path => JSON.stringify(path))
|
|
140
|
+
);
|
|
112
141
|
let indexCount = 0;
|
|
113
142
|
|
|
114
143
|
await Promise.all(
|
|
115
144
|
selectedColumnChunks.map(async columnChunk => {
|
|
145
|
+
const columnOrdinal = rowGroup.columns.indexOf(columnChunk);
|
|
116
146
|
const path = columnChunk.meta_data!.path_in_schema;
|
|
117
|
-
const pathKey =
|
|
147
|
+
const pathKey = JSON.stringify(path);
|
|
118
148
|
const offsetIndexRange = getParquetIndexRange(
|
|
119
149
|
columnChunk.offset_index_offset,
|
|
120
150
|
columnChunk.offset_index_length,
|
|
@@ -130,14 +160,23 @@ export async function createParquetPagePruningPlan(
|
|
|
130
160
|
);
|
|
131
161
|
let pages: ParquetDataPageLocation[];
|
|
132
162
|
try {
|
|
133
|
-
|
|
163
|
+
const decryptedBytes = options?.decryptModule
|
|
164
|
+
? await options.decryptModule(
|
|
165
|
+
toUint8Array(offsetIndexBytes),
|
|
166
|
+
'offset-index',
|
|
167
|
+
options.rowGroupOrdinal ?? 0,
|
|
168
|
+
columnOrdinal,
|
|
169
|
+
columnChunk
|
|
170
|
+
)
|
|
171
|
+
: toUint8Array(offsetIndexBytes);
|
|
172
|
+
pages = decodeOffsetIndex(decryptedBytes, rowCount);
|
|
134
173
|
} catch {
|
|
135
174
|
return;
|
|
136
175
|
}
|
|
137
176
|
pageLocations[pathKey] = pages;
|
|
138
177
|
indexCount++;
|
|
139
178
|
|
|
140
|
-
if (
|
|
179
|
+
if (!predicatePaths.has(pathKey)) {
|
|
141
180
|
return;
|
|
142
181
|
}
|
|
143
182
|
const columnIndexRange = getParquetIndexRange(
|
|
@@ -155,9 +194,18 @@ export async function createParquetPagePruningPlan(
|
|
|
155
194
|
);
|
|
156
195
|
const field = schema.findField(path);
|
|
157
196
|
try {
|
|
158
|
-
|
|
197
|
+
const decryptedBytes = options?.decryptModule
|
|
198
|
+
? await options.decryptModule(
|
|
199
|
+
toUint8Array(columnIndexBytes),
|
|
200
|
+
'column-index',
|
|
201
|
+
options.rowGroupOrdinal ?? 0,
|
|
202
|
+
columnOrdinal,
|
|
203
|
+
columnChunk
|
|
204
|
+
)
|
|
205
|
+
: toUint8Array(columnIndexBytes);
|
|
206
|
+
pageStatistics[pathKey] = {
|
|
159
207
|
pages,
|
|
160
|
-
statistics:
|
|
208
|
+
statistics: decodeParquetColumnIndex(decryptedBytes, pages, field, options)
|
|
161
209
|
};
|
|
162
210
|
} catch {
|
|
163
211
|
return;
|
|
@@ -168,12 +216,16 @@ export async function createParquetPagePruningPlan(
|
|
|
168
216
|
|
|
169
217
|
if (
|
|
170
218
|
selectedColumnChunks.some(
|
|
171
|
-
columnChunk => !pageLocations[columnChunk.meta_data!.path_in_schema
|
|
219
|
+
columnChunk => !pageLocations[JSON.stringify(columnChunk.meta_data!.path_in_schema)]
|
|
172
220
|
)
|
|
173
221
|
) {
|
|
174
222
|
return undefined;
|
|
175
223
|
}
|
|
176
224
|
|
|
225
|
+
if (!hasCompatiblePageBoundaries(schema, selectedColumnChunks, pageLocations)) {
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
|
|
177
229
|
const candidateRanges = getPredicateRowRanges(predicate, pageStatistics, rowCount);
|
|
178
230
|
if (candidateRanges === undefined) {
|
|
179
231
|
return undefined;
|
|
@@ -206,18 +258,21 @@ export async function createParquetPagePruningPlan(
|
|
|
206
258
|
export function getParquetPageReadRanges(
|
|
207
259
|
rowGroup: RowGroup,
|
|
208
260
|
selectedColumnPaths: readonly string[][],
|
|
209
|
-
plan: ParquetPagePruningPlan
|
|
261
|
+
plan: ParquetPagePruningPlan,
|
|
262
|
+
schema: ParquetSchema
|
|
210
263
|
): Array<{offset: number; length: number}> {
|
|
211
264
|
const ranges: Array<{offset: number; length: number}> = [];
|
|
212
265
|
for (const columnChunk of getSelectedColumnChunks(rowGroup, selectedColumnPaths)) {
|
|
213
266
|
const columnMetadata = columnChunk.meta_data!;
|
|
214
|
-
const pages = plan.pageLocations[columnMetadata.path_in_schema
|
|
267
|
+
const pages = plan.pageLocations[JSON.stringify(columnMetadata.path_in_schema)];
|
|
215
268
|
const selectedPages = pages.filter(page =>
|
|
216
269
|
plan.rowRanges.some(range => page.endRowIndex > range.start && page.firstRowIndex < range.end)
|
|
217
270
|
);
|
|
218
271
|
if (!selectedPages.length) {
|
|
219
272
|
continue;
|
|
220
273
|
}
|
|
274
|
+
const field = schema.findField(columnMetadata.path_in_schema);
|
|
275
|
+
const repeated = field.rLevelMax > 0 || field.repetitionType === 'REPEATED';
|
|
221
276
|
const dictionaryPageOffset = Number(columnMetadata.dictionary_page_offset);
|
|
222
277
|
if (Number.isSafeInteger(dictionaryPageOffset) && dictionaryPageOffset > 0) {
|
|
223
278
|
ranges.push({
|
|
@@ -232,7 +287,9 @@ export function getParquetPageReadRanges(
|
|
|
232
287
|
if (!overlappingPages.length) {
|
|
233
288
|
continue;
|
|
234
289
|
}
|
|
235
|
-
|
|
290
|
+
// A repeated page may begin with a continuation level. Transfer the complete prefix so
|
|
291
|
+
// worker-backed readers can probe predecessor pages before decoding the selected range.
|
|
292
|
+
const firstPage = repeated ? pages[0] : overlappingPages[0];
|
|
236
293
|
const lastPage = overlappingPages[overlappingPages.length - 1];
|
|
237
294
|
ranges.push({
|
|
238
295
|
offset: firstPage.offset,
|
|
@@ -253,10 +310,27 @@ export function decodeOffsetIndex(bytes: Uint8Array, rowCount: number): ParquetD
|
|
|
253
310
|
) {
|
|
254
311
|
throw new Error('Invalid Parquet offset index page locations');
|
|
255
312
|
}
|
|
313
|
+
let previousFirstRowIndex = -1;
|
|
314
|
+
for (const location of offsetIndex.page_locations) {
|
|
315
|
+
const firstRowIndex = Number(location.first_row_index);
|
|
316
|
+
if (!Number.isSafeInteger(firstRowIndex) || firstRowIndex < previousFirstRowIndex) {
|
|
317
|
+
throw new Error('Invalid Parquet offset index page locations');
|
|
318
|
+
}
|
|
319
|
+
previousFirstRowIndex = firstRowIndex;
|
|
320
|
+
}
|
|
256
321
|
return offsetIndex.page_locations.map((location, index, locations) => {
|
|
257
322
|
const firstRowIndex = Number(location.first_row_index);
|
|
258
|
-
|
|
259
|
-
|
|
323
|
+
// A repeated row may continue on one or more pages. In that case the offset index
|
|
324
|
+
// legitimately repeats first_row_index. Extend each continuation page to the next
|
|
325
|
+
// strictly larger row start so selecting the row includes the complete continuation.
|
|
326
|
+
let endRowIndex = rowCount;
|
|
327
|
+
for (let nextIndex = index + 1; nextIndex < locations.length; nextIndex++) {
|
|
328
|
+
const nextFirstRowIndex = Number(locations[nextIndex].first_row_index);
|
|
329
|
+
if (nextFirstRowIndex > firstRowIndex) {
|
|
330
|
+
endRowIndex = nextFirstRowIndex;
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
260
334
|
const offset = Number(location.offset);
|
|
261
335
|
const compressedByteLength = location.compressed_page_size;
|
|
262
336
|
if (
|
|
@@ -308,7 +382,7 @@ function getPredicateRowRanges(
|
|
|
308
382
|
| ParquetComparisonPredicate
|
|
309
383
|
| ParquetInPredicate
|
|
310
384
|
| ParquetNullPredicate;
|
|
311
|
-
const column = columns[leafPredicate.args[0]
|
|
385
|
+
const column = columns[JSON.stringify(getParquetPredicatePath(leafPredicate.args[0]))];
|
|
312
386
|
if (!column) {
|
|
313
387
|
return undefined;
|
|
314
388
|
}
|
|
@@ -328,11 +402,12 @@ function getPredicateRowRanges(
|
|
|
328
402
|
return mergeRowRanges(ranges);
|
|
329
403
|
}
|
|
330
404
|
|
|
331
|
-
/** Decodes column-index values into
|
|
332
|
-
function
|
|
405
|
+
/** Decodes column-index values into logical per-page statistics. */
|
|
406
|
+
export function decodeParquetColumnIndex(
|
|
333
407
|
bytes: Uint8Array,
|
|
334
408
|
pages: readonly ParquetDataPageLocation[],
|
|
335
|
-
field: ParquetField
|
|
409
|
+
field: ParquetField,
|
|
410
|
+
options?: Pick<ParquetPagePruningOptions, 'int96AsTimestamp'>
|
|
336
411
|
): ParquetPageStatistics[] {
|
|
337
412
|
const protocol = new Uint8ArrayCompactProtocol(new Uint8ArrayTransport(bytes));
|
|
338
413
|
const columnIndex = ColumnIndex.read(protocol as any);
|
|
@@ -347,10 +422,10 @@ function decodeColumnIndex(
|
|
|
347
422
|
return pages.map((_page, pageIndex) => ({
|
|
348
423
|
min: columnIndex.null_pages[pageIndex]
|
|
349
424
|
? undefined
|
|
350
|
-
: decodeParquetPageStatisticsValue(columnIndex.min_values[pageIndex], field),
|
|
425
|
+
: decodeParquetPageStatisticsValue(columnIndex.min_values[pageIndex], field, options),
|
|
351
426
|
max: columnIndex.null_pages[pageIndex]
|
|
352
427
|
? undefined
|
|
353
|
-
: decodeParquetPageStatisticsValue(columnIndex.max_values[pageIndex], field),
|
|
428
|
+
: decodeParquetPageStatisticsValue(columnIndex.max_values[pageIndex], field, options),
|
|
354
429
|
nullCount:
|
|
355
430
|
columnIndex.null_counts?.[pageIndex] !== undefined
|
|
356
431
|
? Number(columnIndex.null_counts[pageIndex])
|
|
@@ -363,7 +438,11 @@ function decodeColumnIndex(
|
|
|
363
438
|
}
|
|
364
439
|
|
|
365
440
|
/** Decodes one physical page-index statistic and applies its Parquet logical annotation. */
|
|
366
|
-
export function decodeParquetPageStatisticsValue(
|
|
441
|
+
export function decodeParquetPageStatisticsValue(
|
|
442
|
+
bytes: Uint8Array,
|
|
443
|
+
field: ParquetField,
|
|
444
|
+
options?: Pick<ParquetPagePruningOptions, 'int96AsTimestamp'>
|
|
445
|
+
): unknown {
|
|
367
446
|
let primitiveValue: unknown;
|
|
368
447
|
switch (field.primitiveType) {
|
|
369
448
|
case 'BOOLEAN':
|
|
@@ -384,6 +463,18 @@ export function decodeParquetPageStatisticsValue(bytes: Uint8Array, field: Parqu
|
|
|
384
463
|
primitiveValue = readDoubleLE(bytes, 0);
|
|
385
464
|
break;
|
|
386
465
|
case 'INT96':
|
|
466
|
+
if (options?.int96AsTimestamp && bytes.byteLength >= 12) {
|
|
467
|
+
const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
468
|
+
const nanosecondsOfDay = dataView.getBigUint64(0, true);
|
|
469
|
+
if (nanosecondsOfDay < 86_400_000_000_000n) {
|
|
470
|
+
primitiveValue =
|
|
471
|
+
(BigInt(dataView.getInt32(8, true)) - 2440588n) * 86_400_000_000_000n +
|
|
472
|
+
nanosecondsOfDay;
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
primitiveValue = copyUint8Array(bytes);
|
|
477
|
+
break;
|
|
387
478
|
case 'BYTE_ARRAY':
|
|
388
479
|
case 'FIXED_LEN_BYTE_ARRAY':
|
|
389
480
|
primitiveValue = copyUint8Array(bytes);
|
|
@@ -409,16 +500,13 @@ function getSelectedColumnChunks(
|
|
|
409
500
|
});
|
|
410
501
|
}
|
|
411
502
|
|
|
412
|
-
/** Restricts selective page reads to
|
|
413
|
-
function
|
|
414
|
-
schema: ParquetSchema,
|
|
415
|
-
columnChunks: readonly ColumnChunk[]
|
|
416
|
-
): boolean {
|
|
503
|
+
/** Restricts selective page reads to primitive leaves with safe page boundaries. */
|
|
504
|
+
function isSafePageSelection(schema: ParquetSchema, columnChunks: readonly ColumnChunk[]): boolean {
|
|
417
505
|
return (
|
|
418
506
|
columnChunks.length > 0 &&
|
|
419
507
|
columnChunks.every(columnChunk => {
|
|
420
508
|
const path = columnChunk.meta_data?.path_in_schema;
|
|
421
|
-
if (!path
|
|
509
|
+
if (!path) {
|
|
422
510
|
return false;
|
|
423
511
|
}
|
|
424
512
|
const field = schema.findField(path);
|
|
@@ -427,9 +515,7 @@ function isSafeFlatPageSelection(
|
|
|
427
515
|
);
|
|
428
516
|
const dictionaryPageOffset = Number(columnChunk.meta_data!.dictionary_page_offset);
|
|
429
517
|
return (
|
|
430
|
-
field.
|
|
431
|
-
field.repetitionType !== 'REPEATED' &&
|
|
432
|
-
field.rLevelMax === 0 &&
|
|
518
|
+
field.primitiveType !== undefined &&
|
|
433
519
|
(!dictionaryEncoded ||
|
|
434
520
|
(Number.isSafeInteger(dictionaryPageOffset) && dictionaryPageOffset > 0))
|
|
435
521
|
);
|
|
@@ -437,6 +523,66 @@ function isSafeFlatPageSelection(
|
|
|
437
523
|
);
|
|
438
524
|
}
|
|
439
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Returns whether a column can be decoded from selected page ranges without changing row shape.
|
|
528
|
+
*
|
|
529
|
+
* Repeated leaves are safe only when the selected columns share complete logical-row boundaries.
|
|
530
|
+
*/
|
|
531
|
+
export function canUseParquetPageIndexForColumn(
|
|
532
|
+
schema: ParquetSchema,
|
|
533
|
+
columnChunk: ColumnChunk
|
|
534
|
+
): boolean {
|
|
535
|
+
const path = columnChunk.meta_data?.path_in_schema;
|
|
536
|
+
if (!path) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
const field = schema.findField(path);
|
|
540
|
+
const dictionaryEncoded = columnChunk.meta_data!.encodings.some(
|
|
541
|
+
encoding => encoding === Encoding.PLAIN_DICTIONARY || encoding === Encoding.RLE_DICTIONARY
|
|
542
|
+
);
|
|
543
|
+
const dictionaryPageOffset = Number(columnChunk.meta_data!.dictionary_page_offset);
|
|
544
|
+
return (
|
|
545
|
+
field.primitiveType !== undefined &&
|
|
546
|
+
field.repetitionType !== 'REPEATED' &&
|
|
547
|
+
field.rLevelMax === 0 &&
|
|
548
|
+
(!dictionaryEncoded || (Number.isSafeInteger(dictionaryPageOffset) && dictionaryPageOffset > 0))
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Ensures repeated selective reads keep every selected column on identical row boundaries. */
|
|
553
|
+
function hasCompatiblePageBoundaries(
|
|
554
|
+
schema: ParquetSchema,
|
|
555
|
+
columnChunks: readonly ColumnChunk[],
|
|
556
|
+
pageLocations: ParquetPageLocations
|
|
557
|
+
): boolean {
|
|
558
|
+
const hasRepeatedLeaf = columnChunks.some(columnChunk => {
|
|
559
|
+
const field = schema.findField(columnChunk.meta_data!.path_in_schema);
|
|
560
|
+
return field.rLevelMax > 0 || field.repetitionType === 'REPEATED';
|
|
561
|
+
});
|
|
562
|
+
if (!hasRepeatedLeaf) {
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
565
|
+
// Offset indexes identify the first logical row represented by each page, but do not
|
|
566
|
+
// expose repetition levels. Equal starts therefore indicate a continuation page whose
|
|
567
|
+
// boundary cannot be proven safe for a selective read; retain the full-column fallback.
|
|
568
|
+
if (
|
|
569
|
+
columnChunks.some(columnChunk => {
|
|
570
|
+
const pages = pageLocations[JSON.stringify(columnChunk.meta_data!.path_in_schema)];
|
|
571
|
+
return pages.some(
|
|
572
|
+
(page, pageIndex) =>
|
|
573
|
+
pageIndex > 0 && page.firstRowIndex === pages[pageIndex - 1].firstRowIndex
|
|
574
|
+
);
|
|
575
|
+
})
|
|
576
|
+
) {
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
const signatures = columnChunks.map(columnChunk => {
|
|
580
|
+
const pages = pageLocations[JSON.stringify(columnChunk.meta_data!.path_in_schema)];
|
|
581
|
+
return pages.map(page => `${page.firstRowIndex}:${page.endRowIndex}`).join('|');
|
|
582
|
+
});
|
|
583
|
+
return signatures.every(signature => signature === signatures[0]);
|
|
584
|
+
}
|
|
585
|
+
|
|
440
586
|
/** Validates one optional footer index byte range against the containing file. */
|
|
441
587
|
export function getParquetIndexRange(
|
|
442
588
|
offsetValue: ColumnChunk['offset_index_offset'],
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
ParquetNotPredicate,
|
|
13
13
|
ParquetNullPredicate,
|
|
14
14
|
ParquetPredicate,
|
|
15
|
+
ParquetPredicateProperty,
|
|
15
16
|
ParquetPredicateValue,
|
|
16
17
|
ParquetRowGroupMetadata
|
|
17
18
|
} from '../parquet-source-types';
|
|
@@ -19,14 +20,20 @@ import {encodeUtf8} from '../parquetjs/utils/binary-utils';
|
|
|
19
20
|
|
|
20
21
|
/** Returns the unique top-level columns referenced by a predicate. */
|
|
21
22
|
export function getParquetPredicateColumns(predicate: ParquetPredicate): string[] {
|
|
22
|
-
|
|
23
|
+
return [...new Set(getParquetPredicatePaths(predicate).map(path => path[0]))];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Returns the unique physical schema paths referenced by a predicate. */
|
|
27
|
+
export function getParquetPredicatePaths(predicate: ParquetPredicate): string[][] {
|
|
28
|
+
const paths = new Map<string, string[]>();
|
|
23
29
|
visitParquetPredicate(predicate, child => {
|
|
24
30
|
const property = getPredicateProperty(child);
|
|
25
31
|
if (property) {
|
|
26
|
-
|
|
32
|
+
const path = [...getParquetPredicatePath(property)];
|
|
33
|
+
paths.set(path.join('\0'), path);
|
|
27
34
|
}
|
|
28
35
|
});
|
|
29
|
-
return [...
|
|
36
|
+
return [...paths.values()];
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
/** Copies a predicate tree and mutable scalar values for read-scoped option snapshots. */
|
|
@@ -75,8 +82,12 @@ export function validateParquetPredicate(
|
|
|
75
82
|
return;
|
|
76
83
|
}
|
|
77
84
|
const property = child.args[0];
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
const path = getParquetPredicatePath(property);
|
|
86
|
+
if (!path.length || path.some(pathComponent => !pathComponent)) {
|
|
87
|
+
throw new Error('Parquet predicate property path must contain non-empty strings');
|
|
88
|
+
}
|
|
89
|
+
if (!availableColumns.has(path[0])) {
|
|
90
|
+
throw new Error(`Parquet predicate column not found: ${path.join('.')}`);
|
|
80
91
|
}
|
|
81
92
|
if (child.op === 'in' && child.args[1].length === 0) {
|
|
82
93
|
throw new Error('Parquet predicate in requires at least one value');
|
|
@@ -99,11 +110,11 @@ export function canParquetRowGroupMatch(
|
|
|
99
110
|
if (child.op !== 'isNull') {
|
|
100
111
|
return true;
|
|
101
112
|
}
|
|
102
|
-
const column = getRowGroupColumn(rowGroup, child.args[0]
|
|
113
|
+
const column = getRowGroupColumn(rowGroup, getParquetPredicatePath(child.args[0]));
|
|
103
114
|
return !column?.statistics || column.statistics.nullCount !== rowGroup.rowCount;
|
|
104
115
|
}
|
|
105
116
|
|
|
106
|
-
const column = getRowGroupColumn(rowGroup, predicate.args[0]
|
|
117
|
+
const column = getRowGroupColumn(rowGroup, getParquetPredicatePath(predicate.args[0]));
|
|
107
118
|
const statistics = column?.statistics;
|
|
108
119
|
if (!statistics) {
|
|
109
120
|
return true;
|
|
@@ -160,7 +171,7 @@ export function gatherParquetColumns(
|
|
|
160
171
|
if (selectedColumns && !selectedColumns.has(name)) {
|
|
161
172
|
continue;
|
|
162
173
|
}
|
|
163
|
-
gatheredColumns[name] = rowIndices.map(rowIndex =>
|
|
174
|
+
gatheredColumns[name] = rowIndices.map(rowIndex => (column as ArrayLike<unknown>)[rowIndex]);
|
|
164
175
|
}
|
|
165
176
|
return gatheredColumns;
|
|
166
177
|
}
|
|
@@ -182,7 +193,7 @@ function evaluateParquetPredicate(
|
|
|
182
193
|
const result = evaluateParquetPredicate(predicate.args[0], columns, rowIndex);
|
|
183
194
|
return result === null ? null : !result;
|
|
184
195
|
}
|
|
185
|
-
const value = getColumnValue(columns
|
|
196
|
+
const value = getColumnValue(columns, getParquetPredicatePath(predicate.args[0]), rowIndex);
|
|
186
197
|
if (predicate.op === 'isNull') {
|
|
187
198
|
return value === null || value === undefined;
|
|
188
199
|
}
|
|
@@ -311,11 +322,27 @@ function compareUint8Arrays(left: Uint8Array, right: Uint8Array): number {
|
|
|
311
322
|
}
|
|
312
323
|
|
|
313
324
|
/** Reads one value from an array-like materialized Parquet column. */
|
|
314
|
-
function getColumnValue(
|
|
325
|
+
function getColumnValue(
|
|
326
|
+
columns: Record<string, ArrayType>,
|
|
327
|
+
path: readonly string[],
|
|
328
|
+
rowIndex: number
|
|
329
|
+
): unknown {
|
|
330
|
+
const column = columns[path[0]];
|
|
315
331
|
if (!column) {
|
|
316
332
|
throw new Error('Parquet predicate column was not decoded');
|
|
317
333
|
}
|
|
318
|
-
|
|
334
|
+
let value = (column as ArrayLike<unknown>)[rowIndex];
|
|
335
|
+
for (let pathIndex = 1; pathIndex < path.length; pathIndex++) {
|
|
336
|
+
if (value === null || value === undefined || typeof value !== 'object') {
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
const property = path[pathIndex];
|
|
340
|
+
value =
|
|
341
|
+
typeof (value as {get?: unknown}).get === 'function'
|
|
342
|
+
? (value as {get: (name: string) => unknown}).get(property)
|
|
343
|
+
: (value as Record<string, unknown>)[property];
|
|
344
|
+
}
|
|
345
|
+
return value;
|
|
319
346
|
}
|
|
320
347
|
|
|
321
348
|
/** Copies mutable binary and date predicate values. */
|
|
@@ -330,21 +357,30 @@ function copyPredicateValue(value: ParquetPredicateValue): ParquetPredicateValue
|
|
|
330
357
|
}
|
|
331
358
|
|
|
332
359
|
/** Copies a predicate property reference. */
|
|
333
|
-
function copyPredicateProperty(property:
|
|
334
|
-
return {
|
|
360
|
+
function copyPredicateProperty(property: ParquetPredicateProperty): ParquetPredicateProperty {
|
|
361
|
+
return {
|
|
362
|
+
property: Array.isArray(property.property) ? [...property.property] : property.property
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/** Returns one predicate property as an explicit Parquet schema path. */
|
|
367
|
+
export function getParquetPredicatePath(property: ParquetPredicateProperty): readonly string[] {
|
|
368
|
+
return Array.isArray(property.property) ? property.property : [property.property as string];
|
|
335
369
|
}
|
|
336
370
|
|
|
337
371
|
/** Returns the property reference from a leaf predicate. */
|
|
338
|
-
function getPredicateProperty(predicate: ParquetPredicate):
|
|
372
|
+
function getPredicateProperty(predicate: ParquetPredicate): ParquetPredicateProperty | undefined {
|
|
339
373
|
return isParquetLogicalPredicate(predicate) || isParquetNotPredicate(predicate)
|
|
340
374
|
? undefined
|
|
341
375
|
: predicate.args[0];
|
|
342
376
|
}
|
|
343
377
|
|
|
344
378
|
/** Returns one top-level column chunk from normalized row-group metadata. */
|
|
345
|
-
function getRowGroupColumn(rowGroup: ParquetRowGroupMetadata,
|
|
379
|
+
function getRowGroupColumn(rowGroup: ParquetRowGroupMetadata, path: readonly string[]) {
|
|
346
380
|
return rowGroup.columns.find(
|
|
347
|
-
columnChunk =>
|
|
381
|
+
columnChunk =>
|
|
382
|
+
columnChunk.path.length === path.length &&
|
|
383
|
+
columnChunk.path.every((pathComponent, index) => pathComponent === path[index])
|
|
348
384
|
);
|
|
349
385
|
}
|
|
350
386
|
|