@loaders.gl/scan 5.0.0-alpha.3 → 5.0.0-alpha.5

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/dist/iceberg.cjs CHANGED
@@ -6829,6 +6829,12 @@ function serializeArrowType(arrowType) {
6829
6829
  type: "list",
6830
6830
  children: [serializeArrowField(listField)]
6831
6831
  };
6832
+ case arrow2.LargeList:
6833
+ const largeListType = arrowType;
6834
+ return {
6835
+ type: "large-list",
6836
+ children: [serializeArrowField(largeListType.valueField)]
6837
+ };
6832
6838
  case arrow2.FixedSizeList:
6833
6839
  const fixedSizeList = arrowType;
6834
6840
  return {
@@ -6842,6 +6848,15 @@ function serializeArrowType(arrowType) {
6842
6848
  type: "struct",
6843
6849
  children: structType.children.map((arrowField) => serializeArrowField(arrowField))
6844
6850
  };
6851
+ case arrow2.SparseUnion:
6852
+ case arrow2.DenseUnion:
6853
+ const unionType = arrowType;
6854
+ return {
6855
+ type: unionType instanceof arrow2.DenseUnion ? "dense-union" : "sparse-union",
6856
+ typeIds: unionType.typeIds,
6857
+ children: unionType.children.map((arrowField) => serializeArrowField(arrowField)),
6858
+ typeIdToChildIndex: { ...unionType.typeIdToChildIndex }
6859
+ };
6845
6860
  case arrow2.Dictionary:
6846
6861
  const dictionaryType = arrowType;
6847
6862
  return {
@@ -6870,6 +6885,10 @@ function deserializeArrowType(dataType, options) {
6870
6885
  const field = deserializeArrowField(dataType.children[0], options);
6871
6886
  return new arrow2.List(field);
6872
6887
  }
6888
+ case "large-list": {
6889
+ const field = deserializeArrowField(dataType.children[0], options);
6890
+ return new arrow2.LargeList(field);
6891
+ }
6873
6892
  case "fixed-size-list": {
6874
6893
  const child = deserializeArrowField(dataType.children[0], options);
6875
6894
  return new arrow2.FixedSizeList(dataType.listSize, child);
@@ -6882,6 +6901,13 @@ function deserializeArrowType(dataType, options) {
6882
6901
  );
6883
6902
  return new arrow2.Struct(children);
6884
6903
  }
6904
+ case "sparse-union":
6905
+ case "dense-union": {
6906
+ const children = dataType.children.map(
6907
+ (arrowField) => deserializeArrowField(arrowField, options)
6908
+ );
6909
+ return dataType.type === "dense-union" ? new arrow2.DenseUnion(dataType.typeIds, children) : new arrow2.SparseUnion(dataType.typeIds, children);
6910
+ }
6885
6911
  case "dictionary": {
6886
6912
  return new arrow2.Dictionary(
6887
6913
  deserializeArrowType(dataType.dictionary, options),
@@ -7519,8 +7545,85 @@ var init_deprecated = __esm({
7519
7545
  }
7520
7546
  });
7521
7547
 
7522
- // ../schema-utils/src/index.ts
7548
+ // ../schema/src/metadata.ts
7549
+ function getMetadataValue(metadata, key) {
7550
+ return metadata instanceof Map ? metadata.get(key) || null : metadata[key] || null;
7551
+ }
7552
+ function setMetadataValue(metadata, key, value) {
7553
+ if (metadata instanceof Map) {
7554
+ metadata.set(key, value);
7555
+ } else {
7556
+ metadata[key] = value;
7557
+ }
7558
+ }
7559
+ function getGeoMetadata(metadata) {
7560
+ if (!metadata) {
7561
+ return null;
7562
+ }
7563
+ const stringifiedGeoMetadata = getMetadataValue(metadata, "geo");
7564
+ const geoMetadata = stringifiedGeoMetadata && parseJSONStringMetadata(stringifiedGeoMetadata);
7565
+ if (!geoMetadata) {
7566
+ return null;
7567
+ }
7568
+ for (const column of Object.values(geoMetadata.columns || {})) {
7569
+ if (column && typeof column === "object" && typeof column.encoding === "string") {
7570
+ column.encoding = column.encoding.toLowerCase();
7571
+ }
7572
+ }
7573
+ return geoMetadata;
7574
+ }
7575
+ function unpackGeoMetadata(metadata) {
7576
+ const geoMetadata = getGeoMetadata(metadata);
7577
+ if (!geoMetadata) {
7578
+ return;
7579
+ }
7580
+ const { version: version2, primary_column: primaryColumn, columns } = geoMetadata;
7581
+ if (version2) {
7582
+ setMetadataValue(metadata, "geo.version", version2);
7583
+ }
7584
+ if (primaryColumn) {
7585
+ setMetadataValue(metadata, "geo.primary_column", primaryColumn);
7586
+ }
7587
+ setMetadataValue(metadata, "geo.columns", Object.keys(columns || {}).join(","));
7588
+ }
7589
+ function unpackJSONStringMetadata(metadata, metadataKey) {
7590
+ const stringifiedMetadata = getMetadataValue(metadata, metadataKey);
7591
+ const json = stringifiedMetadata && parseJSONStringMetadata(stringifiedMetadata);
7592
+ for (const [key, value] of Object.entries(json || {})) {
7593
+ setMetadataValue(
7594
+ metadata,
7595
+ `${metadataKey}.${key}`,
7596
+ typeof value === "string" ? value : JSON.stringify(value)
7597
+ );
7598
+ }
7599
+ }
7600
+ function parseJSONStringMetadata(stringifiedMetadata) {
7601
+ if (!stringifiedMetadata) {
7602
+ return null;
7603
+ }
7604
+ try {
7605
+ const metadata = JSON.parse(stringifiedMetadata);
7606
+ return metadata && typeof metadata === "object" ? metadata : null;
7607
+ } catch {
7608
+ return null;
7609
+ }
7610
+ }
7611
+ var init_metadata = __esm({
7612
+ "../schema/src/metadata.ts"() {
7613
+ "use strict";
7614
+ }
7615
+ });
7616
+
7617
+ // ../schema/src/index.ts
7523
7618
  var init_src4 = __esm({
7619
+ "../schema/src/index.ts"() {
7620
+ "use strict";
7621
+ init_metadata();
7622
+ }
7623
+ });
7624
+
7625
+ // ../schema-utils/src/index.ts
7626
+ var init_src5 = __esm({
7524
7627
  "../schema-utils/src/index.ts"() {
7525
7628
  "use strict";
7526
7629
  init_convert_arrow_schema();
@@ -8116,35 +8219,26 @@ var init_arrow_table_transport = __esm({
8116
8219
  "../arrow/src/lib/utils/arrow-table-transport.ts"() {
8117
8220
  "use strict";
8118
8221
  arrow7 = __toESM(require("apache-arrow"), 1);
8119
- init_src4();
8222
+ init_src5();
8120
8223
  init_split_arrow_buffers();
8121
8224
  }
8122
8225
  });
8123
8226
 
8124
8227
  // ../gis/src/lib/geoarrow/metadata-utils.ts
8125
- function getMetadataValue(metadata, key) {
8126
- return metadata instanceof Map ? metadata.get(key) || null : metadata[key] || null;
8127
- }
8128
- function setMetadataValue(metadata, key, value) {
8129
- if (metadata instanceof Map) {
8130
- metadata.set(key, value);
8131
- } else {
8132
- metadata[key] = value;
8133
- }
8134
- }
8135
8228
  var init_metadata_utils = __esm({
8136
8229
  "../gis/src/lib/geoarrow/metadata-utils.ts"() {
8137
8230
  "use strict";
8231
+ init_src4();
8138
8232
  }
8139
8233
  });
8140
8234
 
8141
8235
  // ../gis/src/lib/geoarrow/geoparquet-metadata.ts
8142
- function getGeoMetadata(metadata) {
8236
+ function getGeoMetadata2(metadata) {
8143
8237
  if (!metadata) {
8144
8238
  return null;
8145
8239
  }
8146
8240
  const stringifiedGeoMetadata = getMetadataValue(metadata, "geo");
8147
- const geoMetadata = stringifiedGeoMetadata && parseJSONStringMetadata(stringifiedGeoMetadata);
8241
+ const geoMetadata = stringifiedGeoMetadata && parseJSONStringMetadata2(stringifiedGeoMetadata);
8148
8242
  if (!geoMetadata) {
8149
8243
  return null;
8150
8244
  }
@@ -8155,32 +8249,7 @@ function getGeoMetadata(metadata) {
8155
8249
  }
8156
8250
  return geoMetadata;
8157
8251
  }
8158
- function unpackGeoMetadata(metadata) {
8159
- const geoMetadata = getGeoMetadata(metadata);
8160
- if (!geoMetadata) {
8161
- return;
8162
- }
8163
- const { version: version2, primary_column, columns } = geoMetadata;
8164
- if (version2) {
8165
- setMetadataValue(metadata, "geo.version", version2);
8166
- }
8167
- if (primary_column) {
8168
- setMetadataValue(metadata, "geo.primary_column", primary_column);
8169
- }
8170
- setMetadataValue(metadata, "geo.columns", Object.keys(columns || {}).join(","));
8171
- }
8172
- function unpackJSONStringMetadata(metadata, metadataKey) {
8173
- const stringifiedMetadata = getMetadataValue(metadata, metadataKey);
8174
- const json = stringifiedMetadata && parseJSONStringMetadata(stringifiedMetadata);
8175
- for (const [key, value] of Object.entries(json || {})) {
8176
- setMetadataValue(
8177
- metadata,
8178
- `${metadataKey}.${key}`,
8179
- typeof value === "string" ? value : JSON.stringify(value)
8180
- );
8181
- }
8182
- }
8183
- function parseJSONStringMetadata(stringifiedMetadata) {
8252
+ function parseJSONStringMetadata2(stringifiedMetadata) {
8184
8253
  if (!stringifiedMetadata) {
8185
8254
  return null;
8186
8255
  }
@@ -8202,16 +8271,15 @@ var init_geoparquet_metadata = __esm({
8202
8271
  });
8203
8272
 
8204
8273
  // ../gis/src/index.ts
8205
- var init_src5 = __esm({
8274
+ var init_src6 = __esm({
8206
8275
  "../gis/src/index.ts"() {
8207
8276
  "use strict";
8208
- init_metadata_utils();
8209
8277
  init_geoparquet_metadata();
8210
8278
  }
8211
8279
  });
8212
8280
 
8213
8281
  // ../arrow/src/index.ts
8214
- var init_src6 = __esm({
8282
+ var init_src7 = __esm({
8215
8283
  "../arrow/src/index.ts"() {
8216
8284
  "use strict";
8217
8285
  init_indexed_arrow_table();
@@ -8455,10 +8523,11 @@ function getGeoArrowMetadataFromGeoParquetField(field, columnMetadata) {
8455
8523
  if (!extensionName) {
8456
8524
  return null;
8457
8525
  }
8458
- if (normalizedEncoding === "wkb" && field.type !== "binary") {
8526
+ const isBinaryGeospatialEncoding = normalizedEncoding === "wkb" || normalizedEncoding === "geometry" || normalizedEncoding === "geography";
8527
+ if (isBinaryGeospatialEncoding && !isBinaryFieldType(field.type)) {
8459
8528
  return null;
8460
8529
  }
8461
- if (normalizedEncoding !== "wkb" && (field.type === "binary" || field.type === "utf8")) {
8530
+ if (!isBinaryGeospatialEncoding && (isBinaryFieldType(field.type) || isStringFieldType(field.type))) {
8462
8531
  return null;
8463
8532
  }
8464
8533
  const extensionMetadata = {};
@@ -8472,18 +8541,34 @@ function getGeoArrowMetadataFromGeoParquetField(field, columnMetadata) {
8472
8541
  if (columnMetadata.edges && columnMetadata.edges !== "planar") {
8473
8542
  extensionMetadata.edges = columnMetadata.edges;
8474
8543
  }
8544
+ if (normalizedEncoding === "geography" && !extensionMetadata.edges) {
8545
+ extensionMetadata.edges = "spherical";
8546
+ }
8547
+ for (const [metadataKey, metadataValue] of Object.entries(columnMetadata)) {
8548
+ if (metadataValue !== void 0 && metadataValue !== null && !["encoding", "geometry_types", "crs", "edges"].includes(metadataKey)) {
8549
+ extensionMetadata[metadataKey] = metadataValue;
8550
+ }
8551
+ }
8475
8552
  return Object.keys(extensionMetadata).length > 0 ? { extensionName, extensionMetadata } : { extensionName };
8476
8553
  }
8554
+ function isBinaryFieldType(fieldType) {
8555
+ return typeof fieldType === "string" && (fieldType === "binary" || fieldType === "binary-view");
8556
+ }
8557
+ function isStringFieldType(fieldType) {
8558
+ return typeof fieldType === "string" && (fieldType === "utf8" || fieldType === "utf8-view");
8559
+ }
8477
8560
  var arrow8, GEOARROW_EXTENSION_NAME_KEY, GEOARROW_EXTENSION_METADATA_KEY, GEOPARQUET_TO_GEOARROW_ENCODINGS;
8478
8561
  var init_geospatial_metadata = __esm({
8479
8562
  "../parquet/src/lib/geo/geospatial-metadata.ts"() {
8480
8563
  "use strict";
8481
8564
  arrow8 = __toESM(require("apache-arrow"), 1);
8482
- init_src5();
8565
+ init_src4();
8483
8566
  GEOARROW_EXTENSION_NAME_KEY = "ARROW:extension:name";
8484
8567
  GEOARROW_EXTENSION_METADATA_KEY = "ARROW:extension:metadata";
8485
8568
  GEOPARQUET_TO_GEOARROW_ENCODINGS = {
8486
8569
  wkb: "geoarrow.wkb",
8570
+ geometry: "geoarrow.wkb",
8571
+ geography: "geoarrow.wkb",
8487
8572
  point: "geoarrow.point",
8488
8573
  linestring: "geoarrow.linestring",
8489
8574
  polygon: "geoarrow.polygon",
@@ -8509,7 +8594,7 @@ async function getSchemaFromParquetReader(reader) {
8509
8594
  var init_get_parquet_schema = __esm({
8510
8595
  "../parquet/src/lib/parsers/get-parquet-schema.ts"() {
8511
8596
  "use strict";
8512
- init_src5();
8597
+ init_src4();
8513
8598
  init_convert_schema_from_parquet();
8514
8599
  init_geospatial_metadata();
8515
8600
  }
@@ -8621,7 +8706,7 @@ function doLongitudeIntervalsIntersect(firstWest, firstEast, secondWest, secondE
8621
8706
  var init_geoparquet_covering = __esm({
8622
8707
  "../parquet/src/lib/geo/geoparquet-covering.ts"() {
8623
8708
  "use strict";
8624
- init_src5();
8709
+ init_src4();
8625
8710
  }
8626
8711
  });
8627
8712
 
@@ -15345,7 +15430,7 @@ var init_parse_bson = __esm({
15345
15430
  });
15346
15431
 
15347
15432
  // ../bson/src/index.ts
15348
- var init_src7 = __esm({
15433
+ var init_src8 = __esm({
15349
15434
  "../bson/src/index.ts"() {
15350
15435
  "use strict";
15351
15436
  init_bson_writer();
@@ -15754,7 +15839,7 @@ var PARQUET_LOGICAL_TYPES, kMillisPerDay;
15754
15839
  var init_types = __esm({
15755
15840
  "../parquet/src/parquetjs/schema/types.ts"() {
15756
15841
  "use strict";
15757
- init_src7();
15842
+ init_src8();
15758
15843
  init_binary_utils();
15759
15844
  PARQUET_LOGICAL_TYPES = {
15760
15845
  BOOLEAN: {
@@ -21102,6 +21187,201 @@ var init_decoders = __esm({
21102
21187
  }
21103
21188
  });
21104
21189
 
21190
+ // ../parquet/src/parquetjs/parser/encoded-pages.ts
21191
+ async function scanParquetEncodedPages(buffer, context) {
21192
+ const pages = [];
21193
+ let offset = 0;
21194
+ let dataPageOrdinal = 0;
21195
+ while (offset < buffer.byteLength) {
21196
+ const { pageHeader, length: headerByteLength } = decodePageHeader(buffer, offset);
21197
+ const bodyOffset = offset + headerByteLength;
21198
+ const bodyEnd = bodyOffset + pageHeader.compressed_page_size;
21199
+ if (pageHeader.compressed_page_size < 0 || pageHeader.uncompressed_page_size < 0 || bodyEnd > buffer.byteLength) {
21200
+ throw new Error("Parquet page extends beyond the available column-chunk buffer");
21201
+ }
21202
+ const compressedBody = buffer.subarray(bodyOffset, bodyEnd);
21203
+ verifyEncodedPageChecksum(compressedBody, pageHeader, context.verifyPageChecksums);
21204
+ const pageType = getThriftEnum(PageType, pageHeader.type);
21205
+ if (pageType === "DICTIONARY_PAGE") {
21206
+ pages.push(await createDictionaryPage(compressedBody, pageHeader, context));
21207
+ } else if (pageType === "DATA_PAGE") {
21208
+ pages.push(await createDataPageV1(compressedBody, pageHeader, context, dataPageOrdinal++));
21209
+ } else if (pageType === "DATA_PAGE_V2") {
21210
+ pages.push(await createDataPageV2(compressedBody, pageHeader, context, dataPageOrdinal++));
21211
+ } else {
21212
+ throw new Error(`Unsupported Parquet page type ${pageType}`);
21213
+ }
21214
+ offset = bodyEnd;
21215
+ }
21216
+ return pages;
21217
+ }
21218
+ async function createDictionaryPage(compressedBody, pageHeader, context) {
21219
+ const dictionaryHeader = pageHeader.dictionary_page_header;
21220
+ if (!dictionaryHeader) {
21221
+ throw new Error("Parquet dictionary page is missing its dictionary header");
21222
+ }
21223
+ const preserveCompression = shouldPreserveCompression(context);
21224
+ const data = preserveCompression ? compressedBody : await decompressPageBody(compressedBody, pageHeader.uncompressed_page_size, context);
21225
+ return Object.freeze({
21226
+ type: "dictionary",
21227
+ pageOrdinal: -1,
21228
+ encoding: getThriftEnum(Encoding, dictionaryHeader.encoding),
21229
+ compression: context.compression,
21230
+ compressionState: preserveCompression ? "compressed" : "decompressed",
21231
+ valueCount: dictionaryHeader.num_values,
21232
+ nonNullValueCount: dictionaryHeader.num_values,
21233
+ data,
21234
+ values: preserveCompression ? void 0 : createSection(0, data.byteLength),
21235
+ compressedByteLength: pageHeader.compressed_page_size,
21236
+ uncompressedByteLength: pageHeader.uncompressed_page_size
21237
+ });
21238
+ }
21239
+ async function createDataPageV1(compressedBody, pageHeader, context, pageOrdinal) {
21240
+ const dataHeader = pageHeader.data_page_header;
21241
+ if (!dataHeader) {
21242
+ throw new Error("Parquet V1 data page is missing its data header");
21243
+ }
21244
+ const preserveCompression = shouldPreserveCompression(context);
21245
+ const data = preserveCompression ? compressedBody : await decompressPageBody(compressedBody, pageHeader.uncompressed_page_size, context);
21246
+ let repetitionLevels;
21247
+ let definitionLevels;
21248
+ let values;
21249
+ if (!preserveCompression) {
21250
+ let sectionOffset = 0;
21251
+ const repetitionLevelEncoding = getThriftEnum(Encoding, dataHeader.repetition_level_encoding);
21252
+ repetitionLevels = readV1LevelSection(
21253
+ data,
21254
+ sectionOffset,
21255
+ dataHeader.num_values,
21256
+ context.column.rLevelMax,
21257
+ repetitionLevelEncoding
21258
+ );
21259
+ sectionOffset = repetitionLevels.byteOffset + repetitionLevels.byteLength;
21260
+ const definitionLevelEncoding = getThriftEnum(Encoding, dataHeader.definition_level_encoding);
21261
+ definitionLevels = readV1LevelSection(
21262
+ data,
21263
+ sectionOffset,
21264
+ dataHeader.num_values,
21265
+ context.column.dLevelMax,
21266
+ definitionLevelEncoding
21267
+ );
21268
+ sectionOffset = definitionLevels.byteOffset + definitionLevels.byteLength;
21269
+ values = createSection(sectionOffset, data.byteLength - sectionOffset);
21270
+ }
21271
+ return Object.freeze({
21272
+ type: "data-v1",
21273
+ pageOrdinal,
21274
+ encoding: getThriftEnum(Encoding, dataHeader.encoding),
21275
+ repetitionLevelEncoding: getThriftEnum(Encoding, dataHeader.repetition_level_encoding),
21276
+ definitionLevelEncoding: getThriftEnum(Encoding, dataHeader.definition_level_encoding),
21277
+ compression: context.compression,
21278
+ compressionState: preserveCompression ? "compressed" : "decompressed",
21279
+ valueCount: dataHeader.num_values,
21280
+ data,
21281
+ repetitionLevels,
21282
+ definitionLevels,
21283
+ values,
21284
+ compressedByteLength: pageHeader.compressed_page_size,
21285
+ uncompressedByteLength: pageHeader.uncompressed_page_size
21286
+ });
21287
+ }
21288
+ async function createDataPageV2(compressedBody, pageHeader, context, pageOrdinal) {
21289
+ const dataHeader = pageHeader.data_page_header_v2;
21290
+ if (!dataHeader) {
21291
+ throw new Error("Parquet V2 data page is missing its data header");
21292
+ }
21293
+ const repetitionByteLength = dataHeader.repetition_levels_byte_length;
21294
+ const definitionByteLength = dataHeader.definition_levels_byte_length;
21295
+ const levelsByteLength = repetitionByteLength + definitionByteLength;
21296
+ if (levelsByteLength > compressedBody.byteLength) {
21297
+ throw new Error("Parquet V2 level sections extend beyond the page body");
21298
+ }
21299
+ const valuesAreCompressed = dataHeader.is_compressed !== false && context.compression !== "UNCOMPRESSED";
21300
+ const preserveCompression = valuesAreCompressed && shouldPreserveCompression(context);
21301
+ let data = compressedBody;
21302
+ if (valuesAreCompressed && !preserveCompression) {
21303
+ const uncompressedValuesByteLength = pageHeader.uncompressed_page_size - levelsByteLength;
21304
+ if (uncompressedValuesByteLength < 0) {
21305
+ throw new Error("Invalid Parquet V2 uncompressed value length");
21306
+ }
21307
+ const values = await context.decompressPage(
21308
+ compressedBody.subarray(levelsByteLength),
21309
+ uncompressedValuesByteLength
21310
+ );
21311
+ data = new Uint8Array(levelsByteLength + values.byteLength);
21312
+ data.set(compressedBody.subarray(0, levelsByteLength));
21313
+ data.set(values, levelsByteLength);
21314
+ }
21315
+ return Object.freeze({
21316
+ type: "data-v2",
21317
+ pageOrdinal,
21318
+ encoding: getThriftEnum(Encoding, dataHeader.encoding),
21319
+ repetitionLevelEncoding: "RLE",
21320
+ definitionLevelEncoding: "RLE",
21321
+ compression: context.compression,
21322
+ compressionState: preserveCompression ? "compressed" : "decompressed",
21323
+ valueCount: dataHeader.num_values,
21324
+ nonNullValueCount: dataHeader.num_values - dataHeader.num_nulls,
21325
+ data,
21326
+ repetitionLevels: createSection(0, repetitionByteLength),
21327
+ definitionLevels: createSection(repetitionByteLength, definitionByteLength),
21328
+ values: createSection(levelsByteLength, data.byteLength - levelsByteLength),
21329
+ compressedByteLength: pageHeader.compressed_page_size,
21330
+ uncompressedByteLength: pageHeader.uncompressed_page_size
21331
+ });
21332
+ }
21333
+ function shouldPreserveCompression(context) {
21334
+ var _a;
21335
+ return context.compression !== "UNCOMPRESSED" && Boolean((_a = context.preserveCompression) == null ? void 0 : _a.has(context.compression));
21336
+ }
21337
+ async function decompressPageBody(compressedBody, uncompressedByteLength, context) {
21338
+ if (context.compression === "UNCOMPRESSED") return compressedBody;
21339
+ return await context.decompressPage(compressedBody, uncompressedByteLength);
21340
+ }
21341
+ function readV1LevelSection(data, offset, valueCount, maxLevel, encoding) {
21342
+ if (maxLevel === 0) return createSection(offset, 0);
21343
+ if (encoding === "RLE") {
21344
+ if (offset + 4 > data.byteLength) {
21345
+ throw new Error("Parquet V1 RLE level stream is missing its length prefix");
21346
+ }
21347
+ const byteLength = readUInt32LE(data, offset);
21348
+ const byteOffset = offset + 4;
21349
+ assertSectionBounds(data, byteOffset, byteLength);
21350
+ return createSection(byteOffset, byteLength);
21351
+ }
21352
+ if (encoding === "BIT_PACKED") {
21353
+ const byteLength = Math.ceil(valueCount / 8) * getBitWidth(maxLevel);
21354
+ assertSectionBounds(data, offset, byteLength);
21355
+ return createSection(offset, byteLength);
21356
+ }
21357
+ throw new Error(`Unsupported Parquet V1 level encoding ${encoding}`);
21358
+ }
21359
+ function createSection(byteOffset, byteLength) {
21360
+ return Object.freeze({ byteOffset, byteLength });
21361
+ }
21362
+ function assertSectionBounds(data, byteOffset, byteLength) {
21363
+ if (byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > data.byteLength) {
21364
+ throw new Error("Parquet page section extends beyond the page body");
21365
+ }
21366
+ }
21367
+ function verifyEncodedPageChecksum(compressedBody, pageHeader, verifyPageChecksums = false) {
21368
+ if (!verifyPageChecksums || pageHeader.crc === void 0) return;
21369
+ const expected = pageHeader.crc >>> 0;
21370
+ const actual = crc322(compressedBody);
21371
+ if (actual !== expected) {
21372
+ throw new Error(`Parquet page checksum mismatch: expected ${expected}, calculated ${actual}`);
21373
+ }
21374
+ }
21375
+ var init_encoded_pages = __esm({
21376
+ "../parquet/src/parquetjs/parser/encoded-pages.ts"() {
21377
+ "use strict";
21378
+ init_parquet_thrift();
21379
+ init_crc32();
21380
+ init_binary_utils();
21381
+ init_read_utils();
21382
+ }
21383
+ });
21384
+
21105
21385
  // ../parquet/src/lib/parquet-encryption.ts
21106
21386
  function readParquetEncryptedModule(buffer, offset = 0) {
21107
21387
  if (offset + 4 > buffer.length) {
@@ -21344,6 +21624,7 @@ var init_parquet_reader = __esm({
21344
21624
  "use strict";
21345
21625
  init_schema();
21346
21626
  init_decoders();
21627
+ init_encoded_pages();
21347
21628
  init_shred();
21348
21629
  init_compression2();
21349
21630
  init_constants();
@@ -21830,6 +22111,50 @@ var init_parquet_reader = __esm({
21830
22111
  columnData: Object.fromEntries(columnEntries)
21831
22112
  };
21832
22113
  }
22114
+ /**
22115
+ * Reads selected column chunks as encoded page descriptors without materializing values.
22116
+ *
22117
+ * Page headers, encryption, checksums, and optional decompression remain reader concerns. Value,
22118
+ * dictionary, and level decoding is deliberately left to the downstream consumer.
22119
+ */
22120
+ async readRowGroupEncodedPages(schema, rowGroup, columnList, preserveCompression, signal, rowGroupOrdinal = 0) {
22121
+ await this.resolveColumnMetadata(rowGroup, rowGroupOrdinal, columnList);
22122
+ const selectedColumnChunks = [];
22123
+ for (let columnOrdinal = 0; columnOrdinal < rowGroup.columns.length; columnOrdinal++) {
22124
+ const columnChunk = rowGroup.columns[columnOrdinal];
22125
+ const path = getColumnChunkPath(columnChunk);
22126
+ if (columnList.length > 0 && (!path || fieldIndexOf(columnList, path) < 0)) continue;
22127
+ const physicalColumnOrdinal = getPhysicalColumnOrdinal(columnChunk, columnOrdinal);
22128
+ const metadata = columnChunk.meta_data || await this.getColumnMetadata(columnChunk, rowGroupOrdinal, physicalColumnOrdinal);
22129
+ if (columnList.length === 0 || fieldIndexOf(columnList, metadata.path_in_schema) >= 0) {
22130
+ selectedColumnChunks.push({
22131
+ columnChunk,
22132
+ metadata,
22133
+ columnOrdinal: physicalColumnOrdinal
22134
+ });
22135
+ }
22136
+ }
22137
+ const columns = [];
22138
+ for (let batchStart = 0; batchStart < selectedColumnChunks.length; batchStart += MAXIMUM_CONCURRENT_COLUMN_READS) {
22139
+ columns.push(
22140
+ ...await Promise.all(
22141
+ selectedColumnChunks.slice(batchStart, batchStart + MAXIMUM_CONCURRENT_COLUMN_READS).map(async ({ columnChunk, metadata, columnOrdinal }) => {
22142
+ const encodedColumn = await this.readColumnChunkEncodedPages(
22143
+ schema,
22144
+ columnChunk,
22145
+ preserveCompression,
22146
+ signal,
22147
+ rowGroupOrdinal,
22148
+ columnOrdinal,
22149
+ metadata
22150
+ );
22151
+ return encodedColumn;
22152
+ })
22153
+ )
22154
+ );
22155
+ }
22156
+ return Object.freeze(columns);
22157
+ }
21833
22158
  /** Reads independently materializable non-repeated columns for one row range using page indexes. */
21834
22159
  async readRowGroupRange(schema, rowGroup, columnList, rowRange, pageLocations, signal, rowGroupOrdinal = 0) {
21835
22160
  await this.resolveColumnMetadata(rowGroup, rowGroupOrdinal, columnList);
@@ -22022,6 +22347,99 @@ var init_parquet_reader = __esm({
22022
22347
  ) : chunkBuffer.subarray(pagesRelativeOffset, pagesRelativeOffset + pagesSize);
22023
22348
  return await decodeDataPages(pagesBuf, { ...context, dictionary });
22024
22349
  }
22350
+ /** Reads one column chunk as encoded dictionaries, levels, and values for deferred decoding. */
22351
+ async readColumnChunkEncodedPages(schema, columnChunk, preserveCompression, signal, rowGroupOrdinal = 0, columnOrdinal = 0, resolvedMetadata) {
22352
+ if (columnChunk.file_path !== void 0 && columnChunk.file_path !== null) {
22353
+ throw new Error("external references are not supported");
22354
+ }
22355
+ const metadata = resolvedMetadata || columnChunk.meta_data;
22356
+ if (!metadata) throw new Error("Parquet column metadata is missing");
22357
+ const field = schema.findField(metadata.path_in_schema);
22358
+ const physicalType = getThriftEnum(Type, metadata.type);
22359
+ if (physicalType !== field.primitiveType) {
22360
+ throw new Error(`chunk type not matching schema: ${physicalType}`);
22361
+ }
22362
+ const compression = getThriftEnum(CompressionCodec, metadata.codec);
22363
+ const dataPageOffset = Number(metadata.data_page_offset);
22364
+ const dictionaryPageOffset = metadata.dictionary_page_offset;
22365
+ const validDictionaryPageOffset = dictionaryPageOffset !== void 0 && Number(dictionaryPageOffset) > 0 ? Number(dictionaryPageOffset) : void 0;
22366
+ const chunkOffset = Math.min(dataPageOffset, validDictionaryPageOffset ?? dataPageOffset);
22367
+ const chunkEnd = chunkOffset + Number(metadata.total_compressed_size);
22368
+ const chunkByteLength = Math.min(
22369
+ this.file.size - chunkOffset,
22370
+ Math.max(0, chunkEnd - chunkOffset)
22371
+ );
22372
+ const chunkBuffer = await this.readBytes(chunkOffset, chunkByteLength, signal);
22373
+ const dataPageRelativeOffset = dataPageOffset - chunkOffset;
22374
+ const dataPageByteLength = Math.min(
22375
+ chunkBuffer.byteLength - dataPageRelativeOffset,
22376
+ Math.max(0, chunkEnd - dataPageOffset)
22377
+ );
22378
+ const context = {
22379
+ column: field,
22380
+ compression,
22381
+ decompressPage: this.getPageDecompressor(compression),
22382
+ preserveCompression,
22383
+ verifyPageChecksums: this.props.verifyPageChecksums
22384
+ };
22385
+ let dictionary;
22386
+ if (validDictionaryPageOffset !== void 0) {
22387
+ const dictionaryRelativeOffset = validDictionaryPageOffset - chunkOffset;
22388
+ const dictionaryByteLength = Math.min(
22389
+ Math.max(0, dataPageOffset - validDictionaryPageOffset),
22390
+ chunkBuffer.byteLength - dictionaryRelativeOffset,
22391
+ this.props.defaultDictionarySize
22392
+ );
22393
+ const dictionaryBuffer = chunkBuffer.subarray(
22394
+ dictionaryRelativeOffset,
22395
+ dictionaryRelativeOffset + dictionaryByteLength
22396
+ );
22397
+ const plaintextDictionaryBuffer = columnChunk.crypto_metadata ? await this.decryptColumnPages(
22398
+ dictionaryBuffer,
22399
+ {
22400
+ type: physicalType,
22401
+ rLevelMax: field.rLevelMax,
22402
+ dLevelMax: field.dLevelMax,
22403
+ compression,
22404
+ column: field
22405
+ },
22406
+ rowGroupOrdinal,
22407
+ columnOrdinal,
22408
+ this.getColumnKeyMetadata(columnChunk),
22409
+ true
22410
+ ) : dictionaryBuffer;
22411
+ dictionary = (await scanParquetEncodedPages(plaintextDictionaryBuffer, context))[0];
22412
+ }
22413
+ const dataPageBuffer = chunkBuffer.subarray(
22414
+ dataPageRelativeOffset,
22415
+ dataPageRelativeOffset + dataPageByteLength
22416
+ );
22417
+ const plaintextDataPageBuffer = columnChunk.crypto_metadata ? await this.decryptColumnPages(
22418
+ dataPageBuffer,
22419
+ {
22420
+ type: physicalType,
22421
+ rLevelMax: field.rLevelMax,
22422
+ dLevelMax: field.dLevelMax,
22423
+ compression,
22424
+ column: field
22425
+ },
22426
+ rowGroupOrdinal,
22427
+ columnOrdinal,
22428
+ this.getColumnKeyMetadata(columnChunk)
22429
+ ) : dataPageBuffer;
22430
+ const pages = await scanParquetEncodedPages(plaintextDataPageBuffer, context);
22431
+ return Object.freeze({
22432
+ path: Object.freeze([...metadata.path_in_schema]),
22433
+ physicalType,
22434
+ typeLength: field.typeLength,
22435
+ maxRepetitionLevel: field.rLevelMax,
22436
+ maxDefinitionLevel: field.dLevelMax,
22437
+ compression,
22438
+ valueCount: Number(metadata.num_values),
22439
+ dictionary,
22440
+ pages: Object.freeze(pages)
22441
+ });
22442
+ }
22025
22443
  /** Decrypts the length-prefixed page header and data modules in one column chunk. */
22026
22444
  async decryptColumnPages(encryptedPages, context, rowGroupOrdinal, columnOrdinal, keyMetadata, includesDictionary = false, dataPageOrdinalStart = 0) {
22027
22445
  if (!this.encryptionContext || !this.props.keyRetriever) {
@@ -22842,9 +23260,10 @@ var _preloadParquetSourceLoader, _createMetadataDataSource, ParquetSourceLoaderB
22842
23260
  var init_parquet_source_loader = __esm({
22843
23261
  "../parquet/src/parquet-source-loader.ts"() {
22844
23262
  "use strict";
22845
- init_src6();
23263
+ init_src7();
22846
23264
  init_src2();
22847
- init_src4();
23265
+ init_src5();
23266
+ init_src6();
22848
23267
  init_get_parquet_schema();
22849
23268
  init_geoparquet_covering();
22850
23269
  init_parquet_bloom_filter();
@@ -22998,6 +23417,73 @@ var init_parquet_source_loader = __esm({
22998
23417
  scan(options = {}) {
22999
23418
  return this.read(options);
23000
23419
  }
23420
+ /**
23421
+ * Reads candidate encoded pages without decoding values or constructing Arrow arrays.
23422
+ *
23423
+ * Footer statistics and Bloom filters prune complete row groups. Any exact predicate or spatial
23424
+ * filter is returned as residual work, and its hidden columns are included in the page batch.
23425
+ */
23426
+ async *readPages(options = {}) {
23427
+ const readOptions = this.getReadOptions({
23428
+ rowGroups: options.rowGroups,
23429
+ columns: options.columns,
23430
+ rowGroupFilter: options.rowGroupFilter,
23431
+ predicate: options.predicate,
23432
+ bbox: options.bbox,
23433
+ geometryColumn: options.geometryColumn,
23434
+ signal: options.signal
23435
+ });
23436
+ const readContext = createReadAbortContext(readOptions.signal);
23437
+ this.activeReadControllers.add(readContext.abortController);
23438
+ try {
23439
+ const initialization = await this.getInitialization(readContext.abortController.signal);
23440
+ await this.getCompressionInitialization();
23441
+ throwIfAborted2(readContext.abortController.signal);
23442
+ const physicalPlan = await this.planRowGroups(
23443
+ initialization,
23444
+ readOptions,
23445
+ readContext.abortController.signal
23446
+ );
23447
+ const projectedColumns = normalizeColumns(readOptions.columns, initialization.schema);
23448
+ const predicateColumns = physicalPlan.predicate ? getParquetPredicateColumns(physicalPlan.predicate) : [];
23449
+ const geoMetadata = readOptions.bbox ? getGeoMetadata2(initialization.schema.metadata) : void 0;
23450
+ const geometryColumn = readOptions.bbox ? readOptions.geometryColumn || (geoMetadata == null ? void 0 : geoMetadata.primary_column) : void 0;
23451
+ const filterColumns = [
23452
+ .../* @__PURE__ */ new Set([...predicateColumns, ...geometryColumn ? [geometryColumn] : []])
23453
+ ];
23454
+ const decodedColumns = projectedColumns.length === 0 ? [] : [.../* @__PURE__ */ new Set([...projectedColumns, ...filterColumns])];
23455
+ const columnList = decodedColumns.map((column) => [column]);
23456
+ const preserveCompression = new Set(options.preserveCompression ?? []);
23457
+ const residualFilter = readOptions.predicate || readOptions.bbox ? Object.freeze({
23458
+ predicate: readOptions.predicate,
23459
+ bbox: readOptions.bbox,
23460
+ geometryColumn
23461
+ }) : void 0;
23462
+ for (const rowGroupIndex of physicalPlan.rowGroupIndices) {
23463
+ throwIfAborted2(readContext.abortController.signal);
23464
+ const columns = await initialization.reader.readRowGroupEncodedPages(
23465
+ initialization.parquetSchema,
23466
+ initialization.fileMetadata.row_groups[rowGroupIndex],
23467
+ columnList,
23468
+ preserveCompression,
23469
+ readContext.abortController.signal,
23470
+ rowGroupIndex
23471
+ );
23472
+ yield Object.freeze({
23473
+ shape: "parquet-encoded-pages",
23474
+ rowGroup: initialization.metadata.rowGroups[rowGroupIndex],
23475
+ projectedColumns: Object.freeze([...projectedColumns]),
23476
+ filterColumns: Object.freeze(filterColumns),
23477
+ columns,
23478
+ residualFilter
23479
+ });
23480
+ }
23481
+ } finally {
23482
+ readContext.abortController.abort();
23483
+ readContext.removeSignalListener();
23484
+ this.activeReadControllers.delete(readContext.abortController);
23485
+ }
23486
+ }
23001
23487
  /** Returns a copy of cumulative transport, decode, conversion, and pruning telemetry. */
23002
23488
  getTelemetry() {
23003
23489
  return Object.freeze({ ...this.telemetry });