@lunora/server 0.0.0 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +105 -0
- package/README.md +130 -9
- package/__assets__/package-og.svg +14 -0
- package/dist/data-model.d.mts +328 -0
- package/dist/data-model.d.ts +328 -0
- package/dist/data-model.mjs +1 -0
- package/dist/drizzle.d.mts +1 -0
- package/dist/drizzle.d.ts +1 -0
- package/dist/drizzle.mjs +1 -0
- package/dist/index.d.mts +1741 -0
- package/dist/index.d.ts +1741 -0
- package/dist/index.mjs +24 -0
- package/dist/packem_shared/LunoraError-DhggBJZF.mjs +51 -0
- package/dist/packem_shared/asBucketStorage-Cnxd9y2q.mjs +11 -0
- package/dist/packem_shared/bindTableFacade-DCuyr46L.mjs +71 -0
- package/dist/packem_shared/defineAggregateIndex-DzqxtAyV.mjs +236 -0
- package/dist/packem_shared/defineEnv-DjFkpkSP.mjs +187 -0
- package/dist/packem_shared/defineMigration-CAJLr6fx.mjs +8 -0
- package/dist/packem_shared/definePolicy-De67zPDS.mjs +29 -0
- package/dist/packem_shared/definePresence-D5LtwGl0.mjs +114 -0
- package/dist/packem_shared/defineSchemaExtension-Ck5_TUO8.mjs +100 -0
- package/dist/packem_shared/defineStorageRule-qu0mpilX.mjs +20 -0
- package/dist/packem_shared/httpAction-B7FYUEgr.mjs +340 -0
- package/dist/packem_shared/initLunora-CATvPsVt.mjs +86 -0
- package/dist/packem_shared/mask-CkZJHHMM.mjs +211 -0
- package/dist/packem_shared/onConnect-CIPXKPyw.mjs +13 -0
- package/dist/packem_shared/protectPublic-BjFkQ_Or.mjs +15 -0
- package/dist/packem_shared/rls-Zhf5wEeJ.mjs +551 -0
- package/dist/packem_shared/run-middleware-CYQOuoV6.mjs +18 -0
- package/dist/packem_shared/storageRules-4a30FSpI.mjs +88 -0
- package/dist/packem_shared/types.d-BDY0FYHK.d.ts +135 -0
- package/dist/packem_shared/types.d-DmvyEMD6.d.mts +135 -0
- package/dist/rls/testing.d.mts +63 -0
- package/dist/rls/testing.d.ts +63 -0
- package/dist/rls/testing.mjs +49 -0
- package/dist/types.d.mts +1029 -0
- package/dist/types.d.ts +1029 -0
- package/dist/types.mjs +31 -0
- package/package.json +59 -17
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-independent type machinery for the generated data model.
|
|
3
|
+
*
|
|
4
|
+
* `@lunora/codegen` emits `lunora/_generated/dataModel.ts` with the
|
|
5
|
+
* schema-specific pieces (the per-table `Doc_*` / `Insert_*` interfaces, the
|
|
6
|
+
* `DataModel` / `Relations` / index-name maps) and then binds the generics
|
|
7
|
+
* below to them. Everything here is identical for every project, so it lives
|
|
8
|
+
* in the shipped package rather than in generated output — evolving the query
|
|
9
|
+
* DSL or the table-facade API no longer regenerates a single line of a user's
|
|
10
|
+
* `_generated` directory.
|
|
11
|
+
*
|
|
12
|
+
* The generics are parameterized over the generated maps:
|
|
13
|
+
* - `DM` — `DataModel`: table name → document type
|
|
14
|
+
* - `IM` — `InsertModel`: table name → insert shape
|
|
15
|
+
* - `REL` — `Relations`: table name → relation-descriptor map
|
|
16
|
+
* - `RANK` — `RankIndexNamesByTable`: table name → declared rank-index names
|
|
17
|
+
* - `SEARCH` — `SearchIndexNamesByTable`: table name → declared search-index names
|
|
18
|
+
*
|
|
19
|
+
* Relation descriptors are matched structurally (`{ __relationKind; __target }`)
|
|
20
|
+
* so this module needs no reference to the project-local `OneRelation` /
|
|
21
|
+
* `ManyRelation` aliases the codegen still emits.
|
|
22
|
+
*/
|
|
23
|
+
/** A branded id for table `TName`. Structurally a `string` at runtime. */
|
|
24
|
+
type Id<TName extends string> = string & {
|
|
25
|
+
readonly __table: TName;
|
|
26
|
+
};
|
|
27
|
+
/** Field-level operators for the typed `where` DSL (see `@lunora/do`'s compiler). */
|
|
28
|
+
interface WhereOperators<T> {
|
|
29
|
+
contains?: string;
|
|
30
|
+
eq?: T;
|
|
31
|
+
gt?: T;
|
|
32
|
+
gte?: T;
|
|
33
|
+
in?: T[];
|
|
34
|
+
isNull?: boolean;
|
|
35
|
+
lt?: T;
|
|
36
|
+
lte?: T;
|
|
37
|
+
ne?: T;
|
|
38
|
+
notIn?: T[];
|
|
39
|
+
}
|
|
40
|
+
/** A typed `where` tree over a document's columns. */
|
|
41
|
+
type Where<TDocument> = { [K in keyof TDocument]?: TDocument[K] | WhereOperators<TDocument[K]> } & {
|
|
42
|
+
AND?: Where<TDocument>[];
|
|
43
|
+
NOT?: Where<TDocument>;
|
|
44
|
+
OR?: Where<TDocument>[];
|
|
45
|
+
};
|
|
46
|
+
/** One `{ field: "asc" | "desc" }` ordering entry; `orderBy` is an ordered list. */
|
|
47
|
+
type OrderBy<TDocument> = Partial<Record<keyof TDocument, "asc" | "desc">>;
|
|
48
|
+
interface QueryArgs<TDocument> {
|
|
49
|
+
cursor?: null | string;
|
|
50
|
+
limit?: number;
|
|
51
|
+
orderBy?: OrderBy<TDocument>[];
|
|
52
|
+
where?: Where<TDocument>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A to-one relation predicate node. `is` matches rows whose related record
|
|
56
|
+
* satisfies `W`; `isNot` matches rows whose related record fails `W` *or* has
|
|
57
|
+
* no related record at all (a null/dangling FK) — Prisma's semantics.
|
|
58
|
+
*/
|
|
59
|
+
interface OneRelationWhere<W> {
|
|
60
|
+
is?: W;
|
|
61
|
+
isNot?: W;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A to-many relation predicate node. `some` ⇒ at least one related row matches
|
|
65
|
+
* `W`; `none` ⇒ no related row matches (childless parents included); `every` ⇒
|
|
66
|
+
* every *readable* related row matches (vacuously true for childless parents).
|
|
67
|
+
*/
|
|
68
|
+
interface ManyRelationWhere<W> {
|
|
69
|
+
every?: W;
|
|
70
|
+
none?: W;
|
|
71
|
+
some?: W;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The relation-predicate portion of {@link WhereOf}: each declared relation on
|
|
75
|
+
* `T` contributes a kind-dispatched node — `one` → `{ is?; isNot? }`, `many` →
|
|
76
|
+
* `{ some?; none?; every? }` — whose inner type is the target table's own
|
|
77
|
+
* relation-aware `where` (so multi-hop predicates type-check inside-out).
|
|
78
|
+
*/
|
|
79
|
+
type RelationWhere<DM, REL extends Record<keyof DM, object>, T extends keyof DM> = { [K in keyof REL[T]]?: REL[T][K] extends {
|
|
80
|
+
__relationKind: "one";
|
|
81
|
+
__target: infer Target extends keyof DM;
|
|
82
|
+
} ? OneRelationWhere<WhereOf<DM, REL, Target>> : REL[T][K] extends {
|
|
83
|
+
__relationKind: "many";
|
|
84
|
+
__target: infer Target extends keyof DM;
|
|
85
|
+
} ? ManyRelationWhere<WhereOf<DM, REL, Target>> : never };
|
|
86
|
+
/**
|
|
87
|
+
* Relation-aware `where` tree — the column predicates of {@link Where} plus
|
|
88
|
+
* Prisma-style relation predicates resolved by the `@lunora/do` pre-resolver.
|
|
89
|
+
* `Where<DM[T]>` stays the column-only structural mirror for back-compat; the
|
|
90
|
+
* table facade threads `REL` through this richer form.
|
|
91
|
+
*/
|
|
92
|
+
type WhereOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> = RelationWhere<DM, REL, T> & { [K in keyof DM[T]]?: DM[T][K] | WhereOperators<DM[T][K]> } & {
|
|
93
|
+
AND?: WhereOf<DM, REL, T>[];
|
|
94
|
+
NOT?: WhereOf<DM, REL, T>;
|
|
95
|
+
OR?: WhereOf<DM, REL, T>[];
|
|
96
|
+
};
|
|
97
|
+
/** {@link QueryArgs} with the relation-aware {@link WhereOf} `where` typing. */
|
|
98
|
+
interface QueryArgsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> {
|
|
99
|
+
cursor?: null | string;
|
|
100
|
+
limit?: number;
|
|
101
|
+
orderBy?: OrderBy<DM[T]>[];
|
|
102
|
+
where?: WhereOf<DM, REL, T>;
|
|
103
|
+
}
|
|
104
|
+
interface QueryPage<TDocument> {
|
|
105
|
+
continueCursor: null | string;
|
|
106
|
+
isDone: boolean;
|
|
107
|
+
page: TDocument[];
|
|
108
|
+
}
|
|
109
|
+
/** The nested `with` sub-argument inside a relation's with-value, or `{}`. */
|
|
110
|
+
type NestedWithArgument<WK> = WK extends {
|
|
111
|
+
with: infer NW;
|
|
112
|
+
} ? NW : {};
|
|
113
|
+
/**
|
|
114
|
+
* The `with` argument for table `T`: each relation can be `true` (load with no
|
|
115
|
+
* refinements) or an object. `many` relations accept `where`/`orderBy`/`limit`
|
|
116
|
+
* plus a nested `with`; `one` relations accept only a nested `with`. The
|
|
117
|
+
* reserved `_count` key requests per-relation aggregate counts.
|
|
118
|
+
*/
|
|
119
|
+
type WithArg<DM, REL extends Record<keyof DM, object>, T extends keyof DM> = { [K in keyof REL[T]]?: REL[T][K] extends {
|
|
120
|
+
__relationKind: "many";
|
|
121
|
+
__target: infer Target extends keyof DM;
|
|
122
|
+
} ? boolean | (QueryArgs<DM[Target]> & {
|
|
123
|
+
with?: WithArg<DM, REL, Target>;
|
|
124
|
+
}) : REL[T][K] extends {
|
|
125
|
+
__relationKind: "one";
|
|
126
|
+
__target: infer Target extends keyof DM;
|
|
127
|
+
} ? boolean | {
|
|
128
|
+
with?: WithArg<DM, REL, Target>;
|
|
129
|
+
} : never } & {
|
|
130
|
+
_count?: { [K in keyof REL[T]]?: true };
|
|
131
|
+
};
|
|
132
|
+
/** Resolve a single relation descriptor + its with-value to the loaded type. */
|
|
133
|
+
type LoadRelation<DM, REL extends Record<keyof DM, object>, R, WK> = R extends {
|
|
134
|
+
__relationKind: "one";
|
|
135
|
+
__target: infer Target extends keyof DM;
|
|
136
|
+
} ? LoadWith<DM, REL, Target, NestedWithArgument<WK>> | null : R extends {
|
|
137
|
+
__relationKind: "many";
|
|
138
|
+
__target: infer Target extends keyof DM;
|
|
139
|
+
} ? LoadWith<DM, REL, Target, NestedWithArgument<WK>>[] : never;
|
|
140
|
+
/** The relation keys of `W` that were actually requested (not `false`/`undefined`). */
|
|
141
|
+
type LoadedRelations<DM, REL extends Record<keyof DM, object>, T extends keyof DM, W> = { [K in keyof W as K extends keyof REL[T] ? (W[K] extends false | undefined ? never : K) : never]: K extends keyof REL[T] ? LoadRelation<DM, REL, REL[T][K], W[K]> : never };
|
|
142
|
+
/** The `_count` projection of `W`, if any. */
|
|
143
|
+
type LoadedCount<W> = W extends {
|
|
144
|
+
_count: infer C;
|
|
145
|
+
} ? {
|
|
146
|
+
_count: { [K in keyof C]: number };
|
|
147
|
+
} : {};
|
|
148
|
+
/** `Doc<T>` narrowed to exactly the relations requested in the with-arg `W`. */
|
|
149
|
+
type LoadWith<DM, REL extends Record<keyof DM, object>, T extends keyof DM, W> = DM[T] & LoadedCount<W> & LoadedRelations<DM, REL, T, W>;
|
|
150
|
+
/** Reducer applied by an aggregate (`avg`/`count`/`max`/`min`/`sum`). */
|
|
151
|
+
type AggregateOp = "avg" | "count" | "max" | "min" | "sum";
|
|
152
|
+
/**
|
|
153
|
+
* Query-options shape shared by every aggregate reader. The RLS-aware ctx
|
|
154
|
+
* populates `baseWhere` so it composes here without a hard import.
|
|
155
|
+
* `restrictsCounts: true` flips `count()` into a thrown `COUNT_RLS_UNSUPPORTED`
|
|
156
|
+
* `LunoraError` rather than silently undercount.
|
|
157
|
+
*/
|
|
158
|
+
interface RestrictableQueryOptions<TDocument> {
|
|
159
|
+
baseWhere?: Where<TDocument>;
|
|
160
|
+
restrictsCounts?: boolean;
|
|
161
|
+
where?: Where<TDocument>;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Relation-aware twin of {@link RestrictableQueryOptions}. The `@lunora/do`
|
|
165
|
+
* pre-resolver now resolves relation predicates on the `count`/`aggregate`/
|
|
166
|
+
* `groupBy` paths too (semijoin), so the typed surface threads `REL` through
|
|
167
|
+
* `where`/`baseWhere` to match. `rank`/`rankPage` stay column-only — they use
|
|
168
|
+
* `where` solely to pin a partition and fail closed on a relation predicate.
|
|
169
|
+
*/
|
|
170
|
+
interface RestrictableQueryOptionsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> {
|
|
171
|
+
baseWhere?: WhereOf<DM, REL, T>;
|
|
172
|
+
restrictsCounts?: boolean;
|
|
173
|
+
where?: WhereOf<DM, REL, T>;
|
|
174
|
+
}
|
|
175
|
+
/** Args for `ctx.db.<table>.aggregate({ op, field?, where? })`. */
|
|
176
|
+
interface TableAggregateOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
177
|
+
field?: keyof TDocument & string;
|
|
178
|
+
op: AggregateOp;
|
|
179
|
+
}
|
|
180
|
+
/** Relation-aware twin of {@link TableAggregateOptions} (see {@link RestrictableQueryOptionsOf}). */
|
|
181
|
+
interface TableAggregateOptionsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> extends RestrictableQueryOptionsOf<DM, REL, T> {
|
|
182
|
+
field?: keyof DM[T] & string;
|
|
183
|
+
op: AggregateOp;
|
|
184
|
+
}
|
|
185
|
+
/** Args for `ctx.db.<table>.groupBy({ by, agg?, where? })`. */
|
|
186
|
+
interface TableGroupByOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
187
|
+
agg?: {
|
|
188
|
+
field?: keyof TDocument & string;
|
|
189
|
+
op: AggregateOp;
|
|
190
|
+
};
|
|
191
|
+
by: ReadonlyArray<keyof TDocument & string>;
|
|
192
|
+
}
|
|
193
|
+
/** Relation-aware twin of {@link TableGroupByOptions} (see {@link RestrictableQueryOptionsOf}). */
|
|
194
|
+
interface TableGroupByOptionsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> extends RestrictableQueryOptionsOf<DM, REL, T> {
|
|
195
|
+
agg?: {
|
|
196
|
+
field?: keyof DM[T] & string;
|
|
197
|
+
op: AggregateOp;
|
|
198
|
+
};
|
|
199
|
+
by: ReadonlyArray<keyof DM[T] & string>;
|
|
200
|
+
}
|
|
201
|
+
/** One entry returned by `groupBy` — the group's by-tuple plus the reducer value. */
|
|
202
|
+
interface GroupByEntry<TDocument> {
|
|
203
|
+
key: Partial<TDocument>;
|
|
204
|
+
value: null | number;
|
|
205
|
+
}
|
|
206
|
+
/** Args for `ctx.db.<table>.rank(name, args)`. `row` is either an id or a row doc. */
|
|
207
|
+
interface TableRankOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
208
|
+
row: string | TDocument;
|
|
209
|
+
}
|
|
210
|
+
/** Result of `rank` — 1-based position within the partition + partition total. */
|
|
211
|
+
interface RankResult {
|
|
212
|
+
position: number;
|
|
213
|
+
total: number;
|
|
214
|
+
}
|
|
215
|
+
/** Args for `ctx.db.<table>.rankPage(name, args)`. */
|
|
216
|
+
interface TableRankPageOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
217
|
+
cursor?: null | string;
|
|
218
|
+
take?: number;
|
|
219
|
+
}
|
|
220
|
+
/** One page returned by `rankPage`. */
|
|
221
|
+
interface RankPage<TDocument> {
|
|
222
|
+
continueCursor: null | string;
|
|
223
|
+
isDone: boolean;
|
|
224
|
+
page: TDocument[];
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Builder passed to `.withSearchIndex(name, q => …)`. `.search(field, query)`
|
|
228
|
+
* runs the full-text match against the index's searchable field; `.eq(field,
|
|
229
|
+
* value)` narrows by a declared filter field. Field names are constrained to
|
|
230
|
+
* the table's columns.
|
|
231
|
+
*/
|
|
232
|
+
interface SearchFilterBuilder<TDocument> {
|
|
233
|
+
eq: <F extends keyof TDocument & string>(field: F, value: TDocument[F]) => SearchFilterBuilder<TDocument>;
|
|
234
|
+
search: (field: keyof TDocument & string, query: string) => SearchFilterBuilder<TDocument>;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Chainable reader returned by `.withSearchIndex()` — rows come back ordered
|
|
238
|
+
* by relevance. `.paginate()` is intentionally absent (a relevance-ordered
|
|
239
|
+
* search can't keyset-paginate); cap the result set with `.take(n)`.
|
|
240
|
+
*/
|
|
241
|
+
interface SearchReader<TDocument> {
|
|
242
|
+
collect: () => Promise<TDocument[]>;
|
|
243
|
+
first: () => Promise<TDocument | null>;
|
|
244
|
+
take: (limit: number) => Promise<TDocument[]>;
|
|
245
|
+
unique: () => Promise<TDocument | null>;
|
|
246
|
+
}
|
|
247
|
+
/** Read-only typed table accessor exposed on `QueryCtx.db.<table>`. */
|
|
248
|
+
interface TableReaderFacade<DM, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>, T extends keyof DM> {
|
|
249
|
+
/**
|
|
250
|
+
* Reduce rows in this table to a scalar (`avg`/`max`/`min`/`sum` — `count`
|
|
251
|
+
* lives on its own method). Routes through a declared `aggregateIndex` when
|
|
252
|
+
* the planner can prove the request is answerable; otherwise scans.
|
|
253
|
+
*/
|
|
254
|
+
aggregate: (options: TableAggregateOptionsOf<DM, REL, T>) => Promise<null | number>;
|
|
255
|
+
/**
|
|
256
|
+
* Count rows. The planner routes `where` keys that match a declared
|
|
257
|
+
* `aggregateIndex.by` set to the indexed counter (no scan); otherwise
|
|
258
|
+
* falls back to a SCAN. Accepts either a bare `where` tree or the broader
|
|
259
|
+
* `RestrictableQueryOptions` shape; the latter is the seam the RLS layer
|
|
260
|
+
* uses to inject `baseWhere` and `restrictsCounts`.
|
|
261
|
+
*/
|
|
262
|
+
count: (where?: RestrictableQueryOptionsOf<DM, REL, T> | WhereOf<DM, REL, T>) => Promise<number>;
|
|
263
|
+
findFirst: <W extends WithArg<DM, REL, T> = {}>(args?: QueryArgsOf<DM, REL, T> & {
|
|
264
|
+
with?: W;
|
|
265
|
+
}) => Promise<LoadWith<DM, REL, T, W> | null>;
|
|
266
|
+
findFirstOrThrow: <W extends WithArg<DM, REL, T> = {}>(args?: QueryArgsOf<DM, REL, T> & {
|
|
267
|
+
with?: W;
|
|
268
|
+
}) => Promise<LoadWith<DM, REL, T, W>>;
|
|
269
|
+
findMany: <W extends WithArg<DM, REL, T> = {}>(args?: QueryArgsOf<DM, REL, T> & {
|
|
270
|
+
with?: W;
|
|
271
|
+
}) => Promise<QueryPage<LoadWith<DM, REL, T, W>>>;
|
|
272
|
+
get: (id: Id<string & T>) => Promise<DM[T] | null>;
|
|
273
|
+
/**
|
|
274
|
+
* Group rows by the named keys and apply `agg` per group (defaults to
|
|
275
|
+
* `count`). Answered from the counter table when an aggregate index's
|
|
276
|
+
* `by` matches `options.by` exactly; otherwise scans.
|
|
277
|
+
*/
|
|
278
|
+
groupBy: (options: TableGroupByOptionsOf<DM, REL, T>) => Promise<ReadonlyArray<GroupByEntry<DM[T]>>>;
|
|
279
|
+
/**
|
|
280
|
+
* Return the 1-based position of `options.row` within its partition
|
|
281
|
+
* under the declared rankIndex `indexName`, plus the partition's total
|
|
282
|
+
* row count. `null` when the row isn't in the index. Honors the same
|
|
283
|
+
* `baseWhere` / `restrictsCounts` RLS seam as `count()`.
|
|
284
|
+
*/
|
|
285
|
+
rank: (indexName: RANK[T], options: TableRankOptions<DM[T]>) => Promise<null | RankResult>;
|
|
286
|
+
/**
|
|
287
|
+
* Walk the rank companion in declared sort order — sorted pagination
|
|
288
|
+
* accelerator. `options.where` may pin the partition; `cursor`/`take`
|
|
289
|
+
* follow the Convex-style keyset shape.
|
|
290
|
+
*/
|
|
291
|
+
rankPage: (indexName: RANK[T], options?: TableRankPageOptions<DM[T]>) => Promise<RankPage<DM[T]>>;
|
|
292
|
+
/**
|
|
293
|
+
* Restrict the query to a declared `.searchIndex()` and run a full-text
|
|
294
|
+
* match. `indexName` is constrained to this table's search indexes
|
|
295
|
+
* (`never` when it declares none). Returns a relevance-ordered reader —
|
|
296
|
+
* finish with `.take(n)` / `.collect()`.
|
|
297
|
+
*/
|
|
298
|
+
withSearchIndex: (indexName: SEARCH[T], search: (q: SearchFilterBuilder<DM[T]>) => SearchFilterBuilder<DM[T]>) => SearchReader<DM[T]>;
|
|
299
|
+
}
|
|
300
|
+
/** Read-write typed table accessor exposed on `MutationCtx.db.<table>` / `ActionCtx.db.<table>`. */
|
|
301
|
+
interface TableWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>, T extends keyof DM> extends TableReaderFacade<DM, REL, RANK, SEARCH, T> {
|
|
302
|
+
delete: (id: Id<string & T>) => Promise<void>;
|
|
303
|
+
/** Delete many rows in this table by id in one call; returns the *requested* id count (unknown ids are no-ops). Atomic within a mutation (a throw rolls the mutation back); an action has no transaction span. */
|
|
304
|
+
deleteMany: (ids: ReadonlyArray<Id<string & T>>, options?: {
|
|
305
|
+
limit?: number;
|
|
306
|
+
}) => Promise<{
|
|
307
|
+
deleted: number;
|
|
308
|
+
}>;
|
|
309
|
+
insert: (values: IM[T]) => Promise<Id<string & T>>;
|
|
310
|
+
/** Insert many documents into this table in one call, returning the minted ids in input order. Atomic within a mutation (a throw rolls the mutation back); an action has no transaction span. */
|
|
311
|
+
insertMany: (values: ReadonlyArray<IM[T]>, options?: {
|
|
312
|
+
limit?: number;
|
|
313
|
+
}) => Promise<Id<string & T>[]>;
|
|
314
|
+
patch: (id: Id<string & T>, values: Partial<IM[T]>) => Promise<void>;
|
|
315
|
+
/** Patch many rows in this table by id in one call. Atomic within a mutation (a throw rolls the mutation back); an action has no transaction span. */
|
|
316
|
+
patchMany: (patches: ReadonlyArray<{
|
|
317
|
+
id: Id<string & T>;
|
|
318
|
+
values: Partial<IM[T]>;
|
|
319
|
+
}>, options?: {
|
|
320
|
+
limit?: number;
|
|
321
|
+
}) => Promise<void>;
|
|
322
|
+
replace: (id: Id<string & T>, values: IM[T]) => Promise<void>;
|
|
323
|
+
}
|
|
324
|
+
/** Per-table read facade — `ctx.db.<table>` on a `QueryCtx`. */
|
|
325
|
+
type DatabaseReaderFacade<DM, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>> = { readonly [T in keyof DM]: TableReaderFacade<DM, REL, RANK, SEARCH, T> };
|
|
326
|
+
/** Per-table read-write facade — `ctx.db.<table>` on a `MutationCtx` / `ActionCtx`. */
|
|
327
|
+
type DatabaseWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>> = { readonly [T in keyof DM]: TableWriterFacade<DM, IM, REL, RANK, SEARCH, T> };
|
|
328
|
+
export { AggregateOp, DatabaseReaderFacade, DatabaseWriterFacade, GroupByEntry, Id, LoadWith, ManyRelationWhere, OneRelationWhere, OrderBy, QueryArgs, QueryArgsOf, QueryPage, RankPage, RankResult, RestrictableQueryOptions, RestrictableQueryOptionsOf, SearchFilterBuilder, SearchReader, TableAggregateOptions, TableAggregateOptionsOf, TableGroupByOptions, TableGroupByOptionsOf, TableRankOptions, TableRankPageOptions, TableReaderFacade, TableWriterFacade, Where, WhereOf, WhereOperators, WithArg };
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-independent type machinery for the generated data model.
|
|
3
|
+
*
|
|
4
|
+
* `@lunora/codegen` emits `lunora/_generated/dataModel.ts` with the
|
|
5
|
+
* schema-specific pieces (the per-table `Doc_*` / `Insert_*` interfaces, the
|
|
6
|
+
* `DataModel` / `Relations` / index-name maps) and then binds the generics
|
|
7
|
+
* below to them. Everything here is identical for every project, so it lives
|
|
8
|
+
* in the shipped package rather than in generated output — evolving the query
|
|
9
|
+
* DSL or the table-facade API no longer regenerates a single line of a user's
|
|
10
|
+
* `_generated` directory.
|
|
11
|
+
*
|
|
12
|
+
* The generics are parameterized over the generated maps:
|
|
13
|
+
* - `DM` — `DataModel`: table name → document type
|
|
14
|
+
* - `IM` — `InsertModel`: table name → insert shape
|
|
15
|
+
* - `REL` — `Relations`: table name → relation-descriptor map
|
|
16
|
+
* - `RANK` — `RankIndexNamesByTable`: table name → declared rank-index names
|
|
17
|
+
* - `SEARCH` — `SearchIndexNamesByTable`: table name → declared search-index names
|
|
18
|
+
*
|
|
19
|
+
* Relation descriptors are matched structurally (`{ __relationKind; __target }`)
|
|
20
|
+
* so this module needs no reference to the project-local `OneRelation` /
|
|
21
|
+
* `ManyRelation` aliases the codegen still emits.
|
|
22
|
+
*/
|
|
23
|
+
/** A branded id for table `TName`. Structurally a `string` at runtime. */
|
|
24
|
+
type Id<TName extends string> = string & {
|
|
25
|
+
readonly __table: TName;
|
|
26
|
+
};
|
|
27
|
+
/** Field-level operators for the typed `where` DSL (see `@lunora/do`'s compiler). */
|
|
28
|
+
interface WhereOperators<T> {
|
|
29
|
+
contains?: string;
|
|
30
|
+
eq?: T;
|
|
31
|
+
gt?: T;
|
|
32
|
+
gte?: T;
|
|
33
|
+
in?: T[];
|
|
34
|
+
isNull?: boolean;
|
|
35
|
+
lt?: T;
|
|
36
|
+
lte?: T;
|
|
37
|
+
ne?: T;
|
|
38
|
+
notIn?: T[];
|
|
39
|
+
}
|
|
40
|
+
/** A typed `where` tree over a document's columns. */
|
|
41
|
+
type Where<TDocument> = { [K in keyof TDocument]?: TDocument[K] | WhereOperators<TDocument[K]> } & {
|
|
42
|
+
AND?: Where<TDocument>[];
|
|
43
|
+
NOT?: Where<TDocument>;
|
|
44
|
+
OR?: Where<TDocument>[];
|
|
45
|
+
};
|
|
46
|
+
/** One `{ field: "asc" | "desc" }` ordering entry; `orderBy` is an ordered list. */
|
|
47
|
+
type OrderBy<TDocument> = Partial<Record<keyof TDocument, "asc" | "desc">>;
|
|
48
|
+
interface QueryArgs<TDocument> {
|
|
49
|
+
cursor?: null | string;
|
|
50
|
+
limit?: number;
|
|
51
|
+
orderBy?: OrderBy<TDocument>[];
|
|
52
|
+
where?: Where<TDocument>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A to-one relation predicate node. `is` matches rows whose related record
|
|
56
|
+
* satisfies `W`; `isNot` matches rows whose related record fails `W` *or* has
|
|
57
|
+
* no related record at all (a null/dangling FK) — Prisma's semantics.
|
|
58
|
+
*/
|
|
59
|
+
interface OneRelationWhere<W> {
|
|
60
|
+
is?: W;
|
|
61
|
+
isNot?: W;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A to-many relation predicate node. `some` ⇒ at least one related row matches
|
|
65
|
+
* `W`; `none` ⇒ no related row matches (childless parents included); `every` ⇒
|
|
66
|
+
* every *readable* related row matches (vacuously true for childless parents).
|
|
67
|
+
*/
|
|
68
|
+
interface ManyRelationWhere<W> {
|
|
69
|
+
every?: W;
|
|
70
|
+
none?: W;
|
|
71
|
+
some?: W;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The relation-predicate portion of {@link WhereOf}: each declared relation on
|
|
75
|
+
* `T` contributes a kind-dispatched node — `one` → `{ is?; isNot? }`, `many` →
|
|
76
|
+
* `{ some?; none?; every? }` — whose inner type is the target table's own
|
|
77
|
+
* relation-aware `where` (so multi-hop predicates type-check inside-out).
|
|
78
|
+
*/
|
|
79
|
+
type RelationWhere<DM, REL extends Record<keyof DM, object>, T extends keyof DM> = { [K in keyof REL[T]]?: REL[T][K] extends {
|
|
80
|
+
__relationKind: "one";
|
|
81
|
+
__target: infer Target extends keyof DM;
|
|
82
|
+
} ? OneRelationWhere<WhereOf<DM, REL, Target>> : REL[T][K] extends {
|
|
83
|
+
__relationKind: "many";
|
|
84
|
+
__target: infer Target extends keyof DM;
|
|
85
|
+
} ? ManyRelationWhere<WhereOf<DM, REL, Target>> : never };
|
|
86
|
+
/**
|
|
87
|
+
* Relation-aware `where` tree — the column predicates of {@link Where} plus
|
|
88
|
+
* Prisma-style relation predicates resolved by the `@lunora/do` pre-resolver.
|
|
89
|
+
* `Where<DM[T]>` stays the column-only structural mirror for back-compat; the
|
|
90
|
+
* table facade threads `REL` through this richer form.
|
|
91
|
+
*/
|
|
92
|
+
type WhereOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> = RelationWhere<DM, REL, T> & { [K in keyof DM[T]]?: DM[T][K] | WhereOperators<DM[T][K]> } & {
|
|
93
|
+
AND?: WhereOf<DM, REL, T>[];
|
|
94
|
+
NOT?: WhereOf<DM, REL, T>;
|
|
95
|
+
OR?: WhereOf<DM, REL, T>[];
|
|
96
|
+
};
|
|
97
|
+
/** {@link QueryArgs} with the relation-aware {@link WhereOf} `where` typing. */
|
|
98
|
+
interface QueryArgsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> {
|
|
99
|
+
cursor?: null | string;
|
|
100
|
+
limit?: number;
|
|
101
|
+
orderBy?: OrderBy<DM[T]>[];
|
|
102
|
+
where?: WhereOf<DM, REL, T>;
|
|
103
|
+
}
|
|
104
|
+
interface QueryPage<TDocument> {
|
|
105
|
+
continueCursor: null | string;
|
|
106
|
+
isDone: boolean;
|
|
107
|
+
page: TDocument[];
|
|
108
|
+
}
|
|
109
|
+
/** The nested `with` sub-argument inside a relation's with-value, or `{}`. */
|
|
110
|
+
type NestedWithArgument<WK> = WK extends {
|
|
111
|
+
with: infer NW;
|
|
112
|
+
} ? NW : {};
|
|
113
|
+
/**
|
|
114
|
+
* The `with` argument for table `T`: each relation can be `true` (load with no
|
|
115
|
+
* refinements) or an object. `many` relations accept `where`/`orderBy`/`limit`
|
|
116
|
+
* plus a nested `with`; `one` relations accept only a nested `with`. The
|
|
117
|
+
* reserved `_count` key requests per-relation aggregate counts.
|
|
118
|
+
*/
|
|
119
|
+
type WithArg<DM, REL extends Record<keyof DM, object>, T extends keyof DM> = { [K in keyof REL[T]]?: REL[T][K] extends {
|
|
120
|
+
__relationKind: "many";
|
|
121
|
+
__target: infer Target extends keyof DM;
|
|
122
|
+
} ? boolean | (QueryArgs<DM[Target]> & {
|
|
123
|
+
with?: WithArg<DM, REL, Target>;
|
|
124
|
+
}) : REL[T][K] extends {
|
|
125
|
+
__relationKind: "one";
|
|
126
|
+
__target: infer Target extends keyof DM;
|
|
127
|
+
} ? boolean | {
|
|
128
|
+
with?: WithArg<DM, REL, Target>;
|
|
129
|
+
} : never } & {
|
|
130
|
+
_count?: { [K in keyof REL[T]]?: true };
|
|
131
|
+
};
|
|
132
|
+
/** Resolve a single relation descriptor + its with-value to the loaded type. */
|
|
133
|
+
type LoadRelation<DM, REL extends Record<keyof DM, object>, R, WK> = R extends {
|
|
134
|
+
__relationKind: "one";
|
|
135
|
+
__target: infer Target extends keyof DM;
|
|
136
|
+
} ? LoadWith<DM, REL, Target, NestedWithArgument<WK>> | null : R extends {
|
|
137
|
+
__relationKind: "many";
|
|
138
|
+
__target: infer Target extends keyof DM;
|
|
139
|
+
} ? LoadWith<DM, REL, Target, NestedWithArgument<WK>>[] : never;
|
|
140
|
+
/** The relation keys of `W` that were actually requested (not `false`/`undefined`). */
|
|
141
|
+
type LoadedRelations<DM, REL extends Record<keyof DM, object>, T extends keyof DM, W> = { [K in keyof W as K extends keyof REL[T] ? (W[K] extends false | undefined ? never : K) : never]: K extends keyof REL[T] ? LoadRelation<DM, REL, REL[T][K], W[K]> : never };
|
|
142
|
+
/** The `_count` projection of `W`, if any. */
|
|
143
|
+
type LoadedCount<W> = W extends {
|
|
144
|
+
_count: infer C;
|
|
145
|
+
} ? {
|
|
146
|
+
_count: { [K in keyof C]: number };
|
|
147
|
+
} : {};
|
|
148
|
+
/** `Doc<T>` narrowed to exactly the relations requested in the with-arg `W`. */
|
|
149
|
+
type LoadWith<DM, REL extends Record<keyof DM, object>, T extends keyof DM, W> = DM[T] & LoadedCount<W> & LoadedRelations<DM, REL, T, W>;
|
|
150
|
+
/** Reducer applied by an aggregate (`avg`/`count`/`max`/`min`/`sum`). */
|
|
151
|
+
type AggregateOp = "avg" | "count" | "max" | "min" | "sum";
|
|
152
|
+
/**
|
|
153
|
+
* Query-options shape shared by every aggregate reader. The RLS-aware ctx
|
|
154
|
+
* populates `baseWhere` so it composes here without a hard import.
|
|
155
|
+
* `restrictsCounts: true` flips `count()` into a thrown `COUNT_RLS_UNSUPPORTED`
|
|
156
|
+
* `LunoraError` rather than silently undercount.
|
|
157
|
+
*/
|
|
158
|
+
interface RestrictableQueryOptions<TDocument> {
|
|
159
|
+
baseWhere?: Where<TDocument>;
|
|
160
|
+
restrictsCounts?: boolean;
|
|
161
|
+
where?: Where<TDocument>;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Relation-aware twin of {@link RestrictableQueryOptions}. The `@lunora/do`
|
|
165
|
+
* pre-resolver now resolves relation predicates on the `count`/`aggregate`/
|
|
166
|
+
* `groupBy` paths too (semijoin), so the typed surface threads `REL` through
|
|
167
|
+
* `where`/`baseWhere` to match. `rank`/`rankPage` stay column-only — they use
|
|
168
|
+
* `where` solely to pin a partition and fail closed on a relation predicate.
|
|
169
|
+
*/
|
|
170
|
+
interface RestrictableQueryOptionsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> {
|
|
171
|
+
baseWhere?: WhereOf<DM, REL, T>;
|
|
172
|
+
restrictsCounts?: boolean;
|
|
173
|
+
where?: WhereOf<DM, REL, T>;
|
|
174
|
+
}
|
|
175
|
+
/** Args for `ctx.db.<table>.aggregate({ op, field?, where? })`. */
|
|
176
|
+
interface TableAggregateOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
177
|
+
field?: keyof TDocument & string;
|
|
178
|
+
op: AggregateOp;
|
|
179
|
+
}
|
|
180
|
+
/** Relation-aware twin of {@link TableAggregateOptions} (see {@link RestrictableQueryOptionsOf}). */
|
|
181
|
+
interface TableAggregateOptionsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> extends RestrictableQueryOptionsOf<DM, REL, T> {
|
|
182
|
+
field?: keyof DM[T] & string;
|
|
183
|
+
op: AggregateOp;
|
|
184
|
+
}
|
|
185
|
+
/** Args for `ctx.db.<table>.groupBy({ by, agg?, where? })`. */
|
|
186
|
+
interface TableGroupByOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
187
|
+
agg?: {
|
|
188
|
+
field?: keyof TDocument & string;
|
|
189
|
+
op: AggregateOp;
|
|
190
|
+
};
|
|
191
|
+
by: ReadonlyArray<keyof TDocument & string>;
|
|
192
|
+
}
|
|
193
|
+
/** Relation-aware twin of {@link TableGroupByOptions} (see {@link RestrictableQueryOptionsOf}). */
|
|
194
|
+
interface TableGroupByOptionsOf<DM, REL extends Record<keyof DM, object>, T extends keyof DM> extends RestrictableQueryOptionsOf<DM, REL, T> {
|
|
195
|
+
agg?: {
|
|
196
|
+
field?: keyof DM[T] & string;
|
|
197
|
+
op: AggregateOp;
|
|
198
|
+
};
|
|
199
|
+
by: ReadonlyArray<keyof DM[T] & string>;
|
|
200
|
+
}
|
|
201
|
+
/** One entry returned by `groupBy` — the group's by-tuple plus the reducer value. */
|
|
202
|
+
interface GroupByEntry<TDocument> {
|
|
203
|
+
key: Partial<TDocument>;
|
|
204
|
+
value: null | number;
|
|
205
|
+
}
|
|
206
|
+
/** Args for `ctx.db.<table>.rank(name, args)`. `row` is either an id or a row doc. */
|
|
207
|
+
interface TableRankOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
208
|
+
row: string | TDocument;
|
|
209
|
+
}
|
|
210
|
+
/** Result of `rank` — 1-based position within the partition + partition total. */
|
|
211
|
+
interface RankResult {
|
|
212
|
+
position: number;
|
|
213
|
+
total: number;
|
|
214
|
+
}
|
|
215
|
+
/** Args for `ctx.db.<table>.rankPage(name, args)`. */
|
|
216
|
+
interface TableRankPageOptions<TDocument> extends RestrictableQueryOptions<TDocument> {
|
|
217
|
+
cursor?: null | string;
|
|
218
|
+
take?: number;
|
|
219
|
+
}
|
|
220
|
+
/** One page returned by `rankPage`. */
|
|
221
|
+
interface RankPage<TDocument> {
|
|
222
|
+
continueCursor: null | string;
|
|
223
|
+
isDone: boolean;
|
|
224
|
+
page: TDocument[];
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Builder passed to `.withSearchIndex(name, q => …)`. `.search(field, query)`
|
|
228
|
+
* runs the full-text match against the index's searchable field; `.eq(field,
|
|
229
|
+
* value)` narrows by a declared filter field. Field names are constrained to
|
|
230
|
+
* the table's columns.
|
|
231
|
+
*/
|
|
232
|
+
interface SearchFilterBuilder<TDocument> {
|
|
233
|
+
eq: <F extends keyof TDocument & string>(field: F, value: TDocument[F]) => SearchFilterBuilder<TDocument>;
|
|
234
|
+
search: (field: keyof TDocument & string, query: string) => SearchFilterBuilder<TDocument>;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Chainable reader returned by `.withSearchIndex()` — rows come back ordered
|
|
238
|
+
* by relevance. `.paginate()` is intentionally absent (a relevance-ordered
|
|
239
|
+
* search can't keyset-paginate); cap the result set with `.take(n)`.
|
|
240
|
+
*/
|
|
241
|
+
interface SearchReader<TDocument> {
|
|
242
|
+
collect: () => Promise<TDocument[]>;
|
|
243
|
+
first: () => Promise<TDocument | null>;
|
|
244
|
+
take: (limit: number) => Promise<TDocument[]>;
|
|
245
|
+
unique: () => Promise<TDocument | null>;
|
|
246
|
+
}
|
|
247
|
+
/** Read-only typed table accessor exposed on `QueryCtx.db.<table>`. */
|
|
248
|
+
interface TableReaderFacade<DM, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>, T extends keyof DM> {
|
|
249
|
+
/**
|
|
250
|
+
* Reduce rows in this table to a scalar (`avg`/`max`/`min`/`sum` — `count`
|
|
251
|
+
* lives on its own method). Routes through a declared `aggregateIndex` when
|
|
252
|
+
* the planner can prove the request is answerable; otherwise scans.
|
|
253
|
+
*/
|
|
254
|
+
aggregate: (options: TableAggregateOptionsOf<DM, REL, T>) => Promise<null | number>;
|
|
255
|
+
/**
|
|
256
|
+
* Count rows. The planner routes `where` keys that match a declared
|
|
257
|
+
* `aggregateIndex.by` set to the indexed counter (no scan); otherwise
|
|
258
|
+
* falls back to a SCAN. Accepts either a bare `where` tree or the broader
|
|
259
|
+
* `RestrictableQueryOptions` shape; the latter is the seam the RLS layer
|
|
260
|
+
* uses to inject `baseWhere` and `restrictsCounts`.
|
|
261
|
+
*/
|
|
262
|
+
count: (where?: RestrictableQueryOptionsOf<DM, REL, T> | WhereOf<DM, REL, T>) => Promise<number>;
|
|
263
|
+
findFirst: <W extends WithArg<DM, REL, T> = {}>(args?: QueryArgsOf<DM, REL, T> & {
|
|
264
|
+
with?: W;
|
|
265
|
+
}) => Promise<LoadWith<DM, REL, T, W> | null>;
|
|
266
|
+
findFirstOrThrow: <W extends WithArg<DM, REL, T> = {}>(args?: QueryArgsOf<DM, REL, T> & {
|
|
267
|
+
with?: W;
|
|
268
|
+
}) => Promise<LoadWith<DM, REL, T, W>>;
|
|
269
|
+
findMany: <W extends WithArg<DM, REL, T> = {}>(args?: QueryArgsOf<DM, REL, T> & {
|
|
270
|
+
with?: W;
|
|
271
|
+
}) => Promise<QueryPage<LoadWith<DM, REL, T, W>>>;
|
|
272
|
+
get: (id: Id<string & T>) => Promise<DM[T] | null>;
|
|
273
|
+
/**
|
|
274
|
+
* Group rows by the named keys and apply `agg` per group (defaults to
|
|
275
|
+
* `count`). Answered from the counter table when an aggregate index's
|
|
276
|
+
* `by` matches `options.by` exactly; otherwise scans.
|
|
277
|
+
*/
|
|
278
|
+
groupBy: (options: TableGroupByOptionsOf<DM, REL, T>) => Promise<ReadonlyArray<GroupByEntry<DM[T]>>>;
|
|
279
|
+
/**
|
|
280
|
+
* Return the 1-based position of `options.row` within its partition
|
|
281
|
+
* under the declared rankIndex `indexName`, plus the partition's total
|
|
282
|
+
* row count. `null` when the row isn't in the index. Honors the same
|
|
283
|
+
* `baseWhere` / `restrictsCounts` RLS seam as `count()`.
|
|
284
|
+
*/
|
|
285
|
+
rank: (indexName: RANK[T], options: TableRankOptions<DM[T]>) => Promise<null | RankResult>;
|
|
286
|
+
/**
|
|
287
|
+
* Walk the rank companion in declared sort order — sorted pagination
|
|
288
|
+
* accelerator. `options.where` may pin the partition; `cursor`/`take`
|
|
289
|
+
* follow the Convex-style keyset shape.
|
|
290
|
+
*/
|
|
291
|
+
rankPage: (indexName: RANK[T], options?: TableRankPageOptions<DM[T]>) => Promise<RankPage<DM[T]>>;
|
|
292
|
+
/**
|
|
293
|
+
* Restrict the query to a declared `.searchIndex()` and run a full-text
|
|
294
|
+
* match. `indexName` is constrained to this table's search indexes
|
|
295
|
+
* (`never` when it declares none). Returns a relevance-ordered reader —
|
|
296
|
+
* finish with `.take(n)` / `.collect()`.
|
|
297
|
+
*/
|
|
298
|
+
withSearchIndex: (indexName: SEARCH[T], search: (q: SearchFilterBuilder<DM[T]>) => SearchFilterBuilder<DM[T]>) => SearchReader<DM[T]>;
|
|
299
|
+
}
|
|
300
|
+
/** Read-write typed table accessor exposed on `MutationCtx.db.<table>` / `ActionCtx.db.<table>`. */
|
|
301
|
+
interface TableWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>, T extends keyof DM> extends TableReaderFacade<DM, REL, RANK, SEARCH, T> {
|
|
302
|
+
delete: (id: Id<string & T>) => Promise<void>;
|
|
303
|
+
/** Delete many rows in this table by id in one call; returns the *requested* id count (unknown ids are no-ops). Atomic within a mutation (a throw rolls the mutation back); an action has no transaction span. */
|
|
304
|
+
deleteMany: (ids: ReadonlyArray<Id<string & T>>, options?: {
|
|
305
|
+
limit?: number;
|
|
306
|
+
}) => Promise<{
|
|
307
|
+
deleted: number;
|
|
308
|
+
}>;
|
|
309
|
+
insert: (values: IM[T]) => Promise<Id<string & T>>;
|
|
310
|
+
/** Insert many documents into this table in one call, returning the minted ids in input order. Atomic within a mutation (a throw rolls the mutation back); an action has no transaction span. */
|
|
311
|
+
insertMany: (values: ReadonlyArray<IM[T]>, options?: {
|
|
312
|
+
limit?: number;
|
|
313
|
+
}) => Promise<Id<string & T>[]>;
|
|
314
|
+
patch: (id: Id<string & T>, values: Partial<IM[T]>) => Promise<void>;
|
|
315
|
+
/** Patch many rows in this table by id in one call. Atomic within a mutation (a throw rolls the mutation back); an action has no transaction span. */
|
|
316
|
+
patchMany: (patches: ReadonlyArray<{
|
|
317
|
+
id: Id<string & T>;
|
|
318
|
+
values: Partial<IM[T]>;
|
|
319
|
+
}>, options?: {
|
|
320
|
+
limit?: number;
|
|
321
|
+
}) => Promise<void>;
|
|
322
|
+
replace: (id: Id<string & T>, values: IM[T]) => Promise<void>;
|
|
323
|
+
}
|
|
324
|
+
/** Per-table read facade — `ctx.db.<table>` on a `QueryCtx`. */
|
|
325
|
+
type DatabaseReaderFacade<DM, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>> = { readonly [T in keyof DM]: TableReaderFacade<DM, REL, RANK, SEARCH, T> };
|
|
326
|
+
/** Per-table read-write facade — `ctx.db.<table>` on a `MutationCtx` / `ActionCtx`. */
|
|
327
|
+
type DatabaseWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends Record<keyof DM, object>, RANK extends Record<keyof DM, string>, SEARCH extends Record<keyof DM, string>> = { readonly [T in keyof DM]: TableWriterFacade<DM, IM, REL, RANK, SEARCH, T> };
|
|
328
|
+
export { AggregateOp, DatabaseReaderFacade, DatabaseWriterFacade, GroupByEntry, Id, LoadWith, ManyRelationWhere, OneRelationWhere, OrderBy, QueryArgs, QueryArgsOf, QueryPage, RankPage, RankResult, RestrictableQueryOptions, RestrictableQueryOptionsOf, SearchFilterBuilder, SearchReader, TableAggregateOptions, TableAggregateOptionsOf, TableGroupByOptions, TableGroupByOptionsOf, TableRankOptions, TableRankPageOptions, TableReaderFacade, TableWriterFacade, Where, WhereOf, WhereOperators, WithArg };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'drizzle-orm/sqlite-core';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'drizzle-orm/sqlite-core';
|
package/dist/drizzle.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'drizzle-orm/sqlite-core';
|