@gscdump/engine 7.3.1 → 7.3.2
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/README.md +10 -0
- package/dist/adapters/hyparquet.d.mts +6 -2
- package/dist/adapters/hyparquet.mjs +11 -5
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -20,6 +20,16 @@ npm install @gscdump/engine
|
|
|
20
20
|
The CLI installs this peer. Browser consumers use `@gscdump/engine-duckdb-wasm`.
|
|
21
21
|
The package includes `hyparquet` and `hyparquet-writer` for JavaScript Parquet encoding and decoding.
|
|
22
22
|
|
|
23
|
+
The `/hyparquet` encoders accept optional `fileMetadata: Record<string, string>`:
|
|
24
|
+
use `encodeRowsToParquet(table, rows, { fileMetadata })`, or include it in the
|
|
25
|
+
options for `encodeRowsToParquetFlex`. Metadata is stored in the file footer, not as fact
|
|
26
|
+
columns, including for empty files. Keys are sorted for deterministic encoding;
|
|
27
|
+
omitting metadata or passing an empty object preserves the existing bytes.
|
|
28
|
+
A publication coordinator can supply a unique identifier so identical rows from
|
|
29
|
+
different publications produce different bytes. It must retain and replay the
|
|
30
|
+
exact encoded bytes for retries; this option does not provide publication or
|
|
31
|
+
recovery coordination itself.
|
|
32
|
+
|
|
23
33
|
## Subpath exports
|
|
24
34
|
|
|
25
35
|
| Subpath | Purpose |
|
|
@@ -2,8 +2,12 @@ import { ParquetQueryFilter } from "../node_modules/.pnpm/hyparquet@1.31.1/node_
|
|
|
2
2
|
import "../node_modules/.pnpm/hyparquet@1.31.1/node_modules/hyparquet/types/node.mjs";
|
|
3
3
|
import { CodecCtx, DataSource, ParquetCodec, Row, TableName } from "../storage.mjs";
|
|
4
4
|
import { ColumnDef } from "../schema.mjs";
|
|
5
|
-
export
|
|
6
|
-
|
|
5
|
+
export interface EncodeParquetOptions {
|
|
6
|
+
/** File footer metadata, without adding fact columns. Keys are encoded in sorted order. */
|
|
7
|
+
fileMetadata?: Readonly<Record<string, string>>;
|
|
8
|
+
}
|
|
9
|
+
export declare function encodeRowsToParquet(table: TableName, rows: readonly Row[], opts?: EncodeParquetOptions): Uint8Array;
|
|
10
|
+
export interface EncodeFlexOptions extends EncodeParquetOptions {
|
|
7
11
|
/** Columns defining the output schema + order. */
|
|
8
12
|
columns: readonly ColumnDef[];
|
|
9
13
|
/** Sort key columns (subset of `columns` by name). Empty = preserve input order. */
|
|
@@ -157,7 +157,7 @@ function indexRow(index, key, row) {
|
|
|
157
157
|
} else if (sameNaturalKey(key, existing, row)) index.set(hash, row);
|
|
158
158
|
else index.set(hash, [existing, row]);
|
|
159
159
|
}
|
|
160
|
-
function encodeOrderedRows(rows, columns, rowGroupSize) {
|
|
160
|
+
function encodeOrderedRows(rows, columns, rowGroupSize, fileMetadata) {
|
|
161
161
|
const schema = buildWriteSchema(columns);
|
|
162
162
|
const codecs = columns.map((col) => ({
|
|
163
163
|
name: col.name,
|
|
@@ -177,18 +177,24 @@ function encodeOrderedRows(rows, columns, rowGroupSize) {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
const writer = new ByteWriter();
|
|
180
|
+
const metadataKeys = Object.keys(fileMetadata ?? {}).sort();
|
|
181
|
+
const kvMetadata = metadataKeys.length > 0 ? metadataKeys.map((key) => ({
|
|
182
|
+
key,
|
|
183
|
+
value: fileMetadata[key]
|
|
184
|
+
})) : void 0;
|
|
180
185
|
parquetWriteRows({
|
|
181
186
|
writer,
|
|
182
187
|
rows: coercedRows(),
|
|
183
188
|
columns: columnSpecs,
|
|
184
189
|
schema,
|
|
185
|
-
rowGroupSize
|
|
190
|
+
rowGroupSize,
|
|
191
|
+
kvMetadata
|
|
186
192
|
});
|
|
187
193
|
return new Uint8Array(writer.getBuffer());
|
|
188
194
|
}
|
|
189
|
-
function encodeRowsToParquet(table, rows) {
|
|
195
|
+
function encodeRowsToParquet(table, rows, opts = {}) {
|
|
190
196
|
const schema = SCHEMAS[table];
|
|
191
|
-
return encodeOrderedRows(sortRowsByClusterKey(table, rows), schema.columns, ROW_GROUP_SIZE);
|
|
197
|
+
return encodeOrderedRows(sortRowsByClusterKey(table, rows), schema.columns, ROW_GROUP_SIZE, opts.fileMetadata);
|
|
192
198
|
}
|
|
193
199
|
function encodeRowsToParquetFlex(rows, opts) {
|
|
194
200
|
const { columns, sortKey = [], rowGroupSize = ROW_GROUP_SIZE } = opts;
|
|
@@ -198,7 +204,7 @@ function encodeRowsToParquetFlex(rows, opts) {
|
|
|
198
204
|
if (cmp !== 0) return cmp;
|
|
199
205
|
}
|
|
200
206
|
return 0;
|
|
201
|
-
}), columns, rowGroupSize);
|
|
207
|
+
}), columns, rowGroupSize, opts.fileMetadata);
|
|
202
208
|
}
|
|
203
209
|
function asyncBufferFromBytes(bytes) {
|
|
204
210
|
const base = bytes.byteOffset;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/engine",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.3.
|
|
4
|
+
"version": "7.3.2",
|
|
5
5
|
"description": "Append-only Parquet/DuckDB storage engine + planner + adapters for the gscdump pipeline. Node + edge runtimes; opt-in heavy peers.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -189,10 +189,10 @@
|
|
|
189
189
|
}
|
|
190
190
|
},
|
|
191
191
|
"dependencies": {
|
|
192
|
-
"@gscdump/contracts": "^7.3.
|
|
193
|
-
"@gscdump/lakehouse": "^7.3.
|
|
192
|
+
"@gscdump/contracts": "^7.3.2",
|
|
193
|
+
"@gscdump/lakehouse": "^7.3.2",
|
|
194
194
|
"drizzle-orm": "1.0.0-rc.4",
|
|
195
|
-
"gscdump": "^7.3.
|
|
195
|
+
"gscdump": "^7.3.2",
|
|
196
196
|
"pathe": "^2.0.3",
|
|
197
197
|
"proper-lockfile": "^4.1.2"
|
|
198
198
|
},
|