rowpipe 1.1.0 → 1.2.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.
Files changed (100) hide show
  1. package/README.md +302 -9
  2. package/dist/cli/commands/diff.d.ts +30 -0
  3. package/dist/cli/commands/diff.d.ts.map +1 -0
  4. package/dist/cli/commands/diff.js +143 -0
  5. package/dist/cli/commands/diff.js.map +1 -0
  6. package/dist/cli/commands/files.d.ts +35 -0
  7. package/dist/cli/commands/files.d.ts.map +1 -0
  8. package/dist/cli/commands/files.js +93 -0
  9. package/dist/cli/commands/files.js.map +1 -0
  10. package/dist/cli/index.js +85 -1
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/core/errors.d.ts +23 -0
  13. package/dist/core/errors.d.ts.map +1 -1
  14. package/dist/core/errors.js +38 -0
  15. package/dist/core/errors.js.map +1 -1
  16. package/dist/core/types.d.ts +2 -0
  17. package/dist/core/types.d.ts.map +1 -1
  18. package/dist/diff/comparator.d.ts +17 -0
  19. package/dist/diff/comparator.d.ts.map +1 -0
  20. package/dist/diff/comparator.js +158 -0
  21. package/dist/diff/comparator.js.map +1 -0
  22. package/dist/diff/engine.d.ts +10 -0
  23. package/dist/diff/engine.d.ts.map +1 -0
  24. package/dist/diff/engine.js +333 -0
  25. package/dist/diff/engine.js.map +1 -0
  26. package/dist/diff/hash.d.ts +6 -0
  27. package/dist/diff/hash.d.ts.map +1 -0
  28. package/dist/diff/hash.js +50 -0
  29. package/dist/diff/hash.js.map +1 -0
  30. package/dist/diff/key.d.ts +21 -0
  31. package/dist/diff/key.d.ts.map +1 -0
  32. package/dist/diff/key.js +107 -0
  33. package/dist/diff/key.js.map +1 -0
  34. package/dist/diff/reporter.d.ts +18 -0
  35. package/dist/diff/reporter.d.ts.map +1 -0
  36. package/dist/diff/reporter.js +133 -0
  37. package/dist/diff/reporter.js.map +1 -0
  38. package/dist/diff/schema.d.ts +7 -0
  39. package/dist/diff/schema.d.ts.map +1 -0
  40. package/dist/diff/schema.js +65 -0
  41. package/dist/diff/schema.js.map +1 -0
  42. package/dist/diff/storage/disk-index.d.ts +28 -0
  43. package/dist/diff/storage/disk-index.d.ts.map +1 -0
  44. package/dist/diff/storage/disk-index.js +105 -0
  45. package/dist/diff/storage/disk-index.js.map +1 -0
  46. package/dist/diff/storage/memory-index.d.ts +23 -0
  47. package/dist/diff/storage/memory-index.d.ts.map +1 -0
  48. package/dist/diff/storage/memory-index.js +69 -0
  49. package/dist/diff/storage/memory-index.js.map +1 -0
  50. package/dist/diff/storage/spillable-index.d.ts +30 -0
  51. package/dist/diff/storage/spillable-index.d.ts.map +1 -0
  52. package/dist/diff/storage/spillable-index.js +108 -0
  53. package/dist/diff/storage/spillable-index.js.map +1 -0
  54. package/dist/diff/types.d.ts +127 -0
  55. package/dist/diff/types.d.ts.map +1 -0
  56. package/dist/diff/types.js +2 -0
  57. package/dist/diff/types.js.map +1 -0
  58. package/dist/files/glob.d.ts +21 -0
  59. package/dist/files/glob.d.ts.map +1 -0
  60. package/dist/files/glob.js +132 -0
  61. package/dist/files/glob.js.map +1 -0
  62. package/dist/files/hash.d.ts +10 -0
  63. package/dist/files/hash.d.ts.map +1 -0
  64. package/dist/files/hash.js +67 -0
  65. package/dist/files/hash.js.map +1 -0
  66. package/dist/files/index.d.ts +6 -0
  67. package/dist/files/index.d.ts.map +1 -0
  68. package/dist/files/index.js +6 -0
  69. package/dist/files/index.js.map +1 -0
  70. package/dist/files/mime.d.ts +9 -0
  71. package/dist/files/mime.d.ts.map +1 -0
  72. package/dist/files/mime.js +128 -0
  73. package/dist/files/mime.js.map +1 -0
  74. package/dist/files/reader.d.ts +19 -0
  75. package/dist/files/reader.d.ts.map +1 -0
  76. package/dist/files/reader.js +344 -0
  77. package/dist/files/reader.js.map +1 -0
  78. package/dist/files/types.d.ts +47 -0
  79. package/dist/files/types.d.ts.map +1 -0
  80. package/dist/files/types.js +2 -0
  81. package/dist/files/types.js.map +1 -0
  82. package/dist/index.d.ts +16 -1
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +18 -1
  85. package/dist/index.js.map +1 -1
  86. package/dist/readers/csv.d.ts.map +1 -1
  87. package/dist/readers/csv.js +39 -19
  88. package/dist/readers/csv.js.map +1 -1
  89. package/dist/readers/index.d.ts +1 -0
  90. package/dist/readers/index.d.ts.map +1 -1
  91. package/dist/readers/index.js +28 -0
  92. package/dist/readers/index.js.map +1 -1
  93. package/dist/transforms/expression.d.ts.map +1 -1
  94. package/dist/transforms/expression.js +73 -7
  95. package/dist/transforms/expression.js.map +1 -1
  96. package/dist/writers/csv.d.ts.map +1 -1
  97. package/dist/writers/csv.js +21 -7
  98. package/dist/writers/csv.js.map +1 -1
  99. package/package.json +4 -2
  100. package/skills/rowpipe/SKILL.md +82 -0
