csvql-query 2.5.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,23 @@
1
1
  # csvql-query
2
2
 
3
- Fast SQL queries on CSV files from Node.js — powered by a Zig/SIMD engine via N-API.
3
+ **SQL on CSV files, in place.** No database, no import, no ingest — point a query at the file where it already lives. A Zig/SIMD engine via N-API, with prebuilt binaries for macOS (arm64/x64), Linux (x64/arm64), and Windows (x64). No compiler needed.
4
4
 
5
- The engine streams through the file instead of loading it into memory, so RAM stays flat — tens of MB — regardless of file size. Prebuilt native binaries ship for macOS (arm64/x64), Linux (x64/arm64), and Windows (x64) — no compiler needed.
5
+ The engine streams the file instead of loading it, so RAM stays flat — tens of MB — regardless of file size.
6
+
7
+ ## Try it without installing anything
8
+
9
+ ```bash
10
+ npx csvql-query "SELECT city, COUNT(*) AS n FROM 'data.csv' GROUP BY city ORDER BY n DESC"
11
+ ```
12
+
13
+ File paths go in single quotes inside `FROM`. `npx csvql-query --help` for the rest.
14
+
15
+ ```bash
16
+ npx csvql-query --json "SELECT * FROM 'sales.csv' WHERE amount > 1000 LIMIT 10"
17
+ npx csvql-query -d '\t' "SELECT * FROM 'data.tsv' LIMIT 3"
18
+ ```
19
+
20
+ Exit codes are meant to be branched on: `0` success, `1` usage error, `2` query error, `3` file/IO error.
6
21
 
7
22
  ## Install
8
23
 
@@ -69,9 +84,35 @@ Operators in `where`: `= != > >= < <=`, combined with `AND` / `OR`. Values are a
69
84
 
70
85
  `opts`: `{ delimiter, comment, skipEmptyLines }`. TypeScript declarations are bundled.
71
86
 
