rowpipe 1.2.0 → 2.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 +238 -55
- package/dist/cli/commands/count.d.ts +12 -0
- package/dist/cli/commands/count.d.ts.map +1 -0
- package/dist/cli/commands/count.js +49 -0
- package/dist/cli/commands/count.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +3 -0
- package/dist/cli/commands/explain.d.ts.map +1 -0
- package/dist/cli/commands/explain.js +11 -0
- package/dist/cli/commands/explain.js.map +1 -0
- package/dist/cli/commands/files.d.ts +3 -1
- package/dist/cli/commands/files.d.ts.map +1 -1
- package/dist/cli/commands/files.js +6 -2
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/group.d.ts +12 -0
- package/dist/cli/commands/group.d.ts.map +1 -0
- package/dist/cli/commands/group.js +51 -0
- package/dist/cli/commands/group.js.map +1 -0
- package/dist/cli/commands/head.d.ts +7 -0
- package/dist/cli/commands/head.d.ts.map +1 -0
- package/dist/cli/commands/head.js +6 -0
- package/dist/cli/commands/head.js.map +1 -0
- package/dist/cli/commands/limit.d.ts +11 -0
- package/dist/cli/commands/limit.d.ts.map +1 -0
- package/dist/cli/commands/limit.js +40 -0
- package/dist/cli/commands/limit.js.map +1 -0
- package/dist/cli/commands/offset.d.ts +11 -0
- package/dist/cli/commands/offset.d.ts.map +1 -0
- package/dist/cli/commands/offset.js +39 -0
- package/dist/cli/commands/offset.js.map +1 -0
- package/dist/cli/commands/pipeline.d.ts +43 -0
- package/dist/cli/commands/pipeline.d.ts.map +1 -0
- package/dist/cli/commands/pipeline.js +198 -0
- package/dist/cli/commands/pipeline.js.map +1 -0
- package/dist/cli/commands/sort.d.ts +17 -0
- package/dist/cli/commands/sort.d.ts.map +1 -0
- package/dist/cli/commands/sort.js +55 -0
- package/dist/cli/commands/sort.js.map +1 -0
- package/dist/cli/commands/tail.d.ts +13 -0
- package/dist/cli/commands/tail.d.ts.map +1 -0
- package/dist/cli/commands/tail.js +39 -0
- package/dist/cli/commands/tail.js.map +1 -0
- package/dist/cli/commands/top.d.ts +19 -0
- package/dist/cli/commands/top.d.ts.map +1 -0
- package/dist/cli/commands/top.js +51 -0
- package/dist/cli/commands/top.js.map +1 -0
- package/dist/cli/commands/unique.d.ts +15 -0
- package/dist/cli/commands/unique.d.ts.map +1 -0
- package/dist/cli/commands/unique.js +44 -0
- package/dist/cli/commands/unique.js.map +1 -0
- package/dist/cli/index.js +253 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/pipeline.d.ts +40 -0
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +65 -0
- package/dist/core/pipeline.js.map +1 -1
- package/dist/files/reader.d.ts.map +1 -1
- package/dist/files/reader.js +4 -0
- package/dist/files/reader.js.map +1 -1
- package/dist/files/types.d.ts +2 -0
- package/dist/files/types.d.ts.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/planner/executor.d.ts +8 -0
- package/dist/planner/executor.d.ts.map +1 -0
- package/dist/planner/executor.js +86 -0
- package/dist/planner/executor.js.map +1 -0
- package/dist/planner/explain.d.ts +6 -0
- package/dist/planner/explain.d.ts.map +1 -0
- package/dist/planner/explain.js +91 -0
- package/dist/planner/explain.js.map +1 -0
- package/dist/planner/index.d.ts +5 -0
- package/dist/planner/index.d.ts.map +1 -0
- package/dist/planner/index.js +5 -0
- package/dist/planner/index.js.map +1 -0
- package/dist/planner/optimizer.d.ts +9 -0
- package/dist/planner/optimizer.d.ts.map +1 -0
- package/dist/planner/optimizer.js +78 -0
- package/dist/planner/optimizer.js.map +1 -0
- package/dist/planner/types.d.ts +63 -0
- package/dist/planner/types.d.ts.map +1 -0
- package/dist/planner/types.js +2 -0
- package/dist/planner/types.js.map +1 -0
- package/dist/transforms/count.d.ts +21 -0
- package/dist/transforms/count.d.ts.map +1 -0
- package/dist/transforms/count.js +65 -0
- package/dist/transforms/count.js.map +1 -0
- package/dist/transforms/expression.d.ts.map +1 -1
- package/dist/transforms/expression.js +15 -0
- package/dist/transforms/expression.js.map +1 -1
- package/dist/transforms/group.d.ts +25 -0
- package/dist/transforms/group.d.ts.map +1 -0
- package/dist/transforms/group.js +71 -0
- package/dist/transforms/group.js.map +1 -0
- package/dist/transforms/limit.d.ts +7 -0
- package/dist/transforms/limit.d.ts.map +1 -0
- package/dist/transforms/limit.js +40 -0
- package/dist/transforms/limit.js.map +1 -0
- package/dist/transforms/offset.d.ts +7 -0
- package/dist/transforms/offset.d.ts.map +1 -0
- package/dist/transforms/offset.js +38 -0
- package/dist/transforms/offset.js.map +1 -0
- package/dist/transforms/sort/comparator.d.ts +43 -0
- package/dist/transforms/sort/comparator.d.ts.map +1 -0
- package/dist/transforms/sort/comparator.js +131 -0
- package/dist/transforms/sort/comparator.js.map +1 -0
- package/dist/transforms/sort/external-sort.d.ts +8 -0
- package/dist/transforms/sort/external-sort.d.ts.map +1 -0
- package/dist/transforms/sort/external-sort.js +159 -0
- package/dist/transforms/sort/external-sort.js.map +1 -0
- package/dist/transforms/sort/index.d.ts +10 -0
- package/dist/transforms/sort/index.d.ts.map +1 -0
- package/dist/transforms/sort/index.js +11 -0
- package/dist/transforms/sort/index.js.map +1 -0
- package/dist/transforms/tail.d.ts +6 -0
- package/dist/transforms/tail.d.ts.map +1 -0
- package/dist/transforms/tail.js +27 -0
- package/dist/transforms/tail.js.map +1 -0
- package/dist/transforms/top.d.ts +17 -0
- package/dist/transforms/top.d.ts.map +1 -0
- package/dist/transforms/top.js +52 -0
- package/dist/transforms/top.js.map +1 -0
- package/dist/transforms/unique.d.ts +13 -0
- package/dist/transforms/unique.d.ts.map +1 -0
- package/dist/transforms/unique.js +91 -0
- package/dist/transforms/unique.js.map +1 -0
- package/dist/utils/formatting.d.ts +1 -0
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +34 -4
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/heap.d.ts +25 -0
- package/dist/utils/heap.d.ts.map +1 -0
- package/dist/utils/heap.js +90 -0
- package/dist/utils/heap.js.map +1 -0
- package/dist/utils/keystore.d.ts +80 -0
- package/dist/utils/keystore.d.ts.map +1 -0
- package/dist/utils/keystore.js +217 -0
- package/dist/utils/keystore.js.map +1 -0
- package/dist/utils/ring-buffer.d.ts +15 -0
- package/dist/utils/ring-buffer.d.ts.map +1 -0
- package/dist/utils/ring-buffer.js +40 -0
- package/dist/utils/ring-buffer.js.map +1 -0
- package/dist/writers/markdown.d.ts.map +1 -1
- package/dist/writers/markdown.js +41 -12
- package/dist/writers/markdown.js.map +1 -1
- package/package.json +3 -2
- package/skills/rowpipe/SKILL.md +27 -9
package/README.md
CHANGED
|
@@ -555,6 +555,214 @@ rowpipe files diff ./dist-v1 ./dist-v2 --hash sha256
|
|
|
555
555
|
|
|
556
556
|
---
|
|
557
557
|
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Tabular Operations & Execution Planner
|
|
561
|
+
|
|
562
|
+
Rowpipe 2.0 introduces a comprehensive set of Unix-like tabular data operations, powered by a rule-based execution planner that optimizes multi-transform pipelines and enforces strict memory bounds.
|
|
563
|
+
|
|
564
|
+
> **Streaming is the default. Global state is explicit, bounded, and spillable.**
|
|
565
|
+
|
|
566
|
+
### Streaming Safety Classification
|
|
567
|
+
|
|
568
|
+
| Classification | Operations | Memory Complexity | Description |
|
|
569
|
+
|----------------|------------|-------------------|-------------|
|
|
570
|
+
| **Fully Streaming** | `limit`, `offset`, `head`, `filter`, `select`, `rename`, `cast`, `map`, `count` | $O(1)$ | Consumes stream in batches, cancels upstream sources immediately upon completion. |
|
|
571
|
+
| **Bounded State** | `tail`, `top`, `sample` | $O(K)$ / $O(N)$ | Maintains a fixed-size ring buffer ($O(N)$) or binary min/max heap ($O(K)$). |
|
|
572
|
+
| **Spillable Global State** | `sort`, `unique`, `group`, `reduce`, `diff` | $O(1)$ RAM threshold + Disk Spilling | Buffers in-memory runs up to `--memory-limit` and transparently spills to disk partitions or runs. |
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
### Operations Reference
|
|
577
|
+
|
|
578
|
+
#### 1. Limit & Head
|
|
579
|
+
Emit the first $N$ rows and immediately cancel upstream stream reading:
|
|
580
|
+
|
|
581
|
+
```bash
|
|
582
|
+
# Explicit limit command
|
|
583
|
+
rowpipe limit users.csv 100
|
|
584
|
+
|
|
585
|
+
# Pipeline flag
|
|
586
|
+
rowpipe users.csv --limit 100
|
|
587
|
+
|
|
588
|
+
# Head alias (default: 10 rows)
|
|
589
|
+
rowpipe head users.csv
|
|
590
|
+
rowpipe head users.csv -n 50
|
|
591
|
+
|
|
592
|
+
# Streaming through Unix pipe
|
|
593
|
+
cat data.csv | rowpipe limit - 100
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
#### 2. Offset
|
|
597
|
+
Skip the first $N$ rows and stream everything after without scanning unneeded rows:
|
|
598
|
+
|
|
599
|
+
```bash
|
|
600
|
+
rowpipe offset users.csv 1000
|
|
601
|
+
rowpipe users.csv --offset 1000
|
|
602
|
+
|
|
603
|
+
# Combine with limit (automatically halts reading after 1,100 rows)
|
|
604
|
+
rowpipe users.csv --offset 1000 --limit 100
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
#### 3. Tail
|
|
608
|
+
Emit the last $N$ rows using a bounded circular ring buffer without buffering the entire dataset in RAM:
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
# Default: last 10 rows
|
|
612
|
+
rowpipe tail server_logs.jsonl
|
|
613
|
+
|
|
614
|
+
# Specify row count
|
|
615
|
+
rowpipe tail server_logs.jsonl -n 100
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
#### 4. External Merge Sort (`sort`)
|
|
619
|
+
Multi-column typed sorting with deterministic sequence stability, natural sorting, case-insensitivity, null handling, and disk run spilling:
|
|
620
|
+
|
|
621
|
+
```bash
|
|
622
|
+
# Single column sort (numeric, boolean, date, string typed)
|
|
623
|
+
rowpipe sort users.csv --by age:desc
|
|
624
|
+
|
|
625
|
+
# Multi-column sort
|
|
626
|
+
rowpipe sort sales.csv --by country --by revenue:desc
|
|
627
|
+
|
|
628
|
+
# Compact syntax
|
|
629
|
+
rowpipe sort sales.csv --by "country,revenue:desc"
|
|
630
|
+
|
|
631
|
+
# Natural filename / alphanumeric sort
|
|
632
|
+
rowpipe sort files.csv --by name --natural
|
|
633
|
+
|
|
634
|
+
# Null value positioning
|
|
635
|
+
rowpipe sort users.csv --by age --nulls first # or --nulls last
|
|
636
|
+
|
|
637
|
+
# Memory threshold before disk run spilling
|
|
638
|
+
rowpipe sort huge.csv --by created_at --memory-limit 256mb --temp-dir /tmp/rowpipe
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
#### 5. Top-K Bounded Heap (`top`)
|
|
642
|
+
Extract the top (or bottom) $K$ records using a bounded $O(K)$ binary heap:
|
|
643
|
+
|
|
644
|
+
```bash
|
|
645
|
+
# Top 10 largest by revenue
|
|
646
|
+
rowpipe top sales.csv --by revenue -n 10
|
|
647
|
+
|
|
648
|
+
# Top 20 largest files
|
|
649
|
+
rowpipe files ./src --sort size:desc --limit 20 # Automatically rewritten to TopK(20)!
|
|
650
|
+
|
|
651
|
+
# Bottom 5 smallest
|
|
652
|
+
rowpipe top users.csv --by score -n 5 --smallest
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### 6. Unique Deduplication (`unique`)
|
|
656
|
+
Deduplicate rows by key columns or entire rows with spillable hash partitions:
|
|
657
|
+
|
|
658
|
+
```bash
|
|
659
|
+
# Unique by single field (keeps first occurrence by default)
|
|
660
|
+
rowpipe unique users.csv --by email
|
|
661
|
+
|
|
662
|
+
# Composite uniqueness
|
|
663
|
+
rowpipe unique users.csv --by country,email
|
|
664
|
+
|
|
665
|
+
# Keep last occurrence
|
|
666
|
+
rowpipe unique logs.jsonl --by user_id --keep last
|
|
667
|
+
|
|
668
|
+
# Entire row deduplication
|
|
669
|
+
rowpipe unique dataset.csv
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
#### 7. Count Analyzer (`count`)
|
|
673
|
+
Ultra-lightweight streaming row, distinct, and group counting:
|
|
674
|
+
|
|
675
|
+
```bash
|
|
676
|
+
# Total row count
|
|
677
|
+
rowpipe count dataset.parquet
|
|
678
|
+
# Output: 8,531,221
|
|
679
|
+
|
|
680
|
+
# Distinct column count (exact or approximate HyperLogLog)
|
|
681
|
+
rowpipe count users.csv --distinct email
|
|
682
|
+
rowpipe count users.csv --distinct email --approx
|
|
683
|
+
|
|
684
|
+
# Group-by count
|
|
685
|
+
rowpipe count users.csv --by country
|
|
686
|
+
|
|
687
|
+
# Machine-readable JSON output
|
|
688
|
+
rowpipe count users.csv --by country --json
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
#### 8. Group & Aggregations (`group`)
|
|
692
|
+
Group tabular streams with single-pass hash accumulators and multi-column aggregations:
|
|
693
|
+
|
|
694
|
+
```bash
|
|
695
|
+
# Group count
|
|
696
|
+
rowpipe group sales.csv --by country --count
|
|
697
|
+
|
|
698
|
+
# Multi-field aggregations
|
|
699
|
+
rowpipe group sales.csv \
|
|
700
|
+
--by country \
|
|
701
|
+
--count \
|
|
702
|
+
--sum revenue \
|
|
703
|
+
--avg revenue \
|
|
704
|
+
--max quantity
|
|
705
|
+
|
|
706
|
+
# Compact aggregation spec
|
|
707
|
+
rowpipe group sales.csv \
|
|
708
|
+
--by country,category \
|
|
709
|
+
--agg "orders=count(),total_rev=sum(revenue),avg_rev=avg(revenue)" \
|
|
710
|
+
--to markdown
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
715
|
+
### Combined Multi-Transform Pipeline
|
|
716
|
+
|
|
717
|
+
Chain multiple operations in a **single process** without writing temporary intermediate files:
|
|
718
|
+
|
|
719
|
+
```bash
|
|
720
|
+
# Reader -> Filter -> Select -> TopK -> Writer
|
|
721
|
+
rowpipe users.csv \
|
|
722
|
+
--filter "age >= 18 && active == true" \
|
|
723
|
+
--select id,name,age,country,revenue \
|
|
724
|
+
--sort revenue:desc \
|
|
725
|
+
--limit 50 \
|
|
726
|
+
--to markdown
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
### Execution Plan Visualizer (`rowpipe explain`)
|
|
730
|
+
|
|
731
|
+
Inspect the planned execution pipeline and see automatic optimizations in action:
|
|
732
|
+
|
|
733
|
+
```bash
|
|
734
|
+
rowpipe explain sales.csv \
|
|
735
|
+
--filter "active == true" \
|
|
736
|
+
--sort revenue:desc \
|
|
737
|
+
--limit 10 \
|
|
738
|
+
--to jsonl
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
Output:
|
|
742
|
+
```text
|
|
743
|
+
======================================================
|
|
744
|
+
Rowpipe Execution Plan
|
|
745
|
+
======================================================
|
|
746
|
+
|
|
747
|
+
CSVReader (sales.csv)
|
|
748
|
+
↓
|
|
749
|
+
Filter (active == true)
|
|
750
|
+
↓
|
|
751
|
+
TopK (revenue DESC, 10) [Bounded Heap]
|
|
752
|
+
↓
|
|
753
|
+
JSONLWriter (stdout)
|
|
754
|
+
|
|
755
|
+
------------------------------------------------------
|
|
756
|
+
Optimizations Applied:
|
|
757
|
+
• sort(revenue desc) + limit(10) -> top-k (10)
|
|
758
|
+
------------------------------------------------------
|
|
759
|
+
Memory Classification:
|
|
760
|
+
Bounded State (O(K) fixed memory bound)
|
|
761
|
+
======================================================
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
558
766
|
## Node.js Library API
|
|
559
767
|
|
|
560
768
|
Rowpipe can be imported directly in your Node.js projects:
|
|
@@ -569,59 +777,34 @@ import {
|
|
|
569
777
|
FileSystemReader,
|
|
570
778
|
filterRows,
|
|
571
779
|
selectColumns,
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
780
|
+
limitRows,
|
|
781
|
+
offsetRows,
|
|
782
|
+
tailRows,
|
|
783
|
+
sortRows,
|
|
784
|
+
topRows,
|
|
785
|
+
uniqueRows,
|
|
786
|
+
groupRows,
|
|
787
|
+
countStream,
|
|
575
788
|
diffRows,
|
|
576
789
|
computeDiff,
|
|
577
790
|
} from "rowpipe";
|
|
578
791
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
579
792
|
|
|
580
|
-
//
|
|
793
|
+
// Fluent Pipeline API
|
|
581
794
|
const reader = new CSVReader(createReadStream("sales.csv"));
|
|
582
|
-
const writer = new JSONLWriter(createWriteStream("
|
|
795
|
+
const writer = new JSONLWriter(createWriteStream("top_sales.jsonl"));
|
|
583
796
|
|
|
584
797
|
await createPipeline(reader)
|
|
585
|
-
.
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
}))
|
|
589
|
-
.pipe(filterRows("margin >= 15"))
|
|
590
|
-
.pipe(reduceRows({
|
|
591
|
-
by: ["country"],
|
|
592
|
-
aggregations: [
|
|
593
|
-
"total_profit = sum(profit)",
|
|
594
|
-
"avg_margin = avg(margin)",
|
|
595
|
-
"count = count()",
|
|
596
|
-
],
|
|
597
|
-
}))
|
|
798
|
+
.filter("status == 'completed'")
|
|
799
|
+
.sort({ by: "revenue:desc" })
|
|
800
|
+
.limit(100)
|
|
598
801
|
.to(writer);
|
|
599
802
|
|
|
600
|
-
//
|
|
601
|
-
const fsReader = new FileSystemReader({
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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
|
-
}
|
|
803
|
+
// Filesystem as Tabular Source + Top 10 Largest Files
|
|
804
|
+
const fsReader = new FileSystemReader({ root: "./src" });
|
|
805
|
+
const largestFiles = await createPipeline(fsReader)
|
|
806
|
+
.top({ by: "size:desc", count: 10 })
|
|
807
|
+
.toArray();
|
|
625
808
|
```
|
|
626
809
|
|
|
627
810
|
---
|
|
@@ -643,20 +826,19 @@ Rowpipe uses standardized POSIX exit codes:
|
|
|
643
826
|
|
|
644
827
|
## Memory & Performance Benchmarks
|
|
645
828
|
|
|
646
|
-
### 1.
|
|
647
|
-
|
|
648
|
-
| Dataset Size | Throughput | Execution Time | Peak RSS Memory | Memory Scaling |
|
|
649
|
-
|--------------|------------|----------------|-----------------|----------------|
|
|
650
|
-
| **100,000 rows** | **~318,000 rows/s** | 0.31s | ~106 MB | $O(1)$ Bounded |
|
|
651
|
-
| **1,000,000 rows** | **~500,000 rows/s** | 2.00s | ~153 MB | $O(1)$ Bounded |
|
|
652
|
-
|
|
653
|
-
### 2. Diff Engine Benchmark (`rowpipe diff`):
|
|
829
|
+
### 1. Operations Benchmark (`1,000,000 rows`, 47.1 MB CSV):
|
|
654
830
|
|
|
655
|
-
|
|
|
656
|
-
|
|
657
|
-
| **
|
|
831
|
+
| Scenario | Throughput | Elapsed Time | Peak RSS Memory | Memory Scaling |
|
|
832
|
+
|----------|------------|--------------|-----------------|----------------|
|
|
833
|
+
| **Limit 100** (Early Stream Cancel) | **Instant** | 0.01s | ~492 MB | $O(1)$ Early Termination |
|
|
834
|
+
| **Tail 100** (Bounded RingBuffer) | **1,029,866 rows/s** (48.5 MB/s) | 0.97s | ~514 MB | $O(N)$ Bounded |
|
|
835
|
+
| **Top-100** (Bounded Min-Heap) | **731,529 rows/s** (34.4 MB/s) | 1.37s | ~530 MB | $O(K)$ Bounded |
|
|
836
|
+
| **Count + Distinct** (Streaming HLL) | **764,526 rows/s** (36.0 MB/s) | 1.31s | ~530 MB | $O(1)$ Bounded |
|
|
837
|
+
| **Group-by** (Sum/Avg/Min/Max) | **611,995 rows/s** (28.8 MB/s) | 1.63s | ~516 MB | $O(1)$ Stream Hash |
|
|
838
|
+
| **Unique** (Composite Deduplication) | **532,481 rows/s** (25.1 MB/s) | 1.88s | ~516 MB | Spillable Hash |
|
|
839
|
+
| **External Merge Sort** (16MB threshold) | **73,185 rows/s** (3.4 MB/s) | 13.66s | ~606 MB | Spillable $K$-Way Merge |
|
|
658
840
|
|
|
659
|
-
###
|
|
841
|
+
### 2. Filesystem Streaming Benchmark (`rowpipe files`):
|
|
660
842
|
|
|
661
843
|
| File Count | Operation | Throughput | Peak RSS Memory | Memory Scaling |
|
|
662
844
|
|------------|-----------|------------|-----------------|----------------|
|
|
@@ -668,6 +850,7 @@ To run the benchmarks locally:
|
|
|
668
850
|
|
|
669
851
|
```bash
|
|
670
852
|
npm run bench
|
|
853
|
+
npm run benchmark:ops
|
|
671
854
|
npm run benchmark:diff
|
|
672
855
|
npm run benchmark:files
|
|
673
856
|
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CountCommandOptions {
|
|
2
|
+
by?: string | string[];
|
|
3
|
+
distinct?: string;
|
|
4
|
+
approx?: boolean;
|
|
5
|
+
from?: string;
|
|
6
|
+
sheet?: string;
|
|
7
|
+
delimiter?: string;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
quiet?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function countCommand(inputPath?: string, options?: CountCommandOptions): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=count.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"count.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/count.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,mBAAmB;IAClC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,YAAY,CAChC,SAAS,SAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAmDf"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createReader, inferFormatFromPath as inferReaderFormat } from "../../readers/index.js";
|
|
2
|
+
import { countStream } from "../../transforms/count.js";
|
|
3
|
+
import { openReadableStream } from "../../utils/compression.js";
|
|
4
|
+
import { formatNumber, formatTable } from "../../utils/formatting.js";
|
|
5
|
+
export async function countCommand(inputPath = "-", options = {}) {
|
|
6
|
+
let fromFormat = options.from?.toLowerCase();
|
|
7
|
+
if (!fromFormat && inputPath !== "-") {
|
|
8
|
+
fromFormat = inferReaderFormat(inputPath) ?? undefined;
|
|
9
|
+
}
|
|
10
|
+
if (!fromFormat) {
|
|
11
|
+
fromFormat = "csv";
|
|
12
|
+
}
|
|
13
|
+
const inputStream = openReadableStream(inputPath);
|
|
14
|
+
const reader = createReader(inputStream, {
|
|
15
|
+
format: fromFormat,
|
|
16
|
+
sheet: options.sheet,
|
|
17
|
+
delimiter: options.delimiter,
|
|
18
|
+
batchSize: 5000,
|
|
19
|
+
filePath: inputPath,
|
|
20
|
+
});
|
|
21
|
+
const result = await countStream(reader.read(), {
|
|
22
|
+
by: options.by,
|
|
23
|
+
distinct: options.distinct,
|
|
24
|
+
approx: options.approx,
|
|
25
|
+
json: options.json,
|
|
26
|
+
});
|
|
27
|
+
if (options.json) {
|
|
28
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (options.by && result.groups) {
|
|
32
|
+
const headers = ["group", "count"];
|
|
33
|
+
const rows = result.groups.map((g) => {
|
|
34
|
+
const keyStr = Object.entries(g.key)
|
|
35
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
36
|
+
.join(", ");
|
|
37
|
+
return [keyStr, formatNumber(g.count)];
|
|
38
|
+
});
|
|
39
|
+
process.stdout.write(formatTable(headers, rows, ["left", "right"]) + "\n");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (options.distinct) {
|
|
43
|
+
const approxPrefix = result.isApproximate ? "~" : "";
|
|
44
|
+
process.stdout.write(`distinct ${options.distinct}: ${approxPrefix}${formatNumber(result.distinctCount ?? 0)}\n`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
process.stdout.write(`${formatNumber(result.totalRows)}\n`);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=count.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"count.js","sourceRoot":"","sources":["../../../src/cli/commands/count.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,IAAI,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAatE,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAAS,GAAG,GAAG,EACf,UAA+B,EAAE;IAEjC,IAAI,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;IAC7C,IAAI,CAAC,UAAU,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;QACrC,UAAU,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC;IACzD,CAAC;IACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE;QACvC,MAAM,EAAE,UAAU;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,SAAS;KACpB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;QAC9C,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7D,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACnC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;iBACjC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;iBAC5B,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,YAAY,OAAO,CAAC,QAAQ,KAAK,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC,IAAI,CAC5F,CAAC;QACF,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAEtF,wBAAsB,cAAc,CAClC,SAAS,SAAM,EACf,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { formatExecutionPlan, optimizePipeline } from "../../planner/index.js";
|
|
2
|
+
import { buildOperationsFromOptions } from "./pipeline.js";
|
|
3
|
+
export async function explainCommand(inputPath = "-", options = {}) {
|
|
4
|
+
const operations = buildOperationsFromOptions(options);
|
|
5
|
+
const plan = optimizePipeline(operations);
|
|
6
|
+
const inputDesc = inputPath === "-" ? "Stdin Stream" : `Reader (${inputPath})`;
|
|
7
|
+
const outputDesc = options.output ? `Writer (${options.output})` : "Stdout Writer";
|
|
8
|
+
const formatted = formatExecutionPlan(plan, inputDesc, outputDesc);
|
|
9
|
+
process.stdout.write(formatted);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=explain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAA6B,MAAM,eAAe,CAAC;AAEtF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAS,GAAG,GAAG,EACf,UAAqC,EAAE;IAEvC,MAAM,UAAU,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAG,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,SAAS,GAAG,CAAC;IAC/E,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC;IAEnF,MAAM,SAAS,GAAG,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { UnifiedPipelineCliOptions } from "./pipeline.js";
|
|
1
2
|
import type { FileTypeFilter } from "../../files/types.js";
|
|
2
3
|
import { DiffCommandOptions } from "./diff.js";
|
|
3
|
-
export interface FilesCommandOptions {
|
|
4
|
+
export interface FilesCommandOptions extends UnifiedPipelineCliOptions {
|
|
4
5
|
recursive?: boolean;
|
|
5
6
|
maxDepth?: string | number;
|
|
6
7
|
include?: string | string[];
|
|
@@ -10,6 +11,7 @@ export interface FilesCommandOptions {
|
|
|
10
11
|
type?: FileTypeFilter;
|
|
11
12
|
hash?: string | false;
|
|
12
13
|
mime?: boolean;
|
|
14
|
+
human?: boolean;
|
|
13
15
|
concurrency?: string | number;
|
|
14
16
|
onError?: "fail" | "skip";
|
|
15
17
|
to?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/files.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAGtF,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,sBAAsB,CAAC;AAK1E,OAAO,EAAe,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE5D,MAAM,WAAW,mBAAoB,SAAQ,yBAAyB;IACpE,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,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,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,CAmEf;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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildOperationsFromOptions } from "./pipeline.js";
|
|
2
|
+
import { executePlannedPipeline, optimizePipeline } from "../../planner/index.js";
|
|
2
3
|
import { FileSystemReader } from "../../files/reader.js";
|
|
3
4
|
import { createWriter, inferFormatFromPath as inferWriterFormat } from "../../writers/index.js";
|
|
4
5
|
import { openWritableStream } from "../../utils/compression.js";
|
|
@@ -37,11 +38,14 @@ export async function filesCommand(targetPath = ".", options = {}) {
|
|
|
37
38
|
type: options.type ?? "file",
|
|
38
39
|
hash: hashAlgo,
|
|
39
40
|
mime: options.mime ?? false,
|
|
41
|
+
human: options.human ?? false,
|
|
40
42
|
concurrency,
|
|
41
43
|
onError: options.onError ?? "fail",
|
|
42
44
|
deterministic: options.deterministic ?? false,
|
|
43
45
|
batchSize: effectiveBatchSize,
|
|
44
46
|
});
|
|
47
|
+
const operations = buildOperationsFromOptions(options);
|
|
48
|
+
const plan = optimizePipeline(operations);
|
|
45
49
|
// Determine output format
|
|
46
50
|
let toFormat = options.to?.toLowerCase();
|
|
47
51
|
if (options.json) {
|
|
@@ -59,7 +63,7 @@ export async function filesCommand(targetPath = ".", options = {}) {
|
|
|
59
63
|
format: toFormat,
|
|
60
64
|
});
|
|
61
65
|
const progress = new ProgressReporter(options);
|
|
62
|
-
const pipeline =
|
|
66
|
+
const pipeline = executePlannedPipeline(reader, plan, { batchSize: effectiveBatchSize });
|
|
63
67
|
pipeline.onProgress((info) => progress.update(info));
|
|
64
68
|
await pipeline.to(writer);
|
|
65
69
|
progress.done();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/cli/commands/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/cli/commands/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAA6B,MAAM,eAAe,CAAC;AACtF,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,mBAAmB,IAAI,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAsB,MAAM,WAAW,CAAC;AAwB5D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,UAAU,GAAG,GAAG,EAChB,UAA+B,EAAE;IAEjC,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IAC7D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACvF,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhG,IAAI,QAAQ,GAA0B,KAAK,CAAC;IAC5C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACnD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACxD,QAAQ,GAAG,OAAwB,CAAC;QACtC,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;QAC7B,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxE,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;QAC7B,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxE,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC;QAClC,IAAI,EAAE,UAAU;QAChB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI;QACpC,QAAQ;QACR,OAAO;QACP,OAAO;QACP,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;QAC/B,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,KAAK;QAC/C,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,MAAM;QAC5B,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;QAC3B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK;QAC7B,WAAW;QACX,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,MAAM;QAClC,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,KAAK;QAC7C,SAAS,EAAE,kBAAkB;KAC9B,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAE1C,0BAA0B;IAC1B,IAAI,QAAQ,GAAG,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,QAAQ,GAAG,MAAM,CAAC;IACpB,CAAC;SAAM,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACjE,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,KAAK,CAAC;IACnB,CAAC;IAED,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC;IAC9C,MAAM,YAAY,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,YAAY,CAAC,YAAY,EAAE;QACxC,MAAM,EAAE,QAAQ;KACjB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,sBAAsB,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACzF,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAErD,MAAM,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChB,cAAc,EAAE,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,UAAU,GAAG,GAAG,EAChB,UAA+B,EAAE;IAEjC,MAAM,eAAe,GAAwB;QAC3C,GAAG,OAAO;QACV,aAAa,EAAE,IAAI;QACnB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ;QAC9B,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;KACpD,CAAC;IAEF,MAAM,YAAY,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,SAAiB,EACjB,UAAoD,EAAE;IAEtD,MAAM,QAAQ,GAAuB;QACnC,GAAG,OAAO;QACV,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,OAAO;QAClB,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,eAAe;QACnC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,oCAAoC;KAC/D,CAAC;IAEF,MAAM,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GroupOptions } from "../../transforms/group.js";
|
|
2
|
+
export interface GroupCommandOptions extends Omit<GroupOptions, "batchSize"> {
|
|
3
|
+
from?: string;
|
|
4
|
+
to?: string;
|
|
5
|
+
sheet?: string;
|
|
6
|
+
delimiter?: string;
|
|
7
|
+
batchSize?: string | number;
|
|
8
|
+
quiet?: boolean;
|
|
9
|
+
noProgress?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function groupCommand(inputPath?: string, options?: GroupCommandOptions): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/group.ts"],"names":[],"mappings":"AAGA,OAAO,EAAa,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAKpE,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,YAAY,CAChC,SAAS,SAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAkDf"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createPipeline } from "../../core/pipeline.js";
|
|
2
|
+
import { createReader, inferFormatFromPath as inferReaderFormat } from "../../readers/index.js";
|
|
3
|
+
import { createWriter } from "../../writers/index.js";
|
|
4
|
+
import { groupRows } from "../../transforms/group.js";
|
|
5
|
+
import { openReadableStream } from "../../utils/compression.js";
|
|
6
|
+
import { logMemoryDebug } from "../../utils/formatting.js";
|
|
7
|
+
import { ProgressReporter } from "../../utils/progress.js";
|
|
8
|
+
export async function groupCommand(inputPath = "-", options = {}) {
|
|
9
|
+
const effectiveBatchSize = Number(options.batchSize) || 1000;
|
|
10
|
+
const progress = new ProgressReporter(options);
|
|
11
|
+
let fromFormat = options.from?.toLowerCase();
|
|
12
|
+
if (!fromFormat && inputPath !== "-") {
|
|
13
|
+
fromFormat = inferReaderFormat(inputPath) ?? undefined;
|
|
14
|
+
}
|
|
15
|
+
if (!fromFormat) {
|
|
16
|
+
fromFormat = "csv";
|
|
17
|
+
}
|
|
18
|
+
const toFormat = options.to?.toLowerCase() || (fromFormat === "xlsx" ? "csv" : fromFormat);
|
|
19
|
+
const inputStream = openReadableStream(inputPath);
|
|
20
|
+
const reader = createReader(inputStream, {
|
|
21
|
+
format: fromFormat,
|
|
22
|
+
sheet: options.sheet,
|
|
23
|
+
delimiter: options.delimiter,
|
|
24
|
+
batchSize: effectiveBatchSize,
|
|
25
|
+
filePath: inputPath,
|
|
26
|
+
});
|
|
27
|
+
const writer = createWriter(process.stdout, {
|
|
28
|
+
format: toFormat,
|
|
29
|
+
delimiter: options.delimiter,
|
|
30
|
+
});
|
|
31
|
+
const pipeline = createPipeline(reader, { batchSize: effectiveBatchSize });
|
|
32
|
+
pipeline.pipe(groupRows({
|
|
33
|
+
by: options.by,
|
|
34
|
+
count: options.count,
|
|
35
|
+
sum: options.sum,
|
|
36
|
+
avg: options.avg,
|
|
37
|
+
min: options.min,
|
|
38
|
+
max: options.max,
|
|
39
|
+
first: options.first,
|
|
40
|
+
last: options.last,
|
|
41
|
+
agg: options.agg,
|
|
42
|
+
memoryLimit: options.memoryLimit,
|
|
43
|
+
tempDir: options.tempDir,
|
|
44
|
+
batchSize: effectiveBatchSize,
|
|
45
|
+
}));
|
|
46
|
+
pipeline.onProgress((info) => progress.update(info));
|
|
47
|
+
await pipeline.to(writer);
|
|
48
|
+
progress.done();
|
|
49
|
+
logMemoryDebug();
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group.js","sourceRoot":"","sources":["../../../src/cli/commands/group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,mBAAmB,IAAI,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAgB,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAY3D,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAAS,GAAG,GAAG,EACf,UAA+B,EAAE;IAEjC,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE/C,IAAI,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;IAC7C,IAAI,CAAC,UAAU,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;QACrC,UAAU,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC;IACzD,CAAC;IACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAE3F,MAAM,WAAW,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE;QACvC,MAAM,EAAE,UAAU;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,kBAAkB;QAC7B,QAAQ,EAAE,SAAS;KACpB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE;QAC1C,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3E,QAAQ,CAAC,IAAI,CACX,SAAS,CAAC;QACR,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS,EAAE,kBAAkB;KAC9B,CAAC,CACH,CAAC;IACF,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAErD,MAAM,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChB,cAAc,EAAE,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { LimitCommandOptions } from "./limit.js";
|
|
2
|
+
export interface HeadCommandOptions extends LimitCommandOptions {
|
|
3
|
+
lines?: string | number;
|
|
4
|
+
n?: string | number;
|
|
5
|
+
}
|
|
6
|
+
export declare function headCommand(inputPath?: string, options?: HeadCommandOptions): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=head.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/head.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;IAC7D,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AAED,wBAAsB,WAAW,CAC/B,SAAS,SAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head.js","sourceRoot":"","sources":["../../../src/cli/commands/head.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,YAAY,CAAC;AAO/D,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAS,GAAG,GAAG,EACf,UAA8B,EAAE;IAEhC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7D,MAAM,YAAY,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface LimitCommandOptions {
|
|
2
|
+
from?: string;
|
|
3
|
+
to?: string;
|
|
4
|
+
sheet?: string;
|
|
5
|
+
delimiter?: string;
|
|
6
|
+
batchSize?: string | number;
|
|
7
|
+
quiet?: boolean;
|
|
8
|
+
noProgress?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function limitCommand(inputPath?: string, count?: number, options?: LimitCommandOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limit.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/limit.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,YAAY,CAChC,SAAS,SAAM,EACf,KAAK,SAAK,EACV,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAqCf"}
|