package/README.md CHANGED
@@ -16,6 +16,9 @@ Designed around stream backpressure and batch processing, Rowpipe processes mult
16
16
  - **Rich Format Ecosystem**: Native streaming support for **CSV, TSV / PSV, JSON, JSONL, XLSX, Apache Parquet (`.parquet`), Markdown tables (`.md`), and Gzip (`.gz`)**.
17
17
  - **Apache Parquet Support**: High-performance columnar binary format reader (Snappy, Zstd, Gzip decompression via pure JS) and streaming writer.
18
18
  - **Cross-Format Conversion & Multi-Sheet Export**: Convert seamlessly across all formats. Export individual Excel sheets or bulk export all worksheets with `--all-sheets`.
19
+ - **Filesystem as Data (`rowpipe files`)**: First-class streaming filesystem source adapter. Directories and files become streams of tabular records (`path`, `size`, `type`, `extension`, `modified_at`, streaming `hash`, `mime`) composable with `filter`, `select`, `stats`, `convert`, and `diff`.
20
+ - **Cross-Format Dataset Diffing (`rowpipe diff`)**: High-performance, stream-first comparison across CSV, JSONL, XLSX, and Parquet with bounded memory and automatic spill-to-disk. Supports composite keys, duplicate policies, value tolerance, column filtering, schema diffing, JSONL patch generation, and CI `--fail-on-diff` mode.
21
+
19
22
  - **Zero-`eval` Safe Expression Engine**: Ultra-fast JIT closure-compiled evaluators supporting arithmetic (`revenue - cost`), string/date pipe functions (`email | lower | trim`), and direct JSON dot-notation (`payload.user.city`).
20
23
  - **Map & Reduce Streaming Engine**: Compute row derivations (`rowpipe map`) and global or group-by aggregations (`rowpipe reduce --by country`) in a single pass.
21
24
  - **Numerically Stable Streaming Stats**: Online Welford statistics (mean, variance, stddev, min, max, sum) and $O(1)$ HyperLogLog distinct cardinality estimation.
@@ -305,6 +308,253 @@ cat transactions.csv |
305
308
 
306
309
  ---
307
310
 
