@inixiative/json-rules 2.21.1 → 2.23.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 +39 -9
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -3
- package/dist/index.d.ts +30 -3
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ check(rule, { age: 16 }); // "Must be 18 or older"
|
|
|
46
46
|
- ordered windowing — first/last `N` with `orderBy` / `take` / `skip` (check-only)
|
|
47
47
|
- date comparisons with timezone-aware runtime evaluation
|
|
48
48
|
- relative & calendar date expressions — "last 30 days", "this month" — via `within` and `ago`/`ahead`/`this`/`last`/`next`
|
|
49
|
-
- relative value references via `path
|
|
49
|
+
- relative value references via `path`, and `$$.` scope refs up through nested arrays
|
|
50
50
|
- custom error messages on every rule
|
|
51
51
|
- compilation to Prisma and PostgreSQL for supported subsets
|
|
52
52
|
|
|
@@ -332,22 +332,43 @@ In runtime validation, a plain path is resolved from the root context:
|
|
|
332
332
|
}
|
|
333
333
|
```
|
|
334
334
|
|
|
335
|
-
###
|
|
335
|
+
### Scope References
|
|
336
336
|
|
|
337
|
-
Inside array
|
|
337
|
+
Inside an array operator's `condition` or `filter`, `$.` reads from the current element.
|
|
338
|
+
Each additional `$` reaches one enclosing element further out: `$$.` is the element of the
|
|
339
|
+
enclosing array operator, `$$$.` the one above that, up to the root row. Logical
|
|
340
|
+
combinators (`all` / `any` / `if`) never add a level — only array and aggregate rules do.
|
|
341
|
+
|
|
342
|
+
Both `field` and `path` take the prefix. A bare `field` is always the current element; a
|
|
343
|
+
bare `path` is always the root context (`options.context`, defaulting to the root row).
|
|
338
344
|
|
|
339
345
|
```ts
|
|
340
346
|
{
|
|
341
347
|
field: 'orders',
|
|
342
348
|
arrayOperator: ArrayOperator.all,
|
|
343
349
|
condition: {
|
|
344
|
-
field: '
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
350
|
+
field: 'lineItems',
|
|
351
|
+
arrayOperator: ArrayOperator.all,
|
|
352
|
+
condition: {
|
|
353
|
+
all: [
|
|
354
|
+
// line item qty against its order's cap
|
|
355
|
+
{ field: 'qty', operator: Operator.lessThanEquals, path: '$$.maxQty' },
|
|
356
|
+
// order cap against the root row's limit — neither side is the line item
|
|
357
|
+
{ field: '$$.maxQty', operator: Operator.lessThanEquals, path: '$$$.orgLimit' },
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
},
|
|
348
361
|
}
|
|
349
362
|
```
|
|
350
363
|
|
|
364
|
+
A ref deeper than the nesting (`$$.` at the top level, `$$$.` one array deep) throws in
|
|
365
|
+
`check()`, is a `scope_out_of_bounds` issue from `validateRule`, and a violation from
|
|
366
|
+
`checkRuleAgainstLens`. A reachable ancestor that lacks the named key fails the comparison
|
|
367
|
+
like any absent field.
|
|
368
|
+
|
|
369
|
+
`toSql()` keeps `path: '$.x'` as a same-row column comparison. Every other scope ref — a
|
|
370
|
+
`$$.` path or any prefixed `field` — is check-only; both compilers throw.
|
|
371
|
+
|
|
351
372
|
## Rule Introspection
|
|
352
373
|
|
|
353
374
|
Reading a stored rule's own content — which values it names, which bindings it needs — is
|
|
@@ -356,9 +377,17 @@ format grows a node type, and it goes blind silently.
|
|
|
356
377
|
|
|
357
378
|
| Function | Purpose |
|
|
358
379
|
| --- | --- |
|
|
359
|
-
| `requiredBindings(rule)` | Names
|
|
380
|
+
| `requiredBindings(rule)` | Names a bindings map must cover — every `{ bind }` token not marked `bindOptional`. A name optional at one leaf and required at another is required. |
|
|
381
|
+
| `bindingNames(rule)` | Every `{ bind }` name in the tree, optional or not — what a lens declares. |
|
|
360
382
|
| `resolveBindings(rule, bindings)` | Substitutes covered binds with their values, leaving uncovered tokens in place (partial resolution). |
|
|
361
383
|
|
|
384
|
+
A leaf may mark its bind optional: `{ field, operator, bind: 'region', bindOptional: true }`. An
|
|
385
|
+
unsupplied required bind is a caller bug — `check()` throws, and both compilers refuse a
|
|
386
|
+
surviving token. An unsupplied *optional* bind is `null` wherever absence is final: `check()`
|
|
387
|
+
compares against `null`, `toPrisma` / `toSql` compile the token as `null`. The rule is evaluated
|
|
388
|
+
as written — the leaf is never pruned, so `in {{bind}}` with nothing bound matches nothing rather
|
|
389
|
+
than everything.
|
|
390
|
+
|
|
362
391
|
|
|
363
392
|
## Runtime Validation
|
|
364
393
|
|
|
@@ -517,6 +546,7 @@ Not every backend supports every rule shape.
|
|
|
517
546
|
| `dayIn` / `dayNotIn` | Yes | No | Yes |
|
|
518
547
|
| Windowing (`orderBy` / `take` / `skip`) | Yes | Extremal (`take:1`, aligned) | No |
|
|
519
548
|
| `path: '$.field'` current-element / same-row refs | Yes | No | Yes |
|
|
549
|
+
| `$$.` scope refs and `$`-prefixed `field` | Yes | No | No |
|
|
520
550
|
|
|
521
551
|
### NULL Semantics
|
|
522
552
|
|
|
@@ -572,7 +602,7 @@ positive operator, ask for them:
|
|
|
572
602
|
|
|
573
603
|
- `matches` and `notMatches` are not supported by Prisma output
|
|
574
604
|
- `dayIn` and `dayNotIn` are not supported by Prisma output
|
|
575
|
-
- `path: '$.field'` column-to-column comparisons are not supported by Prisma `WHERE`
|
|
605
|
+
- `path: '$.field'` column-to-column comparisons are not supported by Prisma `WHERE`; no scope ref (`$$.` path, prefixed `field`) compiles
|
|
576
606
|
- count-based and aggregate relation operators require `{ map, model }`
|
|
577
607
|
- aggregate rules with `notBetween` are not supported by Prisma output
|
|
578
608
|
- aggregate rules on JSON/native stored arrays are not supported by Prisma — use `toSql()` or `check()` for those
|