@prisma-idb/adapter-idb 0.12.0 → 0.13.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 +6 -0
- package/dist/runtime.d.mts +44 -17
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +107 -41
- package/dist/runtime.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -10,6 +10,12 @@ npm install --save-dev @prisma-idb/adapter-idb
|
|
|
10
10
|
|
|
11
11
|
Part of [Prisma 8 IDB](https://prisma-idb.dev/docs/prisma-8), a typed IndexedDB client for Prisma 8. Start with the [Quick Start](https://prisma-idb.dev/docs/prisma-8/getting-started). For how the packages fit together, see [ARCHITECTURE.md](https://github.com/prisma-idb/prisma-idb/blob/main/packages/prisma-orm/docs/ARCHITECTURE.md).
|
|
12
12
|
|
|
13
|
+
## Lowered query identity
|
|
14
|
+
|
|
15
|
+
The adapter preserves the driver operation and adds `queryIdentity` when the query AST provides a serializable filter or sort specification. The identities are canonical strings. Sort identity preserves field priority as well as direction. The driver ignores this metadata; middleware uses it for cache identity.
|
|
16
|
+
|
|
17
|
+
An AST supplied by a custom query builder must describe the plan's filter and comparator closures, including those in range-split child scans. Missing or unsupported structured values leave the corresponding closure opaque. The runtime then prevents cache reuse for that closure. Middleware receives the lowered plan, rather than the original `ast`.
|
|
18
|
+
|
|
13
19
|
## License
|
|
14
20
|
|
|
15
21
|
MIT
|
package/dist/runtime.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RuntimeAdapterDescriptor, RuntimeAdapterInstance } from "@prisma/orm-framework/components/execution";
|
|
2
2
|
import { CodecCallContext, CodecLookup } from "@prisma/orm-framework/components/codec";
|
|
3
|
-
import { IdbPlanBody } from "@prisma-idb/driver-idb/runtime";
|
|
4
3
|
import { QueryPlan } from "@prisma/orm-framework/components/runtime";
|
|
4
|
+
import { IdbPlanBody } from "@prisma-idb/driver-idb/runtime";
|
|
5
5
|
//#region src/core/idb-filter-expr.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Filter expression AST for IDB queries.
|
|
@@ -40,15 +40,16 @@ interface IdbNotExpr {
|
|
|
40
40
|
readonly expr: IdbFilterExpr;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
* fields as
|
|
45
|
-
*
|
|
43
|
+
* Explicit null check. Like `eq(null)` and `neq(null)`, it treats null
|
|
44
|
+
* and absent fields as equivalent and always returns true or false.
|
|
45
|
+
* Other nullable comparisons can be unknown until the full filter is evaluated.
|
|
46
46
|
*/
|
|
47
47
|
interface IdbNullCheckExpr {
|
|
48
48
|
readonly kind: "null-check";
|
|
49
49
|
readonly field: string;
|
|
50
50
|
readonly isNull: boolean;
|
|
51
51
|
}
|
|
52
|
+
/** A field predicate, logical combination, or null check in the IDB filter AST. */
|
|
52
53
|
type IdbFilterExpr = IdbFieldFilter | IdbAndExpr | IdbOrExpr | IdbNotExpr | IdbNullCheckExpr;
|
|
53
54
|
/** Build a frozen field-filter node. */
|
|
54
55
|
declare const fieldFilter: (field: string, op: IdbFilterOp, value: unknown) => IdbFieldFilter;
|
|
@@ -216,11 +217,11 @@ declare const __idbQueryPlanRow: unique symbol;
|
|
|
216
217
|
* adds the IDB execution plan as `idbPlan`. Because IDB has no query language
|
|
217
218
|
* of its own, the plan already carries the execution-ready {@link IdbPlanBody}
|
|
218
219
|
* — there is no AST compilation step as in SQL. The adapter's `lower()` step
|
|
219
|
-
*
|
|
220
|
+
* preserves that body and adds semantic identities for structured row closures.
|
|
220
221
|
*
|
|
221
222
|
* The optional `ast` field carries a lightweight {@link IdbQueryAst} describing
|
|
222
223
|
* the query intent. It is populated by the ORM lane (`client-idb`) so middleware
|
|
223
|
-
* can
|
|
224
|
+
* can derive cache identity without inspecting closure source code. This mirrors
|
|
224
225
|
* the upstream pattern where {@link SqlQueryPlan} carries an `ast: AnyQueryAst`.
|
|
225
226
|
*
|
|
226
227
|
* @template Row - The TypeScript row shape inferred from the lane builder.
|
|
@@ -233,13 +234,29 @@ interface IdbQueryPlan<Row = unknown> extends QueryPlan<Row> {
|
|
|
233
234
|
/**
|
|
234
235
|
* Optional lightweight AST describing the query intent.
|
|
235
236
|
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
237
|
+
* The adapter uses this to populate `queryIdentity` on the lowered plan.
|
|
238
|
+
* Middleware receives that lowered plan, rather than this AST. Absent for
|
|
239
|
+
* plans constructed outside the ORM lane. The AST must describe the
|
|
240
|
+
* filter and comparator closures in `idbPlan`.
|
|
238
241
|
*/
|
|
239
242
|
readonly ast?: IdbQueryAst;
|
|
240
243
|
/** Phantom row brand — matches the `_row` slot on the base QueryPlan. */
|
|
241
244
|
readonly [__idbQueryPlanRow]?: Row;
|
|
242
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Execution-ready plan with canonical identities for structured row closures.
|
|
248
|
+
*
|
|
249
|
+
* The driver ignores this metadata. Middleware can use it to distinguish
|
|
250
|
+
* captured filter values and comparator field priority and directions.
|
|
251
|
+
* For range-split batches, the identity also describes each child scan's
|
|
252
|
+
* closures. Missing identities mean those closures must be treated as opaque.
|
|
253
|
+
*/
|
|
254
|
+
type IdbLoweredPlan = IdbPlanBody & {
|
|
255
|
+
readonly queryIdentity?: {
|
|
256
|
+
readonly filter?: string;
|
|
257
|
+
readonly comparator?: string;
|
|
258
|
+
};
|
|
259
|
+
};
|
|
243
260
|
//#endregion
|
|
244
261
|
//#region src/core/runtime-adapter-instance.d.ts
|
|
245
262
|
/**
|
|
@@ -260,7 +277,7 @@ interface IdbLowererContext<TContract = unknown> extends CodecCallContext {
|
|
|
260
277
|
*
|
|
261
278
|
* Extends the generic `RuntimeAdapterInstance` marker with the IDB-specific
|
|
262
279
|
* `lower()` method. `lower()` is the core of the adapter: it translates an
|
|
263
|
-
* {@link IdbQueryPlan} (IDB execution plan + meta) into an {@link
|
|
280
|
+
* {@link IdbQueryPlan} (IDB execution plan + meta) into an {@link IdbLoweredPlan}
|
|
264
281
|
* (one of the strongly-typed IDB operation plans) that the driver can execute
|
|
265
282
|
* directly against `window.indexedDB`.
|
|
266
283
|
*
|
|
@@ -278,25 +295,34 @@ interface IdbRuntimeAdapterInstance extends RuntimeAdapterInstance<"idb", "idb">
|
|
|
278
295
|
* `AbortSignal` for cooperative cancellation.
|
|
279
296
|
* @returns The IDB plan body describing the exact IDB operation(s) to run.
|
|
280
297
|
*/
|
|
281
|
-
lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<
|
|
298
|
+
lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbLoweredPlan>;
|
|
282
299
|
}
|
|
283
300
|
//#endregion
|
|
284
301
|
//#region src/core/filter-eval.d.ts
|
|
285
|
-
/**
|
|
286
|
-
|
|
302
|
+
/** Codec metadata determines which string fields have numeric Decimal semantics. */
|
|
303
|
+
type FilterFieldMetadata = Readonly<Record<string, {
|
|
304
|
+
readonly codecId?: string | undefined;
|
|
305
|
+
readonly collection?: boolean;
|
|
306
|
+
}>>;
|
|
307
|
+
/** Reject invalid Decimal operands even when no stored row reaches the evaluator. */
|
|
308
|
+
declare function assertValidDecimalFilter(expr: IdbFilterExpr, fields: FilterFieldMetadata): void;
|
|
309
|
+
/** Evaluate an AST node against a single row. Only SQL TRUE keeps the row. */
|
|
310
|
+
declare function evaluateFilter(expr: IdbFilterExpr, row: Record<string, unknown>, fields?: FilterFieldMetadata): boolean;
|
|
287
311
|
//#endregion
|
|
288
312
|
//#region src/core/idb-adapter.d.ts
|
|
289
313
|
/**
|
|
290
314
|
* Concrete IDB runtime adapter.
|
|
291
315
|
*
|
|
292
316
|
* Implements {@link IdbRuntimeAdapterInstance} — the `lower()` method that
|
|
293
|
-
* translates an {@link IdbQueryPlan} into an {@link
|
|
317
|
+
* translates an {@link IdbQueryPlan} into an {@link IdbLoweredPlan} ready for
|
|
294
318
|
* the driver.
|
|
295
319
|
*
|
|
296
|
-
* `lower()`
|
|
320
|
+
* `lower()` preserves the driver operation: the `idbPlan` carried by
|
|
297
321
|
* `IdbQueryPlan` is already execution-ready because IDB has no query
|
|
298
322
|
* language to compile from. Every current `idb/*` codec is an identity
|
|
299
|
-
* transform for stored values, so no field needs encoding.
|
|
323
|
+
* transform for stored values, so no field needs encoding. Structured AST
|
|
324
|
+
* filters and sort specifications become canonical closure identities for
|
|
325
|
+
* middleware; the driver remains independent of the query layer.
|
|
300
326
|
*
|
|
301
327
|
* The `codecs` constructor parameter matches the framework adapter shape and
|
|
302
328
|
* is the extension point for field encoding with non-identity codecs.
|
|
@@ -306,11 +332,12 @@ declare class IdbAdapter implements IdbRuntimeAdapterInstance {
|
|
|
306
332
|
readonly familyId: "idb";
|
|
307
333
|
readonly targetId: "idb";
|
|
308
334
|
constructor(codecs: CodecLookup);
|
|
309
|
-
|
|
335
|
+
/** Preserve the driver operation and carry structured closure identity through lowering. */
|
|
336
|
+
lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbLoweredPlan>;
|
|
310
337
|
}
|
|
311
338
|
//#endregion
|
|
312
339
|
//#region src/exports/runtime.d.ts
|
|
313
340
|
declare const idbRuntimeAdapterDescriptor: RuntimeAdapterDescriptor<"idb", "idb", IdbRuntimeAdapterInstance>;
|
|
314
341
|
//#endregion
|
|
315
|
-
export { IdbAdapter, type IdbAggregateAst, type IdbAggregateRequest, type IdbAndExpr, type IdbCountAst, type IdbCreateAllAst, type IdbCreateAst, type IdbCreateCountAst, type IdbDeleteAllAst, type IdbDeleteAst, type IdbDeleteCountAst, type IdbFieldFilter, type IdbFilterExpr, type IdbFilterOp, type IdbFindManyAst, type IdbFindUniqueAst, type IdbGroupByAst, type IdbLowererContext, type IdbNotExpr, type IdbNullCheckExpr, type IdbOrExpr, type IdbQueryAst, type IdbQueryPlan, type IdbRuntimeAdapterInstance, type IdbUpdateAllAst, type IdbUpdateAst, type IdbUpdateCountAst, andExpr, idbRuntimeAdapterDescriptor as default, evaluateFilter, fieldFilter, notExpr, nullCheckExpr, orExpr, shorthandToFilterExpr };
|
|
342
|
+
export { IdbAdapter, type IdbAggregateAst, type IdbAggregateRequest, type IdbAndExpr, type IdbCountAst, type IdbCreateAllAst, type IdbCreateAst, type IdbCreateCountAst, type IdbDeleteAllAst, type IdbDeleteAst, type IdbDeleteCountAst, type IdbFieldFilter, type IdbFilterExpr, type IdbFilterOp, type IdbFindManyAst, type IdbFindUniqueAst, type IdbGroupByAst, type IdbLoweredPlan, type IdbLowererContext, type IdbNotExpr, type IdbNullCheckExpr, type IdbOrExpr, type IdbQueryAst, type IdbQueryPlan, type IdbRuntimeAdapterInstance, type IdbUpdateAllAst, type IdbUpdateAst, type IdbUpdateCountAst, andExpr, assertValidDecimalFilter, idbRuntimeAdapterDescriptor as default, evaluateFilter, fieldFilter, notExpr, nullCheckExpr, orExpr, shorthandToFilterExpr };
|
|
316
343
|
//# sourceMappingURL=runtime.d.mts.map
|
package/dist/runtime.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/core/idb-filter-expr.ts","../src/core/idb-query-ast.ts","../src/core/idb-query-plan.ts","../src/core/runtime-adapter-instance.ts","../src/core/filter-eval.ts","../src/core/idb-adapter.ts","../src/exports/runtime.ts"],"mappings":";;;;;;;;;;;;;;;;;;KAcY;;UAIK;WACN;WACA;WACA,IAAI;WACJ;;;UAIM;WACN;WACA,OAAO,cAAc;;;UAIf;WACN;WACA,OAAO,cAAc;;;UAIf;WACN;WACA,MAAM;;;;;;;UAQA;WACN;WACA;WACA
|
|
1
|
+
{"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/core/idb-filter-expr.ts","../src/core/idb-query-ast.ts","../src/core/idb-query-plan.ts","../src/core/runtime-adapter-instance.ts","../src/core/filter-eval.ts","../src/core/idb-adapter.ts","../src/exports/runtime.ts"],"mappings":";;;;;;;;;;;;;;;;;;KAcY;;UAIK;WACN;WACA;WACA,IAAI;WACJ;;;UAIM;WACN;WACA,OAAO,cAAc;;;UAIf;WACN;WACA,OAAO,cAAc;;;UAIf;WACN;WACA,MAAM;;;;;;;UAQA;WACN;WACA;WACA;;;KAIC,gBAAgB,iBAAiB,aAAa,YAAY,aAAa;;cAKtE,cAAe,eAAe,IAAI,aAAa,mBAAiB;;cAIhE,UAAW,OAAO,cAAc,mBAAiB;;cAIjD,SAAU,OAAO,cAAc,mBAAiB;;cAIhD,UAAW,MAAM,kBAAgB;;cAGjC,gBAAiB,eAAe,oBAAkB;;;;;;;;;;;iBAe/C,sBAAsB,SAAS,0BAA0B;;;;;;;;;;KCpE7D,cACR,iBACA,mBACA,eACA,eACA,eACA,kBACA,oBACA,kBACA,oBACA,kBACA,oBACA,cACA,kBACA;;UAGa;WACN;;WAEA;;WAEA,QAAQ;;WAER,UAAU;;WAEV;;WAEA;;;UAIM;WACN;;WAEA;;WAEA;;;UAIM;WACN;;WAEA;;WAEA,MAAM;;;UAIA;WACN;;WAEA;;WAEA;;;UAIM;WACN;WACA;WACA,OAAO;WACP,QAAQ;;;UAIF;WACN;WACA;WACA,OAAO;WACP,QAAQ;;;UAIF;WACN;WACA;WACA,OAAO;WACP,QAAQ;;;UAIF;WACN;WACA;WACA,MAAM;;;UAIA;WACN;WACA;WACA,MAAM;;;UAIA;WACN;WACA;WACA,QAAQ;;;UAIF;WACN;WACA;WACA,QAAQ;;;UAIF;WACN;WACA;WACA,QAAQ;;;UAIF;;WAEN;;WAEA;;;;;;;;;UAUM;WACN;WACA;WACA,QAAQ;;WAER,YAAY,SAAS,eAAe;;;;;;;;UAS9B;WACN;WACA;WACA,QAAQ;;WAER;;WAEA,YAAY,SAAS,eAAe;;;;cC1KjC;;;;;;;;;;;;;;;;;;;UAoBG,aAAa,uBAAuB,UAAU;;WAEpD,SAAS;;;;;;;;;WAST,MAAM;;YAEL,qBAAqB;;;;;;;;;;KAWrB,iBAAiB;WAClB;aACE;aACA;;;;;;;;;;;;;;UCvCI,kBAAkB,6BAA6B;;WAErD,UAAU;;;;;;;;;;;;;;;UAgBJ,kCAAkC;;;;;;;;;;EAUjD,MAAM,MAAM,cAAc,KAAK,oBAAoB,QAAQ;;;;;KCjBjD,sBAAsB,SAChC;WAA0B;WAAuC;;;iBAInD,yBAAyB,MAAM,eAAe,QAAQ;;iBAwBtD,eACd,MAAM,eACN,KAAK,yBACL,SAAQ;;;;;;;;;;;;;;;;;;;;cClCG,sBAAsB;;WACxB;WACA;EAIG,YAAA,QAAQ;;EAKpB,MAAM,MAAM,cAAc,KAAK,oBAAoB,QAAQ;;;;cCMvD,6BAA6B,uCAAuC"}
|
package/dist/runtime.mjs
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { t as idbAdapterDescriptorMeta } from "./descriptor-meta-Dxdc_q_O.mjs";
|
|
2
|
-
import { compareFieldValues, fieldValuesEqual, idbCodecLookup } from "@prisma-idb/target-idb/runtime";
|
|
2
|
+
import { compareDecimalValues, compareFieldValues, fieldValuesEqual, idbCodecLookup, isDecimalString } from "@prisma-idb/target-idb/runtime";
|
|
3
|
+
import { canonicalStringify } from "@prisma/orm-framework/utils/canonical-stringify";
|
|
3
4
|
//#region src/core/idb-adapter.ts
|
|
4
5
|
/**
|
|
5
6
|
* Concrete IDB runtime adapter.
|
|
6
7
|
*
|
|
7
8
|
* Implements {@link IdbRuntimeAdapterInstance} — the `lower()` method that
|
|
8
|
-
* translates an {@link IdbQueryPlan} into an {@link
|
|
9
|
+
* translates an {@link IdbQueryPlan} into an {@link IdbLoweredPlan} ready for
|
|
9
10
|
* the driver.
|
|
10
11
|
*
|
|
11
|
-
* `lower()`
|
|
12
|
+
* `lower()` preserves the driver operation: the `idbPlan` carried by
|
|
12
13
|
* `IdbQueryPlan` is already execution-ready because IDB has no query
|
|
13
14
|
* language to compile from. Every current `idb/*` codec is an identity
|
|
14
|
-
* transform for stored values, so no field needs encoding.
|
|
15
|
+
* transform for stored values, so no field needs encoding. Structured AST
|
|
16
|
+
* filters and sort specifications become canonical closure identities for
|
|
17
|
+
* middleware; the driver remains independent of the query layer.
|
|
15
18
|
*
|
|
16
19
|
* The `codecs` constructor parameter matches the framework adapter shape and
|
|
17
20
|
* is the extension point for field encoding with non-identity codecs.
|
|
@@ -23,13 +26,34 @@ var IdbAdapter = class {
|
|
|
23
26
|
constructor(codecs) {
|
|
24
27
|
this.#codecs = codecs;
|
|
25
28
|
}
|
|
29
|
+
/** Preserve the driver operation and carry structured closure identity through lowering. */
|
|
26
30
|
lower(plan, ctx) {
|
|
27
31
|
this.#codecs;
|
|
28
32
|
ctx.contract;
|
|
29
33
|
ctx.signal;
|
|
30
|
-
|
|
34
|
+
const ast = plan.ast;
|
|
35
|
+
if (ast === void 0) return Promise.resolve(plan.idbPlan);
|
|
36
|
+
const filter = "where" in ast ? closureIdentity(ast.where) : void 0;
|
|
37
|
+
const comparator = "orderBy" in ast && ast.orderBy !== void 0 ? closureIdentity(Object.entries(ast.orderBy)) : void 0;
|
|
38
|
+
if (filter === void 0 && comparator === void 0) return Promise.resolve(plan.idbPlan);
|
|
39
|
+
return Promise.resolve({
|
|
40
|
+
...plan.idbPlan,
|
|
41
|
+
queryIdentity: {
|
|
42
|
+
...filter === void 0 ? {} : { filter },
|
|
43
|
+
...comparator === void 0 ? {} : { comparator }
|
|
44
|
+
}
|
|
45
|
+
});
|
|
31
46
|
}
|
|
32
47
|
};
|
|
48
|
+
/** Leave unsupported structured values opaque so identity generation cannot break a query. */
|
|
49
|
+
function closureIdentity(value) {
|
|
50
|
+
if (value === void 0) return void 0;
|
|
51
|
+
try {
|
|
52
|
+
return canonicalStringify(value);
|
|
53
|
+
} catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
33
57
|
//#endregion
|
|
34
58
|
//#region src/core/idb-filter-expr.ts
|
|
35
59
|
/** Build a frozen field-filter node. */
|
|
@@ -93,56 +117,97 @@ function shorthandToFilterExpr(filters) {
|
|
|
93
117
|
* passes that to the driver. The driver therefore never imports the
|
|
94
118
|
* adapter's AST types, and keeps no dependency on the adapter.
|
|
95
119
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
120
|
+
* Decimal metadata selects exact numeric comparison. Other fields compare
|
|
121
|
+
* values the way IndexedDB compares keys, so a filter agrees with an index
|
|
98
122
|
* key range. Plain `===` would never match two equal `Date`s or byte arrays,
|
|
99
123
|
* because values read back from IndexedDB are fresh objects. String
|
|
100
124
|
* operations coerce both sides via `String(...)` so they work on numbers too.
|
|
101
125
|
*/
|
|
102
|
-
/**
|
|
103
|
-
function
|
|
126
|
+
/** Reject invalid Decimal operands even when no stored row reaches the evaluator. */
|
|
127
|
+
function assertValidDecimalFilter(expr, fields) {
|
|
128
|
+
if (expr.kind === "and" || expr.kind === "or") expr.exprs.forEach((child) => assertValidDecimalFilter(child, fields));
|
|
129
|
+
else if (expr.kind === "not") assertValidDecimalFilter(expr.expr, fields);
|
|
130
|
+
else if (expr.kind === "field" && isDecimalField(fields, expr.field)) {
|
|
131
|
+
if (expr.op === "contains" || expr.op === "startsWith" || expr.op === "endsWith") return;
|
|
132
|
+
const values = expr.op === "in" || expr.op === "notIn" ? expr.value : [expr.value];
|
|
133
|
+
if (Array.isArray(values) && values.some((value) => isPresent(value) && !isDecimalString(value))) throw new TypeError(`Expected finite Decimal text for field "${expr.field}"`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Identify scalar Decimal fields without reinterpreting string or collection values. */
|
|
137
|
+
function isDecimalField(fields, field) {
|
|
138
|
+
return fields[field]?.codecId === "idb/decimal@1" && !fields[field]?.collection;
|
|
139
|
+
}
|
|
140
|
+
/** Evaluate an AST node against a single row. Only SQL TRUE keeps the row. */
|
|
141
|
+
function evaluateFilter(expr, row, fields = {}) {
|
|
142
|
+
return evaluatePredicate(expr, row, fields) === true;
|
|
143
|
+
}
|
|
144
|
+
/** Preserve unknown through logical composition so negation cannot admit null comparisons. */
|
|
145
|
+
function evaluatePredicate(expr, row, fields) {
|
|
104
146
|
switch (expr.kind) {
|
|
105
|
-
case "field": return evalFieldOp(expr.field, expr.op, expr.value, row);
|
|
106
|
-
case "and":
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
147
|
+
case "field": return evalFieldOp(expr.field, expr.op, expr.value, row, fields);
|
|
148
|
+
case "and": {
|
|
149
|
+
let result = true;
|
|
150
|
+
for (const e of expr.exprs) {
|
|
151
|
+
const child = evaluatePredicate(e, row, fields);
|
|
152
|
+
if (child === false) return false;
|
|
153
|
+
if (child === null) result = null;
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
case "or": {
|
|
158
|
+
let result = false;
|
|
159
|
+
for (const e of expr.exprs) {
|
|
160
|
+
const child = evaluatePredicate(e, row, fields);
|
|
161
|
+
if (child === true) return true;
|
|
162
|
+
if (child === null) result = null;
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
case "not": {
|
|
167
|
+
const result = evaluatePredicate(expr.expr, row, fields);
|
|
168
|
+
return result === null ? null : !result;
|
|
169
|
+
}
|
|
114
170
|
case "null-check": {
|
|
115
|
-
const
|
|
116
|
-
const isNullish = v === null || v === void 0;
|
|
171
|
+
const isNullish = !isPresent(row[expr.field]);
|
|
117
172
|
return expr.isNull ? isNullish : !isNullish;
|
|
118
173
|
}
|
|
119
174
|
}
|
|
120
175
|
}
|
|
121
|
-
|
|
176
|
+
/** Evaluate one field predicate with the same comparisons used by index-backed queries. */
|
|
177
|
+
function evalFieldOp(field, op, value, row, fields) {
|
|
122
178
|
const cell = row[field];
|
|
179
|
+
if (value === null && (op === "eq" || op === "neq")) return op === "eq" ? !isPresent(cell) : isPresent(cell);
|
|
180
|
+
const decimal = isDecimalField(fields, field);
|
|
181
|
+
const compare = decimal ? compareDecimalValues : compareFieldValues;
|
|
182
|
+
const equal = decimal ? (a, b) => compareDecimalValues(a, b) === 0 : fieldValuesEqual;
|
|
183
|
+
if (op === "in" || op === "notIn") {
|
|
184
|
+
const result = evaluateMembership(cell, value, equal);
|
|
185
|
+
if (result === null) return null;
|
|
186
|
+
return op === "in" ? result : !result;
|
|
187
|
+
}
|
|
188
|
+
if (!isPresent(cell) || !isPresent(value)) return null;
|
|
123
189
|
switch (op) {
|
|
124
|
-
case "eq":
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
case "
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
case "
|
|
131
|
-
case "
|
|
132
|
-
case "
|
|
133
|
-
case "lte": return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) <= 0;
|
|
134
|
-
case "in":
|
|
135
|
-
if (!Array.isArray(value)) return false;
|
|
136
|
-
return value.some((v) => fieldValuesEqual(cell, v));
|
|
137
|
-
case "notIn":
|
|
138
|
-
if (!Array.isArray(value)) return true;
|
|
139
|
-
return !value.some((v) => fieldValuesEqual(cell, v));
|
|
140
|
-
case "contains": return isPresent(cell) && String(cell).includes(String(value));
|
|
141
|
-
case "startsWith": return isPresent(cell) && String(cell).startsWith(String(value));
|
|
142
|
-
case "endsWith": return isPresent(cell) && String(cell).endsWith(String(value));
|
|
190
|
+
case "eq": return equal(cell, value);
|
|
191
|
+
case "neq": return !equal(cell, value);
|
|
192
|
+
case "gt": return compare(cell, value) > 0;
|
|
193
|
+
case "lt": return compare(cell, value) < 0;
|
|
194
|
+
case "gte": return compare(cell, value) >= 0;
|
|
195
|
+
case "lte": return compare(cell, value) <= 0;
|
|
196
|
+
case "contains": return String(cell).includes(String(value));
|
|
197
|
+
case "startsWith": return String(cell).startsWith(String(value));
|
|
198
|
+
case "endsWith": return String(cell).endsWith(String(value));
|
|
143
199
|
default: return false;
|
|
144
200
|
}
|
|
145
201
|
}
|
|
202
|
+
/** Match SQL IN: empty lists are false; otherwise null operands leave an unmatched result unknown. */
|
|
203
|
+
function evaluateMembership(cell, values, equal) {
|
|
204
|
+
if (!Array.isArray(values) || values.length === 0) return false;
|
|
205
|
+
if (!isPresent(cell)) return null;
|
|
206
|
+
let result = false;
|
|
207
|
+
for (const value of values) if (!isPresent(value)) result = null;
|
|
208
|
+
else if (equal(cell, value)) return true;
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
146
211
|
function isPresent(value) {
|
|
147
212
|
return value !== null && value !== void 0;
|
|
148
213
|
}
|
|
@@ -150,11 +215,12 @@ function isPresent(value) {
|
|
|
150
215
|
//#region src/exports/runtime.ts
|
|
151
216
|
const idbRuntimeAdapterDescriptor = {
|
|
152
217
|
...idbAdapterDescriptorMeta,
|
|
218
|
+
/** Build an adapter with the codec registry shared by the IDB runtime stack. */
|
|
153
219
|
create(_stack) {
|
|
154
220
|
return new IdbAdapter(idbCodecLookup);
|
|
155
221
|
}
|
|
156
222
|
};
|
|
157
223
|
//#endregion
|
|
158
|
-
export { IdbAdapter, andExpr, idbRuntimeAdapterDescriptor as default, evaluateFilter, fieldFilter, notExpr, nullCheckExpr, orExpr, shorthandToFilterExpr };
|
|
224
|
+
export { IdbAdapter, andExpr, assertValidDecimalFilter, idbRuntimeAdapterDescriptor as default, evaluateFilter, fieldFilter, notExpr, nullCheckExpr, orExpr, shorthandToFilterExpr };
|
|
159
225
|
|
|
160
226
|
//# sourceMappingURL=runtime.mjs.map
|
package/dist/runtime.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.mjs","names":["#codecs"],"sources":["../src/core/idb-adapter.ts","../src/core/idb-filter-expr.ts","../src/core/filter-eval.ts","../src/exports/runtime.ts"],"sourcesContent":["import type { CodecLookup } from \"@prisma/orm-framework/components/codec\";\nimport type { IdbPlanBody } from \"@prisma-idb/driver-idb/runtime\";\nimport type { IdbQueryPlan } from \"./idb-query-plan\";\nimport type { IdbLowererContext, IdbRuntimeAdapterInstance } from \"./runtime-adapter-instance\";\n\n/**\n * Concrete IDB runtime adapter.\n *\n * Implements {@link IdbRuntimeAdapterInstance} — the `lower()` method that\n * translates an {@link IdbQueryPlan} into an {@link IdbPlanBody} ready for\n * the driver.\n *\n * `lower()` is a structural passthrough: the `idbPlan` carried by\n * `IdbQueryPlan` is already execution-ready because IDB has no query\n * language to compile from. Every current `idb/*` codec is an identity\n * transform for stored values, so no field needs encoding.\n *\n * The `codecs` constructor parameter matches the framework adapter shape and\n * is the extension point for field encoding with non-identity codecs.\n */\nexport class IdbAdapter implements IdbRuntimeAdapterInstance {\n readonly familyId = \"idb\" as const;\n readonly targetId = \"idb\" as const;\n\n readonly #codecs: CodecLookup;\n\n constructor(codecs: CodecLookup) {\n this.#codecs = codecs;\n }\n\n lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbPlanBody> {\n // If a codec ever transforms stored values, encode plan.idbPlan's\n // record and key fields here: resolve each field's codec through\n // this.#codecs and ctx.contract, then call codec.encode(value, ctx).\n void this.#codecs; // codec registry for per-field encoding\n void ctx.contract; // contract storage schema (field→codec resolution)\n void ctx.signal; // AbortSignal for cooperative cancellation\n return Promise.resolve(plan.idbPlan);\n }\n}\n","/**\n * Filter expression AST for IDB queries.\n *\n * Plain frozen objects (not classes) — IDB has no codec trait gating to\n * worry about and no visitor pattern needed (a recursive `evaluateFilter`\n * is plenty). Mirrors the design of Prisma ORM's Mongo family\n * (`MongoFieldFilter`, `MongoAndExpr`, ...) and the SQL ORM's `BinaryExpr`,\n * but with the class machinery stripped out.\n *\n * The AST is carried on `IdbQueryAst` (intent layer) and lowered into an\n * `IdbRowFilter` closure that the driver applies during cursor scans —\n * keeping the driver free of any AST imports.\n */\n\nexport type IdbFilterOp =\n \"eq\" | \"neq\" | \"gt\" | \"lt\" | \"gte\" | \"lte\" | \"in\" | \"notIn\" | \"contains\" | \"startsWith\" | \"endsWith\";\n\n/** Comparison / membership predicate on a single field. */\nexport interface IdbFieldFilter {\n readonly kind: \"field\";\n readonly field: string;\n readonly op: IdbFilterOp;\n readonly value: unknown;\n}\n\n/** Conjunction. Empty `exprs` is truthy (vacuously true). */\nexport interface IdbAndExpr {\n readonly kind: \"and\";\n readonly exprs: ReadonlyArray<IdbFilterExpr>;\n}\n\n/** Disjunction. Empty `exprs` is falsy. */\nexport interface IdbOrExpr {\n readonly kind: \"or\";\n readonly exprs: ReadonlyArray<IdbFilterExpr>;\n}\n\n/** Logical NOT. */\nexport interface IdbNotExpr {\n readonly kind: \"not\";\n readonly expr: IdbFilterExpr;\n}\n\n/**\n * Null check. Distinct from `eq null` because IDB serialises absent\n * fields as `undefined`; a null check treats `null` and `undefined`\n * as equivalent (matching the shorthand `where({ field: null })`).\n */\nexport interface IdbNullCheckExpr {\n readonly kind: \"null-check\";\n readonly field: string;\n readonly isNull: boolean;\n}\n\nexport type IdbFilterExpr = IdbFieldFilter | IdbAndExpr | IdbOrExpr | IdbNotExpr | IdbNullCheckExpr;\n\n// ── Factory helpers ───────────────────────────────────────────────────────────\n\n/** Build a frozen field-filter node. */\nexport const fieldFilter = (field: string, op: IdbFilterOp, value: unknown): IdbFieldFilter =>\n Object.freeze({ kind: \"field\", field, op, value });\n\n/** Build a frozen AND combinator with a frozen `exprs` array. */\nexport const andExpr = (exprs: ReadonlyArray<IdbFilterExpr>): IdbAndExpr =>\n Object.freeze({ kind: \"and\", exprs: Object.freeze([...exprs]) });\n\n/** Build a frozen OR combinator with a frozen `exprs` array. */\nexport const orExpr = (exprs: ReadonlyArray<IdbFilterExpr>): IdbOrExpr =>\n Object.freeze({ kind: \"or\", exprs: Object.freeze([...exprs]) });\n\n/** Build a frozen NOT combinator. */\nexport const notExpr = (expr: IdbFilterExpr): IdbNotExpr => Object.freeze({ kind: \"not\", expr });\n\n/** Build a frozen null-check node. */\nexport const nullCheckExpr = (field: string, isNull: boolean): IdbNullCheckExpr =>\n Object.freeze({ kind: \"null-check\", field, isNull });\n\n// ── Shorthand → expression ────────────────────────────────────────────────────\n\n/**\n * Convert a shorthand equality object (e.g. `{ active: true, email: \"x\" }`)\n * into the canonical AST form. `undefined` entries are dropped; `null`\n * values become null-checks rather than literal-null equalities (IDB\n * stores absent fields as `undefined`, so a literal-null equality misses).\n *\n * Returns `undefined` when the input has no usable entries — callers can\n * skip filter installation in that case rather than testing an empty\n * AND node every row.\n */\nexport function shorthandToFilterExpr(filters: Record<string, unknown>): IdbFilterExpr | undefined {\n const exprs: IdbFilterExpr[] = [];\n for (const [field, value] of Object.entries(filters)) {\n if (value === undefined) continue;\n if (value === null) {\n exprs.push(nullCheckExpr(field, true));\n continue;\n }\n exprs.push(fieldFilter(field, \"eq\", value));\n }\n if (exprs.length === 0) return undefined;\n return exprs.length === 1 ? exprs[0]! : andExpr(exprs);\n}\n","/**\n * Pure-JS evaluator for {@link IdbFilterExpr}.\n *\n * The driver's `IdbRowFilter` type stays as `(row) => boolean` — the\n * accessor builds a closure that calls `evaluateFilter(expr, row)` and\n * passes that to the driver. The driver therefore never imports the\n * adapter's AST types, and keeps no dependency on the adapter.\n *\n * Equality and ordering compare values the way IndexedDB compares keys, so\n * a filter gives the same answer whether it runs here or through an index\n * key range. Plain `===` would never match two equal `Date`s or byte arrays,\n * because values read back from IndexedDB are fresh objects. String\n * operations coerce both sides via `String(...)` so they work on numbers too.\n */\n\nimport { compareFieldValues, fieldValuesEqual } from \"@prisma-idb/target-idb/runtime\";\nimport type { IdbFilterExpr, IdbFilterOp } from \"./idb-filter-expr\";\n\n/** Evaluate an AST node against a single row. Returns `true` to keep the row. */\nexport function evaluateFilter(expr: IdbFilterExpr, row: Record<string, unknown>): boolean {\n switch (expr.kind) {\n case \"field\":\n return evalFieldOp(expr.field, expr.op, expr.value, row);\n case \"and\": {\n for (const e of expr.exprs) {\n if (!evaluateFilter(e, row)) return false;\n }\n return true;\n }\n case \"or\": {\n if (expr.exprs.length === 0) return false;\n for (const e of expr.exprs) {\n if (evaluateFilter(e, row)) return true;\n }\n return false;\n }\n case \"not\":\n return !evaluateFilter(expr.expr, row);\n case \"null-check\": {\n const v = row[expr.field];\n const isNullish = v === null || v === undefined;\n return expr.isNull ? isNullish : !isNullish;\n }\n }\n}\n\nfunction evalFieldOp(field: string, op: IdbFilterOp, value: unknown, row: Record<string, unknown>): boolean {\n const cell = row[field];\n switch (op) {\n case \"eq\":\n // `eq` treats null and undefined as equivalent so the shorthand path\n // (`{ field: someValue }`) keeps working when stored rows omit the\n // field. Literal-null equality goes through `null-check` instead.\n if (value === null) return cell === null || cell === undefined;\n return fieldValuesEqual(cell, value);\n case \"neq\":\n if (value === null) return cell !== null && cell !== undefined;\n return !fieldValuesEqual(cell, value);\n case \"gt\":\n return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) > 0;\n case \"lt\":\n return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) < 0;\n case \"gte\":\n return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) >= 0;\n case \"lte\":\n return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) <= 0;\n case \"in\": {\n if (!Array.isArray(value)) return false;\n return value.some((v) => fieldValuesEqual(cell, v));\n }\n case \"notIn\": {\n if (!Array.isArray(value)) return true;\n return !value.some((v) => fieldValuesEqual(cell, v));\n }\n case \"contains\":\n return isPresent(cell) && String(cell).includes(String(value));\n case \"startsWith\":\n return isPresent(cell) && String(cell).startsWith(String(value));\n case \"endsWith\":\n return isPresent(cell) && String(cell).endsWith(String(value));\n default:\n return false;\n }\n}\n\nfunction isPresent(value: unknown): boolean {\n return value !== null && value !== undefined;\n}\n","import type { RuntimeAdapterDescriptor, ExecutionStack } from \"@prisma/orm-framework/components/execution\";\nimport { idbCodecLookup } from \"@prisma-idb/target-idb/runtime\";\nimport { idbAdapterDescriptorMeta } from \"../core/descriptor-meta\";\nimport { IdbAdapter } from \"../core/idb-adapter\";\nimport type { IdbRuntimeAdapterInstance } from \"../core/runtime-adapter-instance\";\n\nexport type { IdbRuntimeAdapterInstance, IdbLowererContext } from \"../core/runtime-adapter-instance\";\nexport type { IdbQueryPlan } from \"../core/idb-query-plan\";\nexport type {\n IdbQueryAst,\n IdbFindManyAst,\n IdbFindUniqueAst,\n IdbCreateAst,\n IdbDeleteAst,\n IdbUpdateAst,\n IdbUpdateAllAst,\n IdbUpdateCountAst,\n IdbCreateAllAst,\n IdbCreateCountAst,\n IdbDeleteAllAst,\n IdbDeleteCountAst,\n IdbCountAst,\n IdbAggregateAst,\n IdbGroupByAst,\n IdbAggregateRequest,\n} from \"../core/idb-query-ast\";\nexport type {\n IdbFilterExpr,\n IdbFieldFilter,\n IdbAndExpr,\n IdbOrExpr,\n IdbNotExpr,\n IdbNullCheckExpr,\n IdbFilterOp,\n} from \"../core/idb-filter-expr\";\nexport { fieldFilter, andExpr, orExpr, notExpr, nullCheckExpr, shorthandToFilterExpr } from \"../core/idb-filter-expr\";\nexport { evaluateFilter } from \"../core/filter-eval\";\nexport { IdbAdapter } from \"../core/idb-adapter\";\n\nconst idbRuntimeAdapterDescriptor: RuntimeAdapterDescriptor<\"idb\", \"idb\", IdbRuntimeAdapterInstance> = {\n ...idbAdapterDescriptorMeta,\n create(_stack: ExecutionStack<\"idb\", \"idb\">): IdbRuntimeAdapterInstance {\n // Construct the adapter with the real IDB codec lookup so per-field\n // encoding works when non-identity codecs are added. The current set\n // is all-identity, so output behavior is unchanged; this wiring makes\n // the descriptor-built adapter match the hand-constructed one in\n // `createIdbClient`.\n return new IdbAdapter(idbCodecLookup);\n },\n};\n\nexport default idbRuntimeAdapterDescriptor;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runtime.mjs","names":["#codecs"],"sources":["../src/core/idb-adapter.ts","../src/core/idb-filter-expr.ts","../src/core/filter-eval.ts","../src/exports/runtime.ts"],"sourcesContent":["import type { CodecLookup } from \"@prisma/orm-framework/components/codec\";\nimport { canonicalStringify } from \"@prisma/orm-framework/utils/canonical-stringify\";\nimport type { IdbLoweredPlan, IdbQueryPlan } from \"./idb-query-plan\";\nimport type { IdbLowererContext, IdbRuntimeAdapterInstance } from \"./runtime-adapter-instance\";\n\n/**\n * Concrete IDB runtime adapter.\n *\n * Implements {@link IdbRuntimeAdapterInstance} — the `lower()` method that\n * translates an {@link IdbQueryPlan} into an {@link IdbLoweredPlan} ready for\n * the driver.\n *\n * `lower()` preserves the driver operation: the `idbPlan` carried by\n * `IdbQueryPlan` is already execution-ready because IDB has no query\n * language to compile from. Every current `idb/*` codec is an identity\n * transform for stored values, so no field needs encoding. Structured AST\n * filters and sort specifications become canonical closure identities for\n * middleware; the driver remains independent of the query layer.\n *\n * The `codecs` constructor parameter matches the framework adapter shape and\n * is the extension point for field encoding with non-identity codecs.\n */\nexport class IdbAdapter implements IdbRuntimeAdapterInstance {\n readonly familyId = \"idb\" as const;\n readonly targetId = \"idb\" as const;\n\n readonly #codecs: CodecLookup;\n\n constructor(codecs: CodecLookup) {\n this.#codecs = codecs;\n }\n\n /** Preserve the driver operation and carry structured closure identity through lowering. */\n lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbLoweredPlan> {\n // If a codec ever transforms stored values, encode plan.idbPlan's\n // record and key fields here: resolve each field's codec through\n // this.#codecs and ctx.contract, then call codec.encode(value, ctx).\n void this.#codecs; // codec registry for per-field encoding\n void ctx.contract; // contract storage schema (field→codec resolution)\n void ctx.signal; // AbortSignal for cooperative cancellation\n const ast = plan.ast;\n if (ast === undefined) return Promise.resolve(plan.idbPlan);\n\n const filter = \"where\" in ast ? closureIdentity(ast.where) : undefined;\n // Comparators visit fields in declaration order. Canonicalizing the record\n // itself would sort its keys and lose the priority of multi-field sorts.\n const comparator =\n \"orderBy\" in ast && ast.orderBy !== undefined ? closureIdentity(Object.entries(ast.orderBy)) : undefined;\n if (filter === undefined && comparator === undefined) return Promise.resolve(plan.idbPlan);\n\n return Promise.resolve({\n ...plan.idbPlan,\n queryIdentity: {\n ...(filter === undefined ? {} : { filter }),\n ...(comparator === undefined ? {} : { comparator }),\n },\n });\n }\n}\n\n/** Leave unsupported structured values opaque so identity generation cannot break a query. */\nfunction closureIdentity(value: unknown): string | undefined {\n if (value === undefined) return undefined;\n try {\n return canonicalStringify(value);\n } catch {\n return undefined;\n }\n}\n","/**\n * Filter expression AST for IDB queries.\n *\n * Plain frozen objects (not classes) — IDB has no codec trait gating to\n * worry about and no visitor pattern needed (a recursive `evaluateFilter`\n * is plenty). Mirrors the design of Prisma ORM's Mongo family\n * (`MongoFieldFilter`, `MongoAndExpr`, ...) and the SQL ORM's `BinaryExpr`,\n * but with the class machinery stripped out.\n *\n * The AST is carried on `IdbQueryAst` (intent layer) and lowered into an\n * `IdbRowFilter` closure that the driver applies during cursor scans —\n * keeping the driver free of any AST imports.\n */\n\nexport type IdbFilterOp =\n \"eq\" | \"neq\" | \"gt\" | \"lt\" | \"gte\" | \"lte\" | \"in\" | \"notIn\" | \"contains\" | \"startsWith\" | \"endsWith\";\n\n/** Comparison / membership predicate on a single field. */\nexport interface IdbFieldFilter {\n readonly kind: \"field\";\n readonly field: string;\n readonly op: IdbFilterOp;\n readonly value: unknown;\n}\n\n/** Conjunction. Empty `exprs` is truthy (vacuously true). */\nexport interface IdbAndExpr {\n readonly kind: \"and\";\n readonly exprs: ReadonlyArray<IdbFilterExpr>;\n}\n\n/** Disjunction. Empty `exprs` is falsy. */\nexport interface IdbOrExpr {\n readonly kind: \"or\";\n readonly exprs: ReadonlyArray<IdbFilterExpr>;\n}\n\n/** Logical NOT. */\nexport interface IdbNotExpr {\n readonly kind: \"not\";\n readonly expr: IdbFilterExpr;\n}\n\n/**\n * Explicit null check. Like `eq(null)` and `neq(null)`, it treats null\n * and absent fields as equivalent and always returns true or false.\n * Other nullable comparisons can be unknown until the full filter is evaluated.\n */\nexport interface IdbNullCheckExpr {\n readonly kind: \"null-check\";\n readonly field: string;\n readonly isNull: boolean;\n}\n\n/** A field predicate, logical combination, or null check in the IDB filter AST. */\nexport type IdbFilterExpr = IdbFieldFilter | IdbAndExpr | IdbOrExpr | IdbNotExpr | IdbNullCheckExpr;\n\n// ── Factory helpers ───────────────────────────────────────────────────────────\n\n/** Build a frozen field-filter node. */\nexport const fieldFilter = (field: string, op: IdbFilterOp, value: unknown): IdbFieldFilter =>\n Object.freeze({ kind: \"field\", field, op, value });\n\n/** Build a frozen AND combinator with a frozen `exprs` array. */\nexport const andExpr = (exprs: ReadonlyArray<IdbFilterExpr>): IdbAndExpr =>\n Object.freeze({ kind: \"and\", exprs: Object.freeze([...exprs]) });\n\n/** Build a frozen OR combinator with a frozen `exprs` array. */\nexport const orExpr = (exprs: ReadonlyArray<IdbFilterExpr>): IdbOrExpr =>\n Object.freeze({ kind: \"or\", exprs: Object.freeze([...exprs]) });\n\n/** Build a frozen NOT combinator. */\nexport const notExpr = (expr: IdbFilterExpr): IdbNotExpr => Object.freeze({ kind: \"not\", expr });\n\n/** Build a frozen null-check node. */\nexport const nullCheckExpr = (field: string, isNull: boolean): IdbNullCheckExpr =>\n Object.freeze({ kind: \"null-check\", field, isNull });\n\n// ── Shorthand → expression ────────────────────────────────────────────────────\n\n/**\n * Convert a shorthand equality object (e.g. `{ active: true, email: \"x\" }`)\n * into the canonical AST form. `undefined` entries are dropped; `null`\n * values become null-checks rather than literal-null equalities (IDB\n * stores absent fields as `undefined`, so a literal-null equality misses).\n *\n * Returns `undefined` when the input has no usable entries — callers can\n * skip filter installation in that case rather than testing an empty\n * AND node every row.\n */\nexport function shorthandToFilterExpr(filters: Record<string, unknown>): IdbFilterExpr | undefined {\n const exprs: IdbFilterExpr[] = [];\n for (const [field, value] of Object.entries(filters)) {\n if (value === undefined) continue;\n if (value === null) {\n exprs.push(nullCheckExpr(field, true));\n continue;\n }\n exprs.push(fieldFilter(field, \"eq\", value));\n }\n if (exprs.length === 0) return undefined;\n return exprs.length === 1 ? exprs[0]! : andExpr(exprs);\n}\n","/**\n * Pure-JS evaluator for {@link IdbFilterExpr}.\n *\n * The driver's `IdbRowFilter` type stays as `(row) => boolean` — the\n * accessor builds a closure that calls `evaluateFilter(expr, row)` and\n * passes that to the driver. The driver therefore never imports the\n * adapter's AST types, and keeps no dependency on the adapter.\n *\n * Decimal metadata selects exact numeric comparison. Other fields compare\n * values the way IndexedDB compares keys, so a filter agrees with an index\n * key range. Plain `===` would never match two equal `Date`s or byte arrays,\n * because values read back from IndexedDB are fresh objects. String\n * operations coerce both sides via `String(...)` so they work on numbers too.\n */\n\nimport {\n compareDecimalValues,\n compareFieldValues,\n fieldValuesEqual,\n isDecimalString,\n} from \"@prisma-idb/target-idb/runtime\";\nimport type { IdbFilterExpr, IdbFilterOp } from \"./idb-filter-expr\";\n\n/** Codec metadata determines which string fields have numeric Decimal semantics. */\nexport type FilterFieldMetadata = Readonly<\n Record<string, { readonly codecId?: string | undefined; readonly collection?: boolean }>\n>;\n\n/** Reject invalid Decimal operands even when no stored row reaches the evaluator. */\nexport function assertValidDecimalFilter(expr: IdbFilterExpr, fields: FilterFieldMetadata): void {\n if (expr.kind === \"and\" || expr.kind === \"or\") {\n expr.exprs.forEach((child) => assertValidDecimalFilter(child, fields));\n } else if (expr.kind === \"not\") {\n assertValidDecimalFilter(expr.expr, fields);\n } else if (expr.kind === \"field\" && isDecimalField(fields, expr.field)) {\n // Text operators inspect the stored spelling and need no numeric operand.\n if (expr.op === \"contains\" || expr.op === \"startsWith\" || expr.op === \"endsWith\") return;\n const values = expr.op === \"in\" || expr.op === \"notIn\" ? expr.value : [expr.value];\n if (Array.isArray(values) && values.some((value) => isPresent(value) && !isDecimalString(value))) {\n throw new TypeError(`Expected finite Decimal text for field \"${expr.field}\"`);\n }\n }\n}\n\n/** Identify scalar Decimal fields without reinterpreting string or collection values. */\nfunction isDecimalField(fields: FilterFieldMetadata, field: string): boolean {\n return fields[field]?.codecId === \"idb/decimal@1\" && !fields[field]?.collection;\n}\n\n/** SQL predicate result before the outer WHERE boundary discards unknown. */\ntype PredicateResult = boolean | null;\n\n/** Evaluate an AST node against a single row. Only SQL TRUE keeps the row. */\nexport function evaluateFilter(\n expr: IdbFilterExpr,\n row: Record<string, unknown>,\n fields: FilterFieldMetadata = {}\n): boolean {\n return evaluatePredicate(expr, row, fields) === true;\n}\n\n/** Preserve unknown through logical composition so negation cannot admit null comparisons. */\nfunction evaluatePredicate(\n expr: IdbFilterExpr,\n row: Record<string, unknown>,\n fields: FilterFieldMetadata\n): PredicateResult {\n switch (expr.kind) {\n case \"field\":\n return evalFieldOp(expr.field, expr.op, expr.value, row, fields);\n case \"and\": {\n let result: PredicateResult = true;\n for (const e of expr.exprs) {\n const child = evaluatePredicate(e, row, fields);\n if (child === false) return false;\n if (child === null) result = null;\n }\n return result;\n }\n case \"or\": {\n let result: PredicateResult = false;\n for (const e of expr.exprs) {\n const child = evaluatePredicate(e, row, fields);\n if (child === true) return true;\n if (child === null) result = null;\n }\n return result;\n }\n case \"not\": {\n const result = evaluatePredicate(expr.expr, row, fields);\n return result === null ? null : !result;\n }\n case \"null-check\": {\n const isNullish = !isPresent(row[expr.field]);\n return expr.isNull ? isNullish : !isNullish;\n }\n }\n}\n\n/** Evaluate one field predicate with the same comparisons used by index-backed queries. */\nfunction evalFieldOp(\n field: string,\n op: IdbFilterOp,\n value: unknown,\n row: Record<string, unknown>,\n fields: FilterFieldMetadata\n): PredicateResult {\n const cell = row[field];\n // Upstream eq(null) and neq(null) are explicit null checks, not SQL comparisons.\n if (value === null && (op === \"eq\" || op === \"neq\")) {\n return op === \"eq\" ? !isPresent(cell) : isPresent(cell);\n }\n const decimal = isDecimalField(fields, field);\n const compare = decimal ? compareDecimalValues : compareFieldValues;\n const equal = decimal ? (a: unknown, b: unknown) => compareDecimalValues(a, b) === 0 : fieldValuesEqual;\n if (op === \"in\" || op === \"notIn\") {\n const result = evaluateMembership(cell, value, equal);\n if (result === null) return null;\n return op === \"in\" ? result : !result;\n }\n if (!isPresent(cell) || !isPresent(value)) return null;\n\n switch (op) {\n case \"eq\":\n return equal(cell, value);\n case \"neq\":\n return !equal(cell, value);\n case \"gt\":\n return compare(cell, value) > 0;\n case \"lt\":\n return compare(cell, value) < 0;\n case \"gte\":\n return compare(cell, value) >= 0;\n case \"lte\":\n return compare(cell, value) <= 0;\n case \"contains\":\n return String(cell).includes(String(value));\n case \"startsWith\":\n return String(cell).startsWith(String(value));\n case \"endsWith\":\n return String(cell).endsWith(String(value));\n default:\n return false;\n }\n}\n\n/** Match SQL IN: empty lists are false; otherwise null operands leave an unmatched result unknown. */\nfunction evaluateMembership(\n cell: unknown,\n values: unknown,\n equal: (a: unknown, b: unknown) => boolean\n): PredicateResult {\n if (!Array.isArray(values) || values.length === 0) return false;\n if (!isPresent(cell)) return null;\n let result: PredicateResult = false;\n for (const value of values) {\n if (!isPresent(value)) result = null;\n else if (equal(cell, value)) return true;\n }\n return result;\n}\n\nfunction isPresent(value: unknown): boolean {\n return value !== null && value !== undefined;\n}\n","import type { RuntimeAdapterDescriptor, ExecutionStack } from \"@prisma/orm-framework/components/execution\";\nimport { idbCodecLookup } from \"@prisma-idb/target-idb/runtime\";\nimport { idbAdapterDescriptorMeta } from \"../core/descriptor-meta\";\nimport { IdbAdapter } from \"../core/idb-adapter\";\nimport type { IdbRuntimeAdapterInstance } from \"../core/runtime-adapter-instance\";\n\nexport type { IdbRuntimeAdapterInstance, IdbLowererContext } from \"../core/runtime-adapter-instance\";\nexport type { IdbQueryPlan, IdbLoweredPlan } from \"../core/idb-query-plan\";\nexport type {\n IdbQueryAst,\n IdbFindManyAst,\n IdbFindUniqueAst,\n IdbCreateAst,\n IdbDeleteAst,\n IdbUpdateAst,\n IdbUpdateAllAst,\n IdbUpdateCountAst,\n IdbCreateAllAst,\n IdbCreateCountAst,\n IdbDeleteAllAst,\n IdbDeleteCountAst,\n IdbCountAst,\n IdbAggregateAst,\n IdbGroupByAst,\n IdbAggregateRequest,\n} from \"../core/idb-query-ast\";\nexport type {\n IdbFilterExpr,\n IdbFieldFilter,\n IdbAndExpr,\n IdbOrExpr,\n IdbNotExpr,\n IdbNullCheckExpr,\n IdbFilterOp,\n} from \"../core/idb-filter-expr\";\nexport { fieldFilter, andExpr, orExpr, notExpr, nullCheckExpr, shorthandToFilterExpr } from \"../core/idb-filter-expr\";\nexport { evaluateFilter, assertValidDecimalFilter } from \"../core/filter-eval\";\nexport { IdbAdapter } from \"../core/idb-adapter\";\n\nconst idbRuntimeAdapterDescriptor: RuntimeAdapterDescriptor<\"idb\", \"idb\", IdbRuntimeAdapterInstance> = {\n ...idbAdapterDescriptorMeta,\n /** Build an adapter with the codec registry shared by the IDB runtime stack. */\n create(_stack: ExecutionStack<\"idb\", \"idb\">): IdbRuntimeAdapterInstance {\n // Construct the adapter with the real IDB codec lookup so per-field\n // encoding works when non-identity codecs are added. The current set\n // is all-identity, so output behavior is unchanged; this wiring makes\n // the descriptor-built adapter match the hand-constructed one in\n // `createIdbClient`.\n return new IdbAdapter(idbCodecLookup);\n },\n};\n\nexport default idbRuntimeAdapterDescriptor;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-idb/adapter-idb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Prisma 8 IDB family — adapter (lowers query AST to opaque IDB plan body)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"./package.json": "./package.json"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@prisma-idb/driver-idb": "0.
|
|
33
|
-
"@prisma-idb/target-idb": "0.
|
|
34
|
-
"@prisma/orm-framework": "8.0.0-rc.
|
|
32
|
+
"@prisma-idb/driver-idb": "0.13.0",
|
|
33
|
+
"@prisma-idb/target-idb": "0.13.0",
|
|
34
|
+
"@prisma/orm-framework": "8.0.0-rc.18"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"tsdown": "^0.22.14",
|