311
+ ## Compare Datasets (`rowpipe diff`)
312
+
313
+ `rowpipe diff` is a production-grade, stream-first comparison engine that compares two tabular datasets by primary or composite key and reports:
314
+
315
+ - **Added rows** (present in right dataset, absent in left)
316
+ - **Removed rows** (present in left dataset, absent in right)
317
+ - **Changed rows** (matching key, different values)
318
+ - **Unchanged rows** (matching key, identical values)
319
+ - **Changed columns breakdown** (ranked by frequency of changes)
320
+ - **Schema differences** (added/removed columns and type changes)
321
+
322
+ ```bash
323
+ rowpipe diff yesterday.csv today.csv --key id
324
+ ```
325
+
326
+ Example Summary Output:
327
+
328
+ ```text
329
+ Comparing:
330
+ yesterday.csv
331
+ today.csv
332
+
333
+ Key: id
334
+
335
+ Rows
336
+ added 1,283
337
+ removed 412
338
+ changed 8,921
339
+ unchanged 91,204
340
+
341
+ Changed columns
342
+ price 5,821
343
+ status 2,101
344
+ email 999
345
+
346
+ Schema
347
+ + loyalty_level: string
348
+ ~ price: integer -> number
349
+ - legacy_code: string
350
+ ```
351
+
352
+ ### Key Capabilities & Examples
353
+
354
+ #### 1. Composite Keys
355
+ Use comma-separated column names for multi-column composite keys with collision-proof typed encoding:
356
+ ```bash
357
+ rowpipe diff old.csv new.csv --key country,user_id
358
+ ```
359
+
360
+ #### 2. Cross-Format Comparison
361
+ Compare datasets seamlessly across any combination of supported formats (CSV, TSV, JSONL, XLSX, Apache Parquet):
362
+ ```bash
363
+ # Compare CSV with Parquet
364
+ rowpipe diff old.csv new.parquet --key id
365
+
366
+ # Compare JSONL with Excel
367
+ rowpipe diff old.jsonl new.xlsx --key user_id --sheet Users
368
+
369
+ # Compare specific sheets between two Excel workbooks
370
+ rowpipe diff old.xlsx new.xlsx --left-sheet Nov --right-sheet Dec --key sku
371
+ ```
372
+
373
+ #### 3. Ignore or Select Specific Columns
374
+ ```bash
375
+ # Ignore volatile timestamp or audit columns
376
+ rowpipe diff old.csv new.csv --key id --ignore updated_at,last_seen
377
+
378
+ # Compare only specific columns for changes
379
+ rowpipe diff old.csv new.csv --key id --columns price,status
380
+ ```
381
+
382
+ #### 4. Value Equality, Tolerance & Coercion
383
+ - **Strict by default**: `null != ""` and `0 != "0"`.
384
+ - **`--coerce`**: Coerces types (e.g. `"42" == 42`, `"true" == true`) across formats.
385
+ - **`--epsilon <val>`**: Floating point comparison tolerance (`abs(a - b) <= epsilon`).
386
+ - **`--trim` & `--ignore-case`**: String normalization options.
387
+
388
+ ```bash
389
+ rowpipe diff old.csv new.csv --key id --epsilon 0.001 --trim --ignore-case
390
+ ```
391
+
392
+ #### 5. Duplicate Key Policies
393
+ Duplicate keys in either dataset are never silently ignored:
394
+ - `--duplicate-key error` *(default)*: Exits immediately with row context.
395
+ - `--duplicate-key first`: Keeps the first occurrence.
396
+ - `--duplicate-key last`: Keeps the latest occurrence.
397
+
398
+ #### 6. Detailed Row & JSONL Patch Output Modes
399
+ ```bash
400
+ # Detailed row change output with limit
401
+ rowpipe diff old.csv new.csv --key id --format rows --only changed --limit 50
402
+
403
+ # Stream JSONL patches (suitable for ETL change feeds or audit logs)
404
+ rowpipe diff old.csv new.csv --key id --format patch > changes.jsonl
405
+
406
+ # Machine-readable JSON summary metadata
407
+ rowpipe diff old.csv new.csv --key id --json
408
+ ```
409
+
410
+ Example JSONL patch output:
411
+ ```json
412
+ {"op":"update","key":{"id":24},"changes":{"price":{"old":120,"new":125}}}
413
+ {"op":"insert","key":{"id":31},"row":{"id":31,"name":"Alice"}}
414
+ {"op":"delete","key":{"id":51},"row":{"id":51,"name":"Bob"}}
415
+ ```
416
+
417
+ #### 7. CI/CD Validation (`--fail-on-diff`)
418
+ Exit with non-zero code (`1`) when differences exist, or `0` when datasets are equivalent:
419
+
420
+ ```bash
421
+ rowpipe diff expected.csv actual.csv \
422
+ --key id \
423
+ --fail-on-diff
424
+ ```
425
+
426
+ This makes Rowpipe ideal for automated verification of:
427
+ - **Database migrations**
428
+ - **ETL jobs & data pipelines**
429
+ - **API export validation**
430
+ - **Regression test fixtures**
431
+ - **Scheduled report auditing**
432
+
433
+ #### 8. Bounded Memory Architecture & Automatic Spill-to-Disk
434
+ Keyed diffing is classified as **Global State / Spillable**. Rowpipe buffers indexed keys in memory and automatically spills to disk using an append-only temp file index when `--memory-limit` is reached (default: 256MB).
435
+
436
+ ```bash
437
+ # Handle multi-million-row diffs with bounded RAM
438
+ rowpipe diff huge-old.csv huge-new.csv \
439
+ --key id \
440
+ --memory-limit 128mb
441
+ ```
442
+
443
+ ---
444
+
445
+ ## Filesystem as Data (`rowpipe files`)
446
+
447
+ > **Everything becomes a stream of records.**
448
+
449
+ Rowpipe treats files and directories as another first-class streaming record source. A directory tree becomes a stream of metadata records that can be filtered, selected, mapped, reduced, converted, and diffed using the exact same stream pipeline used for CSV, JSONL, XLSX, and Parquet.
450
+
451
+ ```bash
452
+ rowpipe files ./uploads
453
+ ```
454
+
455
+ Example Output (as Table / CSV / JSONL):
456
+
457
+ ```text
458
+ path name ext size modified_at
459
+ uploads/avatar.png avatar.png png 182312 2026-09-16T08:13:11.923Z
460
+ uploads/users.csv users.csv csv 8123102 2026-09-15T19:42:01.114Z
461
+ uploads/archive/data.zip data.zip zip 12931231 2026-09-12T11:05:30.852Z
462
+ ```
463
+
464
+ ### Standard Record Fields
465
+ Each file record contains rich, standardized metadata:
466
+ - `path`: Full normalized path
467
+ - `relative_path`: Normalized path relative to root directory (uses `/` across all operating systems)
468
+ - `name`: File name with extension (e.g. `logo.png`)
469
+ - `basename`: File name without extension (e.g. `logo`)
470
+ - `extension`: Lowercase extension without dot (e.g. `png`)
471
+ - `directory`: Parent directory path
472
+ - `type`: Record type (`"file"`, `"directory"`, `"symlink"`)
473
+ - `size`: Numeric size in bytes (`0` for directories)
474
+ - `created_at`, `modified_at`, `accessed_at`: ISO 8601 timestamp strings
475
+ - `mode`: File permission mode
476
+ - `is_file`, `is_directory`, `is_symlink`: Boolean flags
477
+ - `hash` *(optional)*: Streaming content hash (`sha256`, `sha1`, `md5`, `fast`)
478
+ - `mime` & `category` *(optional)*: Inferred MIME type (`image/png`, `text/csv`) and category (`image`, `data`, `code`, `archive`, `document`, `video`, `audio`)
479
+
480
+ ---
481
+
482
+ ### Filesystem CLI Workflows & Examples
483
+
484
+ #### 1. Recursive Traversal & Glob Filtering
485
+ ```bash
486
+ # Scan directory recursively (default)
487
+ rowpipe files ./src
488
+
489
+ # Limit traversal depth
490
+ rowpipe files . --max-depth 2
491
+
492
+ # Include specific globs
493
+ rowpipe files ./src --include "**/*.ts"
494
+
495
+ # Exclude patterns (e.g. node_modules, build artifacts)
496
+ rowpipe files . --exclude "dist/**" --exclude "*.tmp"
497
+
498
+ # Include hidden files & dot directories
499
+ rowpipe files . --hidden
500
+ ```
501
+
502
+ #### 2. Streaming Hashes & MIME Type Detection
503
+ ```bash
504
+ # Compute streaming SHA-256 hashes (never loads full file into memory)
505
+ rowpipe files ./assets --hash sha256
506
+
507
+ # Fast non-cryptographic fingerprinting (size + mtime + content sampling)
508
+ rowpipe files ./dataset --hash fast
509
+
510
+ # Infer MIME types and high-level categories
511
+ rowpipe files ./uploads --mime
512
+ ```
513
+
514
+ #### 3. Unix Pipeline Composition
515
+ Compose filesystem metadata directly into Rowpipe streams:
516
+
517
+ ```bash
518
+ # Filter large files (> 1MB)
519
+ rowpipe files ./uploads | rowpipe filter - 'size > 1000000'
520
+
521
+ # Project specific columns
522
+ rowpipe files ./src | rowpipe select - path,size,extension
523
+
524
+ # Calculate disk usage stats across file types
525
+ rowpipe files ./src --to jsonl | \
526
+ rowpipe reduce - "total_size=sum(size)" "file_count=count()" --by extension
527
+ ```
528
+
529
+ #### 4. Deterministic Snapshots & Build Verification
530
+ Create stable, reproducible file inventory snapshots for build artifacts, deployments, or backups:
531
+
532
+ ```bash
533
+ # Generate deterministic snapshot
534
+ rowpipe files snapshot ./dist \
535
+ --hash sha256 \
536
+ --to jsonl > dist.snapshot.v1.jsonl
537
+
538
+ # Generate snapshot of next build
539
+ rowpipe files snapshot ./dist \
540
+ --hash sha256 \
541
+ --to jsonl > dist.snapshot.v2.jsonl
542
+
543
+ # Compare snapshots using Rowpipe's diff engine
544
+ rowpipe diff dist.snapshot.v1.jsonl dist.snapshot.v2.jsonl \
545
+ --key relative_path \
546
+ --ignore modified_at,accessed_at
547
+ ```
548
+
549
+ #### 5. Native Directory Diffing (`rowpipe files diff`)
550
+ Compare two directory trees directly:
551
+
552
+ ```bash
553
+ rowpipe files diff ./dist-v1 ./dist-v2 --hash sha256
554
+ ```
555
+
556
+ ---
557
+
308
558
  ## Node.js Library API
