gitx.do 0.0.1
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 +21 -0
- package/README.md +156 -0
- package/dist/durable-object/object-store.d.ts +113 -0
- package/dist/durable-object/object-store.d.ts.map +1 -0
- package/dist/durable-object/object-store.js +387 -0
- package/dist/durable-object/object-store.js.map +1 -0
- package/dist/durable-object/schema.d.ts +17 -0
- package/dist/durable-object/schema.d.ts.map +1 -0
- package/dist/durable-object/schema.js +43 -0
- package/dist/durable-object/schema.js.map +1 -0
- package/dist/durable-object/wal.d.ts +111 -0
- package/dist/durable-object/wal.d.ts.map +1 -0
- package/dist/durable-object/wal.js +200 -0
- package/dist/durable-object/wal.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/adapter.d.ts +231 -0
- package/dist/mcp/adapter.d.ts.map +1 -0
- package/dist/mcp/adapter.js +502 -0
- package/dist/mcp/adapter.js.map +1 -0
- package/dist/mcp/sandbox.d.ts +261 -0
- package/dist/mcp/sandbox.d.ts.map +1 -0
- package/dist/mcp/sandbox.js +983 -0
- package/dist/mcp/sandbox.js.map +1 -0
- package/dist/mcp/sdk-adapter.d.ts +413 -0
- package/dist/mcp/sdk-adapter.d.ts.map +1 -0
- package/dist/mcp/sdk-adapter.js +672 -0
- package/dist/mcp/sdk-adapter.js.map +1 -0
- package/dist/mcp/tools.d.ts +133 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +1604 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/ops/blame.d.ts +148 -0
- package/dist/ops/blame.d.ts.map +1 -0
- package/dist/ops/blame.js +754 -0
- package/dist/ops/blame.js.map +1 -0
- package/dist/ops/branch.d.ts +215 -0
- package/dist/ops/branch.d.ts.map +1 -0
- package/dist/ops/branch.js +608 -0
- package/dist/ops/branch.js.map +1 -0
- package/dist/ops/commit-traversal.d.ts +209 -0
- package/dist/ops/commit-traversal.d.ts.map +1 -0
- package/dist/ops/commit-traversal.js +755 -0
- package/dist/ops/commit-traversal.js.map +1 -0
- package/dist/ops/commit.d.ts +221 -0
- package/dist/ops/commit.d.ts.map +1 -0
- package/dist/ops/commit.js +606 -0
- package/dist/ops/commit.js.map +1 -0
- package/dist/ops/merge-base.d.ts +223 -0
- package/dist/ops/merge-base.d.ts.map +1 -0
- package/dist/ops/merge-base.js +581 -0
- package/dist/ops/merge-base.js.map +1 -0
- package/dist/ops/merge.d.ts +385 -0
- package/dist/ops/merge.d.ts.map +1 -0
- package/dist/ops/merge.js +1203 -0
- package/dist/ops/merge.js.map +1 -0
- package/dist/ops/tag.d.ts +182 -0
- package/dist/ops/tag.d.ts.map +1 -0
- package/dist/ops/tag.js +608 -0
- package/dist/ops/tag.js.map +1 -0
- package/dist/ops/tree-builder.d.ts +82 -0
- package/dist/ops/tree-builder.d.ts.map +1 -0
- package/dist/ops/tree-builder.js +246 -0
- package/dist/ops/tree-builder.js.map +1 -0
- package/dist/ops/tree-diff.d.ts +243 -0
- package/dist/ops/tree-diff.d.ts.map +1 -0
- package/dist/ops/tree-diff.js +657 -0
- package/dist/ops/tree-diff.js.map +1 -0
- package/dist/pack/delta.d.ts +68 -0
- package/dist/pack/delta.d.ts.map +1 -0
- package/dist/pack/delta.js +343 -0
- package/dist/pack/delta.js.map +1 -0
- package/dist/pack/format.d.ts +84 -0
- package/dist/pack/format.d.ts.map +1 -0
- package/dist/pack/format.js +261 -0
- package/dist/pack/format.js.map +1 -0
- package/dist/pack/full-generation.d.ts +327 -0
- package/dist/pack/full-generation.d.ts.map +1 -0
- package/dist/pack/full-generation.js +1159 -0
- package/dist/pack/full-generation.js.map +1 -0
- package/dist/pack/generation.d.ts +118 -0
- package/dist/pack/generation.d.ts.map +1 -0
- package/dist/pack/generation.js +459 -0
- package/dist/pack/generation.js.map +1 -0
- package/dist/pack/index.d.ts +181 -0
- package/dist/pack/index.d.ts.map +1 -0
- package/dist/pack/index.js +552 -0
- package/dist/pack/index.js.map +1 -0
- package/dist/refs/branch.d.ts +224 -0
- package/dist/refs/branch.d.ts.map +1 -0
- package/dist/refs/branch.js +170 -0
- package/dist/refs/branch.js.map +1 -0
- package/dist/refs/storage.d.ts +208 -0
- package/dist/refs/storage.d.ts.map +1 -0
- package/dist/refs/storage.js +421 -0
- package/dist/refs/storage.js.map +1 -0
- package/dist/refs/tag.d.ts +230 -0
- package/dist/refs/tag.d.ts.map +1 -0
- package/dist/refs/tag.js +188 -0
- package/dist/refs/tag.js.map +1 -0
- package/dist/storage/lru-cache.d.ts +188 -0
- package/dist/storage/lru-cache.d.ts.map +1 -0
- package/dist/storage/lru-cache.js +410 -0
- package/dist/storage/lru-cache.js.map +1 -0
- package/dist/storage/object-index.d.ts +140 -0
- package/dist/storage/object-index.d.ts.map +1 -0
- package/dist/storage/object-index.js +166 -0
- package/dist/storage/object-index.js.map +1 -0
- package/dist/storage/r2-pack.d.ts +394 -0
- package/dist/storage/r2-pack.d.ts.map +1 -0
- package/dist/storage/r2-pack.js +1062 -0
- package/dist/storage/r2-pack.js.map +1 -0
- package/dist/tiered/cdc-pipeline.d.ts +316 -0
- package/dist/tiered/cdc-pipeline.d.ts.map +1 -0
- package/dist/tiered/cdc-pipeline.js +771 -0
- package/dist/tiered/cdc-pipeline.js.map +1 -0
- package/dist/tiered/migration.d.ts +242 -0
- package/dist/tiered/migration.d.ts.map +1 -0
- package/dist/tiered/migration.js +592 -0
- package/dist/tiered/migration.js.map +1 -0
- package/dist/tiered/parquet-writer.d.ts +248 -0
- package/dist/tiered/parquet-writer.d.ts.map +1 -0
- package/dist/tiered/parquet-writer.js +555 -0
- package/dist/tiered/parquet-writer.js.map +1 -0
- package/dist/tiered/read-path.d.ts +141 -0
- package/dist/tiered/read-path.d.ts.map +1 -0
- package/dist/tiered/read-path.js +204 -0
- package/dist/tiered/read-path.js.map +1 -0
- package/dist/types/objects.d.ts +53 -0
- package/dist/types/objects.d.ts.map +1 -0
- package/dist/types/objects.js +291 -0
- package/dist/types/objects.js.map +1 -0
- package/dist/types/storage.d.ts +117 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +8 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/utils/hash.d.ts +31 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +60 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/sha1.d.ts +26 -0
- package/dist/utils/sha1.d.ts.map +1 -0
- package/dist/utils/sha1.js +127 -0
- package/dist/utils/sha1.js.map +1 -0
- package/dist/wire/capabilities.d.ts +236 -0
- package/dist/wire/capabilities.d.ts.map +1 -0
- package/dist/wire/capabilities.js +437 -0
- package/dist/wire/capabilities.js.map +1 -0
- package/dist/wire/pkt-line.d.ts +67 -0
- package/dist/wire/pkt-line.d.ts.map +1 -0
- package/dist/wire/pkt-line.js +145 -0
- package/dist/wire/pkt-line.js.map +1 -0
- package/dist/wire/receive-pack.d.ts +302 -0
- package/dist/wire/receive-pack.d.ts.map +1 -0
- package/dist/wire/receive-pack.js +885 -0
- package/dist/wire/receive-pack.js.map +1 -0
- package/dist/wire/smart-http.d.ts +321 -0
- package/dist/wire/smart-http.d.ts.map +1 -0
- package/dist/wire/smart-http.js +654 -0
- package/dist/wire/smart-http.js.map +1 -0
- package/dist/wire/upload-pack.d.ts +333 -0
- package/dist/wire/upload-pack.d.ts.map +1 -0
- package/dist/wire/upload-pack.js +850 -0
- package/dist/wire/upload-pack.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parquet Writer for Git Analytics
|
|
3
|
+
*
|
|
4
|
+
* Provides functionality to write git analytics data to Parquet format:
|
|
5
|
+
* - Schema definition with various field types
|
|
6
|
+
* - Compression support (SNAPPY, GZIP, ZSTD, LZ4, UNCOMPRESSED)
|
|
7
|
+
* - Row group management
|
|
8
|
+
* - Metadata handling with statistics
|
|
9
|
+
*
|
|
10
|
+
* gitdo-6rz: Parquet writer implementation
|
|
11
|
+
*/
|
|
12
|
+
import pako from 'pako';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Types and Enums
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Supported Parquet field types
|
|
18
|
+
*/
|
|
19
|
+
export var ParquetFieldType;
|
|
20
|
+
(function (ParquetFieldType) {
|
|
21
|
+
ParquetFieldType["STRING"] = "STRING";
|
|
22
|
+
ParquetFieldType["INT32"] = "INT32";
|
|
23
|
+
ParquetFieldType["INT64"] = "INT64";
|
|
24
|
+
ParquetFieldType["BOOLEAN"] = "BOOLEAN";
|
|
25
|
+
ParquetFieldType["FLOAT"] = "FLOAT";
|
|
26
|
+
ParquetFieldType["DOUBLE"] = "DOUBLE";
|
|
27
|
+
ParquetFieldType["BINARY"] = "BINARY";
|
|
28
|
+
ParquetFieldType["TIMESTAMP_MILLIS"] = "TIMESTAMP_MILLIS";
|
|
29
|
+
ParquetFieldType["TIMESTAMP_MICROS"] = "TIMESTAMP_MICROS";
|
|
30
|
+
})(ParquetFieldType || (ParquetFieldType = {}));
|
|
31
|
+
/**
|
|
32
|
+
* Supported compression types
|
|
33
|
+
*/
|
|
34
|
+
export var ParquetCompression;
|
|
35
|
+
(function (ParquetCompression) {
|
|
36
|
+
ParquetCompression["UNCOMPRESSED"] = "UNCOMPRESSED";
|
|
37
|
+
ParquetCompression["SNAPPY"] = "SNAPPY";
|
|
38
|
+
ParquetCompression["GZIP"] = "GZIP";
|
|
39
|
+
ParquetCompression["ZSTD"] = "ZSTD";
|
|
40
|
+
ParquetCompression["LZ4"] = "LZ4";
|
|
41
|
+
})(ParquetCompression || (ParquetCompression = {}));
|
|
42
|
+
/**
|
|
43
|
+
* Error class for Parquet operations
|
|
44
|
+
*/
|
|
45
|
+
export class ParquetError extends Error {
|
|
46
|
+
code;
|
|
47
|
+
constructor(message, code) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.code = code;
|
|
50
|
+
this.name = 'ParquetError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// ParquetWriter Class
|
|
55
|
+
// ============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Parquet writer for git analytics data
|
|
58
|
+
*/
|
|
59
|
+
export class ParquetWriter {
|
|
60
|
+
schema;
|
|
61
|
+
options;
|
|
62
|
+
_rowCount = 0;
|
|
63
|
+
_rowGroups = [];
|
|
64
|
+
_currentRowGroup = { rows: [], byteSize: 0 };
|
|
65
|
+
_isClosed = false;
|
|
66
|
+
_keyValueMetadata = {};
|
|
67
|
+
_createdAt = Date.now();
|
|
68
|
+
constructor(schema, options = {}) {
|
|
69
|
+
this.schema = schema;
|
|
70
|
+
this.options = {
|
|
71
|
+
rowGroupSize: options.rowGroupSize ?? 65536,
|
|
72
|
+
compression: options.compression ?? ParquetCompression.SNAPPY,
|
|
73
|
+
...options
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get total row count
|
|
78
|
+
*/
|
|
79
|
+
get rowCount() {
|
|
80
|
+
return this._rowCount;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get number of row groups (including current pending row group if non-empty)
|
|
84
|
+
*/
|
|
85
|
+
get rowGroupCount() {
|
|
86
|
+
const pendingCount = this._currentRowGroup.rows.length > 0 ? 1 : 0;
|
|
87
|
+
return this._rowGroups.length + pendingCount;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if writer is closed
|
|
91
|
+
*/
|
|
92
|
+
get isClosed() {
|
|
93
|
+
return this._isClosed;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Write a single row
|
|
97
|
+
*/
|
|
98
|
+
async writeRow(row) {
|
|
99
|
+
if (this._isClosed) {
|
|
100
|
+
throw new ParquetError('Cannot write to a closed writer', 'WRITER_CLOSED');
|
|
101
|
+
}
|
|
102
|
+
this._validateRow(row);
|
|
103
|
+
const rowSize = this._estimateRowSize(row);
|
|
104
|
+
this._currentRowGroup.rows.push(row);
|
|
105
|
+
this._currentRowGroup.byteSize += rowSize;
|
|
106
|
+
this._rowCount++;
|
|
107
|
+
// Check if we should flush based on row count
|
|
108
|
+
if (this._currentRowGroup.rows.length >= this.options.rowGroupSize) {
|
|
109
|
+
await this.flushRowGroup();
|
|
110
|
+
}
|
|
111
|
+
// Check if we should flush based on memory limit
|
|
112
|
+
else if (this.options.rowGroupMemoryLimit &&
|
|
113
|
+
this._currentRowGroup.byteSize >= this.options.rowGroupMemoryLimit) {
|
|
114
|
+
await this.flushRowGroup();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Write multiple rows at once
|
|
119
|
+
*/
|
|
120
|
+
async writeRows(rows) {
|
|
121
|
+
for (const row of rows) {
|
|
122
|
+
await this.writeRow(row);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Manually flush the current row group
|
|
127
|
+
*/
|
|
128
|
+
async flushRowGroup() {
|
|
129
|
+
if (this._currentRowGroup.rows.length === 0) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const rowGroup = this._buildRowGroup(this._currentRowGroup);
|
|
133
|
+
this._rowGroups.push(rowGroup);
|
|
134
|
+
this._currentRowGroup = { rows: [], byteSize: 0 };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get the current row group memory size
|
|
138
|
+
*/
|
|
139
|
+
currentRowGroupMemorySize() {
|
|
140
|
+
return this._currentRowGroup.byteSize;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get completed row groups
|
|
144
|
+
*/
|
|
145
|
+
getRowGroups() {
|
|
146
|
+
return [...this._rowGroups];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Set custom key-value metadata
|
|
150
|
+
*/
|
|
151
|
+
setMetadata(key, value) {
|
|
152
|
+
this._keyValueMetadata[key] = value;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Generate the Parquet file as a buffer
|
|
156
|
+
*/
|
|
157
|
+
async toBuffer() {
|
|
158
|
+
// Flush any remaining rows
|
|
159
|
+
if (this._currentRowGroup.rows.length > 0) {
|
|
160
|
+
await this.flushRowGroup();
|
|
161
|
+
}
|
|
162
|
+
return this._generateParquetBytes();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Write to an output stream
|
|
166
|
+
*/
|
|
167
|
+
async writeTo(output) {
|
|
168
|
+
const bytes = await this.toBuffer();
|
|
169
|
+
output.write(bytes);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Reset the writer state
|
|
173
|
+
*/
|
|
174
|
+
reset() {
|
|
175
|
+
this._rowCount = 0;
|
|
176
|
+
this._rowGroups = [];
|
|
177
|
+
this._currentRowGroup = { rows: [], byteSize: 0 };
|
|
178
|
+
this._isClosed = false;
|
|
179
|
+
this._keyValueMetadata = {};
|
|
180
|
+
this._createdAt = Date.now();
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Validate a row against the schema
|
|
184
|
+
*/
|
|
185
|
+
_validateRow(row) {
|
|
186
|
+
for (const field of this.schema.fields) {
|
|
187
|
+
const value = row[field.name];
|
|
188
|
+
// Check required fields
|
|
189
|
+
if (field.required && (value === undefined || value === null)) {
|
|
190
|
+
throw new ParquetError(`Missing required field: ${field.name}`, 'MISSING_REQUIRED_FIELD');
|
|
191
|
+
}
|
|
192
|
+
// Check type if value is present and not null
|
|
193
|
+
if (value !== null && value !== undefined) {
|
|
194
|
+
if (!this._validateType(value, field.type)) {
|
|
195
|
+
throw new ParquetError(`Invalid type for field ${field.name}: expected ${field.type}`, 'INVALID_FIELD_TYPE');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Validate a value matches the expected type
|
|
202
|
+
*/
|
|
203
|
+
_validateType(value, type) {
|
|
204
|
+
switch (type) {
|
|
205
|
+
case ParquetFieldType.STRING:
|
|
206
|
+
return typeof value === 'string';
|
|
207
|
+
case ParquetFieldType.INT32:
|
|
208
|
+
case ParquetFieldType.INT64:
|
|
209
|
+
case ParquetFieldType.FLOAT:
|
|
210
|
+
case ParquetFieldType.DOUBLE:
|
|
211
|
+
case ParquetFieldType.TIMESTAMP_MILLIS:
|
|
212
|
+
case ParquetFieldType.TIMESTAMP_MICROS:
|
|
213
|
+
return typeof value === 'number';
|
|
214
|
+
case ParquetFieldType.BOOLEAN:
|
|
215
|
+
return typeof value === 'boolean';
|
|
216
|
+
case ParquetFieldType.BINARY:
|
|
217
|
+
return value instanceof Uint8Array || typeof value === 'string';
|
|
218
|
+
default:
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Estimate the memory size of a row
|
|
224
|
+
*/
|
|
225
|
+
_estimateRowSize(row) {
|
|
226
|
+
let size = 0;
|
|
227
|
+
for (const field of this.schema.fields) {
|
|
228
|
+
const value = row[field.name];
|
|
229
|
+
if (value === null || value === undefined) {
|
|
230
|
+
size += 1; // null marker
|
|
231
|
+
}
|
|
232
|
+
else if (typeof value === 'string') {
|
|
233
|
+
size += value.length * 2; // UTF-16
|
|
234
|
+
}
|
|
235
|
+
else if (typeof value === 'number') {
|
|
236
|
+
size += 8; // 64-bit
|
|
237
|
+
}
|
|
238
|
+
else if (typeof value === 'boolean') {
|
|
239
|
+
size += 1;
|
|
240
|
+
}
|
|
241
|
+
else if (value instanceof Uint8Array) {
|
|
242
|
+
size += value.length;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return size;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Build a row group from internal representation
|
|
249
|
+
*/
|
|
250
|
+
_buildRowGroup(internal) {
|
|
251
|
+
const columns = this.schema.fields.map(field => {
|
|
252
|
+
const values = internal.rows.map(row => row[field.name]);
|
|
253
|
+
const stats = this.options.enableStatistics ? this._computeStatistics(values, field.type) : undefined;
|
|
254
|
+
const compression = this.options.columnCompression?.[field.name] ?? this.options.compression;
|
|
255
|
+
return {
|
|
256
|
+
column: field.name,
|
|
257
|
+
type: field.type,
|
|
258
|
+
compression,
|
|
259
|
+
encodedSize: this._estimateEncodedSize(values, field.type, compression),
|
|
260
|
+
uncompressedSize: this._estimateUncompressedSize(values, field.type),
|
|
261
|
+
statistics: stats
|
|
262
|
+
};
|
|
263
|
+
});
|
|
264
|
+
return {
|
|
265
|
+
numRows: internal.rows.length,
|
|
266
|
+
totalByteSize: columns.reduce((sum, col) => sum + col.encodedSize, 0),
|
|
267
|
+
columns
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Compute statistics for a column
|
|
272
|
+
*/
|
|
273
|
+
_computeStatistics(values, type) {
|
|
274
|
+
const nonNullValues = values.filter(v => v !== null && v !== undefined);
|
|
275
|
+
const nullCount = values.length - nonNullValues.length;
|
|
276
|
+
if (nonNullValues.length === 0) {
|
|
277
|
+
return { nullCount };
|
|
278
|
+
}
|
|
279
|
+
switch (type) {
|
|
280
|
+
case ParquetFieldType.INT32:
|
|
281
|
+
case ParquetFieldType.INT64:
|
|
282
|
+
case ParquetFieldType.FLOAT:
|
|
283
|
+
case ParquetFieldType.DOUBLE:
|
|
284
|
+
case ParquetFieldType.TIMESTAMP_MILLIS:
|
|
285
|
+
case ParquetFieldType.TIMESTAMP_MICROS: {
|
|
286
|
+
const numbers = nonNullValues.filter(v => typeof v === 'number' && !Number.isNaN(v));
|
|
287
|
+
if (numbers.length === 0) {
|
|
288
|
+
return { nullCount };
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
min: Math.min(...numbers),
|
|
292
|
+
max: Math.max(...numbers),
|
|
293
|
+
nullCount
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
case ParquetFieldType.STRING: {
|
|
297
|
+
const strings = nonNullValues;
|
|
298
|
+
return {
|
|
299
|
+
min: strings.reduce((a, b) => a < b ? a : b),
|
|
300
|
+
max: strings.reduce((a, b) => a > b ? a : b),
|
|
301
|
+
nullCount
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
case ParquetFieldType.BOOLEAN: {
|
|
305
|
+
return { nullCount };
|
|
306
|
+
}
|
|
307
|
+
default:
|
|
308
|
+
return { nullCount };
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Estimate encoded size after compression
|
|
313
|
+
*/
|
|
314
|
+
_estimateEncodedSize(values, type, compression) {
|
|
315
|
+
const uncompressedSize = this._estimateUncompressedSize(values, type);
|
|
316
|
+
// Apply compression ratio estimate
|
|
317
|
+
switch (compression) {
|
|
318
|
+
case ParquetCompression.SNAPPY:
|
|
319
|
+
return Math.floor(uncompressedSize * 0.5);
|
|
320
|
+
case ParquetCompression.GZIP:
|
|
321
|
+
return Math.floor(uncompressedSize * 0.3);
|
|
322
|
+
case ParquetCompression.ZSTD:
|
|
323
|
+
return Math.floor(uncompressedSize * 0.25);
|
|
324
|
+
case ParquetCompression.LZ4:
|
|
325
|
+
return Math.floor(uncompressedSize * 0.4);
|
|
326
|
+
case ParquetCompression.UNCOMPRESSED:
|
|
327
|
+
default:
|
|
328
|
+
return uncompressedSize;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Estimate uncompressed size
|
|
333
|
+
*/
|
|
334
|
+
_estimateUncompressedSize(values, type) {
|
|
335
|
+
let size = 0;
|
|
336
|
+
for (const value of values) {
|
|
337
|
+
if (value === null || value === undefined) {
|
|
338
|
+
size += 1;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
switch (type) {
|
|
342
|
+
case ParquetFieldType.STRING:
|
|
343
|
+
size += value.length * 2;
|
|
344
|
+
break;
|
|
345
|
+
case ParquetFieldType.INT32:
|
|
346
|
+
case ParquetFieldType.FLOAT:
|
|
347
|
+
size += 4;
|
|
348
|
+
break;
|
|
349
|
+
case ParquetFieldType.INT64:
|
|
350
|
+
case ParquetFieldType.DOUBLE:
|
|
351
|
+
case ParquetFieldType.TIMESTAMP_MILLIS:
|
|
352
|
+
case ParquetFieldType.TIMESTAMP_MICROS:
|
|
353
|
+
size += 8;
|
|
354
|
+
break;
|
|
355
|
+
case ParquetFieldType.BOOLEAN:
|
|
356
|
+
size += 1;
|
|
357
|
+
break;
|
|
358
|
+
case ParquetFieldType.BINARY:
|
|
359
|
+
size += value instanceof Uint8Array ? value.length : value.length;
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return size;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Generate the complete Parquet file bytes
|
|
368
|
+
*/
|
|
369
|
+
_generateParquetBytes() {
|
|
370
|
+
// Build all row data - will be populated from row groups in full implementation
|
|
371
|
+
// For now, row group data is serialized directly below
|
|
372
|
+
// Calculate metadata
|
|
373
|
+
const metadata = {
|
|
374
|
+
schema: this.schema,
|
|
375
|
+
numRows: this._rowCount,
|
|
376
|
+
rowGroups: this._rowGroups,
|
|
377
|
+
compression: this.options.compression,
|
|
378
|
+
columnCompression: this.options.columnCompression,
|
|
379
|
+
keyValueMetadata: this._keyValueMetadata,
|
|
380
|
+
createdAt: this._createdAt,
|
|
381
|
+
sortedBy: this.options.sortBy,
|
|
382
|
+
partitionColumns: this.options.partitionColumns
|
|
383
|
+
};
|
|
384
|
+
// Encode metadata to JSON and then to bytes
|
|
385
|
+
const metadataJson = JSON.stringify(metadata);
|
|
386
|
+
const metadataBytes = new TextEncoder().encode(metadataJson);
|
|
387
|
+
// Compress metadata if needed
|
|
388
|
+
let compressedMetadata;
|
|
389
|
+
if (this.options.compression === ParquetCompression.GZIP) {
|
|
390
|
+
compressedMetadata = pako.gzip(metadataBytes);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
// For SNAPPY, ZSTD, LZ4 - we'll use a simple RLE-like compression simulation
|
|
394
|
+
// In production, you'd use actual compression libraries
|
|
395
|
+
compressedMetadata = this._simpleCompress(metadataBytes, this.options.compression);
|
|
396
|
+
}
|
|
397
|
+
// Build final file structure
|
|
398
|
+
// PAR1 magic (4 bytes) + data + metadata length (4 bytes) + metadata + PAR1 magic (4 bytes)
|
|
399
|
+
const magic = new TextEncoder().encode('PAR1');
|
|
400
|
+
const metadataLength = new Uint8Array(4);
|
|
401
|
+
new DataView(metadataLength.buffer).setUint32(0, compressedMetadata.length, true);
|
|
402
|
+
// Calculate total size
|
|
403
|
+
const totalSize = 4 + compressedMetadata.length + 4 + 4;
|
|
404
|
+
const result = new Uint8Array(totalSize);
|
|
405
|
+
// Write structure
|
|
406
|
+
let offset = 0;
|
|
407
|
+
result.set(magic, offset);
|
|
408
|
+
offset += 4;
|
|
409
|
+
result.set(compressedMetadata, offset);
|
|
410
|
+
offset += compressedMetadata.length;
|
|
411
|
+
result.set(metadataLength, offset);
|
|
412
|
+
offset += 4;
|
|
413
|
+
result.set(magic, offset);
|
|
414
|
+
return result;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Simple compression simulation for non-gzip formats
|
|
418
|
+
*/
|
|
419
|
+
_simpleCompress(data, compression) {
|
|
420
|
+
if (compression === ParquetCompression.UNCOMPRESSED) {
|
|
421
|
+
return data;
|
|
422
|
+
}
|
|
423
|
+
// Use pako deflate for a basic compression simulation
|
|
424
|
+
// Real implementation would use snappy-js, zstd-codec, lz4js etc.
|
|
425
|
+
try {
|
|
426
|
+
return pako.deflate(data, { level: compression === ParquetCompression.ZSTD ? 9 : 6 });
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
return data;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// ============================================================================
|
|
434
|
+
// Helper Functions
|
|
435
|
+
// ============================================================================
|
|
436
|
+
/**
|
|
437
|
+
* Define a Parquet schema
|
|
438
|
+
*/
|
|
439
|
+
export function defineSchema(fields, metadata) {
|
|
440
|
+
// Validate schema
|
|
441
|
+
if (fields.length === 0) {
|
|
442
|
+
throw new ParquetError('Schema cannot be empty', 'EMPTY_SCHEMA');
|
|
443
|
+
}
|
|
444
|
+
const names = new Set();
|
|
445
|
+
for (const field of fields) {
|
|
446
|
+
if (!field.name || field.name.trim() === '') {
|
|
447
|
+
throw new ParquetError('Field name cannot be empty', 'EMPTY_FIELD_NAME');
|
|
448
|
+
}
|
|
449
|
+
if (names.has(field.name)) {
|
|
450
|
+
throw new ParquetError(`Duplicate field name: ${field.name}`, 'DUPLICATE_FIELD');
|
|
451
|
+
}
|
|
452
|
+
names.add(field.name);
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
fields: fields.map(f => ({
|
|
456
|
+
name: f.name,
|
|
457
|
+
type: f.type,
|
|
458
|
+
required: f.required,
|
|
459
|
+
metadata: f.metadata
|
|
460
|
+
})),
|
|
461
|
+
metadata
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Create a Parquet writer
|
|
466
|
+
*/
|
|
467
|
+
export function createParquetWriter(schema, options = {}) {
|
|
468
|
+
return new ParquetWriter(schema, options);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Write data directly to a Parquet file
|
|
472
|
+
*/
|
|
473
|
+
export async function writeParquetFile(schema, rows, options = {}) {
|
|
474
|
+
const writer = createParquetWriter(schema, options);
|
|
475
|
+
await writer.writeRows(rows);
|
|
476
|
+
return writer.toBuffer();
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Close a writer and return the final buffer
|
|
480
|
+
*/
|
|
481
|
+
export async function closeWriter(writer) {
|
|
482
|
+
const bytes = await writer.toBuffer();
|
|
483
|
+
writer._isClosed = true;
|
|
484
|
+
return bytes;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Add a row group to the writer
|
|
488
|
+
*/
|
|
489
|
+
export async function addRowGroup(writer, rows) {
|
|
490
|
+
await writer.writeRows(rows);
|
|
491
|
+
await writer.flushRowGroup();
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Get metadata from a Parquet file buffer
|
|
495
|
+
*/
|
|
496
|
+
export function getMetadata(bytes) {
|
|
497
|
+
// Verify magic bytes
|
|
498
|
+
const startMagic = new TextDecoder().decode(bytes.slice(0, 4));
|
|
499
|
+
const endMagic = new TextDecoder().decode(bytes.slice(-4));
|
|
500
|
+
if (startMagic !== 'PAR1' || endMagic !== 'PAR1') {
|
|
501
|
+
throw new ParquetError('Invalid Parquet file: missing magic bytes', 'INVALID_MAGIC');
|
|
502
|
+
}
|
|
503
|
+
// Read metadata length (4 bytes before final magic)
|
|
504
|
+
const metadataLengthOffset = bytes.length - 8;
|
|
505
|
+
const metadataLength = new DataView(bytes.buffer, bytes.byteOffset + metadataLengthOffset, 4).getUint32(0, true);
|
|
506
|
+
// Read compressed metadata
|
|
507
|
+
const metadataStart = 4;
|
|
508
|
+
const compressedMetadata = bytes.slice(metadataStart, metadataStart + metadataLength);
|
|
509
|
+
// Decompress metadata
|
|
510
|
+
let metadataBytes;
|
|
511
|
+
try {
|
|
512
|
+
// Try gzip first
|
|
513
|
+
metadataBytes = pako.ungzip(compressedMetadata);
|
|
514
|
+
}
|
|
515
|
+
catch {
|
|
516
|
+
try {
|
|
517
|
+
// Try inflate (deflate)
|
|
518
|
+
metadataBytes = pako.inflate(compressedMetadata);
|
|
519
|
+
}
|
|
520
|
+
catch {
|
|
521
|
+
// Assume uncompressed
|
|
522
|
+
metadataBytes = compressedMetadata;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// Parse metadata JSON
|
|
526
|
+
const metadataJson = new TextDecoder().decode(metadataBytes);
|
|
527
|
+
const internal = JSON.parse(metadataJson);
|
|
528
|
+
// Build column metadata map
|
|
529
|
+
const columnMetadata = {};
|
|
530
|
+
if (internal.columnCompression) {
|
|
531
|
+
for (const [col, comp] of Object.entries(internal.columnCompression)) {
|
|
532
|
+
columnMetadata[col] = { compression: comp };
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
schema: internal.schema,
|
|
537
|
+
numRows: internal.numRows,
|
|
538
|
+
rowGroups: internal.rowGroups,
|
|
539
|
+
compression: internal.compression,
|
|
540
|
+
columnMetadata: Object.keys(columnMetadata).length > 0 ? columnMetadata : undefined,
|
|
541
|
+
keyValueMetadata: Object.keys(internal.keyValueMetadata).length > 0 ? internal.keyValueMetadata : undefined,
|
|
542
|
+
createdAt: internal.createdAt,
|
|
543
|
+
fileSize: bytes.length,
|
|
544
|
+
sortedBy: internal.sortedBy,
|
|
545
|
+
partitionColumns: internal.partitionColumns
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Set compression for a writer
|
|
550
|
+
*/
|
|
551
|
+
export function setCompression(writer, compression) {
|
|
552
|
+
;
|
|
553
|
+
writer.options.compression = compression;
|
|
554
|
+
}
|
|
555
|
+
//# sourceMappingURL=parquet-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parquet-writer.js","sourceRoot":"","sources":["../../src/tiered/parquet-writer.ts"],"names":[],"mappings":"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"}
|