rowpipe 1.0.0 → 1.1.0
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 +25 -32
- package/dist/cli/index.js +4 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/core/types.d.ts +2 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/readers/csv.d.ts.map +1 -1
- package/dist/readers/csv.js +28 -16
- package/dist/readers/csv.js.map +1 -1
- package/dist/readers/index.d.ts +1 -0
- package/dist/readers/index.d.ts.map +1 -1
- package/dist/readers/index.js +29 -3
- package/dist/readers/index.js.map +1 -1
- package/dist/readers/json.d.ts.map +1 -1
- package/dist/readers/json.js +6 -8
- package/dist/readers/json.js.map +1 -1
- package/dist/readers/jsonl.d.ts.map +1 -1
- package/dist/readers/jsonl.js +5 -7
- package/dist/readers/jsonl.js.map +1 -1
- package/dist/readers/parquet.d.ts +17 -0
- package/dist/readers/parquet.d.ts.map +1 -0
- package/dist/readers/parquet.js +146 -0
- package/dist/readers/parquet.js.map +1 -0
- package/dist/utils/compression.d.ts +30 -6
- package/dist/utils/compression.d.ts.map +1 -1
- package/dist/utils/compression.js +95 -18
- package/dist/utils/compression.js.map +1 -1
- package/dist/writers/csv.d.ts.map +1 -1
- package/dist/writers/csv.js +9 -11
- package/dist/writers/csv.js.map +1 -1
- package/dist/writers/index.d.ts +2 -0
- package/dist/writers/index.d.ts.map +1 -1
- package/dist/writers/index.js +49 -4
- package/dist/writers/index.js.map +1 -1
- package/dist/writers/json.d.ts +1 -1
- package/dist/writers/json.d.ts.map +1 -1
- package/dist/writers/json.js +9 -11
- package/dist/writers/json.js.map +1 -1
- package/dist/writers/jsonl.d.ts +1 -1
- package/dist/writers/jsonl.d.ts.map +1 -1
- package/dist/writers/jsonl.js +9 -11
- package/dist/writers/jsonl.js.map +1 -1
- package/dist/writers/markdown.d.ts +21 -0
- package/dist/writers/markdown.d.ts.map +1 -0
- package/dist/writers/markdown.js +82 -0
- package/dist/writers/markdown.js.map +1 -0
- package/dist/writers/parquet.d.ts +19 -0
- package/dist/writers/parquet.d.ts.map +1 -0
- package/dist/writers/parquet.js +129 -0
- package/dist/writers/parquet.js.map +1 -0
- package/package.json +13 -2
- package/skills/rowpipe/SKILL.md +181 -0
- package/benchmarks/memory-bench.ts +0 -109
- package/src/analytics/reduce.ts +0 -388
- package/src/analytics/schema-inference.ts +0 -217
- package/src/analytics/semantic-types.ts +0 -36
- package/src/analytics/stats.ts +0 -383
- package/src/analytics/validator.ts +0 -134
- package/src/cli/commands/cast.ts +0 -60
- package/src/cli/commands/convert.ts +0 -128
- package/src/cli/commands/filter.ts +0 -58
- package/src/cli/commands/inspect.ts +0 -193
- package/src/cli/commands/map.ts +0 -66
- package/src/cli/commands/reduce.ts +0 -74
- package/src/cli/commands/rename.ts +0 -59
- package/src/cli/commands/sample.ts +0 -61
- package/src/cli/commands/schema.ts +0 -86
- package/src/cli/commands/select.ts +0 -59
- package/src/cli/commands/stats.ts +0 -100
- package/src/cli/commands/validate.ts +0 -123
- package/src/cli/index.ts +0 -285
- package/src/core/batch.ts +0 -81
- package/src/core/errors.ts +0 -81
- package/src/core/pipeline.ts +0 -150
- package/src/core/types.ts +0 -110
- package/src/index.ts +0 -52
- package/src/readers/csv.ts +0 -302
- package/src/readers/index.ts +0 -88
- package/src/readers/json.ts +0 -256
- package/src/readers/jsonl.ts +0 -126
- package/src/readers/xlsx.ts +0 -182
- package/src/transforms/cast.ts +0 -212
- package/src/transforms/expression.ts +0 -1114
- package/src/transforms/filter.ts +0 -38
- package/src/transforms/map.ts +0 -99
- package/src/transforms/rename.ts +0 -47
- package/src/transforms/sample.ts +0 -57
- package/src/transforms/select.ts +0 -64
- package/src/utils/compression.ts +0 -43
- package/src/utils/formatting.ts +0 -75
- package/src/utils/progress.ts +0 -37
- package/src/writers/csv.ts +0 -106
- package/src/writers/index.ts +0 -87
- package/src/writers/json.ts +0 -52
- package/src/writers/jsonl.ts +0 -49
- package/src/writers/xlsx.ts +0 -87
- package/tests/analytics.test.ts +0 -119
- package/tests/cli-integration.test.ts +0 -187
- package/tests/map-reduce.test.ts +0 -223
- package/tests/readers-writers.test.ts +0 -189
- package/tests/transforms.test.ts +0 -199
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -9
package/dist/writers/json.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/writers/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/writers/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAIzF,MAAM,OAAO,UAAU;IACb,MAAM,CAAoB;IAC1B,aAAa,CAAY;IAEjC,YAAY,MAAyB;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,eAAe,CAAC,IAAoB;QAC1C,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC;QACxB,MAAM,MAAM,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC9B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,MAAgB,EAAE,IAAY;QACrD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAAsB,EAAE,OAAuB;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,UAAU,GAAG,IAAI,CAAC;QAEtB,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAExC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YACrC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC7B,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC3C,UAAU,GAAG,KAAK,CAAC;gBACnB,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
package/dist/writers/jsonl.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare class JSONLWriter implements TabularWriter {
|
|
|
6
6
|
constructor(output: Writable | string);
|
|
7
7
|
private getOutputStream;
|
|
8
8
|
private writeChunk;
|
|
9
|
-
write(dataStream: DataStream,
|
|
9
|
+
write(dataStream: DataStream, options?: WriterOptions): Promise<void>;
|
|
10
10
|
close(): Promise<void>;
|
|
11
11
|
}
|
|
12
12
|
//# sourceMappingURL=jsonl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../src/writers/jsonl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjF,qBAAa,WAAY,YAAW,aAAa;IAC/C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAAC,CAAW;gBAErB,MAAM,EAAE,QAAQ,GAAG,MAAM;IAIrC,OAAO,CAAC,eAAe;
|
|
1
|
+
{"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../src/writers/jsonl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjF,qBAAa,WAAY,YAAW,aAAa;IAC/C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAAC,CAAW;gBAErB,MAAM,EAAE,QAAQ,GAAG,MAAM;IAIrC,OAAO,CAAC,eAAe;YAST,UAAU;IAMlB,KAAK,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|
package/dist/writers/jsonl.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closeWritableStream, openCompressedWriteStream } from "../utils/compression.js";
|
|
2
2
|
export class JSONLWriter {
|
|
3
3
|
output;
|
|
4
4
|
createdStream;
|
|
5
5
|
constructor(output) {
|
|
6
6
|
this.output = output;
|
|
7
7
|
}
|
|
8
|
-
getOutputStream() {
|
|
8
|
+
getOutputStream(opts) {
|
|
9
|
+
const gzip = opts?.gzip;
|
|
10
|
+
const stream = openCompressedWriteStream(this.output, { gzip });
|
|
9
11
|
if (typeof this.output === "string") {
|
|
10
|
-
this.createdStream =
|
|
11
|
-
return this.createdStream;
|
|
12
|
+
this.createdStream = stream;
|
|
12
13
|
}
|
|
13
|
-
return
|
|
14
|
+
return stream;
|
|
14
15
|
}
|
|
15
16
|
async writeChunk(stream, data) {
|
|
16
17
|
if (!stream.write(data)) {
|
|
17
18
|
await new Promise((resolve) => stream.once("drain", resolve));
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
|
-
async write(dataStream,
|
|
21
|
-
const outStream = this.getOutputStream();
|
|
21
|
+
async write(dataStream, options) {
|
|
22
|
+
const outStream = this.getOutputStream(options);
|
|
22
23
|
for await (const batch of dataStream) {
|
|
23
24
|
let chunkText = "";
|
|
24
25
|
for (const row of batch.rows) {
|
|
@@ -31,10 +32,7 @@ export class JSONLWriter {
|
|
|
31
32
|
}
|
|
32
33
|
async close() {
|
|
33
34
|
if (this.createdStream) {
|
|
34
|
-
await
|
|
35
|
-
this.createdStream.end(() => resolve());
|
|
36
|
-
this.createdStream.on("error", reject);
|
|
37
|
-
});
|
|
35
|
+
await closeWritableStream(this.createdStream);
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/writers/jsonl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/writers/jsonl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAIzF,MAAM,OAAO,WAAW;IACd,MAAM,CAAoB;IAC1B,aAAa,CAAY;IAEjC,YAAY,MAAyB;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,eAAe,CAAC,IAAoB;QAC1C,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC;QACxB,MAAM,MAAM,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC9B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,MAAgB,EAAE,IAAY;QACrD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAAsB,EAAE,OAAuB;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAEhD,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YACrC,IAAI,SAAS,GAAG,EAAE,CAAC;YACnB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC7B,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAC1C,CAAC;YACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Writable } from "node:stream";
|
|
2
|
+
import type { DataStream, TabularWriter, WriterOptions } from "../core/types.js";
|
|
3
|
+
export interface MarkdownWriterOptions extends WriterOptions {
|
|
4
|
+
headers?: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Streaming GitHub-Flavored Markdown Table Writer.
|
|
8
|
+
* Formats rows into clean markdown tables with proper cell escaping and backpressure.
|
|
9
|
+
*/
|
|
10
|
+
export declare class MarkdownWriter implements TabularWriter {
|
|
11
|
+
private output;
|
|
12
|
+
private options;
|
|
13
|
+
private createdStream?;
|
|
14
|
+
constructor(output: Writable | string, options?: MarkdownWriterOptions);
|
|
15
|
+
private getOutputStream;
|
|
16
|
+
private escapeCell;
|
|
17
|
+
private writeChunk;
|
|
18
|
+
write(dataStream: DataStream, options?: WriterOptions): Promise<void>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/writers/markdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjF,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,cAAe,YAAW,aAAa;IAClD,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,aAAa,CAAC,CAAW;gBAErB,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,OAAO,GAAE,qBAA0B;IAK1E,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,UAAU;YAUJ,UAAU;IAMlB,KAAK,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA+CrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { closeWritableStream, openCompressedWriteStream } from "../utils/compression.js";
|
|
2
|
+
/**
|
|
3
|
+
* Streaming GitHub-Flavored Markdown Table Writer.
|
|
4
|
+
* Formats rows into clean markdown tables with proper cell escaping and backpressure.
|
|
5
|
+
*/
|
|
6
|
+
export class MarkdownWriter {
|
|
7
|
+
output;
|
|
8
|
+
options;
|
|
9
|
+
createdStream;
|
|
10
|
+
constructor(output, options = {}) {
|
|
11
|
+
this.output = output;
|
|
12
|
+
this.options = { ...options };
|
|
13
|
+
}
|
|
14
|
+
getOutputStream(opts) {
|
|
15
|
+
const gzip = opts?.gzip ?? this.options.gzip;
|
|
16
|
+
const stream = openCompressedWriteStream(this.output, { gzip });
|
|
17
|
+
if (typeof this.output === "string") {
|
|
18
|
+
this.createdStream = stream;
|
|
19
|
+
}
|
|
20
|
+
return stream;
|
|
21
|
+
}
|
|
22
|
+
escapeCell(value) {
|
|
23
|
+
if (value === null || value === undefined) {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
const str = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
27
|
+
return str
|
|
28
|
+
.replace(/\|/g, "\\|")
|
|
29
|
+
.replace(/\r?\n/g, "<br>");
|
|
30
|
+
}
|
|
31
|
+
async writeChunk(stream, data) {
|
|
32
|
+
if (!stream.write(data)) {
|
|
33
|
+
await new Promise((resolve) => stream.once("drain", resolve));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async write(dataStream, options) {
|
|
37
|
+
const mergedOptions = {
|
|
38
|
+
...this.options,
|
|
39
|
+
...options,
|
|
40
|
+
};
|
|
41
|
+
const outStream = this.getOutputStream(mergedOptions);
|
|
42
|
+
let headers = mergedOptions.headers ?? null;
|
|
43
|
+
for await (const batch of dataStream) {
|
|
44
|
+
if (batch.rows.length === 0)
|
|
45
|
+
continue;
|
|
46
|
+
if (headers === null) {
|
|
47
|
+
headers = Object.keys(batch.rows[0] || {});
|
|
48
|
+
if (headers.length === 0) {
|
|
49
|
+
headers = ["value"];
|
|
50
|
+
}
|
|
51
|
+
// Write header row: | Col1 | Col2 |
|
|
52
|
+
const headerLine = `| ${headers.join(" | ")} |\n`;
|
|
53
|
+
// Write separator row: |---|---|
|
|
54
|
+
const separatorLine = `| ${headers.map(() => "---").join(" | ")} |\n`;
|
|
55
|
+
await this.writeChunk(outStream, headerLine + separatorLine);
|
|
56
|
+
}
|
|
57
|
+
let chunk = "";
|
|
58
|
+
for (let r = 0; r < batch.rows.length; r++) {
|
|
59
|
+
const row = batch.rows[r];
|
|
60
|
+
const cells = new Array(headers.length);
|
|
61
|
+
for (let i = 0; i < headers.length; i++) {
|
|
62
|
+
const colName = headers[i];
|
|
63
|
+
cells[i] = this.escapeCell(row[colName]);
|
|
64
|
+
}
|
|
65
|
+
chunk += `| ${cells.join(" | ")} |\n`;
|
|
66
|
+
}
|
|
67
|
+
if (chunk.length > 0) {
|
|
68
|
+
await this.writeChunk(outStream, chunk);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (headers === null) {
|
|
72
|
+
// Empty dataset
|
|
73
|
+
await this.writeChunk(outStream, "| (empty) |\n|---|\n");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async close() {
|
|
77
|
+
if (this.createdStream) {
|
|
78
|
+
await closeWritableStream(this.createdStream);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/writers/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Writable } from "node:stream";
|
|
2
|
+
import type { DataStream, TabularWriter, WriterOptions } from "../core/types.js";
|
|
3
|
+
export interface ParquetWriterOptions extends WriterOptions {
|
|
4
|
+
schema?: Record<string, any>;
|
|
5
|
+
compression?: "UNCOMPRESSED" | "SNAPPY" | "GZIP";
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Streaming Apache Parquet Writer.
|
|
9
|
+
* Batches rows and writes binary columnar data with Snappy compression.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ParquetWriter implements TabularWriter {
|
|
12
|
+
private output;
|
|
13
|
+
private options;
|
|
14
|
+
private writer?;
|
|
15
|
+
constructor(output: Writable | string, options?: ParquetWriterOptions);
|
|
16
|
+
write(dataStream: DataStream, options?: WriterOptions): Promise<void>;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=parquet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parquet.d.ts","sourceRoot":"","sources":["../../src/writers/parquet.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,KAAK,EAAE,UAAU,EAAO,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtF,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;CAClD;AAiED;;;GAGG;AACH,qBAAa,aAAc,YAAW,aAAa;IACjD,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,MAAM,CAAC,CAAM;gBAET,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,OAAO,GAAE,oBAAyB;IAKnE,KAAK,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAS7B"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import parquet from "parquetjs-lite";
|
|
3
|
+
/**
|
|
4
|
+
* Infers a Parquet schema from sample rows.
|
|
5
|
+
*/
|
|
6
|
+
function inferParquetSchema(sampleRows) {
|
|
7
|
+
const schemaDef = {};
|
|
8
|
+
for (const row of sampleRows) {
|
|
9
|
+
for (const [key, val] of Object.entries(row)) {
|
|
10
|
+
if (schemaDef[key] && schemaDef[key].type === "DOUBLE") {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (typeof val === "number") {
|
|
14
|
+
if (!schemaDef[key] || schemaDef[key].type === "INT64") {
|
|
15
|
+
schemaDef[key] = {
|
|
16
|
+
type: Number.isInteger(val) ? "INT64" : "DOUBLE",
|
|
17
|
+
optional: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else if (typeof val === "boolean") {
|
|
22
|
+
schemaDef[key] = { type: "BOOLEAN", optional: true };
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
schemaDef[key] = { type: "UTF8", optional: true };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Ensure at least one field
|
|
30
|
+
if (Object.keys(schemaDef).length === 0) {
|
|
31
|
+
schemaDef["value"] = { type: "UTF8", optional: true };
|
|
32
|
+
}
|
|
33
|
+
return new parquet.ParquetSchema(schemaDef);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Sanitizes a row according to schema definitions before passing to ParquetWriter.
|
|
37
|
+
*/
|
|
38
|
+
function sanitizeRowForParquet(row, schemaDef) {
|
|
39
|
+
const sanitized = {};
|
|
40
|
+
for (const [key, fieldDef] of Object.entries(schemaDef)) {
|
|
41
|
+
const rawVal = row[key];
|
|
42
|
+
if (rawVal === null || rawVal === undefined) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (fieldDef.type === "INT64") {
|
|
46
|
+
const num = Number(rawVal);
|
|
47
|
+
sanitized[key] = isNaN(num) ? 0 : Math.trunc(num);
|
|
48
|
+
}
|
|
49
|
+
else if (fieldDef.type === "DOUBLE" || fieldDef.type === "FLOAT") {
|
|
50
|
+
const num = Number(rawVal);
|
|
51
|
+
sanitized[key] = isNaN(num) ? 0 : num;
|
|
52
|
+
}
|
|
53
|
+
else if (fieldDef.type === "BOOLEAN") {
|
|
54
|
+
sanitized[key] = Boolean(rawVal);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
sanitized[key] = typeof rawVal === "object" ? JSON.stringify(rawVal) : String(rawVal);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return sanitized;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Streaming Apache Parquet Writer.
|
|
64
|
+
* Batches rows and writes binary columnar data with Snappy compression.
|
|
65
|
+
*/
|
|
66
|
+
export class ParquetWriter {
|
|
67
|
+
output;
|
|
68
|
+
options;
|
|
69
|
+
writer;
|
|
70
|
+
constructor(output, options = {}) {
|
|
71
|
+
this.output = output;
|
|
72
|
+
this.options = { ...options };
|
|
73
|
+
}
|
|
74
|
+
async write(dataStream, options) {
|
|
75
|
+
const mergedOptions = {
|
|
76
|
+
...this.options,
|
|
77
|
+
...options,
|
|
78
|
+
};
|
|
79
|
+
let parquetSchema = null;
|
|
80
|
+
let schemaFields = {};
|
|
81
|
+
for await (const batch of dataStream) {
|
|
82
|
+
if (batch.rows.length === 0)
|
|
83
|
+
continue;
|
|
84
|
+
if (!this.writer) {
|
|
85
|
+
parquetSchema = inferParquetSchema(batch.rows);
|
|
86
|
+
schemaFields = parquetSchema.schema;
|
|
87
|
+
if (typeof this.output === "string") {
|
|
88
|
+
this.writer = await parquet.ParquetWriter.openFile(parquetSchema, this.output, {
|
|
89
|
+
useDataPageV2: false,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.writer = await parquet.ParquetWriter.openStream(parquetSchema, this.output, {
|
|
94
|
+
useDataPageV2: false,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (let i = 0; i < batch.rows.length; i++) {
|
|
99
|
+
const row = batch.rows[i];
|
|
100
|
+
const sanitized = sanitizeRowForParquet(row, schemaFields);
|
|
101
|
+
await this.writer.appendRow(sanitized);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!this.writer) {
|
|
105
|
+
// Empty stream fallback
|
|
106
|
+
parquetSchema = new parquet.ParquetSchema({
|
|
107
|
+
empty: { type: "UTF8", optional: true },
|
|
108
|
+
});
|
|
109
|
+
if (typeof this.output === "string") {
|
|
110
|
+
this.writer = await parquet.ParquetWriter.openFile(parquetSchema, this.output);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
this.writer = await parquet.ParquetWriter.openStream(parquetSchema, this.output);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
await this.writer.close();
|
|
117
|
+
}
|
|
118
|
+
async close() {
|
|
119
|
+
if (this.writer) {
|
|
120
|
+
try {
|
|
121
|
+
await this.writer.close();
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Writer already closed
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=parquet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parquet.js","sourceRoot":"","sources":["../../src/writers/parquet.ts"],"names":[],"mappings":"AAEA,aAAa;AACb,OAAO,OAAO,MAAM,gBAAgB,CAAC;AAQrC;;GAEG;AACH,SAAS,kBAAkB,CAAC,UAAiB;IAC3C,MAAM,SAAS,GAAwD,EAAE,CAAC;IAE1E,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7C,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,CAAE,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACxD,SAAS;YACX,CAAC;YAED,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,CAAE,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACxD,SAAS,CAAC,GAAG,CAAC,GAAG;wBACf,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;wBAChD,QAAQ,EAAE,IAAI;qBACf,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,IAAI,OAAO,GAAG,KAAK,SAAS,EAAE,CAAC;gBACpC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACpD,CAAC;QACH,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxD,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,GAAQ,EAAE,SAA8B;IACrE,MAAM,SAAS,GAAwB,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3B,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACnE,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3B,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACxC,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACvC,SAAS,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,GAAG,CAAC,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,aAAa;IAChB,MAAM,CAAoB;IAC1B,OAAO,CAAuB;IAC9B,MAAM,CAAO;IAErB,YAAY,MAAyB,EAAE,UAAgC,EAAE;QACvE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAAsB,EAAE,OAAuB;QACzD,MAAM,aAAa,GAAyB;YAC1C,GAAG,IAAI,CAAC,OAAO;YACf,GAAG,OAAO;SACX,CAAC;QAEF,IAAI,aAAa,GAAQ,IAAI,CAAC;QAC9B,IAAI,YAAY,GAAwB,EAAE,CAAC;QAE3C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YACrC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAEtC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,aAAa,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/C,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC;gBAEpC,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;oBACpC,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,EAAE;wBAC7E,aAAa,EAAE,KAAK;qBACrB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,EAAE;wBAC/E,aAAa,EAAE,KAAK;qBACrB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC;gBAC3B,MAAM,SAAS,GAAG,qBAAqB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;gBAC3D,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,wBAAwB;YACxB,aAAa,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC;gBACxC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;aACxC,CAAC,CAAC;YACH,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACpC,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACjF,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rowpipe",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Stream-first tabular data toolkit for CSV, TSV, JSON, JSONL, XLSX, Apache Parquet, and Markdown",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"bin": {
|
|
8
8
|
"rowpipe": "dist/cli/index.js"
|
|
9
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"skills",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
10
15
|
"type": "module",
|
|
11
16
|
"scripts": {
|
|
12
17
|
"build": "tsc",
|
|
@@ -17,10 +22,13 @@
|
|
|
17
22
|
},
|
|
18
23
|
"keywords": [
|
|
19
24
|
"csv",
|
|
25
|
+
"tsv",
|
|
20
26
|
"json",
|
|
21
27
|
"jsonl",
|
|
22
28
|
"ndjson",
|
|
29
|
+
"parquet",
|
|
23
30
|
"xlsx",
|
|
31
|
+
"markdown",
|
|
24
32
|
"streaming",
|
|
25
33
|
"tabular",
|
|
26
34
|
"data",
|
|
@@ -32,6 +40,9 @@
|
|
|
32
40
|
"license": "MIT",
|
|
33
41
|
"dependencies": {
|
|
34
42
|
"commander": "^13.1.0",
|
|
43
|
+
"hyparquet": "^1.30.1",
|
|
44
|
+
"hyparquet-compressors": "^1.1.1",
|
|
45
|
+
"parquetjs-lite": "^0.8.7",
|
|
35
46
|
"read-excel-file": "^9.3.10",
|
|
36
47
|
"write-excel-file": "^4.1.1"
|
|
37
48
|
},
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rowpipe
|
|
3
|
+
description: Stream-first tabular data toolkit for inspecting, analyzing, transforming, validating, converting, mapping, and reducing large datasets across CSV, TSV, JSON, JSONL, XLSX, Apache Parquet, and Markdown formats with bounded O(1) memory and extreme throughput (~500,000 rows/s).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rowpipe: Stream-First Tabular Data Toolkit
|
|
7
|
+
|
|
8
|
+
Rowpipe is a high-performance, stream-first command-line toolkit and Node.js library for tabular data processing. It processes gigabyte-scale datasets with bounded $O(1)$ memory usage, backpressure, batching, and zero-`eval` safe expression execution.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 🚀 Quick Command Reference
|
|
13
|
+
|
|
14
|
+
| Task | Command Syntax | Description |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| **Inspect** | `rowpipe inspect <file> [--sheet <name>] [--json]` | Inspect row count, column types, null %, and HLL uniqueness |
|
|
17
|
+
| **Convert** | `rowpipe convert <input> <output> [--all-sheets]` | Stream convert between CSV, TSV, JSON, JSONL, XLSX, Parquet, Markdown |
|
|
18
|
+
| **Schema** | `rowpipe schema <file> [--full] [--sample <n>]` | Infer column types and semantic patterns (email, url, uuid) |
|
|
19
|
+
| **Stats** | `rowpipe stats <file> [--column <name>]` | Streaming Welford numeric stats & HyperLogLog distinct count |
|
|
20
|
+
| **Map** | `rowpipe map <file> "<col1=expr1>" "<col2=expr2>"` | Derive and compute columns per row with arithmetic/JSON dot-notation |
|
|
21
|
+
| **Filter** | `rowpipe filter <file> "<expression>"` | Filter rows using safe expression engine and pipe syntax (`\|`) |
|
|
22
|
+
| **Reduce** | `rowpipe reduce <file> "<agg1=func(col)>" [--by <cols>]` | Global & group-by streaming aggregations (`sum`, `avg`, `min`, `max`, `count`, `countDistinct`, `stddev`) |
|
|
23
|
+
| **Select** | `rowpipe select <file> <col1,col2,...>` | Project subset of columns in order |
|
|
24
|
+
| **Rename** | `rowpipe rename <file> <old1=new1> <old2=new2>` | Rename columns in stream |
|
|
25
|
+
| **Cast** | `rowpipe cast <file> <col1:type> [--on-error null]` | Stream cast types (`integer`, `number`, `boolean`, `date`) |
|
|
26
|
+
| **Sample** | `rowpipe sample <file> --rows <n> [--seed <s>]` | Reservoir sampling with bounded memory |
|
|
27
|
+
| **Validate** | `rowpipe validate <file> --schema <schema.json>` | Validate stream against JSON schema definition |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🛠️ Common Workflows & Examples
|
|
32
|
+
|
|
33
|
+
### 1. Inspect & Schema Inference (CSV, TSV, Parquet, Excel)
|
|
34
|
+
```bash
|
|
35
|
+
# Inspect CSV / TSV / JSONL file
|
|
36
|
+
rowpipe inspect dataset.csv
|
|
37
|
+
rowpipe inspect data.tsv
|
|
38
|
+
|
|
39
|
+
# Inspect Apache Parquet file directly
|
|
40
|
+
rowpipe inspect dataset.parquet --json
|
|
41
|
+
|
|
42
|
+
# Inspect multi-sheet Excel workbook
|
|
43
|
+
rowpipe inspect workbook.xlsx
|
|
44
|
+
rowpipe inspect workbook.xlsx --sheet Orders
|
|
45
|
+
|
|
46
|
+
# Full schema inference with semantic types (email, URL, UUID, date)
|
|
47
|
+
rowpipe schema huge.csv --full
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Format Conversion, Parquet & Gzip Streams
|
|
51
|
+
```bash
|
|
52
|
+
# Convert CSV to Apache Parquet
|
|
53
|
+
rowpipe convert sales.csv sales.parquet
|
|
54
|
+
|
|
55
|
+
# Convert Parquet to compressed JSONL (.jsonl.gz)
|
|
56
|
+
rowpipe convert sales.parquet sales.jsonl.gz
|
|
57
|
+
|
|
58
|
+
# Filter Parquet and output directly as GitHub Markdown table
|
|
59
|
+
rowpipe filter dataset.parquet "amount > 500" --to markdown
|
|
60
|
+
|
|
61
|
+
# Convert specific Excel worksheet to TSV
|
|
62
|
+
rowpipe convert workbook.xlsx orders.tsv --sheet Orders
|
|
63
|
+
|
|
64
|
+
# Bulk export all worksheets in workbook to a directory
|
|
65
|
+
rowpipe convert workbook.xlsx --all-sheets --out-dir ./exported_sheets --to csv
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. Row Derivations & Calculations (`map`)
|
|
69
|
+
Derive calculated columns using arithmetic, strings, dates, and direct JSON dot-notation:
|
|
70
|
+
```bash
|
|
71
|
+
# Arithmetic & percentage formulas
|
|
72
|
+
rowpipe map sales.csv \
|
|
73
|
+
"profit = revenue - cost" \
|
|
74
|
+
"tax = revenue * 0.20" \
|
|
75
|
+
"margin = ((revenue - cost) / revenue) * 100"
|
|
76
|
+
|
|
77
|
+
# Direct JSON dot-notation & pipe transformations
|
|
78
|
+
rowpipe map events.jsonl \
|
|
79
|
+
"city = payload.user.address.city" \
|
|
80
|
+
"email = payload.user.email | lower | trim" \
|
|
81
|
+
"item_price = payload.items.0.price" \
|
|
82
|
+
"year = created_at | year"
|
|
83
|
+
|
|
84
|
+
# Conditional mapping
|
|
85
|
+
rowpipe map orders.csv "net_total = total | if(is_vip, total * 0.90, total) | round(2)"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 4. Advanced Row Filtering (`filter`)
|
|
89
|
+
```bash
|
|
90
|
+
# Arithmetic & comparison on Parquet / CSV
|
|
91
|
+
rowpipe filter sales.parquet '(revenue - cost) / revenue >= 0.25'
|
|
92
|
+
|
|
93
|
+
# Pipe syntax for string & date functions
|
|
94
|
+
rowpipe filter users.csv 'email | lower | endsWith("@corp.com")'
|
|
95
|
+
rowpipe filter orders.csv 'created_at | year == 2026 && total > 500'
|
|
96
|
+
|
|
97
|
+
# Direct JSON dot-notation in filter
|
|
98
|
+
rowpipe filter events.jsonl.gz 'payload.user.city == "Istanbul" && payload.items.0.price > 50'
|
|
99
|
+
|
|
100
|
+
# Set membership and range checks
|
|
101
|
+
rowpipe filter products.tsv 'category | in("Electronics", "Computers") && price | between(100, 1000)'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 5. Group-By & Global Aggregations (`reduce`)
|
|
105
|
+
```bash
|
|
106
|
+
# 1. Global summary (Single row output)
|
|
107
|
+
rowpipe reduce sales.parquet \
|
|
108
|
+
"total_revenue = sum(revenue)" \
|
|
109
|
+
"avg_margin = avg(margin)" \
|
|
110
|
+
"min_price = min(price)" \
|
|
111
|
+
"max_price = max(price)" \
|
|
112
|
+
"total_orders = count()" \
|
|
113
|
+
"unique_customers = countDistinct(customer_id)"
|
|
114
|
+
|
|
115
|
+
# 2. Group-By Streaming Aggregations
|
|
116
|
+
rowpipe reduce sales.csv \
|
|
117
|
+
"total_revenue = sum(revenue)" \
|
|
118
|
+
"avg_profit = avg(profit)" \
|
|
119
|
+
"order_count = count()" \
|
|
120
|
+
--by country,category
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Supported reduce functions:
|
|
124
|
+
- `sum(col)` — Numeric sum
|
|
125
|
+
- `avg(col)` / `mean(col)` — Average
|
|
126
|
+
- `min(col)` / `max(col)` — Minimum / Maximum
|
|
127
|
+
- `count()` / `count(col)` — Row / non-null count
|
|
128
|
+
- `countDistinct(col)` — HyperLogLog distinct cardinality ($O(1)$ memory)
|
|
129
|
+
- `stddev(col)` / `variance(col)` — Welford single-pass online standard deviation / variance
|
|
130
|
+
- `first(col)` / `last(col)` — First non-null / last value
|
|
131
|
+
|
|
132
|
+
### 6. End-to-End Unix Pipe Processing Chain
|
|
133
|
+
```bash
|
|
134
|
+
cat transactions.csv.gz | \
|
|
135
|
+
rowpipe map - "profit=revenue - cost" "margin=((revenue - cost) / revenue) * 100" | \
|
|
136
|
+
rowpipe filter - "margin >= 15" | \
|
|
137
|
+
rowpipe reduce - "total_profit=sum(profit)" "avg_margin=avg(margin)" "count=count()" --by country | \
|
|
138
|
+
rowpipe convert - --to markdown
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 💻 Node.js Library API
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import {
|
|
147
|
+
createPipeline,
|
|
148
|
+
createReader,
|
|
149
|
+
createWriter,
|
|
150
|
+
CSVReader,
|
|
151
|
+
JSONLWriter,
|
|
152
|
+
ParquetReader,
|
|
153
|
+
ParquetWriter,
|
|
154
|
+
MarkdownWriter,
|
|
155
|
+
XLSXReader,
|
|
156
|
+
mapRows,
|
|
157
|
+
filterRows,
|
|
158
|
+
reduceRows,
|
|
159
|
+
} from "rowpipe";
|
|
160
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
161
|
+
|
|
162
|
+
// 1. Streaming Parquet -> Filter -> Markdown Pipeline
|
|
163
|
+
const reader = new ParquetReader("sales.parquet");
|
|
164
|
+
const writer = new MarkdownWriter(createWriteStream("summary.md"));
|
|
165
|
+
|
|
166
|
+
await createPipeline(reader)
|
|
167
|
+
.pipe(mapRows({
|
|
168
|
+
profit: "revenue - cost",
|
|
169
|
+
margin: "((revenue - cost) / revenue) * 100",
|
|
170
|
+
}))
|
|
171
|
+
.pipe(filterRows("margin >= 15"))
|
|
172
|
+
.pipe(reduceRows({
|
|
173
|
+
by: ["country"],
|
|
174
|
+
aggregations: [
|
|
175
|
+
"total_profit = sum(profit)",
|
|
176
|
+
"avg_margin = avg(margin)",
|
|
177
|
+
"count = count()",
|
|
178
|
+
],
|
|
179
|
+
}))
|
|
180
|
+
.to(writer);
|
|
181
|
+
```
|