309
559
 
310
560
  Rowpipe can be imported directly in your Node.js projects:
@@ -315,12 +565,15 @@ import {
315
565
  CSVReader,
316
566
  JSONLWriter,
317
567
  XLSXReader,
568
+ ParquetReader,
569
+ FileSystemReader,
318
570
  filterRows,
319
571
  selectColumns,
320
572
  castColumns,
321
573
  mapRows,
322
574
  reduceRows,
323
- DatasetStatsAggregator,
575
+ diffRows,
576
+ computeDiff,
324
577
  } from "rowpipe";
325
578
  import { createReadStream, createWriteStream } from "node:fs";
326
579
 
@@ -344,10 +597,31 @@ await createPipeline(reader)
344
597
  }))
345
598
  .to(writer);
346
599
 
347
- // 2. Multi-Sheet Excel Inspection
348
- const xlsxReader = new XLSXReader("workbook.xlsx");
349
- const metadata = await xlsxReader.inspect();
350
- console.log("Workbook Sheets:", metadata.sheets);
600
+ // 2. Stream Filesystem Directory as Tabular Rows
601
+ const fsReader = new FileSystemReader({
602
+ root: "./src",
603
+ include: ["**/*.ts"],
604
+ hash: "sha256",
605
+ mime: true,
606
+ });
607
+
608
+ for await (const batch of fsReader.read()) {
609
+ for (const file of batch.rows) {
610
+ console.log(`${file.relative_path} (${file.size} bytes) - Hash: ${file.hash}`);
611
+ }
612
+ }
613
+
614
+ // 3. Streaming Dataset Diffing (Async Iterable Events)
615
+ for await (const event of diffRows({
616
+ leftPath: "old.csv",
617
+ rightPath: "new.parquet",
618
+ keys: ["id"],
619
+ ignore: ["updated_at"],
620
+ })) {
621
+ if (event.type === "changed") {
622
+ console.log(`Key ${JSON.stringify(event.key)} changed:`, event.changes);
623
+ }
624
+ }
351
625
  ```
352
626
 
353
627
  ---
@@ -359,32 +633,49 @@ Rowpipe uses standardized POSIX exit codes:
359
633
  | Code | Meaning | Description |
360
634
  |------|---------|-------------|
361
635
  | `0` | Success | Command executed successfully |
362
- | `1` | Generic Failure | Unexpected runtime or internal error |
636
+ | `1` | Generic / Diff Mismatch | Runtime error or diff mismatch when `--fail-on-diff` is specified |
363
637
  | `2` | Invalid Arguments | Missing or invalid CLI flags or arguments |
364
638
  | `3` | Parse Error | Corrupted or malformed CSV/JSON/XLSX input with row/column context |
365
639
  | `4` | Validation Failure | Schema validation violations detected |
640
+ | `5` | Duplicate Key Error | Duplicate key encountered during keyed diff under `--duplicate-key error` |
366
641
 
367
642
  ---
368
643
 
369
644
  ## Memory & Performance Benchmarks
370
645
 
371
- Tested on 1,000,000 synthetic rows through a complete pipeline (`Filter` -> `Select` -> `Cast` -> `Online Stats`):
646
+ ### 1. Pipeline Benchmark (`Filter` -> `Select` -> `Cast` -> `Online Stats`):
372
647
 
373
648
  | Dataset Size | Throughput | Execution Time | Peak RSS Memory | Memory Scaling |
374
649
  |--------------|------------|----------------|-----------------|----------------|
375
650
  | **100,000 rows** | **~318,000 rows/s** | 0.31s | ~106 MB | $O(1)$ Bounded |
376
651
  | **1,000,000 rows** | **~500,000 rows/s** | 2.00s | ~153 MB | $O(1)$ Bounded |
377
652
 
378
- To run the benchmark locally:
653
+ ### 2. Diff Engine Benchmark (`rowpipe diff`):
654
+
655
+ | Comparison Size | Memory Limit | Throughput | Peak RSS Memory | Disk Spilled | Result |
656
+ |-----------------|--------------|------------|-----------------|--------------|--------|
657
+ | **2,000,000 rows** (1M vs 1M) | 64 MB | **~73,000 rows/s** | ~145 MB | Active | 100% Exact Match |
658
+
659
+ ### 3. Filesystem Streaming Benchmark (`rowpipe files`):
660
+
661
+ | File Count | Operation | Throughput | Peak RSS Memory | Memory Scaling |
662
+ |------------|-----------|------------|-----------------|----------------|
663
+ | **50,000 files** | Stream Traversal + Metadata | **~24,100 files/s** | ~147 MB | $O(1)$ Bounded |
664
+ | **50,000 files** | Filter + Select Pipeline | **~13,800 files/s** | ~147 MB | $O(1)$ Bounded |
665
+ | **50,000 files** | Fast Fingerprint Hashing | **~3,470 files/s** | ~148 MB | $O(1)$ Bounded |
666
+
667
+ To run the benchmarks locally:
379
668
 
380
669
  ```bash
