@jarenjs/linq 0.72.2 → 0.73.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/ARCHITECTURE.md CHANGED
@@ -49,6 +49,10 @@ document (`{ $count: … }`), and `groupBy` packs its default return as
49
49
  `{ key: …, items: [ '$it' ] }` because an object member takes exactly
50
50
  one item.
51
51
 
52
+ The emitter also owns `requireNonNegativeInteger`, the shared count/index guard
53
+ for synchronous and asynchronous sequence windows and positional terminals.
54
+ Both surfaces report the same `JL0005` refusal at their existing call boundary.
55
+
52
56
  ## The typed surface (`types/index.d.ts`)
53
57
 
54
58
  Hand-authored declarations are the public type contract (the runtime
package/docs/DB-CLIENT.md CHANGED
@@ -826,7 +826,7 @@ never builds one; the migration between two of them is
826
826
 
827
827
  ## 7. Cost
828
828
 
829
- `@jarenjs/linq/db` builds to **<!--fact:bundle.db-->627,770<!--/fact--> bytes** as a minified,
829
+ `@jarenjs/linq/db` builds to **<!--fact:bundle.db-->627,769<!--/fact--> bytes** as a minified,
830
830
  tree-shaken ESM bundle — the figure `scripts/check-tree-shaking.js`
831
831
  measures and `npm run test:tree-shaking` reports, published rounded
832
832
  (<!--fact:bundle.db.kb-->628<!--/fact--> kB) beside the other nine subpath prices in
@@ -205,7 +205,7 @@ and the bundle is the byte count the tree-shaking probe builds.
205
205
  | Document | Subpath | Lines | Mapping rows | Worked examples | Refusals | Bundle |
206
206
  |---|---|---:|---:|---:|---:|---:|
207
207
  | [LINQ-FORMAT.md](LINQ-FORMAT.md) | — | 948 | — | — | — | — |
208
- | [QUERY-PEN.md](QUERY-PEN.md) | `.` | 1,725 | 34 | 8 | 15 | 174,188 B |
208
+ | [QUERY-PEN.md](QUERY-PEN.md) | `.` | 1,725 | 34 | 8 | 15 | 174,131 B |
209
209
  | [SCHEMA-PEN.md](SCHEMA-PEN.md) | `./schema` | 1,205 | 82 | 10 | 4 | 36,717 B |
210
210
  | [MODEL-PEN.md](MODEL-PEN.md) | `./model` | 1,092 | 28 | 6 | 3 | 45,143 B |
211
211
  | [JSLT-PEN.md](JSLT-PEN.md) | `./jslt` | 955 | 17 | 8 | 3 | 19,856 B |
@@ -219,7 +219,7 @@ and the bundle is the byte count the tree-shaking probe builds.
219
219
  | [JTLT-PEN.md](JTLT-PEN.md) | `./jtlt` | 83 | 13 | 1 | 2 | 16,725 B |
220
220
  | [PROJECT-PEN.md](PROJECT-PEN.md) | `./project` | 75 | 9 | 1 | 1 | 15,132 B |
221
221
  | [CHARTS-PEN.md](CHARTS-PEN.md) | `./charts` | 94 | 21 | 1 | 1 | 17,014 B |
222
- | [DB-CLIENT.md](DB-CLIENT.md) | `./db` | 893 | 41 | 4 | 2 | 627,770 B |
222
+ | [DB-CLIENT.md](DB-CLIENT.md) | `./db` | 893 | 41 | 4 | 2 | 627,769 B |
223
223
  | **16 documents** | | **12,391** | **371** | **73** | | |
224
224
  <!--/fact-->
225
225
 
@@ -262,7 +262,7 @@ it and each document publishes it. The rounded column is what
262
262
  <!--fact:pens.cost-->
263
263
  | Subpath | Document | Bundle | Rounded |
264
264
  |---|---|---:|---:|
265
- | `@jarenjs/linq` | [QUERY-PEN.md](QUERY-PEN.md) | 174,188 B | 174 kB |
265
+ | `@jarenjs/linq` | [QUERY-PEN.md](QUERY-PEN.md) | 174,131 B | 174 kB |
266
266
  | `@jarenjs/linq/schema` | [SCHEMA-PEN.md](SCHEMA-PEN.md) | 36,717 B | 37 kB |
267
267
  | `@jarenjs/linq/model` | [MODEL-PEN.md](MODEL-PEN.md) | 45,143 B | 45 kB |
268
268
  | `@jarenjs/linq/jslt` | [JSLT-PEN.md](JSLT-PEN.md) | 19,856 B | 20 kB |
@@ -276,7 +276,7 @@ it and each document publishes it. The rounded column is what
276
276
  | `@jarenjs/linq/jtlt` | [JTLT-PEN.md](JTLT-PEN.md) | 16,725 B | 17 kB |
277
277
  | `@jarenjs/linq/project` | [PROJECT-PEN.md](PROJECT-PEN.md) | 15,132 B | 15 kB |
278
278
  | `@jarenjs/linq/charts` | [CHARTS-PEN.md](CHARTS-PEN.md) | 17,014 B | 17 kB |
279
- | `@jarenjs/linq/db` | [DB-CLIENT.md](DB-CLIENT.md) | 627,770 B | 628 kB |
279
+ | `@jarenjs/linq/db` | [DB-CLIENT.md](DB-CLIENT.md) | 627,769 B | 628 kB |
280
280
  <!--/fact-->
281
281
 
282
282
  Read these as prices, not as scores. `./db` is the largest by an order of
package/docs/QUERY-PEN.md CHANGED
@@ -1672,14 +1672,14 @@ are shorter:
1672
1672
  ## 17. Cost
1673
1673
 
1674
1674
  A consumer importing `from` from `@jarenjs/linq` and calling one
1675
- terminal bundles **<!--fact:bundle.chain-->174,188<!--/fact--> bytes** (esbuild, ESM, minified, tree-shaken,
1675
+ terminal bundles **<!--fact:bundle.chain-->174,131<!--/fact--> bytes** (esbuild, ESM, minified, tree-shaken,
1676
1676
  `platform: 'neutral'`). The figure is measured by
1677
1677
  `scripts/check-tree-shaking.js`'s chain probe and compared with this
1678
1678
  section on every `npm run test:tree-shaking`: it is derived, never typed,
1679
1679
  and a stale one is red here rather than wrong in a document somebody
1680
1680
  reads.
1681
1681
 
1682
- Of that, **<!--fact:bundle.chain.own-->40,258<!--/fact--> bytes** are the chain's own modules — `sequence.js`,
1682
+ Of that, **<!--fact:bundle.chain.own-->40,131<!--/fact--> bytes** are the chain's own modules — `sequence.js`,
1683
1683
  `async.js`, `expression.js`, `document.js`, `provider.js`,
1684
1684
  `concurrency.js`, `errors.js` and `schema-of.js`. The remaining ~134 kB
1685
1685
  is the query ENGINE and the core it stands on: a chain's document has to
@@ -1715,7 +1715,7 @@ the reason is worth knowing: a bundler counts a shared module once, and
1715
1715
  the chain and every pen share the expression capture (`expression.js`)
1716
1716
  and the coded errors under it (`errors.js`, and `@jarenjs/core`'s error
1717
1717
  and object helpers). A consumer importing the chain AND the schema pen
1718
- bundles **<!--fact:bundle.chain.withSchemaPen-->198,858<!--/fact--> bytes** — **<!--fact:bundle.chain.shared-->12,047<!--/fact--> bytes** less than the sum of the
1718
+ bundles **<!--fact:bundle.chain.withSchemaPen-->198,801<!--/fact--> bytes** — **<!--fact:bundle.chain.shared-->12,047<!--/fact--> bytes** less than the sum of the
1719
1719
  figure above and [SCHEMA-PEN.md](SCHEMA-PEN.md#7-cost) §7's, which is
1720
1720
  what those shared modules weigh. The probe measures that pair too, so
1721
1721
  the saving is derived like everything else here. What the chain does NOT
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jarenjs/linq",
3
3
  "private": false,
4
- "version": "0.72.2",
4
+ "version": "0.73.0",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./types/index.d.ts",
@@ -104,13 +104,13 @@
104
104
  "prepack": "npm run build:types"
105
105
  },
106
106
  "dependencies": {
107
- "@jarenjs/core": "^0.72.2",
108
- "@jarenjs/json": "^0.72.2"
107
+ "@jarenjs/core": "^0.73.0",
108
+ "@jarenjs/json": "^0.73.0"
109
109
  },
110
110
  "peerDependencies": {
111
- "@jarenjs/db": "^0.72.2",
112
- "@jarenjs/formats": "^0.72.2",
113
- "@jarenjs/validate": "^0.72.2"
111
+ "@jarenjs/db": "^0.73.0",
112
+ "@jarenjs/formats": "^0.73.0",
113
+ "@jarenjs/validate": "^0.73.0"
114
114
  },
115
115
  "peerDependenciesMeta": {
116
116
  "@jarenjs/db": {
package/src/async.js CHANGED
@@ -45,7 +45,7 @@ import {
45
45
  } from './provider.js';
46
46
  import {
47
47
  emitDocument, wrapTerminal, snapshot, fanProjection, isReservedBinding, RESERVED_BINDINGS_TEXT,
48
- PROJECTING_STAGES,
48
+ PROJECTING_STAGES, requireNonNegativeInteger,
49
49
  } from './document.js';
50
50
  import { adaptAsyncSource } from './sources.js';
51
51
  import { applyMapAsync, normalizeMapAsyncOptions } from './concurrency.js';
@@ -369,8 +369,8 @@ export class AsyncSequence {
369
369
  }, params);
370
370
  }
371
371
 
372
- skip(count) { return this.#with({ kind: 'skip', count: requireIndex(count, 'skip') }); }
373
- take(count) { return this.#with({ kind: 'take', count: requireIndex(count, 'take') }); }
372
+ skip(count) { return this.#with({ kind: 'skip', count: requireNonNegativeInteger(count, 'skip') }); }
373
+ take(count) { return this.#with({ kind: 'take', count: requireNonNegativeInteger(count, 'take') }); }
374
374
  distinct() { return this.#with({ kind: 'distinct' }); }
375
375
  reverse() { return this.#with({ kind: 'reverse' }); }
376
376
 
@@ -722,7 +722,7 @@ export class AsyncSequence {
722
722
 
723
723
  /** @param {number} index */
724
724
  async elementAt(index) {
725
- requireIndex(index, 'elementAt');
725
+ requireNonNegativeInteger(index, 'elementAt');
726
726
  const w = this.#pushable()
727
727
  ? await this.#pushWindow('elementAt', [index]) : await this.skip(index).#window(1);
728
728
  if (w.length === 0) throw new LinqRuntimeError('JL2003', `elementAt(${index}) is out of range`);
@@ -731,7 +731,7 @@ export class AsyncSequence {
731
731
 
732
732
  /** @param {number} index @param {any} [defaultValue] */
733
733
  async elementAtOrDefault(index, defaultValue) {
734
- requireIndex(index, 'elementAtOrDefault');
734
+ requireNonNegativeInteger(index, 'elementAtOrDefault');
735
735
  const w = this.#pushable()
736
736
  ? await this.#pushWindow('elementAt', [index]) : await this.skip(index).#window(1);
737
737
  return w.length === 0 ? defaultValue : w[0];
@@ -832,14 +832,6 @@ async function collect(stream) {
832
832
  return out;
833
833
  }
834
834
 
835
- /** @param {number} value @param {string} what */
836
- function requireIndex(value, what) {
837
- if (!Number.isInteger(value) || value < 0) {
838
- throw new LinqBuildError('JL0005', `${what} takes a non-negative integer, got ${value}`);
839
- }
840
- return value;
841
- }
842
-
843
835
  /** @param {any} bindings */
844
836
  function validateParams(bindings) {
845
837
  if (bindings === null || typeof bindings !== 'object' || Array.isArray(bindings)) {
package/src/db/ledger.js CHANGED
@@ -132,7 +132,8 @@ export function createDbLedger(client, options = {}) {
132
132
  return inside(async (tx) => {
133
133
  const c = rows(tx);
134
134
  const record = await c.get(r.id);
135
- if (record === undefined || record.generation !== r.generation || record.status !== 'started') {
135
+ if (record === undefined || record.generation !== r.generation || record.status !== 'started'
136
+ || record.expiresAt <= at) {
136
137
  throw stale(ref, 'the key expired, was reclaimed under a newer generation, or was settled already');
137
138
  }
138
139
  await c.put({ ...record, ...changes, updatedAt: at }, r.id);
package/src/document.js CHANGED
@@ -39,6 +39,19 @@
39
39
 
40
40
  import { LinqBuildError } from './errors.js';
41
41
 
42
+ /**
43
+ * Validate a sequence window's count or a positional terminal's index.
44
+ * @param {number} value
45
+ * @param {string} what - The operator named by a refusal
46
+ * @returns {number} The unchanged count or index
47
+ */
48
+ export function requireNonNegativeInteger(value, what) {
49
+ if (!Number.isInteger(value) || value < 0) {
50
+ throw new LinqBuildError('JL0005', `${what} takes a non-negative integer, got ${value}`);
51
+ }
52
+ return value;
53
+ }
54
+
42
55
  /** The binding names the emitted documents own (QUERY-PEN §7): the
43
56
  * item bindings, the accumulator and the group — and the relation-hop
44
57
  * bindings `r1`, `r2`, … a capture allocates (expression.js). A
package/src/sequence.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  } from './expression.js';
21
21
  import {
22
22
  emitDocument, wrapTerminal, snapshot, fanProjection, isReservedBinding, RESERVED_BINDINGS_TEXT,
23
- PROJECTING_STAGES,
23
+ PROJECTING_STAGES, requireNonNegativeInteger,
24
24
  } from './document.js';
25
25
  import {
26
26
  classifySource, compileDocument, executeInMemory, providerRoot, providerRelations, sharesScope,
@@ -31,14 +31,6 @@ import { schemaOf } from './schema-of.js';
31
31
 
32
32
  const VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
33
33
 
34
- /** @param {number} value @param {string} what */
35
- function requireIndex(value, what) {
36
- if (!Number.isInteger(value) || value < 0) {
37
- throw new LinqBuildError('JL0005', `${what} takes a non-negative integer, got ${value}`);
38
- }
39
- return value;
40
- }
41
-
42
34
  /** The immutable query sequence. Construct via `from`/`fromDocument`. */
43
35
  export class Sequence {
44
36
  #source;
@@ -315,11 +307,11 @@ export class Sequence {
315
307
  }
316
308
 
317
309
  skip(count) {
318
- return this.#with({ kind: 'skip', count: requireIndex(count, 'skip') });
310
+ return this.#with({ kind: 'skip', count: requireNonNegativeInteger(count, 'skip') });
319
311
  }
320
312
 
321
313
  take(count) {
322
- return this.#with({ kind: 'take', count: requireIndex(count, 'take') });
314
+ return this.#with({ kind: 'take', count: requireNonNegativeInteger(count, 'take') });
323
315
  }
324
316
 
325
317
  distinct() {
@@ -557,7 +549,7 @@ export class Sequence {
557
549
  }
558
550
 
559
551
  elementAt(index) {
560
- requireIndex(index, 'elementAt');
552
+ requireNonNegativeInteger(index, 'elementAt');
561
553
  const w = this.#window('elementAt', [index]);
562
554
  if (w.length === 0) throw new LinqRuntimeError('JL2003', `elementAt(${index}) is out of range`);
563
555
  return w[0];
@@ -565,7 +557,7 @@ export class Sequence {
565
557
 
566
558
  /** @param {number} index @param {any} [defaultValue] */
567
559
  elementAtOrDefault(index, defaultValue) {
568
- requireIndex(index, 'elementAtOrDefault');
560
+ requireNonNegativeInteger(index, 'elementAtOrDefault');
569
561
  const w = this.#window('elementAt', [index]);
570
562
  return w.length === 0 ? defaultValue : w[0];
571
563
  }