@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 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
@@ -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
- * Null check. Distinct from `eq null` because IDB serialises absent
44
- * fields as `undefined`; a null check treats `null` and `undefined`
45
- * as equivalent (matching the shorthand `where({ field: null })`).
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
- * passes that body through to the driver unchanged.
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 inspect query structure without parsing opaque plan bodies. This mirrors
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
- * Available to middleware via `plan.ast`. Absent for plans constructed
237
- * outside the ORM lane (e.g. direct driver usage).
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 IdbPlanBody}
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<IdbPlanBody>;
298
+ lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbLoweredPlan>;
282
299
  }
283
300
  //#endregion
284
301
  //#region src/core/filter-eval.d.ts
285
- /** Evaluate an AST node against a single row. Returns `true` to keep the row. */
286
- declare function evaluateFilter(expr: IdbFilterExpr, row: Record<string, unknown>): boolean;
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 IdbPlanBody} ready for
317
+ * translates an {@link IdbQueryPlan} into an {@link IdbLoweredPlan} ready for
294
318
  * the driver.
295
319
  *
296
- * `lower()` is a structural passthrough: the `idbPlan` carried by
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
- lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbPlanBody>;
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
@@ -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;;KAGC,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;;;;;;;;;;KCnE7D,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;;;;;;;WAOT,MAAM;;YAEL,qBAAqB;;;;;;;;;;;;;UCtBhB,kBAAkB,6BAA6B;;WAErD,UAAU;;;;;;;;;;;;;;;UAgBJ,kCAAkC;;;;;;;;;;EAUjD,MAAM,MAAM,cAAc,KAAK,oBAAoB,QAAQ;;;;;iBCvB7C,eAAe,MAAM,eAAe,KAAK;;;;;;;;;;;;;;;;;;cCC5C,sBAAsB;;WACxB;WACA;EAIG,YAAA,QAAQ;EAIpB,MAAM,MAAM,cAAc,KAAK,oBAAoB,QAAQ;;;;cCSvD,6BAA6B,uCAAuC"}
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 IdbPlanBody} ready for
9
+ * translates an {@link IdbQueryPlan} into an {@link IdbLoweredPlan} ready for
9
10
  * the driver.
10
11
  *
11
- * `lower()` is a structural passthrough: the `idbPlan` carried by
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
- return Promise.resolve(plan.idbPlan);
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
- * Equality and ordering compare values the way IndexedDB compares keys, so
97
- * a filter gives the same answer whether it runs here or through an index
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
- /** Evaluate an AST node against a single row. Returns `true` to keep the row. */
103
- function evaluateFilter(expr, row) {
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
- for (const e of expr.exprs) if (!evaluateFilter(e, row)) return false;
108
- return true;
109
- case "or":
110
- if (expr.exprs.length === 0) return false;
111
- for (const e of expr.exprs) if (evaluateFilter(e, row)) return true;
112
- return false;
113
- case "not": return !evaluateFilter(expr.expr, row);
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 v = row[expr.field];
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
- function evalFieldOp(field, op, value, row) {
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
- if (value === null) return cell === null || cell === void 0;
126
- return fieldValuesEqual(cell, value);
127
- case "neq":
128
- if (value === null) return cell !== null && cell !== void 0;
129
- return !fieldValuesEqual(cell, value);
130
- case "gt": return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) > 0;
131
- case "lt": return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) < 0;
132
- case "gte": return isPresent(cell) && isPresent(value) && compareFieldValues(cell, value) >= 0;
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
@@ -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.12.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.12.0",
33
- "@prisma-idb/target-idb": "0.12.0",
34
- "@prisma/orm-framework": "8.0.0-rc.12"
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",