381
670
  npm run bench
671
+ npm run benchmark:diff
672
+ npm run benchmark:files
382
673
  ```
383
674
 
384
675
  To enable real-time memory debugging on any command:
385
676
 
386
677
  ```bash
387
- ROWPIPE_DEBUG_MEMORY=1 rowpipe stats huge.csv
678
+ ROWPIPE_DEBUG_MEMORY=1 rowpipe files ./huge-directory --hash fast
388
679
  ```
389
680
 
390
681
  ---
@@ -392,3 +683,5 @@ ROWPIPE_DEBUG_MEMORY=1 rowpipe stats huge.csv
392
683
  ## License
393
684
 
394
685
  MIT
686
+
687
+
@@ -0,0 +1,30 @@
1
+ import type { DiffOnlyFilter, DiffOutputFormat, DuplicateKeyPolicy } from "../../diff/types.js";
2
+ export interface DiffCommandOptions {
3
+ key?: string;
4
+ format?: DiffOutputFormat;
5
+ only?: DiffOnlyFilter;
6
+ columns?: string;
7
+ ignore?: string;
8
+ limit?: string | number;
9
+ json?: boolean;
10
+ output?: string;
11
+ failOnDiff?: boolean;
12
+ duplicateKey?: DuplicateKeyPolicy;
13
+ coerce?: boolean;
14
+ epsilon?: string | number;
15
+ ignoreCase?: boolean;
16
+ trim?: boolean;
17
+ memoryLimit?: string;
18
+ sheet?: string;
19
+ leftSheet?: string;
20
+ rightSheet?: string;
21
+ from?: string;
22
+ fromLeft?: string;
23
+ fromRight?: string;
24
+ schema?: boolean;
25
+ quiet?: boolean;
26
+ noProgress?: boolean;
27
+ batchSize?: string | number;
28
+ }
29
+ export declare function diffCommand(leftPath: string, rightPath: string, options?: DiffCommandOptions): Promise<void>;
30
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/diff.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAI7B,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CA+Jf"}
@@ -0,0 +1,143 @@
1
+ import { createWriteStream } from "node:fs";
2
+ import { DiffMismatchError, InvalidArgumentError } from "../../core/errors.js";
3
+ import { computeDiff, diffRows } from "../../diff/engine.js";
4
+ import { formatJson, formatPatchEvent, formatRowEvent, formatSummary, } from "../../diff/reporter.js";
5
+ import { formatNumber } from "../../utils/formatting.js";
6
+ import { parseMemoryLimit } from "../../diff/storage/spillable-index.js";
7
+ export async function diffCommand(leftPath, rightPath, options = {}) {
8
+ if (leftPath === "-" && rightPath === "-") {
9
+ throw new InvalidArgumentError("Cannot diff stdin against stdin ('- -'). One side must be a file or named source.");
10
+ }
11
+ if (!options.key) {
12
+ throw new InvalidArgumentError("Missing required option: --key <column1,column2,...>");
13
+ }
14
+ const keys = options.key.split(",").map((k) => k.trim()).filter(Boolean);
15
+ const compareColumns = options.columns
16
+ ? options.columns.split(",").map((c) => c.trim()).filter(Boolean)
17
+ : undefined;
18
+ const ignoreColumns = options.ignore
19
+ ? options.ignore.split(",").map((c) => c.trim()).filter(Boolean)
20
+ : undefined;
21
+ const leftSheet = options.leftSheet || options.sheet;
22
+ const rightSheet = options.rightSheet || options.sheet;
23
+ const leftFormat = options.fromLeft || options.from;
24
+ const rightFormat = options.fromRight || options.from;
25
+ const batchSize = Number(options.batchSize) || 1000;
26
+ const leftOptions = {
27
+ sheet: leftSheet,
28
+ format: leftFormat,
29
+ batchSize,
30
+ filePath: leftPath,
31
+ };
32
+ const rightOptions = {
33
+ sheet: rightSheet,
34
+ format: rightFormat,
35
+ batchSize,
36
+ filePath: rightPath,
37
+ };
38
+ const isTty = process.stderr.isTTY && !options.quiet && options.noProgress !== true;
39
+ const onProgress = (info) => {
40
+ if (!isTty)
41
+ return;
42
+ const isSpilledText = info.isSpilled ? " (disk spilled)" : "";
43
+ if (info.phase === "indexing_left") {
44
+ process.stderr.write(`\r\x1b[2K Indexing left: ${formatNumber(info.leftRowsProcessed)} rows${isSpilledText}...`);
45
+ }
46
+ else if (info.phase === "comparing_right") {
47
+ process.stderr.write(`\r\x1b[2K Comparing right: ${formatNumber(info.rightRowsProcessed)} rows [added: ${formatNumber(info.addedCount)}, changed: ${formatNumber(info.changedCount)}, unchanged: ${formatNumber(info.unchangedCount)}]${isSpilledText}...`);
48
+ }
49
+ else if (info.phase === "finishing") {
50
+ process.stderr.write(`\r\x1b[2K Done comparing.\n`);
51
+ }
52
+ };
53
+ const engineOptions = {
54
+ left: leftPath,
55
+ right: rightPath,
56
+ keys,
57
+ columns: compareColumns,
58
+ ignore: ignoreColumns,
59
+ duplicateKey: options.duplicateKey || "error",
60
+ coerce: options.coerce,
61
+ epsilon: options.epsilon !== undefined ? Number(options.epsilon) : undefined,
62
+ ignoreCase: options.ignoreCase,
63
+ trim: options.trim,
64
+ memoryLimitBytes: parseMemoryLimit(options.memoryLimit),
65
+ includeSchema: options.schema !== false,
66
+ leftOptions,
67
+ rightOptions,
68
+ onProgress,
69
+ };
70
+ const formatMode = options.format || "summary";
71
+ const limit = options.limit !== undefined ? Number(options.limit) : undefined;
72
+ const onlyFilter = options.only;
73
+ let outStream = process.stdout;
74
+ let fileStream = null;
75
+ if (options.output) {
76
+ fileStream = createWriteStream(options.output, "utf-8");
77
+ outStream = fileStream;
78
+ }
79
+ const writeOut = async (chunk) => {
80
+ if (!outStream.write(chunk)) {
81
+ await new Promise((resolve) => outStream.once("drain", resolve));
82
+ }
83
+ };
84
+ try {
85
+ if (options.json || formatMode === "summary") {
86
+ const summary = await computeDiff(engineOptions);
87
+ if (isTty) {
88
+ process.stderr.write("\r\x1b[2K");
89
+ }
90
+ if (options.json) {
91
+ await writeOut(formatJson(summary));
92
+ }
93
+ else {
94
+ await writeOut(formatSummary(summary));
95
+ }
96
+ const totalDiffs = summary.rows.added + summary.rows.removed + summary.rows.changed;
97
+ if (options.failOnDiff && totalDiffs > 0) {
98
+ throw new DiffMismatchError(totalDiffs);
99
+ }
100
+ return;
101
+ }
102
+ // -----------------------------------------------------------
103
+ // Streaming row-level output (rows or patch)
104
+ // -----------------------------------------------------------
105
+ let emittedCount = 0;
106
+ let totalDiffCount = 0;
107
+ for await (const event of diffRows(engineOptions)) {
108
+ if (event.type === "added" || event.type === "removed" || event.type === "changed") {
109
+ totalDiffCount++;
110
+ }
111
+ // Filter by --only
112
+ if (onlyFilter && event.type !== onlyFilter) {
113
+ continue;
114
+ }
115
+ if (limit !== undefined && emittedCount >= limit) {
116
+ continue;
117
+ }
118
+ let formattedText = null;
119
+ if (formatMode === "rows") {
120
+ formattedText = formatRowEvent(event);
121
+ }
122
+ else if (formatMode === "patch") {
123
+ formattedText = formatPatchEvent(event);
124
+ }
125
+ if (formattedText) {
126
+ await writeOut(formattedText);
127
+ emittedCount++;
128
+ }
129
+ }
130
+ if (isTty) {
131
+ process.stderr.write("\r\x1b[2K");
132
+ }
133
+ if (options.failOnDiff && totalDiffCount > 0) {
134
+ throw new DiffMismatchError(totalDiffCount);
135
+ }
136
+ }
137
+ finally {
138
+ if (fileStream) {
139
+ await new Promise((resolve) => fileStream.end(() => resolve()));
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/cli/commands/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { FileTypeFilter } from "../../files/types.js";
2
+ import { DiffCommandOptions } from "./diff.js";
3
+ export interface FilesCommandOptions {
4
+ recursive?: boolean;
5
+ maxDepth?: string | number;
6
+ include?: string | string[];
7
+ exclude?: string | string[];
8
+ hidden?: boolean;
9
+ followSymlinks?: boolean;
10
+ type?: FileTypeFilter;
11
+ hash?: string | false;
12
+ mime?: boolean;
13
+ concurrency?: string | number;
14
+ onError?: "fail" | "skip";
15
+ to?: string;
16
+ json?: boolean;
17
+ output?: string;
18
+ batchSize?: string | number;
19
+ deterministic?: boolean;
20
+ quiet?: boolean;
21
+ noProgress?: boolean;
22
+ }
23
+ /**
24
+ * Main handler for `rowpipe files <path> [options]`.
25
+ */
26
+ export declare function filesCommand(targetPath?: string, options?: FilesCommandOptions): Promise<void>;
27
+ /**
28
+ * Convenience handler for `rowpipe files snapshot <path> [options]`.
29
+ */
30
+ export declare function filesSnapshotCommand(targetPath?: string, options?: FilesCommandOptions): Promise<void>;
31
+ /**
32
+ * Convenience handler for `rowpipe files diff <left> <right> [options]`.
33
+ */
34
+ export declare function filesDiffCommand(leftPath: string, rightPath: string, options?: DiffCommandOptions & FilesCommandOptions): Promise<void>;
35
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/files.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,sBAAsB,CAAC;AAK1E,OAAO,EAAe,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE5D,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,UAAU,SAAM,EAChB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CA+Df;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,SAAM,EAChB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,kBAAkB,GAAG,mBAAwB,GACrD,OAAO,CAAC,IAAI,CAAC,CAUf"}