@apisr/drizzle-model 0.0.4 → 2.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/DISCLAIMER.md +5 -0
- package/TODO.md +8 -61
- package/package.json +2 -1
- package/src/core/dialect.ts +81 -0
- package/src/core/index.ts +24 -0
- package/src/core/query/error.ts +15 -0
- package/src/core/query/joins.ts +596 -0
- package/src/core/query/projection.ts +136 -0
- package/src/core/query/where.ts +449 -0
- package/src/core/result.ts +297 -0
- package/src/core/runtime.ts +612 -0
- package/src/core/transform.ts +119 -0
- package/src/model/builder.ts +40 -6
- package/src/model/config.ts +9 -9
- package/src/model/format.ts +20 -8
- package/src/model/methods/exclude.ts +1 -7
- package/src/model/methods/return.ts +11 -11
- package/src/model/methods/select.ts +2 -8
- package/src/model/model.ts +10 -16
- package/src/model/query/error.ts +1 -0
- package/src/model/result.ts +134 -21
- package/src/types.ts +38 -0
- package/tests/base/count.test.ts +47 -0
- package/tests/base/delete.test.ts +90 -0
- package/tests/base/find.test.ts +209 -0
- package/tests/base/insert.test.ts +152 -0
- package/tests/base/safe.test.ts +91 -0
- package/tests/base/update.test.ts +88 -0
- package/tests/base/upsert.test.ts +121 -0
- package/tests/base.ts +21 -0
- package/src/model/core/joins.ts +0 -364
- package/src/model/core/projection.ts +0 -61
- package/src/model/core/runtime.ts +0 -334
- package/src/model/core/thenable.ts +0 -94
- package/src/model/core/transform.ts +0 -65
- package/src/model/core/where.ts +0 -249
- package/src/model/core/with.ts +0 -28
- package/tests/builder-v2-mysql.type-test.ts +0 -51
- package/tests/builder-v2.type-test.ts +0 -336
- package/tests/builder.test.ts +0 -63
- package/tests/find.test.ts +0 -166
- package/tests/insert.test.ts +0 -247
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/** Generic record type. */
|
|
2
|
+
type AnyRecord = Record<string, unknown>;
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Safe result wrapper
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A discriminated union that wraps a result with error handling.
|
|
10
|
+
*
|
|
11
|
+
* When the operation succeeds, `data` contains the value and `error`
|
|
12
|
+
* is `undefined`. When it fails, `error` contains the thrown value
|
|
13
|
+
* and `data` is `undefined`.
|
|
14
|
+
*/
|
|
15
|
+
export type SafeResult<T> =
|
|
16
|
+
| { data: T; error: undefined }
|
|
17
|
+
| { data: undefined; error: unknown };
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Query state
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/** Accumulated state for a query operation (findMany / findFirst). */
|
|
24
|
+
export interface QueryState {
|
|
25
|
+
/** Column blacklist for `.exclude()`. */
|
|
26
|
+
exclude?: AnyRecord;
|
|
27
|
+
/** When `true`, formatting is skipped. */
|
|
28
|
+
raw?: boolean;
|
|
29
|
+
/** When `true`, result is wrapped in `{ data, error }`. */
|
|
30
|
+
safe?: boolean;
|
|
31
|
+
/** Column whitelist for `.select()`. */
|
|
32
|
+
select?: AnyRecord;
|
|
33
|
+
/** Compiled where clause. */
|
|
34
|
+
where?: unknown;
|
|
35
|
+
/** Relation inclusions (`.with()` value). */
|
|
36
|
+
with?: unknown;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Mutate state
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
/** Discriminator for mutation kinds. */
|
|
44
|
+
export type MutateKind = "insert" | "update" | "delete" | "upsert";
|
|
45
|
+
|
|
46
|
+
/** Accumulated state for a mutation operation. */
|
|
47
|
+
export interface MutateState {
|
|
48
|
+
/** When `true`, `.return()` or `.returnFirst()` was called. */
|
|
49
|
+
hasReturn?: boolean;
|
|
50
|
+
/** The kind of mutation being performed. */
|
|
51
|
+
kind: MutateKind;
|
|
52
|
+
/** Post-query key exclusion map for `.omit()`. */
|
|
53
|
+
omit?: AnyRecord;
|
|
54
|
+
/** When `true`, only the first element of the returning array is returned. */
|
|
55
|
+
returnFirst?: boolean;
|
|
56
|
+
/** Column selection for `.returning()`. */
|
|
57
|
+
returnSelect?: AnyRecord;
|
|
58
|
+
/** When `true`, result is wrapped in `{ data, error }`. */
|
|
59
|
+
safe?: boolean;
|
|
60
|
+
/** The payload value (insert data, update set, upsert descriptor). */
|
|
61
|
+
value?: unknown;
|
|
62
|
+
/** Compiled where clause (for update / delete). */
|
|
63
|
+
where?: unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// ThenableResult — base class
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A lazy result that implements `PromiseLike` so it can be `await`-ed.
|
|
72
|
+
*
|
|
73
|
+
* Execution is deferred until `.then()` is called, allowing the caller
|
|
74
|
+
* to chain modifiers (`.select()`, `.with()`, …) before the query runs.
|
|
75
|
+
*
|
|
76
|
+
* When `_safe` is `true`, execution errors are caught and the result
|
|
77
|
+
* is wrapped in a {@link SafeResult} discriminated union.
|
|
78
|
+
*
|
|
79
|
+
* @typeParam T - The resolved result type.
|
|
80
|
+
*/
|
|
81
|
+
export class ThenableResult<T> implements PromiseLike<T> {
|
|
82
|
+
/** The deferred execution function. */
|
|
83
|
+
protected readonly _execute: () => Promise<T>;
|
|
84
|
+
|
|
85
|
+
/** When `true`, wraps the result in `{ data, error }`. */
|
|
86
|
+
protected readonly _safe: boolean;
|
|
87
|
+
|
|
88
|
+
constructor(execute: () => Promise<T>, safe = false) {
|
|
89
|
+
this._execute = execute;
|
|
90
|
+
this._safe = safe;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Implements the `PromiseLike` interface.
|
|
95
|
+
*
|
|
96
|
+
* Triggers the deferred execution and forwards to the native
|
|
97
|
+
* `Promise.then()`. When `_safe` is enabled, catches errors and
|
|
98
|
+
* resolves to `{ data, error }` instead of rejecting.
|
|
99
|
+
*/
|
|
100
|
+
then<TResult1 = T, TResult2 = never>(
|
|
101
|
+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
|
102
|
+
onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null
|
|
103
|
+
): Promise<TResult1 | TResult2> {
|
|
104
|
+
if (!this._safe) {
|
|
105
|
+
return this._execute().then(
|
|
106
|
+
onfulfilled as (value: T) => TResult1 | PromiseLike<TResult1>,
|
|
107
|
+
onrejected as (reason: unknown) => TResult2 | PromiseLike<TResult2>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return this._execute()
|
|
112
|
+
.then((data) => ({ data, error: undefined }) as unknown as T)
|
|
113
|
+
.catch((error: unknown) => ({ data: undefined, error }) as unknown as T)
|
|
114
|
+
.then(
|
|
115
|
+
onfulfilled as (value: T) => TResult1 | PromiseLike<TResult1>,
|
|
116
|
+
onrejected as (reason: unknown) => TResult2 | PromiseLike<TResult2>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// QueryResult
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A thenable query result that supports chaining query modifiers.
|
|
127
|
+
*
|
|
128
|
+
* Each modifier returns a **new** `QueryResult` with the updated state,
|
|
129
|
+
* keeping the original immutable.
|
|
130
|
+
*
|
|
131
|
+
* @typeParam T - The resolved result type.
|
|
132
|
+
*/
|
|
133
|
+
export class QueryResult<T> extends ThenableResult<T> {
|
|
134
|
+
/** The current accumulated query state. */
|
|
135
|
+
private readonly state: QueryState;
|
|
136
|
+
|
|
137
|
+
/** The runner function that executes the query with the given state. */
|
|
138
|
+
private readonly runner: (state: QueryState) => Promise<T>;
|
|
139
|
+
|
|
140
|
+
constructor(state: QueryState, runner: (state: QueryState) => Promise<T>) {
|
|
141
|
+
super(() => runner(state), state.safe);
|
|
142
|
+
this.state = state;
|
|
143
|
+
this.runner = runner;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Includes related entities via LEFT JOINs.
|
|
148
|
+
*
|
|
149
|
+
* @param value - A relation selection map (e.g. `{ posts: true }`).
|
|
150
|
+
* @returns A new `QueryResult` with the `.with()` state applied.
|
|
151
|
+
*/
|
|
152
|
+
with(value: AnyRecord): QueryResult<T> {
|
|
153
|
+
return new QueryResult({ ...this.state, with: value }, this.runner);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Whitelists specific fields in the result.
|
|
158
|
+
*
|
|
159
|
+
* @param value - A map of `{ fieldName: true }`.
|
|
160
|
+
* @returns A new `QueryResult` with the `.select()` state applied.
|
|
161
|
+
*/
|
|
162
|
+
select(value: AnyRecord): QueryResult<T> {
|
|
163
|
+
return new QueryResult({ ...this.state, select: value }, this.runner);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Blacklists specific fields from the result.
|
|
168
|
+
*
|
|
169
|
+
* @param value - A map of `{ fieldName: true }`.
|
|
170
|
+
* @returns A new `QueryResult` with the `.exclude()` state applied.
|
|
171
|
+
*/
|
|
172
|
+
exclude(value: AnyRecord): QueryResult<T> {
|
|
173
|
+
return new QueryResult({ ...this.state, exclude: value }, this.runner);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Disables format transformations for this query.
|
|
178
|
+
*
|
|
179
|
+
* @returns A new `QueryResult` with `raw` set to `true`.
|
|
180
|
+
*/
|
|
181
|
+
raw(): QueryResult<T> {
|
|
182
|
+
return new QueryResult({ ...this.state, raw: true }, this.runner);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Wraps the result in a `{ data, error }` discriminated union.
|
|
187
|
+
*
|
|
188
|
+
* When the query succeeds, resolves to `{ data: T, error: undefined }`.
|
|
189
|
+
* When it fails, resolves to `{ data: undefined, error: unknown }`
|
|
190
|
+
* instead of rejecting.
|
|
191
|
+
*
|
|
192
|
+
* @returns A new `QueryResult` with safe error handling enabled.
|
|
193
|
+
*/
|
|
194
|
+
safe(): QueryResult<SafeResult<T>> {
|
|
195
|
+
return new QueryResult(
|
|
196
|
+
{ ...this.state, safe: true },
|
|
197
|
+
this.runner as (state: QueryState) => Promise<SafeResult<T>>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Returns the current query state for debugging purposes.
|
|
203
|
+
*
|
|
204
|
+
* @returns The accumulated {@link QueryState}.
|
|
205
|
+
*/
|
|
206
|
+
debug(): QueryState {
|
|
207
|
+
return this.state;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// MutateResult
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* A thenable mutation result that supports chaining mutation modifiers.
|
|
217
|
+
*
|
|
218
|
+
* Each modifier returns a **new** `MutateResult` with the updated state,
|
|
219
|
+
* keeping the original immutable.
|
|
220
|
+
*
|
|
221
|
+
* @typeParam T - The resolved result type.
|
|
222
|
+
*/
|
|
223
|
+
export class MutateResult<T> extends ThenableResult<T> {
|
|
224
|
+
/** The current accumulated mutation state. */
|
|
225
|
+
private readonly state: MutateState;
|
|
226
|
+
|
|
227
|
+
/** The runner function that executes the mutation with the given state. */
|
|
228
|
+
private readonly runner: (state: MutateState) => Promise<T>;
|
|
229
|
+
|
|
230
|
+
constructor(state: MutateState, runner: (state: MutateState) => Promise<T>) {
|
|
231
|
+
super(() => runner(state), state.safe);
|
|
232
|
+
this.state = state;
|
|
233
|
+
this.runner = runner;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Specifies which columns to return from the mutation (as an array).
|
|
238
|
+
*
|
|
239
|
+
* @param value - Optional column selection map for `.returning()`.
|
|
240
|
+
* @returns A new `MutateResult` with the return selection applied.
|
|
241
|
+
*/
|
|
242
|
+
return(value?: AnyRecord): MutateResult<T> {
|
|
243
|
+
return new MutateResult(
|
|
244
|
+
{ ...this.state, returnSelect: value, hasReturn: true },
|
|
245
|
+
this.runner
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Specifies which columns to return, resolving to only the **first** row.
|
|
251
|
+
*
|
|
252
|
+
* Behaves like `.return()` but unwraps the array to a single object.
|
|
253
|
+
*
|
|
254
|
+
* @param value - Optional column selection map for `.returning()`.
|
|
255
|
+
* @returns A new `MutateResult` with `returnFirst` enabled.
|
|
256
|
+
*/
|
|
257
|
+
returnFirst(value?: AnyRecord): MutateResult<T> {
|
|
258
|
+
return new MutateResult(
|
|
259
|
+
{
|
|
260
|
+
...this.state,
|
|
261
|
+
returnSelect: value,
|
|
262
|
+
returnFirst: true,
|
|
263
|
+
hasReturn: true,
|
|
264
|
+
},
|
|
265
|
+
this.runner
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Excludes specific fields from the mutation result **after** execution.
|
|
271
|
+
*
|
|
272
|
+
* Unlike `.exclude()` on queries (which affects the SQL projection),
|
|
273
|
+
* `.omit()` removes keys from the result objects in-memory.
|
|
274
|
+
*
|
|
275
|
+
* @param value - A map of `{ fieldName: true }` for fields to remove.
|
|
276
|
+
* @returns A new `MutateResult` with the omit map applied.
|
|
277
|
+
*/
|
|
278
|
+
omit(value: AnyRecord): MutateResult<T> {
|
|
279
|
+
return new MutateResult({ ...this.state, omit: value }, this.runner);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Wraps the result in a `{ data, error }` discriminated union.
|
|
284
|
+
*
|
|
285
|
+
* When the mutation succeeds, resolves to `{ data: T, error: undefined }`.
|
|
286
|
+
* When it fails, resolves to `{ data: undefined, error: unknown }`
|
|
287
|
+
* instead of rejecting.
|
|
288
|
+
*
|
|
289
|
+
* @returns A new `MutateResult` with safe error handling enabled.
|
|
290
|
+
*/
|
|
291
|
+
safe(): MutateResult<SafeResult<T>> {
|
|
292
|
+
return new MutateResult(
|
|
293
|
+
{ ...this.state, safe: true },
|
|
294
|
+
this.runner as (state: MutateState) => Promise<SafeResult<T>>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|