@loaders.gl/scan 5.0.0-alpha.3 → 5.0.0-alpha.4
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/delta.cjs +401 -0
- package/dist/delta.cjs.map +2 -2
- package/dist/dist.min.js +7 -7
- package/dist/hudi.cjs +420 -1
- package/dist/hudi.cjs.map +3 -3
- package/dist/hudi.d.ts +4 -0
- package/dist/hudi.d.ts.map +1 -1
- package/dist/hudi.js +24 -1
- package/dist/hudi.js.map +1 -1
- package/dist/iceberg.cjs +401 -0
- package/dist/iceberg.cjs.map +3 -3
- package/dist/index.cjs +7 -7
- package/dist/index.cjs.map +1 -1
- package/dist/scan-engine.d.ts.map +1 -1
- package/dist/scan-engine.js +9 -7
- package/dist/scan-engine.js.map +1 -1
- package/package.json +8 -8
- package/src/hudi.ts +36 -1
- package/src/scan-engine.ts +11 -7
package/dist/dist.min.js
CHANGED
|
@@ -17574,29 +17574,29 @@ return true;`);
|
|
|
17574
17574
|
}
|
|
17575
17575
|
|
|
17576
17576
|
// src/scan-engine.ts
|
|
17577
|
-
var
|
|
17577
|
+
var scanBackends = /* @__PURE__ */ new Map();
|
|
17578
17578
|
var arrowScanBackend = Object.freeze({
|
|
17579
17579
|
name: "arrow",
|
|
17580
17580
|
query: queryArrowTable,
|
|
17581
|
-
queryAsync:
|
|
17581
|
+
queryAsync: (sourceTable, options) => Promise.resolve().then(queryArrowTable.bind(null, sourceTable, options)),
|
|
17582
17582
|
explain: explainArrowTableQuery
|
|
17583
17583
|
});
|
|
17584
|
-
|
|
17584
|
+
scanBackends.set("arrow", arrowScanBackend);
|
|
17585
17585
|
function registerScanBackend(name, loader) {
|
|
17586
17586
|
if (!name || !loader) {
|
|
17587
17587
|
throw new Error("A scan backend name and loader are required");
|
|
17588
17588
|
}
|
|
17589
|
-
|
|
17589
|
+
scanBackends.set(name, loader);
|
|
17590
17590
|
}
|
|
17591
17591
|
async function createScanEngine(options = {}) {
|
|
17592
17592
|
const backendName = options.backend || "arrow";
|
|
17593
|
-
const
|
|
17594
|
-
if (!
|
|
17593
|
+
const registeredBackend = scanBackends.get(backendName);
|
|
17594
|
+
if (!registeredBackend) {
|
|
17595
17595
|
throw new Error(
|
|
17596
17596
|
`Scan backend "${backendName}" is not registered. The built-in backend is "arrow".`
|
|
17597
17597
|
);
|
|
17598
17598
|
}
|
|
17599
|
-
const backend = await
|
|
17599
|
+
const backend = typeof registeredBackend === "function" ? await registeredBackend() : registeredBackend;
|
|
17600
17600
|
if (backend.name !== backendName) {
|
|
17601
17601
|
throw new Error(
|
|
17602
17602
|
`Scan backend loader returned "${backend.name}" while "${backendName}" was requested.`
|
package/dist/hudi.cjs
CHANGED
|
@@ -20676,6 +20676,201 @@ var init_decoders = __esm({
|
|
|
20676
20676
|
}
|
|
20677
20677
|
});
|
|
20678
20678
|
|
|
20679
|
+
// ../parquet/src/parquetjs/parser/encoded-pages.ts
|
|
20680
|
+
async function scanParquetEncodedPages(buffer, context) {
|
|
20681
|
+
const pages = [];
|
|
20682
|
+
let offset = 0;
|
|
20683
|
+
let dataPageOrdinal = 0;
|
|
20684
|
+
while (offset < buffer.byteLength) {
|
|
20685
|
+
const { pageHeader, length: headerByteLength } = decodePageHeader(buffer, offset);
|
|
20686
|
+
const bodyOffset = offset + headerByteLength;
|
|
20687
|
+
const bodyEnd = bodyOffset + pageHeader.compressed_page_size;
|
|
20688
|
+
if (pageHeader.compressed_page_size < 0 || pageHeader.uncompressed_page_size < 0 || bodyEnd > buffer.byteLength) {
|
|
20689
|
+
throw new Error("Parquet page extends beyond the available column-chunk buffer");
|
|
20690
|
+
}
|
|
20691
|
+
const compressedBody = buffer.subarray(bodyOffset, bodyEnd);
|
|
20692
|
+
verifyEncodedPageChecksum(compressedBody, pageHeader, context.verifyPageChecksums);
|
|
20693
|
+
const pageType = getThriftEnum(PageType, pageHeader.type);
|
|
20694
|
+
if (pageType === "DICTIONARY_PAGE") {
|
|
20695
|
+
pages.push(await createDictionaryPage(compressedBody, pageHeader, context));
|
|
20696
|
+
} else if (pageType === "DATA_PAGE") {
|
|
20697
|
+
pages.push(await createDataPageV1(compressedBody, pageHeader, context, dataPageOrdinal++));
|
|
20698
|
+
} else if (pageType === "DATA_PAGE_V2") {
|
|
20699
|
+
pages.push(await createDataPageV2(compressedBody, pageHeader, context, dataPageOrdinal++));
|
|
20700
|
+
} else {
|
|
20701
|
+
throw new Error(`Unsupported Parquet page type ${pageType}`);
|
|
20702
|
+
}
|
|
20703
|
+
offset = bodyEnd;
|
|
20704
|
+
}
|
|
20705
|
+
return pages;
|
|
20706
|
+
}
|
|
20707
|
+
async function createDictionaryPage(compressedBody, pageHeader, context) {
|
|
20708
|
+
const dictionaryHeader = pageHeader.dictionary_page_header;
|
|
20709
|
+
if (!dictionaryHeader) {
|
|
20710
|
+
throw new Error("Parquet dictionary page is missing its dictionary header");
|
|
20711
|
+
}
|
|
20712
|
+
const preserveCompression = shouldPreserveCompression(context);
|
|
20713
|
+
const data = preserveCompression ? compressedBody : await decompressPageBody(compressedBody, pageHeader.uncompressed_page_size, context);
|
|
20714
|
+
return Object.freeze({
|
|
20715
|
+
type: "dictionary",
|
|
20716
|
+
pageOrdinal: -1,
|
|
20717
|
+
encoding: getThriftEnum(Encoding, dictionaryHeader.encoding),
|
|
20718
|
+
compression: context.compression,
|
|
20719
|
+
compressionState: preserveCompression ? "compressed" : "decompressed",
|
|
20720
|
+
valueCount: dictionaryHeader.num_values,
|
|
20721
|
+
nonNullValueCount: dictionaryHeader.num_values,
|
|
20722
|
+
data,
|
|
20723
|
+
values: preserveCompression ? void 0 : createSection(0, data.byteLength),
|
|
20724
|
+
compressedByteLength: pageHeader.compressed_page_size,
|
|
20725
|
+
uncompressedByteLength: pageHeader.uncompressed_page_size
|
|
20726
|
+
});
|
|
20727
|
+
}
|
|
20728
|
+
async function createDataPageV1(compressedBody, pageHeader, context, pageOrdinal) {
|
|
20729
|
+
const dataHeader = pageHeader.data_page_header;
|
|
20730
|
+
if (!dataHeader) {
|
|
20731
|
+
throw new Error("Parquet V1 data page is missing its data header");
|
|
20732
|
+
}
|
|
20733
|
+
const preserveCompression = shouldPreserveCompression(context);
|
|
20734
|
+
const data = preserveCompression ? compressedBody : await decompressPageBody(compressedBody, pageHeader.uncompressed_page_size, context);
|
|
20735
|
+
let repetitionLevels;
|
|
20736
|
+
let definitionLevels;
|
|
20737
|
+
let values;
|
|
20738
|
+
if (!preserveCompression) {
|
|
20739
|
+
let sectionOffset = 0;
|
|
20740
|
+
const repetitionLevelEncoding = getThriftEnum(Encoding, dataHeader.repetition_level_encoding);
|
|
20741
|
+
repetitionLevels = readV1LevelSection(
|
|
20742
|
+
data,
|
|
20743
|
+
sectionOffset,
|
|
20744
|
+
dataHeader.num_values,
|
|
20745
|
+
context.column.rLevelMax,
|
|
20746
|
+
repetitionLevelEncoding
|
|
20747
|
+
);
|
|
20748
|
+
sectionOffset = repetitionLevels.byteOffset + repetitionLevels.byteLength;
|
|
20749
|
+
const definitionLevelEncoding = getThriftEnum(Encoding, dataHeader.definition_level_encoding);
|
|
20750
|
+
definitionLevels = readV1LevelSection(
|
|
20751
|
+
data,
|
|
20752
|
+
sectionOffset,
|
|
20753
|
+
dataHeader.num_values,
|
|
20754
|
+
context.column.dLevelMax,
|
|
20755
|
+
definitionLevelEncoding
|
|
20756
|
+
);
|
|
20757
|
+
sectionOffset = definitionLevels.byteOffset + definitionLevels.byteLength;
|
|
20758
|
+
values = createSection(sectionOffset, data.byteLength - sectionOffset);
|
|
20759
|
+
}
|
|
20760
|
+
return Object.freeze({
|
|
20761
|
+
type: "data-v1",
|
|
20762
|
+
pageOrdinal,
|
|
20763
|
+
encoding: getThriftEnum(Encoding, dataHeader.encoding),
|
|
20764
|
+
repetitionLevelEncoding: getThriftEnum(Encoding, dataHeader.repetition_level_encoding),
|
|
20765
|
+
definitionLevelEncoding: getThriftEnum(Encoding, dataHeader.definition_level_encoding),
|
|
20766
|
+
compression: context.compression,
|
|
20767
|
+
compressionState: preserveCompression ? "compressed" : "decompressed",
|
|
20768
|
+
valueCount: dataHeader.num_values,
|
|
20769
|
+
data,
|
|
20770
|
+
repetitionLevels,
|
|
20771
|
+
definitionLevels,
|
|
20772
|
+
values,
|
|
20773
|
+
compressedByteLength: pageHeader.compressed_page_size,
|
|
20774
|
+
uncompressedByteLength: pageHeader.uncompressed_page_size
|
|
20775
|
+
});
|
|
20776
|
+
}
|
|
20777
|
+
async function createDataPageV2(compressedBody, pageHeader, context, pageOrdinal) {
|
|
20778
|
+
const dataHeader = pageHeader.data_page_header_v2;
|
|
20779
|
+
if (!dataHeader) {
|
|
20780
|
+
throw new Error("Parquet V2 data page is missing its data header");
|
|
20781
|
+
}
|
|
20782
|
+
const repetitionByteLength = dataHeader.repetition_levels_byte_length;
|
|
20783
|
+
const definitionByteLength = dataHeader.definition_levels_byte_length;
|
|
20784
|
+
const levelsByteLength = repetitionByteLength + definitionByteLength;
|
|
20785
|
+
if (levelsByteLength > compressedBody.byteLength) {
|
|
20786
|
+
throw new Error("Parquet V2 level sections extend beyond the page body");
|
|
20787
|
+
}
|
|
20788
|
+
const valuesAreCompressed = dataHeader.is_compressed !== false && context.compression !== "UNCOMPRESSED";
|
|
20789
|
+
const preserveCompression = valuesAreCompressed && shouldPreserveCompression(context);
|
|
20790
|
+
let data = compressedBody;
|
|
20791
|
+
if (valuesAreCompressed && !preserveCompression) {
|
|
20792
|
+
const uncompressedValuesByteLength = pageHeader.uncompressed_page_size - levelsByteLength;
|
|
20793
|
+
if (uncompressedValuesByteLength < 0) {
|
|
20794
|
+
throw new Error("Invalid Parquet V2 uncompressed value length");
|
|
20795
|
+
}
|
|
20796
|
+
const values = await context.decompressPage(
|
|
20797
|
+
compressedBody.subarray(levelsByteLength),
|
|
20798
|
+
uncompressedValuesByteLength
|
|
20799
|
+
);
|
|
20800
|
+
data = new Uint8Array(levelsByteLength + values.byteLength);
|
|
20801
|
+
data.set(compressedBody.subarray(0, levelsByteLength));
|
|
20802
|
+
data.set(values, levelsByteLength);
|
|
20803
|
+
}
|
|
20804
|
+
return Object.freeze({
|
|
20805
|
+
type: "data-v2",
|
|
20806
|
+
pageOrdinal,
|
|
20807
|
+
encoding: getThriftEnum(Encoding, dataHeader.encoding),
|
|
20808
|
+
repetitionLevelEncoding: "RLE",
|
|
20809
|
+
definitionLevelEncoding: "RLE",
|
|
20810
|
+
compression: context.compression,
|
|
20811
|
+
compressionState: preserveCompression ? "compressed" : "decompressed",
|
|
20812
|
+
valueCount: dataHeader.num_values,
|
|
20813
|
+
nonNullValueCount: dataHeader.num_values - dataHeader.num_nulls,
|
|
20814
|
+
data,
|
|
20815
|
+
repetitionLevels: createSection(0, repetitionByteLength),
|
|
20816
|
+
definitionLevels: createSection(repetitionByteLength, definitionByteLength),
|
|
20817
|
+
values: createSection(levelsByteLength, data.byteLength - levelsByteLength),
|
|
20818
|
+
compressedByteLength: pageHeader.compressed_page_size,
|
|
20819
|
+
uncompressedByteLength: pageHeader.uncompressed_page_size
|
|
20820
|
+
});
|
|
20821
|
+
}
|
|
20822
|
+
function shouldPreserveCompression(context) {
|
|
20823
|
+
var _a;
|
|
20824
|
+
return context.compression !== "UNCOMPRESSED" && Boolean((_a = context.preserveCompression) == null ? void 0 : _a.has(context.compression));
|
|
20825
|
+
}
|
|
20826
|
+
async function decompressPageBody(compressedBody, uncompressedByteLength, context) {
|
|
20827
|
+
if (context.compression === "UNCOMPRESSED") return compressedBody;
|
|
20828
|
+
return await context.decompressPage(compressedBody, uncompressedByteLength);
|
|
20829
|
+
}
|
|
20830
|
+
function readV1LevelSection(data, offset, valueCount, maxLevel, encoding) {
|
|
20831
|
+
if (maxLevel === 0) return createSection(offset, 0);
|
|
20832
|
+
if (encoding === "RLE") {
|
|
20833
|
+
if (offset + 4 > data.byteLength) {
|
|
20834
|
+
throw new Error("Parquet V1 RLE level stream is missing its length prefix");
|
|
20835
|
+
}
|
|
20836
|
+
const byteLength = readUInt32LE(data, offset);
|
|
20837
|
+
const byteOffset = offset + 4;
|
|
20838
|
+
assertSectionBounds(data, byteOffset, byteLength);
|
|
20839
|
+
return createSection(byteOffset, byteLength);
|
|
20840
|
+
}
|
|
20841
|
+
if (encoding === "BIT_PACKED") {
|
|
20842
|
+
const byteLength = Math.ceil(valueCount / 8) * getBitWidth(maxLevel);
|
|
20843
|
+
assertSectionBounds(data, offset, byteLength);
|
|
20844
|
+
return createSection(offset, byteLength);
|
|
20845
|
+
}
|
|
20846
|
+
throw new Error(`Unsupported Parquet V1 level encoding ${encoding}`);
|
|
20847
|
+
}
|
|
20848
|
+
function createSection(byteOffset, byteLength) {
|
|
20849
|
+
return Object.freeze({ byteOffset, byteLength });
|
|
20850
|
+
}
|
|
20851
|
+
function assertSectionBounds(data, byteOffset, byteLength) {
|
|
20852
|
+
if (byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > data.byteLength) {
|
|
20853
|
+
throw new Error("Parquet page section extends beyond the page body");
|
|
20854
|
+
}
|
|
20855
|
+
}
|
|
20856
|
+
function verifyEncodedPageChecksum(compressedBody, pageHeader, verifyPageChecksums = false) {
|
|
20857
|
+
if (!verifyPageChecksums || pageHeader.crc === void 0) return;
|
|
20858
|
+
const expected = pageHeader.crc >>> 0;
|
|
20859
|
+
const actual = crc32(compressedBody);
|
|
20860
|
+
if (actual !== expected) {
|
|
20861
|
+
throw new Error(`Parquet page checksum mismatch: expected ${expected}, calculated ${actual}`);
|
|
20862
|
+
}
|
|
20863
|
+
}
|
|
20864
|
+
var init_encoded_pages = __esm({
|
|
20865
|
+
"../parquet/src/parquetjs/parser/encoded-pages.ts"() {
|
|
20866
|
+
"use strict";
|
|
20867
|
+
init_parquet_thrift();
|
|
20868
|
+
init_crc32();
|
|
20869
|
+
init_binary_utils();
|
|
20870
|
+
init_read_utils();
|
|
20871
|
+
}
|
|
20872
|
+
});
|
|
20873
|
+
|
|
20679
20874
|
// ../parquet/src/lib/parquet-encryption.ts
|
|
20680
20875
|
function readParquetEncryptedModule(buffer, offset = 0) {
|
|
20681
20876
|
if (offset + 4 > buffer.length) {
|
|
@@ -20918,6 +21113,7 @@ var init_parquet_reader = __esm({
|
|
|
20918
21113
|
"use strict";
|
|
20919
21114
|
init_schema();
|
|
20920
21115
|
init_decoders();
|
|
21116
|
+
init_encoded_pages();
|
|
20921
21117
|
init_shred();
|
|
20922
21118
|
init_compression2();
|
|
20923
21119
|
init_constants();
|
|
@@ -21404,6 +21600,50 @@ var init_parquet_reader = __esm({
|
|
|
21404
21600
|
columnData: Object.fromEntries(columnEntries)
|
|
21405
21601
|
};
|
|
21406
21602
|
}
|
|
21603
|
+
/**
|
|
21604
|
+
* Reads selected column chunks as encoded page descriptors without materializing values.
|
|
21605
|
+
*
|
|
21606
|
+
* Page headers, encryption, checksums, and optional decompression remain reader concerns. Value,
|
|
21607
|
+
* dictionary, and level decoding is deliberately left to the downstream consumer.
|
|
21608
|
+
*/
|
|
21609
|
+
async readRowGroupEncodedPages(schema, rowGroup, columnList, preserveCompression, signal, rowGroupOrdinal = 0) {
|
|
21610
|
+
await this.resolveColumnMetadata(rowGroup, rowGroupOrdinal, columnList);
|
|
21611
|
+
const selectedColumnChunks = [];
|
|
21612
|
+
for (let columnOrdinal = 0; columnOrdinal < rowGroup.columns.length; columnOrdinal++) {
|
|
21613
|
+
const columnChunk = rowGroup.columns[columnOrdinal];
|
|
21614
|
+
const path = getColumnChunkPath(columnChunk);
|
|
21615
|
+
if (columnList.length > 0 && (!path || fieldIndexOf(columnList, path) < 0)) continue;
|
|
21616
|
+
const physicalColumnOrdinal = getPhysicalColumnOrdinal(columnChunk, columnOrdinal);
|
|
21617
|
+
const metadata = columnChunk.meta_data || await this.getColumnMetadata(columnChunk, rowGroupOrdinal, physicalColumnOrdinal);
|
|
21618
|
+
if (columnList.length === 0 || fieldIndexOf(columnList, metadata.path_in_schema) >= 0) {
|
|
21619
|
+
selectedColumnChunks.push({
|
|
21620
|
+
columnChunk,
|
|
21621
|
+
metadata,
|
|
21622
|
+
columnOrdinal: physicalColumnOrdinal
|
|
21623
|
+
});
|
|
21624
|
+
}
|
|
21625
|
+
}
|
|
21626
|
+
const columns = [];
|
|
21627
|
+
for (let batchStart = 0; batchStart < selectedColumnChunks.length; batchStart += MAXIMUM_CONCURRENT_COLUMN_READS) {
|
|
21628
|
+
columns.push(
|
|
21629
|
+
...await Promise.all(
|
|
21630
|
+
selectedColumnChunks.slice(batchStart, batchStart + MAXIMUM_CONCURRENT_COLUMN_READS).map(async ({ columnChunk, metadata, columnOrdinal }) => {
|
|
21631
|
+
const encodedColumn = await this.readColumnChunkEncodedPages(
|
|
21632
|
+
schema,
|
|
21633
|
+
columnChunk,
|
|
21634
|
+
preserveCompression,
|
|
21635
|
+
signal,
|
|
21636
|
+
rowGroupOrdinal,
|
|
21637
|
+
columnOrdinal,
|
|
21638
|
+
metadata
|
|
21639
|
+
);
|
|
21640
|
+
return encodedColumn;
|
|
21641
|
+
})
|
|
21642
|
+
)
|
|
21643
|
+
);
|
|
21644
|
+
}
|
|
21645
|
+
return Object.freeze(columns);
|
|
21646
|
+
}
|
|
21407
21647
|
/** Reads independently materializable non-repeated columns for one row range using page indexes. */
|
|
21408
21648
|
async readRowGroupRange(schema, rowGroup, columnList, rowRange, pageLocations, signal, rowGroupOrdinal = 0) {
|
|
21409
21649
|
await this.resolveColumnMetadata(rowGroup, rowGroupOrdinal, columnList);
|
|
@@ -21596,6 +21836,99 @@ var init_parquet_reader = __esm({
|
|
|
21596
21836
|
) : chunkBuffer.subarray(pagesRelativeOffset, pagesRelativeOffset + pagesSize);
|
|
21597
21837
|
return await decodeDataPages(pagesBuf, { ...context, dictionary });
|
|
21598
21838
|
}
|
|
21839
|
+
/** Reads one column chunk as encoded dictionaries, levels, and values for deferred decoding. */
|
|
21840
|
+
async readColumnChunkEncodedPages(schema, columnChunk, preserveCompression, signal, rowGroupOrdinal = 0, columnOrdinal = 0, resolvedMetadata) {
|
|
21841
|
+
if (columnChunk.file_path !== void 0 && columnChunk.file_path !== null) {
|
|
21842
|
+
throw new Error("external references are not supported");
|
|
21843
|
+
}
|
|
21844
|
+
const metadata = resolvedMetadata || columnChunk.meta_data;
|
|
21845
|
+
if (!metadata) throw new Error("Parquet column metadata is missing");
|
|
21846
|
+
const field = schema.findField(metadata.path_in_schema);
|
|
21847
|
+
const physicalType = getThriftEnum(Type, metadata.type);
|
|
21848
|
+
if (physicalType !== field.primitiveType) {
|
|
21849
|
+
throw new Error(`chunk type not matching schema: ${physicalType}`);
|
|
21850
|
+
}
|
|
21851
|
+
const compression = getThriftEnum(CompressionCodec, metadata.codec);
|
|
21852
|
+
const dataPageOffset = Number(metadata.data_page_offset);
|
|
21853
|
+
const dictionaryPageOffset = metadata.dictionary_page_offset;
|
|
21854
|
+
const validDictionaryPageOffset = dictionaryPageOffset !== void 0 && Number(dictionaryPageOffset) > 0 ? Number(dictionaryPageOffset) : void 0;
|
|
21855
|
+
const chunkOffset = Math.min(dataPageOffset, validDictionaryPageOffset ?? dataPageOffset);
|
|
21856
|
+
const chunkEnd = chunkOffset + Number(metadata.total_compressed_size);
|
|
21857
|
+
const chunkByteLength = Math.min(
|
|
21858
|
+
this.file.size - chunkOffset,
|
|
21859
|
+
Math.max(0, chunkEnd - chunkOffset)
|
|
21860
|
+
);
|
|
21861
|
+
const chunkBuffer = await this.readBytes(chunkOffset, chunkByteLength, signal);
|
|
21862
|
+
const dataPageRelativeOffset = dataPageOffset - chunkOffset;
|
|
21863
|
+
const dataPageByteLength = Math.min(
|
|
21864
|
+
chunkBuffer.byteLength - dataPageRelativeOffset,
|
|
21865
|
+
Math.max(0, chunkEnd - dataPageOffset)
|
|
21866
|
+
);
|
|
21867
|
+
const context = {
|
|
21868
|
+
column: field,
|
|
21869
|
+
compression,
|
|
21870
|
+
decompressPage: this.getPageDecompressor(compression),
|
|
21871
|
+
preserveCompression,
|
|
21872
|
+
verifyPageChecksums: this.props.verifyPageChecksums
|
|
21873
|
+
};
|
|
21874
|
+
let dictionary;
|
|
21875
|
+
if (validDictionaryPageOffset !== void 0) {
|
|
21876
|
+
const dictionaryRelativeOffset = validDictionaryPageOffset - chunkOffset;
|
|
21877
|
+
const dictionaryByteLength = Math.min(
|
|
21878
|
+
Math.max(0, dataPageOffset - validDictionaryPageOffset),
|
|
21879
|
+
chunkBuffer.byteLength - dictionaryRelativeOffset,
|
|
21880
|
+
this.props.defaultDictionarySize
|
|
21881
|
+
);
|
|
21882
|
+
const dictionaryBuffer = chunkBuffer.subarray(
|
|
21883
|
+
dictionaryRelativeOffset,
|
|
21884
|
+
dictionaryRelativeOffset + dictionaryByteLength
|
|
21885
|
+
);
|
|
21886
|
+
const plaintextDictionaryBuffer = columnChunk.crypto_metadata ? await this.decryptColumnPages(
|
|
21887
|
+
dictionaryBuffer,
|
|
21888
|
+
{
|
|
21889
|
+
type: physicalType,
|
|
21890
|
+
rLevelMax: field.rLevelMax,
|
|
21891
|
+
dLevelMax: field.dLevelMax,
|
|
21892
|
+
compression,
|
|
21893
|
+
column: field
|
|
21894
|
+
},
|
|
21895
|
+
rowGroupOrdinal,
|
|
21896
|
+
columnOrdinal,
|
|
21897
|
+
this.getColumnKeyMetadata(columnChunk),
|
|
21898
|
+
true
|
|
21899
|
+
) : dictionaryBuffer;
|
|
21900
|
+
dictionary = (await scanParquetEncodedPages(plaintextDictionaryBuffer, context))[0];
|
|
21901
|
+
}
|
|
21902
|
+
const dataPageBuffer = chunkBuffer.subarray(
|
|
21903
|
+
dataPageRelativeOffset,
|
|
21904
|
+
dataPageRelativeOffset + dataPageByteLength
|
|
21905
|
+
);
|
|
21906
|
+
const plaintextDataPageBuffer = columnChunk.crypto_metadata ? await this.decryptColumnPages(
|
|
21907
|
+
dataPageBuffer,
|
|
21908
|
+
{
|
|
21909
|
+
type: physicalType,
|
|
21910
|
+
rLevelMax: field.rLevelMax,
|
|
21911
|
+
dLevelMax: field.dLevelMax,
|
|
21912
|
+
compression,
|
|
21913
|
+
column: field
|
|
21914
|
+
},
|
|
21915
|
+
rowGroupOrdinal,
|
|
21916
|
+
columnOrdinal,
|
|
21917
|
+
this.getColumnKeyMetadata(columnChunk)
|
|
21918
|
+
) : dataPageBuffer;
|
|
21919
|
+
const pages = await scanParquetEncodedPages(plaintextDataPageBuffer, context);
|
|
21920
|
+
return Object.freeze({
|
|
21921
|
+
path: Object.freeze([...metadata.path_in_schema]),
|
|
21922
|
+
physicalType,
|
|
21923
|
+
typeLength: field.typeLength,
|
|
21924
|
+
maxRepetitionLevel: field.rLevelMax,
|
|
21925
|
+
maxDefinitionLevel: field.dLevelMax,
|
|
21926
|
+
compression,
|
|
21927
|
+
valueCount: Number(metadata.num_values),
|
|
21928
|
+
dictionary,
|
|
21929
|
+
pages: Object.freeze(pages)
|
|
21930
|
+
});
|
|
21931
|
+
}
|
|
21599
21932
|
/** Decrypts the length-prefixed page header and data modules in one column chunk. */
|
|
21600
21933
|
async decryptColumnPages(encryptedPages, context, rowGroupOrdinal, columnOrdinal, keyMetadata, includesDictionary = false, dataPageOrdinalStart = 0) {
|
|
21601
21934
|
if (!this.encryptionContext || !this.props.keyRetriever) {
|
|
@@ -22419,6 +22752,7 @@ var init_parquet_source_loader = __esm({
|
|
|
22419
22752
|
init_src5();
|
|
22420
22753
|
init_src2();
|
|
22421
22754
|
init_src3();
|
|
22755
|
+
init_src4();
|
|
22422
22756
|
init_get_parquet_schema();
|
|
22423
22757
|
init_geoparquet_covering();
|
|
22424
22758
|
init_parquet_bloom_filter();
|
|
@@ -22572,6 +22906,73 @@ var init_parquet_source_loader = __esm({
|
|
|
22572
22906
|
scan(options = {}) {
|
|
22573
22907
|
return this.read(options);
|
|
22574
22908
|
}
|
|
22909
|
+
/**
|
|
22910
|
+
* Reads candidate encoded pages without decoding values or constructing Arrow arrays.
|
|
22911
|
+
*
|
|
22912
|
+
* Footer statistics and Bloom filters prune complete row groups. Any exact predicate or spatial
|
|
22913
|
+
* filter is returned as residual work, and its hidden columns are included in the page batch.
|
|
22914
|
+
*/
|
|
22915
|
+
async *readPages(options = {}) {
|
|
22916
|
+
const readOptions = this.getReadOptions({
|
|
22917
|
+
rowGroups: options.rowGroups,
|
|
22918
|
+
columns: options.columns,
|
|
22919
|
+
rowGroupFilter: options.rowGroupFilter,
|
|
22920
|
+
predicate: options.predicate,
|
|
22921
|
+
bbox: options.bbox,
|
|
22922
|
+
geometryColumn: options.geometryColumn,
|
|
22923
|
+
signal: options.signal
|
|
22924
|
+
});
|
|
22925
|
+
const readContext = createReadAbortContext(readOptions.signal);
|
|
22926
|
+
this.activeReadControllers.add(readContext.abortController);
|
|
22927
|
+
try {
|
|
22928
|
+
const initialization = await this.getInitialization(readContext.abortController.signal);
|
|
22929
|
+
await this.getCompressionInitialization();
|
|
22930
|
+
throwIfAborted2(readContext.abortController.signal);
|
|
22931
|
+
const physicalPlan = await this.planRowGroups(
|
|
22932
|
+
initialization,
|
|
22933
|
+
readOptions,
|
|
22934
|
+
readContext.abortController.signal
|
|
22935
|
+
);
|
|
22936
|
+
const projectedColumns = normalizeColumns(readOptions.columns, initialization.schema);
|
|
22937
|
+
const predicateColumns = physicalPlan.predicate ? getParquetPredicateColumns(physicalPlan.predicate) : [];
|
|
22938
|
+
const geoMetadata = readOptions.bbox ? getGeoMetadata(initialization.schema.metadata) : void 0;
|
|
22939
|
+
const geometryColumn = readOptions.bbox ? readOptions.geometryColumn || (geoMetadata == null ? void 0 : geoMetadata.primary_column) : void 0;
|
|
22940
|
+
const filterColumns = [
|
|
22941
|
+
.../* @__PURE__ */ new Set([...predicateColumns, ...geometryColumn ? [geometryColumn] : []])
|
|
22942
|
+
];
|
|
22943
|
+
const decodedColumns = projectedColumns.length === 0 ? [] : [.../* @__PURE__ */ new Set([...projectedColumns, ...filterColumns])];
|
|
22944
|
+
const columnList = decodedColumns.map((column) => [column]);
|
|
22945
|
+
const preserveCompression = new Set(options.preserveCompression ?? []);
|
|
22946
|
+
const residualFilter = readOptions.predicate || readOptions.bbox ? Object.freeze({
|
|
22947
|
+
predicate: readOptions.predicate,
|
|
22948
|
+
bbox: readOptions.bbox,
|
|
22949
|
+
geometryColumn
|
|
22950
|
+
}) : void 0;
|
|
22951
|
+
for (const rowGroupIndex of physicalPlan.rowGroupIndices) {
|
|
22952
|
+
throwIfAborted2(readContext.abortController.signal);
|
|
22953
|
+
const columns = await initialization.reader.readRowGroupEncodedPages(
|
|
22954
|
+
initialization.parquetSchema,
|
|
22955
|
+
initialization.fileMetadata.row_groups[rowGroupIndex],
|
|
22956
|
+
columnList,
|
|
22957
|
+
preserveCompression,
|
|
22958
|
+
readContext.abortController.signal,
|
|
22959
|
+
rowGroupIndex
|
|
22960
|
+
);
|
|
22961
|
+
yield Object.freeze({
|
|
22962
|
+
shape: "parquet-encoded-pages",
|
|
22963
|
+
rowGroup: initialization.metadata.rowGroups[rowGroupIndex],
|
|
22964
|
+
projectedColumns: Object.freeze([...projectedColumns]),
|
|
22965
|
+
filterColumns: Object.freeze(filterColumns),
|
|
22966
|
+
columns,
|
|
22967
|
+
residualFilter
|
|
22968
|
+
});
|
|
22969
|
+
}
|
|
22970
|
+
} finally {
|
|
22971
|
+
readContext.abortController.abort();
|
|
22972
|
+
readContext.removeSignalListener();
|
|
22973
|
+
this.activeReadControllers.delete(readContext.abortController);
|
|
22974
|
+
}
|
|
22975
|
+
}
|
|
22575
22976
|
/** Returns a copy of cumulative transport, decode, conversion, and pruning telemetry. */
|
|
22576
22977
|
getTelemetry() {
|
|
22577
22978
|
return Object.freeze({ ...this.telemetry });
|
|
@@ -24021,7 +24422,7 @@ var HudiTableSource = class extends DataSource {
|
|
|
24021
24422
|
}
|
|
24022
24423
|
async loadDescriptor(signal) {
|
|
24023
24424
|
var _a;
|
|
24024
|
-
const text = typeof this.data === "string" ? await (await this.fetch(this.
|
|
24425
|
+
const text = typeof this.data === "string" ? await (await this.fetch(this.url, { headers: (_a = this.options.hudi) == null ? void 0 : _a.headers, signal })).text() : await this.data.text();
|
|
24025
24426
|
let descriptor;
|
|
24026
24427
|
try {
|
|
24027
24428
|
descriptor = JSON.parse(text);
|
|
@@ -24032,6 +24433,24 @@ var HudiTableSource = class extends DataSource {
|
|
|
24032
24433
|
if (!Array.isArray(files)) {
|
|
24033
24434
|
throw new Error("Hudi snapshot descriptor must contain a files array");
|
|
24034
24435
|
}
|
|
24436
|
+
for (const [index, file] of files.entries()) {
|
|
24437
|
+
if (!file || typeof file !== "object" || Array.isArray(file)) {
|
|
24438
|
+
throw new Error(`Hudi snapshot file at index ${index} must be an object`);
|
|
24439
|
+
}
|
|
24440
|
+
const value2 = file;
|
|
24441
|
+
if (typeof value2.path !== "string" || !value2.path) {
|
|
24442
|
+
throw new Error(`Hudi snapshot file at index ${index} must contain a non-empty string path`);
|
|
24443
|
+
}
|
|
24444
|
+
if (value2.size !== void 0 && (typeof value2.size !== "number" || !Number.isFinite(value2.size))) {
|
|
24445
|
+
throw new Error(`Hudi snapshot file at index ${index} size must be a finite number`);
|
|
24446
|
+
}
|
|
24447
|
+
if (value2.numRecords !== void 0 && (typeof value2.numRecords !== "number" || !Number.isFinite(value2.numRecords))) {
|
|
24448
|
+
throw new Error(`Hudi snapshot file at index ${index} numRecords must be a finite number`);
|
|
24449
|
+
}
|
|
24450
|
+
if (value2.partitionValues !== void 0 && (!value2.partitionValues || typeof value2.partitionValues !== "object" || Array.isArray(value2.partitionValues))) {
|
|
24451
|
+
throw new Error(`Hudi snapshot file at index ${index} partitionValues must be an object`);
|
|
24452
|
+
}
|
|
24453
|
+
}
|
|
24035
24454
|
const value = descriptor;
|
|
24036
24455
|
if (value.tableType && value.tableType !== "COPY_ON_WRITE" && value.tableType !== "MERGE_ON_READ") {
|
|
24037
24456
|
throw new Error(`Unsupported Hudi table type: ${String(value.tableType)}`);
|