@inixiative/json-rules 3.4.0 → 3.4.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 +44 -17
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -13
- package/dist/index.d.ts +32 -13
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1228,8 +1228,7 @@ const [query] = toSourceQueries(narrowing);
|
|
|
1228
1228
|
// query.composedWhere => the node's `where` AND the source's eligibility, narrowed as a rule is
|
|
1229
1229
|
// query.prisma => { model: 'User', distinct: ['region'], select: { region: true }, where: { AND: [...] } }
|
|
1230
1230
|
// query.sql => { sql: 'SELECT DISTINCT "t0"."region" FROM "User" AS "t0" WHERE (...)', params: ['t-42', true] }
|
|
1231
|
-
//
|
|
1232
|
-
if (query.prisma === null) throw new Error(query.sql.error);
|
|
1231
|
+
// A query with `recheck` (a source across a bridge) returns candidates; see "Sources across a bridge".
|
|
1233
1232
|
const { distinct, select, where } = query.prisma;
|
|
1234
1233
|
const rows = await prisma.user.findMany({ distinct, select, where });
|
|
1235
1234
|
const values = materializeSourceQuery(query, rows); // { path, mapName, model, field, options: [{ value }] }
|
|
@@ -1243,8 +1242,8 @@ const projection = projectLens(narrowing, { sourceValues: [values] });
|
|
|
1243
1242
|
|
|
1244
1243
|
| Function | Purpose |
|
|
1245
1244
|
| --- | --- |
|
|
1246
|
-
| `toSourceQueries(lensOrNarrowing, options?)` | `SourceQuery[]`, one per sourced field: `{ path, mapName, model, field, label?, groupBy?, composedWhere, prisma, sql }`. `options` is the clock (`now`, `timeZone`, `weekStart`) a relative date in the where compiles with — required for one, a plain usage error without it; bind a lens's binds with `bindLens` first. `prisma.steps` is present when the where needs `executePrismaPlan`. `sql.sql` is `null` with an `error` when SQL can't express the where. A
|
|
1247
|
-
| `materializeSourceQuery(query, rows, { rowShape
|
|
1245
|
+
| `toSourceQueries(lensOrNarrowing, options?)` | `SourceQuery[]`, one per sourced field: `{ path, mapName, model, field, label?, groupBy?, composedWhere, prisma, sql, recheck? }`. `options` is the clock (`now`, `timeZone`, `weekStart`) a relative date in the where compiles with — required for one, a plain usage error without it; bind a lens's binds with `bindLens` first. `prisma.steps` is present when the where needs `executePrismaPlan`. `sql.sql` is `null` with an `error` when SQL can't express the where. A source that reads across a bridge gets an over-fetching query and a `recheck`: its rows are candidates, not options (see "Sources across a bridge"). `distinct` is the value and a sibling label column; a grouped source or a dotted label drops it, so every label comes back and the least one is picked. |
|
|
1246
|
+
| `materializeSourceQuery(query, rows, { rowShape?, lens?, now?, … })` | One query's fetched rows as `SourceValues`. `rowShape` is `'prisma'` (default: a dotted `label` and each `groupBy` axis come nested) or `'sql'` (they come flat as `__label` / `__group_i`). Options are deduplicated and sorted. A query with `recheck` needs `lens` and rows holding the far side: it re-checks each candidate (`check`, with the clock and bindings given) and reads a bridged label or axis from the far side; a missing far side is a `UsageError`. |
|
|
1248
1247
|
| `materializeSources(lensOrNarrowing, rows, options?)` | `SourceValues[]` for every sourced field, from the rows the lens fetches — `toLensSelect`'s rows as fetched, or as `projectRows(…, { keepGrantColumns: true })` keeps them. A viewer's projection drops what sources read: a row lacking any key a read walks — through each relation and list element to the column — that a source or a grant on its path reads throws a `UsageError` (a fetch returns every key it selects, NULL as `null`). The path is walked down the rows — the tree is its link — each level's grants met, and each row it reaches must meet, through `check()` with `options`, its visit's grants, its source `where` narrowed as a rule is, the guards of the relations its label and axes cross and the values the lens allows — so it offers what `toSourceQueries` does. A scalar-list field gives one option per element; a value takes its least label. A `from: 'mapDefaults'` source throws (see below). |
|
|
1249
1248
|
|
|
1250
1249
|
Options never offer a value the lens disallows: `projectLens` drops fetched values outside a
|
|
@@ -1296,29 +1295,57 @@ carries down only in the layer that declares it: every layer before or after it
|
|
|
1296
1295
|
theirs, so a child's pointer can only narrow what its parent gave, and a tenant layer added after a
|
|
1297
1296
|
pointer always narrows it. How depends on how it scopes: through `mapDefaults` (the model's own
|
|
1298
1297
|
grant or source) the pointer still offers unlinked rows; through a root `where` the grant can only
|
|
1299
|
-
reach the pointer down the path, so it offers just the linked rows — and across a bridge
|
|
1300
|
-
grant
|
|
1298
|
+
reach the pointer down the path, so it offers just the linked rows — and across a bridge the
|
|
1299
|
+
grant comes back as the query's `recheck` (below). Scope tenancy through `mapDefaults` to keep a pointer's unlinked rows.
|
|
1301
1300
|
A pointer whose model declares no source fails `validateNarrowing` (`invalid_source`) and throws
|
|
1302
1301
|
from `projectLens` (by path) / `toSourceQueries` / `materializeSources`, even where a layer hides
|
|
1303
1302
|
its field; `projectLens(…, { by: 'model' })` and `describeRuleSources` read the lens without
|
|
1304
1303
|
validating it. Across a bridge it is how a picker gets options at all: the
|
|
1305
1304
|
model source compiles against the far map alone, with that map's own tenancy, where a path source
|
|
1306
|
-
|
|
1305
|
+
over-fetches and re-checks (see "Sources across a bridge"). A grant a path can't carry down — a relation whose
|
|
1307
1306
|
map declares no inverse — is a `LensRefusal`, never an empty list. `materializeSources` refuses a pointer — a fetched collection can't hold unlinked
|
|
1308
1307
|
rows; query it with `toSourceQueries` and `materializeSourceQuery`.
|
|
1309
1308
|
|
|
1310
1309
|
#### Sources across a bridge
|
|
1311
1310
|
|
|
1312
|
-
A source whose path, `where`, `label` or an axis reads across a bridge
|
|
1313
|
-
database holds
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1311
|
+
A source whose path, `where`, `label` or an axis reads across a bridge can't be decided by one
|
|
1312
|
+
database — each holds one side. `toSourceQueries` still returns a real query for the side it can
|
|
1313
|
+
see, and marks it with `recheck`:
|
|
1314
|
+
|
|
1315
|
+
- **The query over-fetches.** What reads across the bridge compiles to TRUE (the compilers'
|
|
1316
|
+
over-fetch), so the query never pre-filters on what it can't see: its rows are a **superset** of
|
|
1317
|
+
the true options. Everything local is still decided by the database.
|
|
1318
|
+
- **`recheck` is what the database couldn't decide** — the conjuncts of `composedWhere` that read
|
|
1319
|
+
across a bridge, or `true` when only the label or an axis does. **If `recheck` is present, the
|
|
1320
|
+
query's rows are candidates, not options.** A source that reads no bridge has no `recheck`.
|
|
1321
|
+
- **The query selects local columns only:** the value, a local label and local axes, the local
|
|
1322
|
+
columns `recheck` reads, and each crossed bridge's local `on` key (under the local relations the
|
|
1323
|
+
read crosses first). It drops `distinct`, since candidates differ in what the re-check reads. A
|
|
1324
|
+
label or axis across the bridge is not selected.
|
|
1325
|
+
- **Load the far side, then materialize.** Put the far row inline on each candidate under its
|
|
1326
|
+
bridge field (the `indexBridges` shape — one row, or a list where the bridge names many) and
|
|
1327
|
+
call `materializeSourceQuery(query, rows, { lens, rowShape?, now? })`. It requires every key the
|
|
1328
|
+
re-check and a bridged label or axis read, as `materializeSources` does — a candidate without
|
|
1329
|
+
the far side, a far row without a column read, or a list where the bridge names one row throws a
|
|
1330
|
+
`UsageError` — keeps the candidates `check(recheck, row)` holds, and reads the label and axes
|
|
1331
|
+
across the bridge from the far side, in either row shape. Without `lens` it throws.
|
|
1332
|
+
- **A source past a bridge** (its path crosses one) is queried against its own model's map; the
|
|
1333
|
+
grants above it are carried back across the bridge through the far model's bridge field, and
|
|
1334
|
+
come back as its `recheck` — so each candidate holds the near rows inline
|
|
1335
|
+
(`{ id, industry, 'prisma:FanUser': [{ email, … }] }`).
|
|
1336
|
+
- **SQL rows are flat**, so a bridged query whose re-check reads through a local relation has
|
|
1337
|
+
`sql.sql: null` (with `sql.error`); run the Prisma form.
|
|
1338
|
+
|
|
1339
|
+
```ts
|
|
1340
|
+
const [query] = toSourceQueries(lens, { now });
|
|
1341
|
+
const candidates = await prisma[query.model].findMany(query.prisma); // superset
|
|
1342
|
+
const rows = query.recheck === undefined ? candidates : await loadFarSide(candidates); // your join
|
|
1343
|
+
const values = materializeSourceQuery(query, rows, { lens, now });
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
`materializeSources` over fetched rows still answers a path source across a bridge when the caller
|
|
1347
|
+
supplies the root rows with the far side inline (`{ id, email, crmId, 'salesforce:Contact': { id,
|
|
1348
|
+
industry } }`); a pointer (`from: 'mapDefaults'`) always goes through the query.
|
|
1322
1349
|
|
|
1323
1350
|
### Fetching Under a Lens
|
|
1324
1351
|
|