@vaultgradient/pipequery-lang 1.12.3 → 1.13.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
@@ -5,13 +5,13 @@
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- <a href="https://github.com/andreadito/pipequery/releases/latest"><img src="https://img.shields.io/github/v/release/andreadito/pipequery?label=release&color=orange" alt="release" /></a>
8
+ <a href="https://github.com/Vault-Gradient/pipequery/releases/latest"><img src="https://img.shields.io/github/v/release/Vault-Gradient/pipequery?label=release&color=orange" alt="release" /></a>
9
9
  <a href="https://www.npmjs.com/package/@vaultgradient/pipequery-lang"><img src="https://img.shields.io/npm/v/@vaultgradient/pipequery-lang?label=npm%20%28engine%29&color=cb3837&logo=npm" alt="engine package" /></a>
10
10
  <a href="https://www.npmjs.com/package/@vaultgradient/pipequery-cli"><img src="https://img.shields.io/npm/v/@vaultgradient/pipequery-cli?label=npm%20%28cli%29&color=cb3837&logo=npm" alt="cli package" /></a>
11
- <a href="https://github.com/andreadito/pipequery/pkgs/container/pipequery"><img src="https://img.shields.io/badge/ghcr.io-pipequery-blue?logo=docker" alt="docker" /></a>
12
- <a href="https://github.com/andreadito/pipequery/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license" /></a>
13
- <a href="https://github.com/andreadito/pipequery"><img src="https://img.shields.io/badge/TypeScript-100%25-blue.svg" alt="TypeScript" /></a>
14
- <a href="https://andreadito.github.io/pipequery"><img src="https://img.shields.io/badge/demo-playground-blueviolet.svg" alt="playground" /></a>
11
+ <a href="https://github.com/Vault-Gradient/pipequery/pkgs/container/pipequery"><img src="https://img.shields.io/badge/ghcr.io-pipequery-blue?logo=docker" alt="docker" /></a>
12
+ <a href="https://github.com/Vault-Gradient/pipequery/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license" /></a>
13
+ <a href="https://github.com/Vault-Gradient/pipequery"><img src="https://img.shields.io/badge/TypeScript-100%25-blue.svg" alt="TypeScript" /></a>
14
+ <a href="https://vault-gradient.github.io/pipequery"><img src="https://img.shields.io/badge/demo-playground-blueviolet.svg" alt="playground" /></a>
15
15
  </p>
16
16
 
17
17
  ---
@@ -86,7 +86,7 @@ The server and CLI are fully decoupled — deploy the server anywhere with Docke
86
86
 
87
87
  ```bash
88
88
  # Run the server in Docker
89
- docker run -p 3000:3000 ghcr.io/andreadito/pipequery
89
+ docker run -p 3000:3000 ghcr.io/vault-gradient/pipequery
90
90
 
91
91
  # From any folder on your machine, connect and start working
92
92
  pq remote connect http://localhost:3000
@@ -151,9 +151,8 @@ query(data, 'where(price > 100) | sort(price desc)');
151
151
  query(data, 'rollup(sum(price) as total, count() as n)');
152
152
  // → [{ total: 1377, n: 3 }]
153
153
 
154
- // Group and aggregate
155
- query(data, 'groupBy(category) | rollup(avg(price) as avgPrice)');
156
- // → [{ category: 'Electronics', avgPrice: 514 }, { category: 'Furniture', avgPrice: 349 }]
154
+ // Group and aggregate (one row per category)
155
+ query(data, 'groupBy(category) | select(category, avg(price) as avgPrice)');
157
156
  ```
158
157
 
159
158
  ## Query Syntax
@@ -262,6 +261,18 @@ const ast = parseQuery('items | where(price > 100)');
262
261
  // Inspect tokens, operations, expressions
263
262
  ```
264
263
 
264
+ ### `printQuery(ast)`
265
+
266
+ Print a pipeline AST back to canonical pipequery text. Parentheses are added only where precedence requires them, numbers and strings are escaped, and invalid nodes throw. Use it to inspect or rewrite a parsed query, for example to cap every result.
267
+
268
+ ```ts
269
+ import { parseQuery, printQuery } from '@andreadito/pipequery-lang';
270
+
271
+ const ast = parseQuery('orders | where(total > 100)');
272
+ ast.operations.push({ kind: 'FirstOp', count: 1000 });
273
+ printQuery(ast); // orders | where(total > 100) | first(1000)
274
+ ```
275
+
265
276
  ### `liveQuery(data, expression, options)`
266
277
 
267
278
  Streaming query evaluator that accepts data patches and re-executes efficiently.
@@ -327,6 +338,67 @@ A TextMate grammar is included at `dist/highlighting/textmate/pipequery.tmLangua
327
338
 