87
+ ## For AI agents (MCP)
88
+
89
+ Pasting a 417 MB CSV into an LLM costs ~230 million tokens — it fits in no context window. Over [MCP](https://modelcontextprotocol.io/), an agent queries the file in place and gets back only the answer, for a few hundred tokens.
90
+
91
+ The MCP server ships in the standalone binary rather than this package:
92
+
93
+ ```bash
94
+ brew install melihbirim/csvql/csvql
95
+ csvql install # registers csvql with Claude Code + Claude Desktop
96
+ ```
97
+
98
+ There's also a one-click `.mcpb` extension for Claude Desktop on the [releases page](https://github.com/melihbirim/csvql/releases). Full setup — VS Code Copilot, Claude Desktop, manual config — in the [main README](https://github.com/melihbirim/csvql#mcp).
99
+
100
+ **Read-only by design.** csvql only runs `SELECT`. It has no `INSERT`/`UPDATE`/`DELETE`/`DROP` and physically cannot modify your data. It makes zero network calls and runs fully air-gapped, so you can put it next to the data instead of shipping files out to an LLM.
101
+
102
+ ## Correctness
103
+
104
+ csvql treats [DuckDB](https://duckdb.org) as the reference implementation and diffs its own output against it — because an agent can't eyeball a wrong answer the way a human scanning a spreadsheet can.
105
+
106
+ - **97 differential checks** against DuckDB on every PR, across Linux x86_64 and macOS ARM
107
+ - **553 unit tests**
108
+ - **A differential query generator** runs ~50,000 generated queries against DuckDB nightly; every run appends a row to a public [verification log](https://github.com/melihbirim/csvql/blob/main/VERIFICATION-LOG.md) — wins and losses both
109
+ - Where behavior intentionally differs from DuckDB, it's [documented and audited](https://github.com/melihbirim/csvql/blob/main/CORRECTNESS.md), not hand-waved
110
+
111
+ Unsupported SQL **errors clearly** rather than silently returning wrong data. That distinction is the entire point.
112
+
72
113
  ## Supported SQL
73
114
 
74
- `SELECT`, `WHERE`, `GROUP BY`, `ORDER BY`, `LIMIT`, `JOIN`, `DISTINCT`, `LIKE`, and `COUNT` / `SUM` / `AVG` / `MIN` / `MAX`.
115
+ `SELECT`, `WHERE`, `GROUP BY`, `HAVING`, `ORDER BY`, `LIMIT`, `JOIN`, `DISTINCT`, `LIKE`, `BETWEEN`, `IN` (including `IN (SELECT ...)` subqueries), `COUNT`/`SUM`/`AVG`/`MIN`/`MAX`, and scalar functions (`UPPER`, `LOWER`, `TRIM`, `LENGTH`, `SUBSTR`, `REPLACE`, `COALESCE`, `CAST`, `ROUND`, …).
75
116
 
76
117
  ## License
77
118
 
Binary file
Binary file
Binary file
Binary file
Binary file
package/cli.js ADDED
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // csvql-query CLI — the zero-install entry point.
5
+ //
6
+ // npx csvql-query "SELECT city, COUNT(*) FROM 'data.csv' GROUP BY city"
7
+ //
8
+ // This exists so someone can try csvql in one line without adding a
9
+ // dependency or writing a script. It is a thin wrapper over the same N-API
10
+ // module index.js exports — no query logic lives here, so it cannot drift
11
+ // from the library.
12
+ //
13
+ // For the MCP server (what an AI agent connects to), install the standalone
14
+ // binary: `brew install melihbirim/csvql/csvql` then `csvql install`. That
15
+ // server lives in the Zig binary, not in this package — see --help.
16
+
17
+ const csvql = require('./index.js');
18
+
19
+ const VERSION = require('./package.json').version;
20
+
21
+ const HELP = `csvql-query ${VERSION} — SQL on CSV files, in place
22
+
23
+ USAGE
24
+ npx csvql-query [options] "<SQL>"
25
+
26
+ File paths go in single quotes inside the FROM clause:
27
+ npx csvql-query "SELECT * FROM 'data.csv' LIMIT 5"
28
+
29
+ OPTIONS
30
+ -j, --json Output JSON instead of CSV
31
+ -d, --delimiter <c> Input delimiter (e.g. -d '\\t' for TSV)
32
+ -c, --comment <s> Skip lines starting with <s>
33
+ -s, --skip-empty Skip blank lines
34
+ -h, --help Show this help
35
+ -v, --version Show version
36
+
37
+ EXAMPLES
38
+ npx csvql-query "SELECT * FROM 'sales.csv' WHERE amount > 1000 LIMIT 10"
39
+ npx csvql-query "SELECT region, SUM(amount) FROM 'sales.csv' GROUP BY region"
40
+ npx csvql-query --json "SELECT COUNT(*) AS n FROM 'sales.csv'"
41
+ npx csvql-query -d '\\t' "SELECT * FROM 'data.tsv' LIMIT 3"
42
+
43
+ SUPPORTED SQL
44
+ SELECT, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, JOIN, DISTINCT, LIKE,
45
+ IN (incl. subqueries), BETWEEN, COUNT/SUM/AVG/MIN/MAX, and scalar functions.
46
+ Read-only: there is no INSERT/UPDATE/DELETE/DROP.
47
+
48
+ FOR AI AGENTS (MCP)
49
+ This package is the Node library + CLI. The MCP server ships in the
50
+ standalone binary so an agent can query a multi-GB CSV for a few hundred
51
+ tokens instead of pasting it into context:
52
+
53
+ brew install melihbirim/csvql/csvql # or grab a release binary
54
+ csvql install # registers it with Claude
55
+
56
+ https://github.com/melihbirim/csvql#mcp
57
+
58
+ EXIT CODES
59
+ 0 success 1 usage error 2 query error 3 file/IO error
60
+ `;
61
+
62
+ function fail(code, msg) {
63
+ process.stderr.write(`csvql-query: ${msg}\n`);
64
+ process.exit(code);
65
+ }
66
+
67
+ function parseArgs(argv) {
68
+ const opts = {};
69
+ let sql = null;
70
+ let json = false;
71
+
72
+ for (let i = 0; i < argv.length; i++) {
73
+ const a = argv[i];
74
+ const needsValue = (name) => {
75
+ const v = argv[++i];
76
+ if (v === undefined) fail(1, `${name} requires a value`);
77
+ return v;
78
+ };
79
+
80
+ switch (a) {
81
+ case '-h':
82
+ case '--help':
83
+ process.stdout.write(HELP);
84
+ process.exit(0);
85
+ break;
86
+ case '-v':
87
+ case '--version':
88
+ process.stdout.write(`${VERSION}\n`);
89
+ process.exit(0);
90
+ break;
91
+ case '-j':
92
+ case '--json':
93
+ json = true;
94
+ break;
95
+ case '-d':
96
+ case '--delimiter':
97
+ // Accept a literal backslash-t from the shell as a real tab, so
98
+ // `-d '\t'` works without the caller needing $'\t' quoting.
99
+ opts.delimiter = needsValue(a).replace(/\\t/g, '\t');
100
+ break;
101
+ case '-c':
102
+ case '--comment':
103
+ opts.comment = needsValue(a);
104
+ break;
105
+ case '-s':
106
+ case '--skip-empty':
107
+ opts.skipEmptyLines = true;
108
+ break;
109
+ default:
110
+ if (a.startsWith('-') && a !== '-') fail(1, `unknown option: ${a}`);
111
+ if (sql !== null) fail(1, 'more than one SQL statement given (quote the whole query)');
112
+ sql = a;
113
+ }
114
+ }
115
+
116
+ return { sql, opts, json };
117
+ }
118
+
119
+ function main() {
120
+ const { sql, opts, json } = parseArgs(process.argv.slice(2));
121
+
122
+ if (sql === null || sql.trim() === '') {
123
+ process.stderr.write(HELP);
124
+ process.exit(1);
125
+ }
126
+
127
+ let out;
128
+ try {
129
+ out = json ? JSON.stringify(csvql.query(sql, opts), null, 2) : csvql.queryCsv(sql, opts);
130
+ } catch (err) {
131
+ // Distinguish "your file is missing" from "your SQL is wrong" so a
132
+ // script (or an agent) can branch on it, matching the standalone
133
+ // binary's exit-code contract.
134
+ const msg = String((err && err.message) || err);
135
+ const isIO = /ENOENT|no such file|FileNotFound|cannot open|EmptyFile/i.test(msg);
136
+ fail(isIO ? 3 : 2, msg);
137
+ }
138
+
139
+ process.stdout.write(out.endsWith('\n') ? out : out + '\n');
140
+ }
141
+
142
+ main();
package/package.json CHANGED
@@ -1,17 +1,22 @@
1
1
  {
2
2
  "name": "csvql-query",
3
- "version": "2.5.0",
4
- "description": "Fast SQL queries on CSV files — Zig/SIMD engine via N-API",
3
+ "version": "2.6.1",
4
+ "description": "SQL on CSV files in place — no import, no database. Zig/SIMD engine for Node and AI agents (MCP). Read-only by design.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
+ "bin": {
8
+ "csvql-query": "cli.js"
9
+ },
7
10
  "files": [
8
11
  "index.js",
9
12
  "index.d.ts",
13
+ "cli.js",
10
14
  "binaries/"
11
15
  ],
12
16
  "scripts": {
13
17
  "build": "zig build node -Doptimize=ReleaseFast && mkdir -p binaries && cp ../zig-out/lib/csvql.node binaries/$(node -p \"process.platform + '-' + process.arch\").node",
14
18
  "test": "node test.js",
19
+ "test:cli": "node test_cli.js",
15
20
  "bench": "node bench.js"
16
21
  },
17
22
  "keywords": [
@@ -24,7 +29,12 @@
24
29
  "parser",
25
30
  "agent",
26
31
  "ai",
27
- "mcp"
32
+ "mcp",
33
+ "llm",
34
+ "cli",
35
+ "duckdb",
36
+ "analytics",
37
+ "dataframe"
28
38
  ],
29
39
  "license": "MIT",
30
40
  "repository": {