@prisma-idb/adapter-idb 0.0.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/LICENSE +21 -0
- package/README.md +24 -0
- package/dist/control.d.mts +6 -0
- package/dist/control.d.mts.map +1 -0
- package/dist/control.mjs +15 -0
- package/dist/control.mjs.map +1 -0
- package/dist/descriptor-meta-DRDNlZjA.mjs +22 -0
- package/dist/descriptor-meta-DRDNlZjA.mjs.map +1 -0
- package/dist/runtime.d.mts +320 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +145 -0
- package/dist/runtime.mjs.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Prisma IDB
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `@prisma-idb/adapter-idb`
|
|
2
|
+
|
|
3
|
+
> Part of the [`@prisma-idb`](https://prisma-idb.dev/) driver stack for Prisma 8.
|
|
4
|
+
|
|
5
|
+
**adapter-idb** is the translation layer. It lowers the Prisma query AST into an opaque IDB plan body that the driver can execute.
|
|
6
|
+
|
|
7
|
+
## Stack position
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
family-idb (CLI / config)
|
|
11
|
+
client-idb (ORM query builder)
|
|
12
|
+
runtime-idb (RuntimeCore)
|
|
13
|
+
adapter-idb ← you are here (query AST → IDB plan)
|
|
14
|
+
driver-idb (window.indexedDB wrapper)
|
|
15
|
+
target-idb (identity + migrations)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
Consumed internally by the rest of the `@prisma-idb` family. You generally do not install this package directly — use [`@prisma-idb/family-idb`](https://www.npmjs.com/package/@prisma-idb/family-idb) as your entry point.
|
|
21
|
+
|
|
22
|
+
## License
|
|
23
|
+
|
|
24
|
+
MIT
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ControlAdapterDescriptor } from "@prisma/orm-framework/components/control";
|
|
2
|
+
//#region src/exports/control.d.ts
|
|
3
|
+
declare const idbControlAdapterDescriptor: ControlAdapterDescriptor<"idb", "idb">;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { idbControlAdapterDescriptor as default };
|
|
6
|
+
//# sourceMappingURL=control.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/exports/control.ts"],"mappings":";;cAOM,6BAA6B"}
|
package/dist/control.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { t as idbAdapterDescriptorMeta } from "./descriptor-meta-DRDNlZjA.mjs";
|
|
2
|
+
//#region src/exports/control.ts
|
|
3
|
+
const idbControlAdapterDescriptor = {
|
|
4
|
+
...idbAdapterDescriptorMeta,
|
|
5
|
+
create(_stack) {
|
|
6
|
+
return {
|
|
7
|
+
familyId: "idb",
|
|
8
|
+
targetId: "idb"
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { idbControlAdapterDescriptor as default };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=control.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.mjs","names":[],"sources":["../src/exports/control.ts"],"sourcesContent":["import type {\n ControlAdapterDescriptor,\n ControlAdapterInstance,\n ControlStack,\n} from \"@prisma/orm-framework/components/control\";\nimport { idbAdapterDescriptorMeta } from \"../core/descriptor-meta\";\n\nconst idbControlAdapterDescriptor: ControlAdapterDescriptor<\"idb\", \"idb\"> = {\n ...idbAdapterDescriptorMeta,\n create(_stack: ControlStack<\"idb\", \"idb\">): ControlAdapterInstance<\"idb\", \"idb\"> {\n return { familyId: \"idb\", targetId: \"idb\" };\n },\n};\n\nexport default idbControlAdapterDescriptor;\n"],"mappings":";;AAOA,MAAM,8BAAsE;CAC1E,GAAG;CACH,OAAO,QAA0E;EAC/E,OAAO;GAAE,UAAU;GAAO,UAAU;EAAM;CAC5C;AACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/core/descriptor-meta.ts
|
|
2
|
+
const idbAdapterDescriptorMeta = {
|
|
3
|
+
kind: "adapter",
|
|
4
|
+
familyId: "idb",
|
|
5
|
+
targetId: "idb",
|
|
6
|
+
id: "idb",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
capabilities: { idb: {
|
|
9
|
+
/** IDB's `upgradeneeded` callback IS a version-change transaction. */
|
|
10
|
+
transactionalDDL: true,
|
|
11
|
+
/** DDL can ONLY run inside `upgradeneeded` — never at query time. */
|
|
12
|
+
ddlOnlyInUpgrade: true,
|
|
13
|
+
/** IDB has no RETURNING clause. */
|
|
14
|
+
returning: false,
|
|
15
|
+
/** Compound keys are forbidden by sync ownership invariants. */
|
|
16
|
+
compoundKeys: false
|
|
17
|
+
} }
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
20
|
+
export { idbAdapterDescriptorMeta as t };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=descriptor-meta-DRDNlZjA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor-meta-DRDNlZjA.mjs","names":[],"sources":["../src/core/descriptor-meta.ts"],"sourcesContent":["import type { AdapterDescriptor } from \"@prisma/orm-framework/components/components\";\n\nexport const idbAdapterDescriptorMeta = {\n kind: \"adapter\",\n familyId: \"idb\",\n targetId: \"idb\",\n id: \"idb\",\n version: \"0.0.1\",\n capabilities: {\n idb: {\n /** IDB's `upgradeneeded` callback IS a version-change transaction. */\n transactionalDDL: true,\n /** DDL can ONLY run inside `upgradeneeded` — never at query time. */\n ddlOnlyInUpgrade: true,\n /** IDB has no RETURNING clause. */\n returning: false,\n /** Compound keys are forbidden by sync ownership invariants. */\n compoundKeys: false,\n },\n },\n} satisfies AdapterDescriptor<\"idb\", \"idb\">;\n"],"mappings":";AAEA,MAAa,2BAA2B;CACtC,MAAM;CACN,UAAU;CACV,UAAU;CACV,IAAI;CACJ,SAAS;CACT,cAAc,EACZ,KAAK;;EAEH,kBAAkB;;EAElB,kBAAkB;;EAElB,WAAW;;EAEX,cAAc;CAChB,EACF;AACF"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { RuntimeAdapterDescriptor, RuntimeAdapterInstance } from "@prisma/orm-framework/components/execution";
|
|
2
|
+
import { CodecCallContext, CodecLookup } from "@prisma/orm-framework/components/codec";
|
|
3
|
+
import { IdbPlanBody } from "@prisma-idb/driver-idb/runtime";
|
|
4
|
+
import { QueryPlan } from "@prisma/orm-framework/components/runtime";
|
|
5
|
+
//#region src/core/idb-filter-expr.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Filter expression AST for IDB queries.
|
|
8
|
+
*
|
|
9
|
+
* Plain frozen objects (not classes) — IDB has no codec trait gating to
|
|
10
|
+
* worry about and no visitor pattern needed (a recursive `evaluateFilter`
|
|
11
|
+
* is plenty). Mirrors the design of Prisma ORM's Mongo family
|
|
12
|
+
* (`MongoFieldFilter`, `MongoAndExpr`, ...) and the SQL ORM's `BinaryExpr`,
|
|
13
|
+
* but with the class machinery stripped out.
|
|
14
|
+
*
|
|
15
|
+
* The AST is carried on `IdbQueryAst` (intent layer) and lowered into an
|
|
16
|
+
* `IdbRowFilter` closure that the driver applies during cursor scans —
|
|
17
|
+
* keeping the driver free of any AST imports.
|
|
18
|
+
*/
|
|
19
|
+
type IdbFilterOp = "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "in" | "notIn" | "contains" | "startsWith" | "endsWith";
|
|
20
|
+
/** Comparison / membership predicate on a single field. */
|
|
21
|
+
interface IdbFieldFilter {
|
|
22
|
+
readonly kind: "field";
|
|
23
|
+
readonly field: string;
|
|
24
|
+
readonly op: IdbFilterOp;
|
|
25
|
+
readonly value: unknown;
|
|
26
|
+
}
|
|
27
|
+
/** Conjunction. Empty `exprs` is truthy (vacuously true). */
|
|
28
|
+
interface IdbAndExpr {
|
|
29
|
+
readonly kind: "and";
|
|
30
|
+
readonly exprs: ReadonlyArray<IdbFilterExpr>;
|
|
31
|
+
}
|
|
32
|
+
/** Disjunction. Empty `exprs` is falsy. */
|
|
33
|
+
interface IdbOrExpr {
|
|
34
|
+
readonly kind: "or";
|
|
35
|
+
readonly exprs: ReadonlyArray<IdbFilterExpr>;
|
|
36
|
+
}
|
|
37
|
+
/** Logical NOT. */
|
|
38
|
+
interface IdbNotExpr {
|
|
39
|
+
readonly kind: "not";
|
|
40
|
+
readonly expr: IdbFilterExpr;
|
|
41
|
+
}
|
|
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 })`).
|
|
46
|
+
*/
|
|
47
|
+
interface IdbNullCheckExpr {
|
|
48
|
+
readonly kind: "null-check";
|
|
49
|
+
readonly field: string;
|
|
50
|
+
readonly isNull: boolean;
|
|
51
|
+
}
|
|
52
|
+
type IdbFilterExpr = IdbFieldFilter | IdbAndExpr | IdbOrExpr | IdbNotExpr | IdbNullCheckExpr;
|
|
53
|
+
/** Build a frozen field-filter node. */
|
|
54
|
+
declare const fieldFilter: (field: string, op: IdbFilterOp, value: unknown) => IdbFieldFilter;
|
|
55
|
+
/** Build a frozen AND combinator with a frozen `exprs` array. */
|
|
56
|
+
declare const andExpr: (exprs: ReadonlyArray<IdbFilterExpr>) => IdbAndExpr;
|
|
57
|
+
/** Build a frozen OR combinator with a frozen `exprs` array. */
|
|
58
|
+
declare const orExpr: (exprs: ReadonlyArray<IdbFilterExpr>) => IdbOrExpr;
|
|
59
|
+
/** Build a frozen NOT combinator. */
|
|
60
|
+
declare const notExpr: (expr: IdbFilterExpr) => IdbNotExpr;
|
|
61
|
+
/** Build a frozen null-check node. */
|
|
62
|
+
declare const nullCheckExpr: (field: string, isNull: boolean) => IdbNullCheckExpr;
|
|
63
|
+
/**
|
|
64
|
+
* Convert a shorthand equality object (e.g. `{ active: true, email: "x" }`)
|
|
65
|
+
* into the canonical AST form. `undefined` entries are dropped; `null`
|
|
66
|
+
* values become null-checks rather than literal-null equalities (IDB
|
|
67
|
+
* stores absent fields as `undefined`, so a literal-null equality misses).
|
|
68
|
+
*
|
|
69
|
+
* Returns `undefined` when the input has no usable entries — callers can
|
|
70
|
+
* skip filter installation in that case rather than testing an empty
|
|
71
|
+
* AND node every row.
|
|
72
|
+
*/
|
|
73
|
+
declare function shorthandToFilterExpr(filters: Record<string, unknown>): IdbFilterExpr | undefined;
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/core/idb-query-ast.d.ts
|
|
76
|
+
/**
|
|
77
|
+
* Discriminated union of all IDB query AST nodes.
|
|
78
|
+
*
|
|
79
|
+
* Each node describes one logical operation. The fields are intentionally
|
|
80
|
+
* higher-level than the plan body types — they use model names, field names,
|
|
81
|
+
* and filter shapes rather than store names and key ranges.
|
|
82
|
+
*/
|
|
83
|
+
type IdbQueryAst = IdbFindManyAst | IdbFindUniqueAst | IdbCreateAst | IdbDeleteAst | IdbUpdateAst | IdbUpdateAllAst | IdbUpdateCountAst | IdbCreateAllAst | IdbCreateCountAst | IdbDeleteAllAst | IdbDeleteCountAst | IdbCountAst | IdbAggregateAst | IdbGroupByAst;
|
|
84
|
+
/** Full cursor scan with optional filtering, ordering, and pagination. */
|
|
85
|
+
interface IdbFindManyAst {
|
|
86
|
+
readonly kind: "findMany";
|
|
87
|
+
/** The model (store) being queried. */
|
|
88
|
+
readonly modelName: string;
|
|
89
|
+
/** Where filter expression, lifted from shorthand or callback form. */
|
|
90
|
+
readonly where?: IdbFilterExpr;
|
|
91
|
+
/** Sort order, if any. Maps field name to direction. */
|
|
92
|
+
readonly orderBy?: Record<string, "asc" | "desc">;
|
|
93
|
+
/** Number of rows to skip (OFFSET). */
|
|
94
|
+
readonly skip?: number;
|
|
95
|
+
/** Maximum number of rows to return (LIMIT). */
|
|
96
|
+
readonly take?: number;
|
|
97
|
+
}
|
|
98
|
+
/** Primary-key or unique-index lookup (O(1)). */
|
|
99
|
+
interface IdbFindUniqueAst {
|
|
100
|
+
readonly kind: "findUnique";
|
|
101
|
+
/** The model (store) being queried. */
|
|
102
|
+
readonly modelName: string;
|
|
103
|
+
/** The key value to look up. */
|
|
104
|
+
readonly key: unknown;
|
|
105
|
+
}
|
|
106
|
+
/** Insert a single record. */
|
|
107
|
+
interface IdbCreateAst {
|
|
108
|
+
readonly kind: "create";
|
|
109
|
+
/** The model (store) being inserted into. */
|
|
110
|
+
readonly modelName: string;
|
|
111
|
+
/** The record data to insert. */
|
|
112
|
+
readonly data: Record<string, unknown>;
|
|
113
|
+
}
|
|
114
|
+
/** Delete a record by primary key. */
|
|
115
|
+
interface IdbDeleteAst {
|
|
116
|
+
readonly kind: "delete";
|
|
117
|
+
/** The model (store) being deleted from. */
|
|
118
|
+
readonly modelName: string;
|
|
119
|
+
/** The key value of the record to delete. */
|
|
120
|
+
readonly key: unknown;
|
|
121
|
+
}
|
|
122
|
+
/** Update the first matching record (cursor scan, take:1). Returns updated row or null. */
|
|
123
|
+
interface IdbUpdateAst {
|
|
124
|
+
readonly kind: "update";
|
|
125
|
+
readonly modelName: string;
|
|
126
|
+
readonly patch: Record<string, unknown>;
|
|
127
|
+
readonly where?: IdbFilterExpr;
|
|
128
|
+
}
|
|
129
|
+
/** Update all matching records. Returns updated rows as AsyncIterableResult. */
|
|
130
|
+
interface IdbUpdateAllAst {
|
|
131
|
+
readonly kind: "updateAll";
|
|
132
|
+
readonly modelName: string;
|
|
133
|
+
readonly patch: Record<string, unknown>;
|
|
134
|
+
readonly where?: IdbFilterExpr;
|
|
135
|
+
}
|
|
136
|
+
/** Update all matching records. Returns count only. */
|
|
137
|
+
interface IdbUpdateCountAst {
|
|
138
|
+
readonly kind: "updateCount";
|
|
139
|
+
readonly modelName: string;
|
|
140
|
+
readonly patch: Record<string, unknown>;
|
|
141
|
+
readonly where?: IdbFilterExpr;
|
|
142
|
+
}
|
|
143
|
+
/** Batch insert multiple records. Returns inserted rows as AsyncIterableResult. */
|
|
144
|
+
interface IdbCreateAllAst {
|
|
145
|
+
readonly kind: "createAll";
|
|
146
|
+
readonly modelName: string;
|
|
147
|
+
readonly data: Record<string, unknown>[];
|
|
148
|
+
}
|
|
149
|
+
/** Batch insert multiple records. Returns count only. */
|
|
150
|
+
interface IdbCreateCountAst {
|
|
151
|
+
readonly kind: "createCount";
|
|
152
|
+
readonly modelName: string;
|
|
153
|
+
readonly data: Record<string, unknown>[];
|
|
154
|
+
}
|
|
155
|
+
/** Delete all matching records. Returns deleted rows as AsyncIterableResult. */
|
|
156
|
+
interface IdbDeleteAllAst {
|
|
157
|
+
readonly kind: "deleteAll";
|
|
158
|
+
readonly modelName: string;
|
|
159
|
+
readonly where?: IdbFilterExpr;
|
|
160
|
+
}
|
|
161
|
+
/** Delete all matching records. Returns count only. */
|
|
162
|
+
interface IdbDeleteCountAst {
|
|
163
|
+
readonly kind: "deleteCount";
|
|
164
|
+
readonly modelName: string;
|
|
165
|
+
readonly where?: IdbFilterExpr;
|
|
166
|
+
}
|
|
167
|
+
/** Count matching records. */
|
|
168
|
+
interface IdbCountAst {
|
|
169
|
+
readonly kind: "count";
|
|
170
|
+
readonly modelName: string;
|
|
171
|
+
readonly where?: IdbFilterExpr;
|
|
172
|
+
}
|
|
173
|
+
/** One aggregation request inside an {@link IdbAggregateAst} / {@link IdbGroupByAst}. */
|
|
174
|
+
interface IdbAggregateRequest {
|
|
175
|
+
/** Aggregate function: `count` | `sum` | `avg` | `min` | `max`. */
|
|
176
|
+
readonly fn: string;
|
|
177
|
+
/** Target field for numeric reducers; absent for `count`. */
|
|
178
|
+
readonly field?: string;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* In-memory aggregate over the matching rows (count/sum/avg/min/max).
|
|
182
|
+
*
|
|
183
|
+
* IDB has no aggregation API, so this is computed by the client after a cursor
|
|
184
|
+
* scan materialises the rows. The AST is attached to that scan plan so cache /
|
|
185
|
+
* logging middleware can observe the aggregate intent.
|
|
186
|
+
*/
|
|
187
|
+
interface IdbAggregateAst {
|
|
188
|
+
readonly kind: "aggregate";
|
|
189
|
+
readonly modelName: string;
|
|
190
|
+
readonly where?: IdbFilterExpr;
|
|
191
|
+
/** Requested aggregates keyed by their result alias. */
|
|
192
|
+
readonly aggregates: Readonly<Record<string, IdbAggregateRequest>>;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* In-memory grouped aggregate (`groupBy(...).aggregate(...)`).
|
|
196
|
+
*
|
|
197
|
+
* Like {@link IdbAggregateAst} but partitions the materialised rows by the
|
|
198
|
+
* `by` fields before reducing each group.
|
|
199
|
+
*/
|
|
200
|
+
interface IdbGroupByAst {
|
|
201
|
+
readonly kind: "groupBy";
|
|
202
|
+
readonly modelName: string;
|
|
203
|
+
readonly where?: IdbFilterExpr;
|
|
204
|
+
/** Group key fields, in declaration order. */
|
|
205
|
+
readonly by: readonly string[];
|
|
206
|
+
/** Requested aggregates keyed by their result alias. */
|
|
207
|
+
readonly aggregates: Readonly<Record<string, IdbAggregateRequest>>;
|
|
208
|
+
}
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/core/idb-query-plan.d.ts
|
|
211
|
+
declare const __idbQueryPlanRow: unique symbol;
|
|
212
|
+
/**
|
|
213
|
+
* IDB pre-lowering query plan produced by lanes before lowering.
|
|
214
|
+
*
|
|
215
|
+
* Extends the framework-level {@link QueryPlan}<Row> marker (`meta + _row`) and
|
|
216
|
+
* adds the IDB execution plan as `idbPlan`. Because IDB has no query language
|
|
217
|
+
* of its own, the plan already carries the execution-ready {@link IdbPlanBody}
|
|
218
|
+
* — there is no AST compilation step as in SQL. The adapter's `lower()` step
|
|
219
|
+
* handles codec encoding of field values (e.g. `idb/date@1` → `Date`) and
|
|
220
|
+
* returns the (possibly re-encoded) `IdbPlanBody` to the driver.
|
|
221
|
+
*
|
|
222
|
+
* The optional `ast` field carries a lightweight {@link IdbQueryAst} describing
|
|
223
|
+
* the query intent. It is populated by the ORM lane (`client-idb`) so middleware
|
|
224
|
+
* can inspect query structure without parsing opaque plan bodies. This mirrors
|
|
225
|
+
* the upstream pattern where {@link SqlQueryPlan} carries an `ast: AnyQueryAst`.
|
|
226
|
+
*
|
|
227
|
+
* @template Row - The TypeScript row shape inferred from the lane builder.
|
|
228
|
+
* Phantom-typed: never read at runtime, but constrains the return type of
|
|
229
|
+
* `runtime.query()`.
|
|
230
|
+
*/
|
|
231
|
+
interface IdbQueryPlan<Row = unknown> extends QueryPlan<Row> {
|
|
232
|
+
/** The execution-ready IDB plan produced by the lane builder. */
|
|
233
|
+
readonly idbPlan: IdbPlanBody;
|
|
234
|
+
/**
|
|
235
|
+
* Optional lightweight AST describing the query intent.
|
|
236
|
+
*
|
|
237
|
+
* Available to middleware via `plan.ast`. Absent for plans constructed
|
|
238
|
+
* outside the ORM lane (e.g. direct driver usage).
|
|
239
|
+
*/
|
|
240
|
+
readonly ast?: IdbQueryAst;
|
|
241
|
+
/** Phantom row brand — matches the `_row` slot on the base QueryPlan. */
|
|
242
|
+
readonly [__idbQueryPlanRow]?: Row;
|
|
243
|
+
}
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/core/runtime-adapter-instance.d.ts
|
|
246
|
+
/**
|
|
247
|
+
* Lowering context passed to the adapter's `lower()` method.
|
|
248
|
+
*
|
|
249
|
+
* Extends the framework's {@link CodecCallContext} (which carries an optional
|
|
250
|
+
* `AbortSignal` for cooperative cancellation) with the resolved IDB contract.
|
|
251
|
+
* The contract provides the per-store field→codec schema for per-field
|
|
252
|
+
* codec encoding (e.g. resolving which codec to use for a `DateTime` field).
|
|
253
|
+
*
|
|
254
|
+
* Upstream equivalent: `LowererContext<TContract>` from
|
|
255
|
+
* Prisma ORM's SQL relational query AST.
|
|
256
|
+
*/
|
|
257
|
+
interface IdbLowererContext<TContract = unknown> extends CodecCallContext {
|
|
258
|
+
/** The resolved IDB contract carrying the full storage schema. */
|
|
259
|
+
readonly contract: TContract;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Runtime adapter instance for IndexedDB.
|
|
263
|
+
*
|
|
264
|
+
* Extends the generic `RuntimeAdapterInstance` marker with the IDB-specific
|
|
265
|
+
* `lower()` method. `lower()` is the core of the adapter: it translates an
|
|
266
|
+
* {@link IdbQueryPlan} (IDB execution plan + meta) into an {@link IdbPlanBody}
|
|
267
|
+
* (one of the strongly-typed IDB operation plans) that the driver can execute
|
|
268
|
+
* directly against `window.indexedDB`.
|
|
269
|
+
*
|
|
270
|
+
* The concrete implementation is {@link import('./idb-adapter').IdbAdapter}.
|
|
271
|
+
* This interface exists so `runtime-idb` has a stable contract to depend on
|
|
272
|
+
* when building `IdbRuntimeImpl`.
|
|
273
|
+
*/
|
|
274
|
+
interface IdbRuntimeAdapterInstance extends RuntimeAdapterInstance<"idb", "idb"> {
|
|
275
|
+
/**
|
|
276
|
+
* Lower an IDB query plan to an IDB execution plan.
|
|
277
|
+
*
|
|
278
|
+
* @param plan - The pre-lowering query plan from a Prisma lane. Carries the
|
|
279
|
+
* execution-ready `IdbPlanBody` plus plan metadata.
|
|
280
|
+
* @param ctx - Lowering context with the resolved contract (for per-field
|
|
281
|
+
* codec resolution via the contract's storage schema) and an optional
|
|
282
|
+
* `AbortSignal` for cooperative cancellation.
|
|
283
|
+
* @returns The IDB plan body describing the exact IDB operation(s) to run.
|
|
284
|
+
*/
|
|
285
|
+
lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbPlanBody>;
|
|
286
|
+
}
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/core/filter-eval.d.ts
|
|
289
|
+
/** Evaluate an AST node against a single row. Returns `true` to keep the row. */
|
|
290
|
+
declare function evaluateFilter(expr: IdbFilterExpr, row: Record<string, unknown>): boolean;
|
|
291
|
+
//#endregion
|
|
292
|
+
//#region src/core/idb-adapter.d.ts
|
|
293
|
+
/**
|
|
294
|
+
* Concrete IDB runtime adapter.
|
|
295
|
+
*
|
|
296
|
+
* Implements {@link IdbRuntimeAdapterInstance} — the `lower()` method that
|
|
297
|
+
* translates an {@link IdbQueryPlan} into an {@link IdbPlanBody} ready for
|
|
298
|
+
* the driver.
|
|
299
|
+
*
|
|
300
|
+
* `lower()` is a structural passthrough: the `idbPlan` carried by
|
|
301
|
+
* `IdbQueryPlan` is already execution-ready because IDB has no query
|
|
302
|
+
* language to compile from. The `codecs` lookup and `ctx.contract` are
|
|
303
|
+
* available for per-field codec encoding when custom codecs (e.g.
|
|
304
|
+
* `idb/date@1`) need to transform field values before they reach the
|
|
305
|
+
* driver. Since all current `idb/*` codecs are identity transforms, the
|
|
306
|
+
* passthrough output is correct for the standard type set.
|
|
307
|
+
*/
|
|
308
|
+
declare class IdbAdapter implements IdbRuntimeAdapterInstance {
|
|
309
|
+
#private;
|
|
310
|
+
readonly familyId: "idb";
|
|
311
|
+
readonly targetId: "idb";
|
|
312
|
+
constructor(codecs: CodecLookup);
|
|
313
|
+
lower(plan: IdbQueryPlan, ctx: IdbLowererContext): Promise<IdbPlanBody>;
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/exports/runtime.d.ts
|
|
317
|
+
declare const idbRuntimeAdapterDescriptor: RuntimeAdapterDescriptor<"idb", "idb", IdbRuntimeAdapterInstance>;
|
|
318
|
+
//#endregion
|
|
319
|
+
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 };
|
|
320
|
+
//# sourceMappingURL=runtime.d.mts.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;UAqBG,aAAa,uBAAuB,UAAU;;WAEpD,SAAS;;;;;;;WAOT,MAAM;;YAEL,qBAAqB;;;;;;;;;;;;;;;UCrBhB,kBAAkB,6BAA6B;;WAErD,UAAU;;;;;;;;;;;;;;;UAgBJ,kCAAkC;;;;;;;;;;;EAWjD,MAAM,MAAM,cAAc,KAAK,oBAAoB,QAAQ;;;;;iBC3B7C,eAAe,MAAM,eAAe,KAAK;;;;;;;;;;;;;;;;;;cCE5C,sBAAsB;;WACxB;WACA;EAIG,YAAA,QAAQ;EAIpB,MAAM,MAAM,cAAc,KAAK,oBAAoB,QAAQ;;;;cCSvD,6BAA6B,uCAAuC"}
|
package/dist/runtime.mjs
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { t as idbAdapterDescriptorMeta } from "./descriptor-meta-DRDNlZjA.mjs";
|
|
2
|
+
import { idbCodecLookup } from "@prisma-idb/target-idb/runtime";
|
|
3
|
+
//#region src/core/idb-adapter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Concrete IDB runtime adapter.
|
|
6
|
+
*
|
|
7
|
+
* Implements {@link IdbRuntimeAdapterInstance} — the `lower()` method that
|
|
8
|
+
* translates an {@link IdbQueryPlan} into an {@link IdbPlanBody} ready for
|
|
9
|
+
* the driver.
|
|
10
|
+
*
|
|
11
|
+
* `lower()` is a structural passthrough: the `idbPlan` carried by
|
|
12
|
+
* `IdbQueryPlan` is already execution-ready because IDB has no query
|
|
13
|
+
* language to compile from. The `codecs` lookup and `ctx.contract` are
|
|
14
|
+
* available for per-field codec encoding when custom codecs (e.g.
|
|
15
|
+
* `idb/date@1`) need to transform field values before they reach the
|
|
16
|
+
* driver. Since all current `idb/*` codecs are identity transforms, the
|
|
17
|
+
* passthrough output is correct for the standard type set.
|
|
18
|
+
*/
|
|
19
|
+
var IdbAdapter = class {
|
|
20
|
+
familyId = "idb";
|
|
21
|
+
targetId = "idb";
|
|
22
|
+
#codecs;
|
|
23
|
+
constructor(codecs) {
|
|
24
|
+
this.#codecs = codecs;
|
|
25
|
+
}
|
|
26
|
+
lower(plan, ctx) {
|
|
27
|
+
this.#codecs;
|
|
28
|
+
ctx.contract;
|
|
29
|
+
ctx.signal;
|
|
30
|
+
return Promise.resolve(plan.idbPlan);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/core/idb-filter-expr.ts
|
|
35
|
+
/** Build a frozen field-filter node. */
|
|
36
|
+
const fieldFilter = (field, op, value) => Object.freeze({
|
|
37
|
+
kind: "field",
|
|
38
|
+
field,
|
|
39
|
+
op,
|
|
40
|
+
value
|
|
41
|
+
});
|
|
42
|
+
/** Build a frozen AND combinator with a frozen `exprs` array. */
|
|
43
|
+
const andExpr = (exprs) => Object.freeze({
|
|
44
|
+
kind: "and",
|
|
45
|
+
exprs: Object.freeze([...exprs])
|
|
46
|
+
});
|
|
47
|
+
/** Build a frozen OR combinator with a frozen `exprs` array. */
|
|
48
|
+
const orExpr = (exprs) => Object.freeze({
|
|
49
|
+
kind: "or",
|
|
50
|
+
exprs: Object.freeze([...exprs])
|
|
51
|
+
});
|
|
52
|
+
/** Build a frozen NOT combinator. */
|
|
53
|
+
const notExpr = (expr) => Object.freeze({
|
|
54
|
+
kind: "not",
|
|
55
|
+
expr
|
|
56
|
+
});
|
|
57
|
+
/** Build a frozen null-check node. */
|
|
58
|
+
const nullCheckExpr = (field, isNull) => Object.freeze({
|
|
59
|
+
kind: "null-check",
|
|
60
|
+
field,
|
|
61
|
+
isNull
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Convert a shorthand equality object (e.g. `{ active: true, email: "x" }`)
|
|
65
|
+
* into the canonical AST form. `undefined` entries are dropped; `null`
|
|
66
|
+
* values become null-checks rather than literal-null equalities (IDB
|
|
67
|
+
* stores absent fields as `undefined`, so a literal-null equality misses).
|
|
68
|
+
*
|
|
69
|
+
* Returns `undefined` when the input has no usable entries — callers can
|
|
70
|
+
* skip filter installation in that case rather than testing an empty
|
|
71
|
+
* AND node every row.
|
|
72
|
+
*/
|
|
73
|
+
function shorthandToFilterExpr(filters) {
|
|
74
|
+
const exprs = [];
|
|
75
|
+
for (const [field, value] of Object.entries(filters)) {
|
|
76
|
+
if (value === void 0) continue;
|
|
77
|
+
if (value === null) {
|
|
78
|
+
exprs.push(nullCheckExpr(field, true));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
exprs.push(fieldFilter(field, "eq", value));
|
|
82
|
+
}
|
|
83
|
+
if (exprs.length === 0) return void 0;
|
|
84
|
+
return exprs.length === 1 ? exprs[0] : andExpr(exprs);
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/core/filter-eval.ts
|
|
88
|
+
/** Evaluate an AST node against a single row. Returns `true` to keep the row. */
|
|
89
|
+
function evaluateFilter(expr, row) {
|
|
90
|
+
switch (expr.kind) {
|
|
91
|
+
case "field": return evalFieldOp(expr.field, expr.op, expr.value, row);
|
|
92
|
+
case "and":
|
|
93
|
+
for (const e of expr.exprs) if (!evaluateFilter(e, row)) return false;
|
|
94
|
+
return true;
|
|
95
|
+
case "or":
|
|
96
|
+
if (expr.exprs.length === 0) return false;
|
|
97
|
+
for (const e of expr.exprs) if (evaluateFilter(e, row)) return true;
|
|
98
|
+
return false;
|
|
99
|
+
case "not": return !evaluateFilter(expr.expr, row);
|
|
100
|
+
case "null-check": {
|
|
101
|
+
const v = row[expr.field];
|
|
102
|
+
const isNullish = v === null || v === void 0;
|
|
103
|
+
return expr.isNull ? isNullish : !isNullish;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function evalFieldOp(field, op, value, row) {
|
|
108
|
+
const cell = row[field];
|
|
109
|
+
switch (op) {
|
|
110
|
+
case "eq":
|
|
111
|
+
if (value === null) return cell === null || cell === void 0;
|
|
112
|
+
return cell === value;
|
|
113
|
+
case "neq":
|
|
114
|
+
if (value === null) return cell !== null && cell !== void 0;
|
|
115
|
+
return cell !== value;
|
|
116
|
+
case "gt": return cell !== void 0 && cell !== null && cell > value;
|
|
117
|
+
case "lt": return cell !== void 0 && cell !== null && cell < value;
|
|
118
|
+
case "gte": return cell !== void 0 && cell !== null && cell >= value;
|
|
119
|
+
case "lte": return cell !== void 0 && cell !== null && cell <= value;
|
|
120
|
+
case "in":
|
|
121
|
+
if (!Array.isArray(value)) return false;
|
|
122
|
+
for (const v of value) if (cell === v) return true;
|
|
123
|
+
return false;
|
|
124
|
+
case "notIn":
|
|
125
|
+
if (!Array.isArray(value)) return true;
|
|
126
|
+
for (const v of value) if (cell === v) return false;
|
|
127
|
+
return true;
|
|
128
|
+
case "contains": return cell !== void 0 && cell !== null && String(cell).includes(String(value));
|
|
129
|
+
case "startsWith": return cell !== void 0 && cell !== null && String(cell).startsWith(String(value));
|
|
130
|
+
case "endsWith": return cell !== void 0 && cell !== null && String(cell).endsWith(String(value));
|
|
131
|
+
default: return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/exports/runtime.ts
|
|
136
|
+
const idbRuntimeAdapterDescriptor = {
|
|
137
|
+
...idbAdapterDescriptorMeta,
|
|
138
|
+
create(_stack) {
|
|
139
|
+
return new IdbAdapter(idbCodecLookup);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
//#endregion
|
|
143
|
+
export { IdbAdapter, andExpr, idbRuntimeAdapterDescriptor as default, evaluateFilter, fieldFilter, notExpr, nullCheckExpr, orExpr, shorthandToFilterExpr };
|
|
144
|
+
|
|
145
|
+
//# sourceMappingURL=runtime.mjs.map
|
|
@@ -0,0 +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. The `codecs` lookup and `ctx.contract` are\n * available for per-field codec encoding when custom codecs (e.g.\n * `idb/date@1`) need to transform field values before they reach the\n * driver. Since all current `idb/*` codecs are identity transforms, the\n * passthrough output is correct for the standard type set.\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 // Passthrough: idbPlan is execution-ready as-is since IDB has no query\n // language. When per-field codec encoding is added, walk\n // plan.idbPlan's record/key fields here, resolve each field's codec via\n // this.#codecs + ctx.contract's per-store schema, and call\n // codec.encode(value, ctx) to produce the wire value.\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, preserving the layering rule in ARCHITECTURE.md.\n *\n * Comparisons use JS semantics (numeric vs string ordering is governed\n * by `<`/`>` on whatever the stored value type is). String operations\n * coerce both sides via `String(...)` so they work on numbers too — the\n * IDB driver stores values via the structured-clone algorithm, so a\n * field that contains an integer is genuinely a JS `number`.\n */\n\nimport type { IdbFilterExpr } 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: string, 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 cell === value;\n case \"neq\":\n if (value === null) return cell !== null && cell !== undefined;\n return cell !== value;\n case \"gt\":\n return cell !== undefined && cell !== null && (cell as number | string) > (value as number | string);\n case \"lt\":\n return cell !== undefined && cell !== null && (cell as number | string) < (value as number | string);\n case \"gte\":\n return cell !== undefined && cell !== null && (cell as number | string) >= (value as number | string);\n case \"lte\":\n return cell !== undefined && cell !== null && (cell as number | string) <= (value as number | string);\n case \"in\": {\n if (!Array.isArray(value)) return false;\n for (const v of value) {\n if (cell === v) return true;\n }\n return false;\n }\n case \"notIn\": {\n if (!Array.isArray(value)) return true;\n for (const v of value) {\n if (cell === v) return false;\n }\n return true;\n }\n case \"contains\":\n return cell !== undefined && cell !== null && String(cell).includes(String(value));\n case \"startsWith\":\n return cell !== undefined && cell !== null && String(cell).startsWith(String(value));\n case \"endsWith\":\n return cell !== undefined && cell !== null && String(cell).endsWith(String(value));\n default:\n return false;\n }\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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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prisma-idb/adapter-idb",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Prisma 8 IDB family — adapter (lowers query AST to opaque IDB plan body)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"keywords": [
|
|
10
|
+
"prisma",
|
|
11
|
+
"prisma-8",
|
|
12
|
+
"indexeddb",
|
|
13
|
+
"offline-first",
|
|
14
|
+
"idb"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/prisma-idb/prisma-idb.git",
|
|
19
|
+
"directory": "packages/prisma-orm/adapter-idb"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://prisma-idb.dev/",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/prisma-idb/prisma-idb/issues"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"exports": {
|
|
27
|
+
"./control": "./dist/control.mjs",
|
|
28
|
+
"./runtime": "./dist/runtime.mjs",
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@prisma/orm-framework": "8.0.0-rc.5",
|
|
33
|
+
"@prisma-idb/driver-idb": "0.0.0",
|
|
34
|
+
"@prisma-idb/target-idb": "0.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"tsdown": "^0.22.14",
|
|
38
|
+
"typescript": "^6.0.3",
|
|
39
|
+
"vitest": "^4.1.10"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsdown",
|
|
46
|
+
"dev": "tsdown --watch",
|
|
47
|
+
"check": "tsc --noEmit",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"lint": "prettier --check . && eslint .",
|
|
50
|
+
"format": "prettier --write ."
|
|
51
|
+
}
|
|
52
|
+
}
|