328
339
  **Peer dependencies:** `@codemirror/language`, `@codemirror/state`, `@codemirror/view`, `@lezer/highlight` (CodeMirror only)
329
340
 
341
+ ### Typed query builder
342
+
343
+ `@andreadito/pipequery-lang/builder` builds queries in code instead of strings. It is a headless utility, not an ORM: it builds the same AST the parser produces, and `toString()` prints it back with `printQuery`. The builder entry imports nothing from React or MUI.
344
+
345
+ ```ts
346
+ import { from, agg, col } from '@andreadito/pipequery-lang/builder';
347
+ import { query } from '@andreadito/pipequery-lang';
348
+
349
+ type Order = { id: number; customerId: number; total: number; status: string; region: string };
350
+
351
+ const paid = from<Order>('orders')
352
+ .where((o) => o.status.eq('paid'))
353
+ .join('customers', (o, c) => o.customerId.eq(c.id))
354
+ .select((o) => ({ id: o.id, name: o.name, total: o.total }));
355
+
356
+ paid.toString();
357
+ // orders | where(status == "paid") | join(customers, customerId == id) | select(id, name, total)
358
+
359
+ paid.run({ orders, customers }); // rows
360
+ query({ orders, customers }, paid.toString()); // same rows
361
+ ```
362
+
363
+ Terminal aggregates end the pipeline and return a `Scalar`, whose `run()` returns one value:
364
+
365
+ ```ts
366
+ from<Order>('orders').where((o) => o.status.eq('paid')).sum((o) => o.total).run({ orders }); // 160
367
+ ```
368
+
369
+ Grouping works with `rollup` (group keys go inside it) or with `groupBy` followed by `select`:
370
+
371
+ ```ts
372
+ from<Order>('orders').rollup('region', agg.sum(col('total')).as('revenue'));
373
+ // orders | rollup(region, sum(total) as revenue)
374
+
375
+ from<Order>('orders')
376
+ .groupBy('region')
377
+ .select((o) => ({ region: o.region, revenue: agg.sum(o.total) }));
378
+ // orders | groupBy(region) | select(region, sum(total) as revenue)
379
+ ```
380
+
381
+ **Escape hatch.** `.pipe()` accepts raw pipequery operations. They are parsed with the real parser, so a malformed string throws a `ParseError`:
382
+
383
+ ```ts
384
+ from<Order>('orders').pipe('where(total > 100) | first(10)');
385
+ ```
386
+
387
+ **Values are escaped.** `o.status.eq(input)` prints `input` as a string literal, so quotes, backslashes and newlines in user input cannot change the query structure.
388
+
389
+ **Invalid input throws at build time.** Bad identifiers, reserved words, `NaN`/`Infinity`, `first(-1)` and misplaced aliases throw a `BuilderError`.
390
+
391
+ #### Grammar limits
392
+
393
+ - **Identifiers** must match `[A-Za-z_][A-Za-z0-9_]*`. Field and source names with spaces, hyphens or other characters cannot be written, and there is no quoted-identifier syntax yet. `from('my-orders')` throws.
394
+ - **Reserved words** `as asc desc true false null` cannot be names.
395
+ - **Aliases** (`.as(name)`) work in `select`, `map`, `rollup`, `pivot` and `reduce`. They throw in `sort`, `groupBy`, `distinct`, `flatten`, `transpose` and standalone aggregates.
396
+ - **`||` is not supported.** The lexer reads it as two pipes. Use `.or()`, which prints as `if(a, true, b)`.
397
+ - **Window functions** (`win.*`) are allowed only as top-level fields of `select`.
398
+ - **Group keys** go in `rollup(keys, aggs)` or `groupBy(...) | select(...)`. `groupBy(k) | rollup(agg)` returns `null` aggregates in the current engine.
399
+ - **Offsets** for `lag` and `lead` must be integers >= 1.
400
+ - **Numbers** such as `1e21` print as plain decimals. Negative literals print as unary minus (`-5`), which re-parses as `-(5)`.
401
+
330
402
  ### React Components
331
403
 
332
404
  ```tsx
@@ -351,7 +423,7 @@ Works in all modern browsers and Node.js 18+. The core engine uses only standard
351
423
  Contributions are welcome! Please open an issue or submit a pull request.
352
424
 
353
425
  ```bash
354
- git clone https://github.com/andreadito/pipequery.git
426
+ git clone https://github.com/Vault-Gradient/pipequery.git
355
427
  cd pipequery
356
428
  npm install
357
429
  npm test