@cleverbrush/knex-schema 4.0.0 → 4.1.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/dist/SchemaQueryBuilder.d.ts +37 -990
- package/dist/index.js +23 -23
- package/dist/index.js.map +1 -1
- package/dist/operations/delete.d.ts +6 -0
- package/dist/operations/helpers.d.ts +57 -0
- package/dist/operations/insert.d.ts +26 -0
- package/dist/operations/join.d.ts +6 -0
- package/dist/operations/pagination.d.ts +15 -0
- package/dist/operations/select.d.ts +15 -0
- package/dist/operations/state.d.ts +39 -0
- package/dist/operations/update.d.ts +7 -0
- package/dist/operations/where.d.ts +29 -0
- package/package.json +2 -2
|
@@ -1,1090 +1,137 @@
|
|
|
1
1
|
import type { InferType } from '@cleverbrush/schema';
|
|
2
|
-
import { EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, ObjectSchemaBuilder } from '@cleverbrush/schema';
|
|
2
|
+
import { EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, type ObjectSchemaBuilder } from '@cleverbrush/schema';
|
|
3
3
|
import type { Knex } from 'knex';
|
|
4
4
|
import { POLYMORPHIC_TYPE_BRAND } from './extension.js';
|
|
5
|
-
import type { ColumnRef, CursorPaginationResult, InsertType, JoinManySpec, JoinOneSpec, PaginationResult, SelectProjection, SelectSelector
|
|
6
|
-
|
|
7
|
-
* Extracts the scope names registered on a schema via `.scope(name, fn)`.
|
|
8
|
-
* Returns `never` when no scopes are defined (making `.scoped()` uncallable).
|
|
9
|
-
* Falls back to `string` for `any`-typed schemas to preserve loose behaviour.
|
|
10
|
-
*
|
|
11
|
-
* @internal
|
|
12
|
-
*/
|
|
5
|
+
import type { ColumnRef, CursorPaginationResult, InsertType, JoinManySpec, JoinOneSpec, PaginationResult, SelectProjection, SelectSelector } from './types.js';
|
|
6
|
+
export { OnConflictBuilder } from './operations/insert.js';
|
|
13
7
|
type ScopesOf<S> = S extends {
|
|
14
8
|
readonly [METHOD_LITERAL_BRAND]?: infer N;
|
|
15
9
|
} ? Extract<N, string> : never;
|
|
16
|
-
/**
|
|
17
|
-
* Extracts the named projection map from a schema type.
|
|
18
|
-
* Returns a `Record<name, readonly keys[]>` type where each key is a
|
|
19
|
-
* registered projection name and the value is the tuple of property keys.
|
|
20
|
-
* Returns `Record<never, never>` (no projections) when the schema has none,
|
|
21
|
-
* making `.projected()` uncallable on undecorated schemas.
|
|
22
|
-
*
|
|
23
|
-
* @internal
|
|
24
|
-
*/
|
|
25
10
|
type ProjectionsOf<S> = S extends {
|
|
26
11
|
readonly [EXTRA_TYPE_BRAND]?: infer P;
|
|
27
12
|
} ? P extends Record<string, readonly string[]> ? P : Record<never, never> : Record<never, never>;
|
|
28
|
-
/**
|
|
29
|
-
* Extracts the string-key union for a specific projection name from a schema
|
|
30
|
-
* type. This indirection is needed because TypeScript cannot directly index
|
|
31
|
-
* `ProjectionsOf<S>[K]` with `number` inside a generic function signature.
|
|
32
|
-
*
|
|
33
|
-
* @internal
|
|
34
|
-
*/
|
|
35
13
|
type ProjectionKeysOf<S, K extends keyof ProjectionsOf<S> & string> = ProjectionsOf<S>[K] extends readonly (infer T extends string)[] ? T : string;
|
|
36
|
-
/**
|
|
37
|
-
* When a schema carries the `POLYMORPHIC_TYPE_BRAND` phantom type (set by
|
|
38
|
-
* `.withVariants()`), extract the discriminated-union result type from it.
|
|
39
|
-
* Otherwise fall back to `InferType<TLocalSchema>`.
|
|
40
|
-
*
|
|
41
|
-
* @internal
|
|
42
|
-
*/
|
|
43
14
|
type QueryResultType<TLocalSchema> = TLocalSchema extends {
|
|
44
15
|
readonly [POLYMORPHIC_TYPE_BRAND]?: infer U;
|
|
45
16
|
} ? NonNullable<U> : InferType<TLocalSchema>;
|
|
46
|
-
/**
|
|
47
|
-
* Intermediate builder returned by {@link SchemaQueryBuilder.onConflict}.
|
|
48
|
-
* Call `.merge()` or `.ignore()` to complete the upsert/insert-ignore operation.
|
|
49
|
-
*
|
|
50
|
-
* @internal
|
|
51
|
-
*/
|
|
52
|
-
export declare class OnConflictBuilder<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TResult> {
|
|
53
|
-
#private;
|
|
54
|
-
/** @internal */
|
|
55
|
-
constructor(knex: Knex, localSchema: TLocalSchema, _parent: SchemaQueryBuilder<TLocalSchema, TResult>, conflictColumns: string[]);
|
|
56
|
-
/**
|
|
57
|
-
* Insert and merge (update) conflicting rows.
|
|
58
|
-
*
|
|
59
|
-
* @param data - Row to insert.
|
|
60
|
-
* @param updateData - Optional partial object of columns to update on
|
|
61
|
-
* conflict. If omitted, all inserted columns are updated.
|
|
62
|
-
* @returns The resulting row.
|
|
63
|
-
*/
|
|
64
|
-
merge(data: InsertType<TLocalSchema>, updateData?: Partial<InferType<TLocalSchema>>): Promise<TResult>;
|
|
65
|
-
/**
|
|
66
|
-
* Insert and silently ignore conflicts.
|
|
67
|
-
*
|
|
68
|
-
* @param data - Row to insert.
|
|
69
|
-
* @returns The row if inserted, or `undefined` if the conflict was ignored.
|
|
70
|
-
*/
|
|
71
|
-
ignore(data: InsertType<TLocalSchema>): Promise<TResult | undefined>;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Type-safe, schema-driven query builder for Knex.
|
|
75
|
-
*
|
|
76
|
-
* `SchemaQueryBuilder` wraps a Knex.QueryBuilder and adds:
|
|
77
|
-
* - **Type-safe column references** — pass a property accessor (`t => t.name`)
|
|
78
|
-
* or a string property name; both are resolved to the correct SQL column
|
|
79
|
-
* through the schema's `hasColumnName()` metadata automatically.
|
|
80
|
-
* - **Eager loading without N+1** — {@link joinOne} and {@link joinMany} use
|
|
81
|
-
* PostgreSQL CTEs and `jsonb_agg` to load related rows in a single query.
|
|
82
|
-
* - **Bidirectional result mapping** — rows returned from Postgres (column
|
|
83
|
-
* names) are converted back to schema property names before being returned.
|
|
84
|
-
* - **Thenable protocol** — the builder itself is `await`-able so you can
|
|
85
|
-
* write `await query(db, Schema)` without calling {@link execute} explicitly.
|
|
86
|
-
*
|
|
87
|
-
* Create instances via the {@link query} factory function rather than
|
|
88
|
-
* calling the constructor directly.
|
|
89
|
-
*
|
|
90
|
-
* @typeParam TLocalSchema - The `ObjectSchemaBuilder` describing the main table.
|
|
91
|
-
* @typeParam TResult - The inferred row type, widened automatically as joins
|
|
92
|
-
* are registered via {@link joinOne} / {@link joinMany}.
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* ```ts
|
|
96
|
-
* import knex from 'knex';
|
|
97
|
-
* import { query, object, string, number } from '@cleverbrush/knex-schema';
|
|
98
|
-
*
|
|
99
|
-
* const UserSchema = object({
|
|
100
|
-
* id: number(),
|
|
101
|
-
* name: string(),
|
|
102
|
-
* age: number().optional(),
|
|
103
|
-
* }).hasTableName('users');
|
|
104
|
-
*
|
|
105
|
-
* const db = knex({ client: 'pg', connection: process.env.DB_URL });
|
|
106
|
-
*
|
|
107
|
-
* // Fetch all users older than 18, ordered by name
|
|
108
|
-
* const adults = await query(db, UserSchema)
|
|
109
|
-
* .where(t => t.age, '>', 18)
|
|
110
|
-
* .orderBy(t => t.name);
|
|
111
|
-
* // adults: Array<{ id: number; name: string; age?: number }>
|
|
112
|
-
* ```
|
|
113
|
-
*/
|
|
114
17
|
export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TResult> {
|
|
115
|
-
#private;
|
|
116
|
-
/**
|
|
117
|
-
* @param knex - A configured Knex instance.
|
|
118
|
-
* @param localSchema - The `ObjectSchemaBuilder` for the primary table.
|
|
119
|
-
* Must have a table name set via `.hasTableName()`.
|
|
120
|
-
* @param baseQuery - Optional pre-configured `Knex.QueryBuilder` to use as
|
|
121
|
-
* the base query instead of the default `knex(tableName)`. Useful when you
|
|
122
|
-
* need custom joins, CTEs, or other Knex features not exposed by this API.
|
|
123
|
-
*/
|
|
124
18
|
constructor(knex: Knex, localSchema: TLocalSchema, baseQuery?: Knex.QueryBuilder);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
* record are excluded (inner join); if `false`, they are included with
|
|
139
|
-
* `null` (left join).
|
|
140
|
-
* - `foreignQuery` — optional pre-filtered `Knex.QueryBuilder` for the
|
|
141
|
-
* foreign table (e.g. to apply scopes).
|
|
142
|
-
*
|
|
143
|
-
* @returns `this` (with an updated `TResult` type that includes the new field)
|
|
144
|
-
* for chaining.
|
|
145
|
-
*
|
|
146
|
-
* @example
|
|
147
|
-
* ```ts
|
|
148
|
-
* const PostSchema = object({
|
|
149
|
-
* id: number(),
|
|
150
|
-
* title: string(),
|
|
151
|
-
* authorId: number(),
|
|
152
|
-
* }).hasTableName('posts');
|
|
153
|
-
*
|
|
154
|
-
* const AuthorSchema = object({
|
|
155
|
-
* id: number(),
|
|
156
|
-
* name: string(),
|
|
157
|
-
* }).hasTableName('authors');
|
|
158
|
-
*
|
|
159
|
-
* const posts = await query(db, PostSchema)
|
|
160
|
-
* .joinOne({
|
|
161
|
-
* foreignSchema: AuthorSchema,
|
|
162
|
-
* localColumn: t => t.authorId,
|
|
163
|
-
* foreignColumn: t => t.id,
|
|
164
|
-
* as: 'author',
|
|
165
|
-
* });
|
|
166
|
-
* // posts[0].author.name — typed as string ✓
|
|
167
|
-
* ```
|
|
168
|
-
*/
|
|
169
|
-
joinOne<TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TFieldName extends string, TRequired extends boolean = true>(spec: JoinOneSpec<TLocalSchema, TForeignSchema, TFieldName, TRequired>): SchemaQueryBuilder<TLocalSchema, WithJoinedOne<TResult, TFieldName, TForeignSchema, TRequired>>;
|
|
170
|
-
/**
|
|
171
|
-
* Eager-load a collection of related rows (one-to-many relationship).
|
|
172
|
-
*
|
|
173
|
-
* Related rows are fetched via a single CTE + `jsonb_agg` query. The
|
|
174
|
-
* collection is attached to each result row under the field name specified
|
|
175
|
-
* by `spec.as`. Supports `limit`, `offset`, and `orderBy` per-parent
|
|
176
|
-
* using a `row_number()` window function to avoid fetching the full
|
|
177
|
-
* relation before slicing.
|
|
178
|
-
*
|
|
179
|
-
* @param spec - Join specification. Key fields:
|
|
180
|
-
* - `foreignSchema` — the `ObjectSchemaBuilder` of the related table.
|
|
181
|
-
* - `localColumn` — the primary/unique key on the local table.
|
|
182
|
-
* - `foreignColumn` — the column on the foreign table that references `localColumn`.
|
|
183
|
-
* - `as` — the property name to attach the array under.
|
|
184
|
-
* - `limit` / `offset` — optional pagination per parent row.
|
|
185
|
-
* - `orderBy` — optional `{ column, direction }` for the sub-collection.
|
|
186
|
-
* - `foreignQuery` — optional pre-filtered `Knex.QueryBuilder`.
|
|
187
|
-
*
|
|
188
|
-
* @returns `this` (with an updated `TResult` type that includes the new field)
|
|
189
|
-
* for chaining.
|
|
190
|
-
*
|
|
191
|
-
* @example
|
|
192
|
-
* ```ts
|
|
193
|
-
* const UserSchema = object({
|
|
194
|
-
* id: number(),
|
|
195
|
-
* name: string(),
|
|
196
|
-
* }).hasTableName('users');
|
|
197
|
-
*
|
|
198
|
-
* const PostSchema = object({
|
|
199
|
-
* id: number(),
|
|
200
|
-
* title: string(),
|
|
201
|
-
* authorId: number(),
|
|
202
|
-
* }).hasTableName('posts');
|
|
203
|
-
*
|
|
204
|
-
* const users = await query(db, UserSchema)
|
|
205
|
-
* .joinMany({
|
|
206
|
-
* foreignSchema: PostSchema,
|
|
207
|
-
* localColumn: t => t.id,
|
|
208
|
-
* foreignColumn: t => t.authorId,
|
|
209
|
-
* as: 'posts',
|
|
210
|
-
* limit: 5,
|
|
211
|
-
* orderBy: { column: t => t.id, direction: 'desc' },
|
|
212
|
-
* });
|
|
213
|
-
* // users[0].posts — typed as Array<{ id: number; title: string; authorId: number }>
|
|
214
|
-
* ```
|
|
215
|
-
*/
|
|
216
|
-
joinMany<TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TFieldName extends string>(spec: JoinManySpec<TLocalSchema, TForeignSchema, TFieldName>): SchemaQueryBuilder<TLocalSchema, WithJoinedMany<TResult, TFieldName, TForeignSchema>>;
|
|
217
|
-
/**
|
|
218
|
-
* Add a `WHERE` clause to the query.
|
|
219
|
-
*
|
|
220
|
-
* Accepts a column reference, an optional operator, and a value:
|
|
221
|
-
* - `where(t => t.age, '>', 18)` — property accessor + operator + value.
|
|
222
|
-
* - `where('age', 18)` — string key + value (defaults to `=`).
|
|
223
|
-
* - `where({ name: 'Alice' })` — record object; property keys are mapped
|
|
224
|
-
* to column names automatically.
|
|
225
|
-
* - `where(builder => { ... })` — Knex sub-builder callback for grouped
|
|
226
|
-
* conditions.
|
|
227
|
-
* - `where(knex.raw('...'))` — raw SQL expression.
|
|
228
|
-
*
|
|
229
|
-
* Multiple `.where()` calls are combined with `AND`.
|
|
230
|
-
*
|
|
231
|
-
* @returns `this` for chaining.
|
|
232
|
-
*/
|
|
19
|
+
select(...columns: (ColumnRef<TLocalSchema> | Knex.Raw)[]): this;
|
|
20
|
+
select<TSel extends SelectSelector<TLocalSchema>>(selector: TSel): SchemaQueryBuilder<TLocalSchema, SelectProjection<ReturnType<TSel>>>;
|
|
21
|
+
distinct(...columns: (ColumnRef<TLocalSchema> | Knex.Raw)[]): this;
|
|
22
|
+
count(column?: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
23
|
+
countDistinct(column?: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
24
|
+
min(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
25
|
+
max(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
26
|
+
sum(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
27
|
+
avg(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
28
|
+
selectRaw(sql: string, bindings?: any[]): this;
|
|
29
|
+
projected<K extends keyof ProjectionsOf<TLocalSchema> & string>(name: K): SchemaQueryBuilder<TLocalSchema, Pick<TResult, ProjectionKeysOf<TLocalSchema, K> & keyof TResult>>;
|
|
30
|
+
scoped<K extends ScopesOf<TLocalSchema>>(name: K): this;
|
|
31
|
+
unscoped(): this;
|
|
233
32
|
where(column: ColumnRef<TLocalSchema>, operator: string, value: any): this;
|
|
234
33
|
where(column: ColumnRef<TLocalSchema>, value: any): this;
|
|
235
34
|
where(raw: Knex.Raw, operator: string, value: any): this;
|
|
236
35
|
where(callback: (builder: Knex.QueryBuilder) => void): this;
|
|
237
36
|
where(record: Record<string, any>): this;
|
|
238
37
|
where(raw: Knex.Raw): this;
|
|
239
|
-
/**
|
|
240
|
-
* Alias for {@link where} — explicitly adds an `AND WHERE` clause.
|
|
241
|
-
* Identical to calling `.where()` when no logical-OR grouping is needed.
|
|
242
|
-
* @returns `this` for chaining.
|
|
243
|
-
*/
|
|
244
38
|
andWhere(column: ColumnRef<TLocalSchema>, operator: string, value: any): this;
|
|
245
39
|
andWhere(column: ColumnRef<TLocalSchema>, value: any): this;
|
|
246
40
|
andWhere(record: Record<string, any>): this;
|
|
247
41
|
andWhere(callback: (builder: Knex.QueryBuilder) => void): this;
|
|
248
42
|
andWhere(raw: Knex.Raw): this;
|
|
249
|
-
/**
|
|
250
|
-
* Add an `OR WHERE` clause. Use this to create alternative filter branches.
|
|
251
|
-
* @returns `this` for chaining.
|
|
252
|
-
*/
|
|
253
43
|
orWhere(column: ColumnRef<TLocalSchema>, operator: string, value: any): this;
|
|
254
44
|
orWhere(column: ColumnRef<TLocalSchema>, value: any): this;
|
|
255
45
|
orWhere(record: Record<string, any>): this;
|
|
256
46
|
orWhere(callback: (builder: Knex.QueryBuilder) => void): this;
|
|
257
47
|
orWhere(raw: Knex.Raw): this;
|
|
258
|
-
/**
|
|
259
|
-
* Add a `WHERE NOT` clause — negates the condition.
|
|
260
|
-
* @returns `this` for chaining.
|
|
261
|
-
*/
|
|
262
48
|
whereNot(column: ColumnRef<TLocalSchema>, operator: string, value: any): this;
|
|
263
49
|
whereNot(column: ColumnRef<TLocalSchema>, value: any): this;
|
|
264
50
|
whereNot(record: Record<string, any>): this;
|
|
265
51
|
whereNot(callback: (builder: Knex.QueryBuilder) => void): this;
|
|
266
52
|
whereNot(raw: Knex.Raw): this;
|
|
267
|
-
/**
|
|
268
|
-
* Add a `WHERE column IN (values)` clause.
|
|
269
|
-
* @param column - Column reference (property accessor or string key).
|
|
270
|
-
* @param values - Array of values or a sub-query.
|
|
271
|
-
* @returns `this` for chaining.
|
|
272
|
-
*/
|
|
273
53
|
whereIn(column: ColumnRef<TLocalSchema>, values: readonly any[] | Knex.QueryBuilder): this;
|
|
274
|
-
/**
|
|
275
|
-
* Add a `WHERE column NOT IN (values)` clause.
|
|
276
|
-
* @param column - Column reference.
|
|
277
|
-
* @param values - Array of values or a sub-query.
|
|
278
|
-
* @returns `this` for chaining.
|
|
279
|
-
*/
|
|
280
54
|
whereNotIn(column: ColumnRef<TLocalSchema>, values: readonly any[] | Knex.QueryBuilder): this;
|
|
281
|
-
/**
|
|
282
|
-
* Add an `OR WHERE column IN (values)` clause.
|
|
283
|
-
* @returns `this` for chaining.
|
|
284
|
-
*/
|
|
285
55
|
orWhereIn(column: ColumnRef<TLocalSchema>, values: readonly any[] | Knex.QueryBuilder): this;
|
|
286
|
-
/**
|
|
287
|
-
* Add an `OR WHERE column NOT IN (values)` clause.
|
|
288
|
-
* @returns `this` for chaining.
|
|
289
|
-
*/
|
|
290
56
|
orWhereNotIn(column: ColumnRef<TLocalSchema>, values: readonly any[] | Knex.QueryBuilder): this;
|
|
291
|
-
/**
|
|
292
|
-
* Add a `WHERE column IS NULL` clause.
|
|
293
|
-
* @returns `this` for chaining.
|
|
294
|
-
*/
|
|
295
57
|
whereNull(column: ColumnRef<TLocalSchema>): this;
|
|
296
|
-
/**
|
|
297
|
-
* Add a `WHERE column IS NOT NULL` clause.
|
|
298
|
-
* @returns `this` for chaining.
|
|
299
|
-
*/
|
|
300
58
|
whereNotNull(column: ColumnRef<TLocalSchema>): this;
|
|
301
|
-
/**
|
|
302
|
-
* Add an `OR WHERE column IS NULL` clause.
|
|
303
|
-
* @returns `this` for chaining.
|
|
304
|
-
*/
|
|
305
59
|
orWhereNull(column: ColumnRef<TLocalSchema>): this;
|
|
306
|
-
/**
|
|
307
|
-
* Add an `OR WHERE column IS NOT NULL` clause.
|
|
308
|
-
* @returns `this` for chaining.
|
|
309
|
-
*/
|
|
310
60
|
orWhereNotNull(column: ColumnRef<TLocalSchema>): this;
|
|
311
|
-
/**
|
|
312
|
-
* Add a `WHERE column BETWEEN low AND high` clause.
|
|
313
|
-
* @param range - A two-element tuple `[low, high]`.
|
|
314
|
-
* @returns `this` for chaining.
|
|
315
|
-
*/
|
|
316
61
|
whereBetween(column: ColumnRef<TLocalSchema>, range: readonly [any, any]): this;
|
|
317
|
-
/**
|
|
318
|
-
* Add a `WHERE column NOT BETWEEN low AND high` clause.
|
|
319
|
-
* @param range - A two-element tuple `[low, high]`.
|
|
320
|
-
* @returns `this` for chaining.
|
|
321
|
-
*/
|
|
322
62
|
whereNotBetween(column: ColumnRef<TLocalSchema>, range: readonly [any, any]): this;
|
|
323
|
-
/**
|
|
324
|
-
* Add a case-sensitive `WHERE column LIKE value` clause.
|
|
325
|
-
* @param value - A SQL LIKE pattern (e.g. `'Alice%'`).
|
|
326
|
-
* @returns `this` for chaining.
|
|
327
|
-
*/
|
|
328
63
|
whereLike(column: ColumnRef<TLocalSchema>, value: string): this;
|
|
329
|
-
/**
|
|
330
|
-
* Add a case-insensitive `WHERE column ILIKE value` clause (PostgreSQL).
|
|
331
|
-
* @param value - A SQL LIKE pattern (e.g. `'alice%'`).
|
|
332
|
-
* @returns `this` for chaining.
|
|
333
|
-
*/
|
|
334
64
|
whereILike(column: ColumnRef<TLocalSchema>, value: string): this;
|
|
335
|
-
/**
|
|
336
|
-
* Add a raw `WHERE` clause. Useful for database-specific expressions.
|
|
337
|
-
* @param sql - Raw SQL string with optional `:binding:` or `?` placeholders.
|
|
338
|
-
* @param bindings - Values for the placeholders.
|
|
339
|
-
* @returns `this` for chaining.
|
|
340
|
-
*/
|
|
341
65
|
whereRaw(sql: string, ...bindings: any[]): this;
|
|
342
|
-
/**
|
|
343
|
-
* Add a `WHERE EXISTS (subquery)` clause.
|
|
344
|
-
* @param callback - A Knex query callback or sub-query builder.
|
|
345
|
-
* @returns `this` for chaining.
|
|
346
|
-
*/
|
|
347
66
|
whereExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this;
|
|
348
|
-
/**
|
|
349
|
-
* Add a `WHERE NOT EXISTS (subquery)` clause.
|
|
350
|
-
* @param callback - A Knex query callback or sub-query builder.
|
|
351
|
-
* @returns `this` for chaining.
|
|
352
|
-
*/
|
|
353
67
|
whereNotExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this;
|
|
354
|
-
/**
|
|
355
|
-
* Add a PostgreSQL JSON path filter using `@?` / `@@` operators or
|
|
356
|
-
* a path-based equality test via `jsonb_path_query_first`.
|
|
357
|
-
*
|
|
358
|
-
* Only supported on `pg` clients — throws at runtime on others.
|
|
359
|
-
*
|
|
360
|
-
* @param column - Column reference for the `jsonb` column.
|
|
361
|
-
* @param path - Dot-separated property path (e.g. `'a.b.c'`) or a
|
|
362
|
-
* JSONPath expression string (e.g. `'$.a.b ? (@ == 1)'`).
|
|
363
|
-
* @param operator - Comparison operator (`=`, `!=`, `<`, `<=`, `>`, `>=`,
|
|
364
|
-
* `@?`, `@@`). Use `@?` / `@@` for JSONPath existence / predicate tests.
|
|
365
|
-
* @param value - The right-hand side value. Ignored for `@?` and `@@`.
|
|
366
|
-
* @returns `this` for chaining.
|
|
367
|
-
*
|
|
368
|
-
* @example
|
|
369
|
-
* ```ts
|
|
370
|
-
* // Filter rows where data->>'status' = 'active'
|
|
371
|
-
* query(db, Schema).whereJsonPath(t => t.data, 'status', '=', 'active');
|
|
372
|
-
*
|
|
373
|
-
* // JSONPath existence
|
|
374
|
-
* query(db, Schema).whereJsonPath(t => t.data, '$.tags[*] ? (@ == "sale")', '@?');
|
|
375
|
-
* ```
|
|
376
|
-
*/
|
|
377
68
|
whereJsonPath(column: ColumnRef<TLocalSchema>, path: string, operator?: string, value?: any): this;
|
|
378
|
-
/**
|
|
379
|
-
* Order the results by a column.
|
|
380
|
-
* @param column - Column reference or raw expression.
|
|
381
|
-
* @param direction - `'asc'` (default) or `'desc'`.
|
|
382
|
-
* @returns `this` for chaining.
|
|
383
|
-
*
|
|
384
|
-
* @example
|
|
385
|
-
* ```ts
|
|
386
|
-
* query(db, UserSchema).orderBy(t => t.name).orderBy(t => t.createdAt, 'desc');
|
|
387
|
-
* ```
|
|
388
|
-
*/
|
|
389
69
|
orderBy(column: ColumnRef<TLocalSchema> | Knex.Raw, direction?: 'asc' | 'desc'): this;
|
|
390
|
-
/**
|
|
391
|
-
* Order the results by a raw SQL expression.
|
|
392
|
-
* @param sql - Raw SQL (e.g. `'LOWER(name) ASC'`).
|
|
393
|
-
* @returns `this` for chaining.
|
|
394
|
-
*/
|
|
395
70
|
orderByRaw(sql: string, ...bindings: any[]): this;
|
|
396
|
-
/**
|
|
397
|
-
* Add a `GROUP BY` clause.
|
|
398
|
-
* @param columns - One or more column references or raw expressions.
|
|
399
|
-
* @returns `this` for chaining.
|
|
400
|
-
*/
|
|
401
71
|
groupBy(...columns: (ColumnRef<TLocalSchema> | Knex.Raw)[]): this;
|
|
402
|
-
/**
|
|
403
|
-
* Add a raw `GROUP BY` expression.
|
|
404
|
-
* @returns `this` for chaining.
|
|
405
|
-
*/
|
|
406
72
|
groupByRaw(sql: string, ...bindings: any[]): this;
|
|
407
|
-
/**
|
|
408
|
-
* Add a `HAVING column operator value` clause (used with `GROUP BY`).
|
|
409
|
-
* @returns `this` for chaining.
|
|
410
|
-
*/
|
|
411
73
|
having(column: ColumnRef<TLocalSchema> | Knex.Raw, operator: string, value: any): this;
|
|
412
|
-
/**
|
|
413
|
-
* Add a raw `HAVING` expression.
|
|
414
|
-
* @returns `this` for chaining.
|
|
415
|
-
*/
|
|
416
74
|
havingRaw(sql: string, ...bindings: any[]): this;
|
|
417
|
-
/**
|
|
418
|
-
* Limit the number of rows returned.
|
|
419
|
-
* @param n - Maximum number of rows.
|
|
420
|
-
* @returns `this` for chaining.
|
|
421
|
-
*/
|
|
422
75
|
limit(n: number): this;
|
|
423
|
-
/**
|
|
424
|
-
* Skip the first `n` rows in the result set (for cursor/offset pagination).
|
|
425
|
-
* @param n - Number of rows to skip.
|
|
426
|
-
* @returns `this` for chaining.
|
|
427
|
-
*/
|
|
428
76
|
offset(n: number): this;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
* shape of the selector's return value (each value typed as the
|
|
440
|
-
* inferred schema-property type).
|
|
441
|
-
*
|
|
442
|
-
* @example
|
|
443
|
-
* ```ts
|
|
444
|
-
* const dtos = await query(db, UserSchema)
|
|
445
|
-
* .where(t => t.id, '>', 0)
|
|
446
|
-
* .select(t => ({ id: t.id, n: t.name }))
|
|
447
|
-
* .execute();
|
|
448
|
-
* // dtos: { id: number; n: string }[]
|
|
449
|
-
* ```
|
|
450
|
-
*/
|
|
451
|
-
select<TSel extends SelectSelector<TLocalSchema>>(selector: TSel): SchemaQueryBuilder<TLocalSchema, SelectProjection<ReturnType<TSel>>>;
|
|
452
|
-
/**
|
|
453
|
-
* Add `DISTINCT` to the select clause. Duplicate rows are eliminated.
|
|
454
|
-
* @param columns - One or more column references or raw expressions.
|
|
455
|
-
* @returns `this` for chaining.
|
|
456
|
-
*/
|
|
457
|
-
distinct(...columns: (ColumnRef<TLocalSchema> | Knex.Raw)[]): this;
|
|
458
|
-
/**
|
|
459
|
-
* Add a `COUNT(*)` or `COUNT(column)` aggregate to the select list.
|
|
460
|
-
* @param column - Optional column to count (defaults to `*`).
|
|
461
|
-
* @returns `this` for chaining.
|
|
462
|
-
*/
|
|
463
|
-
count(column?: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
464
|
-
/**
|
|
465
|
-
* Add a `COUNT(DISTINCT column)` aggregate to the select list.
|
|
466
|
-
* @param column - Optional column (defaults to `*`).
|
|
467
|
-
* @returns `this` for chaining.
|
|
468
|
-
*/
|
|
469
|
-
countDistinct(column?: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
470
|
-
/**
|
|
471
|
-
* Add a `MIN(column)` aggregate.
|
|
472
|
-
* @returns `this` for chaining.
|
|
473
|
-
*/
|
|
474
|
-
min(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
475
|
-
/**
|
|
476
|
-
* Add a `MAX(column)` aggregate.
|
|
477
|
-
* @returns `this` for chaining.
|
|
478
|
-
*/
|
|
479
|
-
max(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
480
|
-
/**
|
|
481
|
-
* Add a `SUM(column)` aggregate.
|
|
482
|
-
* @returns `this` for chaining.
|
|
483
|
-
*/
|
|
484
|
-
sum(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
485
|
-
/**
|
|
486
|
-
* Add an `AVG(column)` aggregate.
|
|
487
|
-
* @returns `this` for chaining.
|
|
488
|
-
*/
|
|
489
|
-
avg(column: ColumnRef<TLocalSchema> | Knex.Raw): this;
|
|
490
|
-
/**
|
|
491
|
-
* Insert a single row into the table and return the inserted record.
|
|
492
|
-
*
|
|
493
|
-
* Property keys are mapped to SQL column names via the schema's
|
|
494
|
-
* `hasColumnName()` metadata before the `INSERT` is executed. The
|
|
495
|
-
* returned row is mapped back to property names.
|
|
496
|
-
*
|
|
497
|
-
* @param data - The object to insert. Keys must be valid schema property names.
|
|
498
|
-
* @returns The full inserted row (including database-generated fields).
|
|
499
|
-
*
|
|
500
|
-
* @example
|
|
501
|
-
* ```ts
|
|
502
|
-
* const user = await query(db, UserSchema).insert({ name: 'Alice', age: 30 });
|
|
503
|
-
* // user.id is populated by the database DEFAULT / SERIAL
|
|
504
|
-
* ```
|
|
505
|
-
*/
|
|
77
|
+
paginate(opts: {
|
|
78
|
+
page: number;
|
|
79
|
+
pageSize: number;
|
|
80
|
+
}): Promise<PaginationResult<TResult>>;
|
|
81
|
+
paginateAfter(opts: {
|
|
82
|
+
cursor?: any;
|
|
83
|
+
limit: number;
|
|
84
|
+
column?: ColumnRef<TLocalSchema>;
|
|
85
|
+
direction?: 'asc' | 'desc';
|
|
86
|
+
}): Promise<CursorPaginationResult<TResult>>;
|
|
506
87
|
insert(data: InsertType<TLocalSchema>): Promise<TResult>;
|
|
507
|
-
/**
|
|
508
|
-
* Insert multiple rows in a single `INSERT` statement and return all
|
|
509
|
-
* inserted records.
|
|
510
|
-
*
|
|
511
|
-
* @param data - Array of objects to insert.
|
|
512
|
-
* @returns The full inserted rows in insertion order.
|
|
513
|
-
*/
|
|
514
88
|
insertMany(data: InsertType<TLocalSchema>[]): Promise<TResult[]>;
|
|
515
|
-
|
|
516
|
-
* Insert a row (or rows) with an `ON CONFLICT` clause.
|
|
517
|
-
*
|
|
518
|
-
* Returns a chainable object with `.merge()` and `.ignore()` methods.
|
|
519
|
-
*
|
|
520
|
-
* - `.merge(updateData?)` — updates the conflicting row with the provided
|
|
521
|
-
* fields (or all insert fields if omitted).
|
|
522
|
-
* - `.ignore()` — skips the insert when a conflict occurs (INSERT IGNORE).
|
|
523
|
-
*
|
|
524
|
-
* @param conflictColumns - Column references that define the conflict target.
|
|
525
|
-
* @returns A chainable conflict builder.
|
|
526
|
-
*
|
|
527
|
-
* @example
|
|
528
|
-
* ```ts
|
|
529
|
-
* // Upsert: insert or update on conflict
|
|
530
|
-
* await query(db, UserSchema)
|
|
531
|
-
* .onConflict(t => t.email)
|
|
532
|
-
* .merge({ name: 'Bob' });
|
|
533
|
-
*
|
|
534
|
-
* // Insert and ignore on conflict
|
|
535
|
-
* await query(db, UserSchema)
|
|
536
|
-
* .onConflict(t => t.email)
|
|
537
|
-
* .ignore();
|
|
538
|
-
* ```
|
|
539
|
-
*/
|
|
540
|
-
onConflict(...conflictColumns: ColumnRef<TLocalSchema>[]): OnConflictBuilder<TLocalSchema, TResult>;
|
|
541
|
-
/**
|
|
542
|
-
* Insert or update a row based on a conflict target (upsert shorthand).
|
|
543
|
-
*
|
|
544
|
-
* Equivalent to calling `.onConflict(conflictColumns).merge(updateData)`.
|
|
545
|
-
*
|
|
546
|
-
* @param data - The row data to insert.
|
|
547
|
-
* @param opts - `{ conflictColumns, updateColumns? }`.
|
|
548
|
-
* @returns The resulting row (inserted or updated).
|
|
549
|
-
*
|
|
550
|
-
* @example
|
|
551
|
-
* ```ts
|
|
552
|
-
* const user = await query(db, UserSchema).upsert(
|
|
553
|
-
* { email: 'alice@example.com', name: 'Alice' },
|
|
554
|
-
* { conflictColumns: [t => t.email], updateColumns: [t => t.name] }
|
|
555
|
-
* );
|
|
556
|
-
* ```
|
|
557
|
-
*/
|
|
89
|
+
onConflict(...conflictColumns: ColumnRef<TLocalSchema>[]): import('./operations/insert.js').OnConflictBuilder<TLocalSchema, TResult>;
|
|
558
90
|
upsert(data: InsertType<TLocalSchema>, opts: {
|
|
559
91
|
conflictColumns: ColumnRef<TLocalSchema>[];
|
|
560
92
|
updateColumns?: ColumnRef<TLocalSchema>[];
|
|
561
93
|
}): Promise<TResult>;
|
|
562
|
-
/**
|
|
563
|
-
* Update all rows that match the current `WHERE` clause and return the
|
|
564
|
-
* updated records.
|
|
565
|
-
*
|
|
566
|
-
* Only the keys present in `data` are updated (partial update). Property
|
|
567
|
-
* keys are resolved to column names automatically.
|
|
568
|
-
*
|
|
569
|
-
* @param data - Partial schema object with fields to update.
|
|
570
|
-
* @returns All rows that were updated.
|
|
571
|
-
*
|
|
572
|
-
* @example
|
|
573
|
-
* ```ts
|
|
574
|
-
* const updated = await query(db, UserSchema)
|
|
575
|
-
* .where(t => t.id, userId)
|
|
576
|
-
* .update({ name: 'Bob' });
|
|
577
|
-
* ```
|
|
578
|
-
*/
|
|
579
|
-
update(data: Partial<InferType<TLocalSchema>>): Promise<TResult[]>;
|
|
580
|
-
/**
|
|
581
|
-
* Delete all rows that match the current `WHERE` clause.
|
|
582
|
-
*
|
|
583
|
-
* If the schema has soft-delete enabled via `.softDelete()`, this performs
|
|
584
|
-
* an `UPDATE SET deleted_at = NOW()` instead of a real `DELETE`.
|
|
585
|
-
* Use {@link hardDelete} for permanent deletion.
|
|
586
|
-
*
|
|
587
|
-
* @returns The number of rows deleted (or soft-deleted).
|
|
588
|
-
*
|
|
589
|
-
* @example
|
|
590
|
-
* ```ts
|
|
591
|
-
* const count = await query(db, UserSchema).where(t => t.id, id).delete();
|
|
592
|
-
* ```
|
|
593
|
-
*/
|
|
594
|
-
delete(): Promise<number>;
|
|
595
|
-
/**
|
|
596
|
-
* Bulk-insert many rows in chunks. The default chunk size of `500` keeps
|
|
597
|
-
* comfortably below Postgres' parameter-count limit of 65535. The chunk
|
|
598
|
-
* size also auto-shrinks when the number of bindings per row would
|
|
599
|
-
* exceed that ceiling.
|
|
600
|
-
*
|
|
601
|
-
* When `opts.onConflict` is supplied each chunk is wrapped in an
|
|
602
|
-
* `INSERT ... ON CONFLICT` clause:
|
|
603
|
-
*
|
|
604
|
-
* - `'ignore'` — `ON CONFLICT (...) DO NOTHING`
|
|
605
|
-
* - `'merge'` — `ON CONFLICT (...) DO UPDATE SET ...` (uses `conflictColumns` as
|
|
606
|
-
* the conflict target and updates every inserted column).
|
|
607
|
-
*
|
|
608
|
-
* `beforeInsert` / `afterInsert` hooks fire per row, identically to
|
|
609
|
-
* {@link insertMany}.
|
|
610
|
-
*
|
|
611
|
-
* @returns The inserted rows (excluding rows skipped by `'ignore'`).
|
|
612
|
-
*/
|
|
613
94
|
bulkInsert(rows: InsertType<TLocalSchema>[], opts?: {
|
|
614
95
|
chunkSize?: number;
|
|
615
96
|
onConflict?: 'ignore' | 'merge';
|
|
616
97
|
conflictColumns?: ColumnRef<TLocalSchema>[];
|
|
617
98
|
}): Promise<TResult[]>;
|
|
618
|
-
/**
|
|
619
|
-
* Bulk-upsert many rows in chunks. Equivalent to
|
|
620
|
-
* `.bulkInsert(rows, { onConflict: 'merge', conflictColumns })`.
|
|
621
|
-
*/
|
|
622
99
|
bulkUpsert(rows: InsertType<TLocalSchema>[], opts: {
|
|
623
100
|
conflictColumns: ColumnRef<TLocalSchema>[];
|
|
624
101
|
chunkSize?: number;
|
|
625
102
|
}): Promise<TResult[]>;
|
|
626
|
-
|
|
627
|
-
* Bulk-update many rows in a single SQL statement using a CASE
|
|
628
|
-
* expression keyed on the entity's primary key.
|
|
629
|
-
*
|
|
630
|
-
* Each entry's `where` clause must fully match the entity's primary key
|
|
631
|
-
* columns (single or composite). Updates that touch different columns
|
|
632
|
-
* are coalesced into one statement; rows whose PK appears in `updates`
|
|
633
|
-
* but whose `set` does not contain a given column retain their existing
|
|
634
|
-
* value.
|
|
635
|
-
*
|
|
636
|
-
* @returns The number of rows affected.
|
|
637
|
-
*/
|
|
103
|
+
update(data: Partial<InferType<TLocalSchema>>): Promise<TResult[]>;
|
|
638
104
|
bulkUpdate(updates: ReadonlyArray<{
|
|
639
105
|
where: Partial<InferType<TLocalSchema>>;
|
|
640
106
|
set: Partial<InferType<TLocalSchema>>;
|
|
641
107
|
}>): Promise<number>;
|
|
642
|
-
|
|
643
|
-
* Escape hatch: apply any Knex method to the underlying base query.
|
|
644
|
-
*
|
|
645
|
-
* Use this when you need a Knex feature not exposed by this API (e.g.
|
|
646
|
-
* `forUpdate()`, CTEs, `join()`, `union()`).
|
|
647
|
-
*
|
|
648
|
-
* @param fn - A callback that receives the raw `Knex.QueryBuilder` and
|
|
649
|
-
* may mutate it in place.
|
|
650
|
-
* @returns `this` for chaining.
|
|
651
|
-
*
|
|
652
|
-
* @example
|
|
653
|
-
* ```ts
|
|
654
|
-
* query(db, UserSchema).apply(qb => qb.forUpdate().noWait());
|
|
655
|
-
* ```
|
|
656
|
-
*/
|
|
657
|
-
apply(fn: (builder: Knex.QueryBuilder) => void): this;
|
|
658
|
-
/**
|
|
659
|
-
* Bind this query builder to a Knex transaction.
|
|
660
|
-
*
|
|
661
|
-
* Returns a **new** builder that runs all operations — SELECT, INSERT,
|
|
662
|
-
* UPDATE, DELETE, and eager-loaded sub-queries — within the given
|
|
663
|
-
* transaction. The original builder is left unchanged.
|
|
664
|
-
*
|
|
665
|
-
* Use this when you already have a transaction obtained from
|
|
666
|
-
* `knex.transaction()` and want all operations performed by the returned
|
|
667
|
-
* builder to participate in that transaction.
|
|
668
|
-
*
|
|
669
|
-
* @param trx - The Knex transaction obtained from `knex.transaction()`.
|
|
670
|
-
* @returns A new {@link SchemaQueryBuilder} bound to the transaction.
|
|
671
|
-
*
|
|
672
|
-
* @example
|
|
673
|
-
* ```ts
|
|
674
|
-
* async function createUser(
|
|
675
|
-
* data: InsertType<typeof UserSchema>,
|
|
676
|
-
* trx: Knex.Transaction
|
|
677
|
-
* ) {
|
|
678
|
-
* return query(db, UserSchema).transacting(trx).insert(data);
|
|
679
|
-
* }
|
|
680
|
-
*
|
|
681
|
-
* await db.transaction(async trx => {
|
|
682
|
-
* const user = await createUser({ name: 'Alice' }, trx);
|
|
683
|
-
* await query(db, PostSchema).transacting(trx).insert({ authorId: user.id, title: 'Hello' });
|
|
684
|
-
* });
|
|
685
|
-
* ```
|
|
686
|
-
*/
|
|
687
|
-
transacting(trx: Knex.Transaction): SchemaQueryBuilder<TLocalSchema, TResult>;
|
|
688
|
-
/**
|
|
689
|
-
* Eager-load a named relation defined via `.hasMany()`, `.belongsTo()`,
|
|
690
|
-
* `.hasOne()`, or `.belongsToMany()` on the schema.
|
|
691
|
-
*
|
|
692
|
-
* @param relationName - The relation name passed to the schema's relation method.
|
|
693
|
-
* @param customize - Optional callback to customise the foreign query
|
|
694
|
-
* (e.g. add ordering, limits).
|
|
695
|
-
* @returns `this` for chaining.
|
|
696
|
-
*
|
|
697
|
-
* @example
|
|
698
|
-
* ```ts
|
|
699
|
-
* const posts = await query(db, PostWithRelations)
|
|
700
|
-
* .include('author')
|
|
701
|
-
* .include('tags');
|
|
702
|
-
* ```
|
|
703
|
-
*/
|
|
704
|
-
include(relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): this;
|
|
705
|
-
/**
|
|
706
|
-
* Eager-load a named relation declared inside a `withVariants` variant spec.
|
|
707
|
-
*
|
|
708
|
-
* The relation is loaded via a LEFT JOIN on the variant's alias table and
|
|
709
|
-
* only populated on rows whose discriminator matches `variantKey`.
|
|
710
|
-
*
|
|
711
|
-
* @param variantKey - The variant key (e.g. `'assigned'`).
|
|
712
|
-
* @param relationName - The relation name declared in `variants[key].relations`.
|
|
713
|
-
* @param customize - Optional callback to restrict which columns are
|
|
714
|
-
* selected from the foreign table (scope / projection).
|
|
715
|
-
*
|
|
716
|
-
* @example
|
|
717
|
-
* ```ts
|
|
718
|
-
* await query(db, TodoActivity)
|
|
719
|
-
* .includeVariant('assigned', 'assignee', q => q.projected('summary'));
|
|
720
|
-
* ```
|
|
721
|
-
*/
|
|
722
|
-
includeVariant(variantKey: string, relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): this;
|
|
723
|
-
/**
|
|
724
|
-
* Apply a named scope defined on the schema via `.scope(name, fn)`.
|
|
725
|
-
*
|
|
726
|
-
* The `name` parameter is constrained to the literal scope names registered
|
|
727
|
-
* on the schema, so IDEs show only valid completions and typos are caught
|
|
728
|
-
* at compile time.
|
|
729
|
-
*
|
|
730
|
-
* @param name - The scope name.
|
|
731
|
-
* @returns `this` for chaining.
|
|
732
|
-
*
|
|
733
|
-
* @example
|
|
734
|
-
* ```ts
|
|
735
|
-
* await query(db, Post).scoped('published').scoped('recent');
|
|
736
|
-
* ```
|
|
737
|
-
*/
|
|
738
|
-
/**
|
|
739
|
-
* Apply a **named projection** defined on the schema via
|
|
740
|
-
* `.projection(name, columns)`.
|
|
741
|
-
*
|
|
742
|
-
* Calling `.projected()` on the query builder does two things:
|
|
743
|
-
* 1. Restricts the SQL `SELECT` clause to the columns registered under
|
|
744
|
-
* `name` (SQL column names are resolved via `.hasColumnName()`).
|
|
745
|
-
* 2. Narrows the TypeScript result row type to `Pick<Row, Keys>` so
|
|
746
|
-
* accessing columns outside the projection is a compile-time error.
|
|
747
|
-
*
|
|
748
|
-
* The `name` parameter is constrained to the literal projection names
|
|
749
|
-
* registered on the schema — TypeScript will report an error for any
|
|
750
|
-
* unregistered name.
|
|
751
|
-
*
|
|
752
|
-
* Calling `.projected()` after `.select()`, any aggregate method
|
|
753
|
-
* (`.count()`, `.min()`, etc.), or a second `.projected()` call throws
|
|
754
|
-
* at runtime with a clear error message.
|
|
755
|
-
*
|
|
756
|
-
* @param name - The projection name.
|
|
757
|
-
* @returns A new builder whose result type is `Pick<Row, ProjectionKeys>`.
|
|
758
|
-
*
|
|
759
|
-
* @example
|
|
760
|
-
* ```ts
|
|
761
|
-
* const PostSchema = object({ id: number(), title: string(), body: string() })
|
|
762
|
-
* .hasTableName('posts')
|
|
763
|
-
* .projection('summary', 'id', 'title');
|
|
764
|
-
*
|
|
765
|
-
* const rows = await query(db, PostSchema)
|
|
766
|
-
* .scoped('published')
|
|
767
|
-
* .projected('summary');
|
|
768
|
-
* // rows: Array<Pick<Post, 'id' | 'title'>>
|
|
769
|
-
* // rows[0].body // ← TS error: not in projection
|
|
770
|
-
* ```
|
|
771
|
-
*
|
|
772
|
-
* @see {@link ddlExtension} `.projection()` for schema-side definition.
|
|
773
|
-
*/
|
|
774
|
-
projected<K extends keyof ProjectionsOf<TLocalSchema> & string>(name: K): SchemaQueryBuilder<TLocalSchema, Pick<TResult, ProjectionKeysOf<TLocalSchema, K> & keyof TResult>>;
|
|
775
|
-
scoped<K extends ScopesOf<TLocalSchema>>(name: K): this;
|
|
776
|
-
/**
|
|
777
|
-
* Bypass the default scope (and soft-delete scope) for this query.
|
|
778
|
-
*
|
|
779
|
-
* @returns `this` for chaining.
|
|
780
|
-
*
|
|
781
|
-
* @example
|
|
782
|
-
* ```ts
|
|
783
|
-
* await query(db, Post).unscoped().where(t => t.id, 1);
|
|
784
|
-
* ```
|
|
785
|
-
*/
|
|
786
|
-
unscoped(): this;
|
|
787
|
-
/**
|
|
788
|
-
* Add a WHERE condition that applies **only to rows matching a specific
|
|
789
|
-
* variant** of a polymorphic schema. Rows for other variants pass through
|
|
790
|
-
* unaffected (the condition is ORed away for non-matching discriminator values).
|
|
791
|
-
*
|
|
792
|
-
* The column name is resolved against the **variant's** schema properties.
|
|
793
|
-
*
|
|
794
|
-
* Only valid on a polymorphic schema (created via `.withVariants()`).
|
|
795
|
-
*
|
|
796
|
-
* @param key - The discriminator value identifying the variant (e.g. `'image'`).
|
|
797
|
-
* @param column - Property key on the variant's schema (e.g. `'width'`).
|
|
798
|
-
* @param operator - SQL comparison operator (`'='`, `'>'`, `'<'`, `'like'`, etc.).
|
|
799
|
-
* @param value - The value to compare against.
|
|
800
|
-
* @returns `this` for chaining.
|
|
801
|
-
*
|
|
802
|
-
* @example
|
|
803
|
-
* ```ts
|
|
804
|
-
* // Return all documents and only images wider than 1024 px
|
|
805
|
-
* const files = await query(db, FileSchema)
|
|
806
|
-
* .whereVariant('image', 'width', '>', 1024);
|
|
807
|
-
* ```
|
|
808
|
-
*/
|
|
809
|
-
whereVariant(key: string, column: string, operator: string, value: any): this;
|
|
810
|
-
/**
|
|
811
|
-
* Restrict the query to only return rows for the specified variant keys.
|
|
812
|
-
*
|
|
813
|
-
* Adds `WHERE <discriminator> IN (...)` to the query and skips the LEFT
|
|
814
|
-
* JOINs for excluded variants. This is more efficient than filtering after
|
|
815
|
-
* loading all variants.
|
|
816
|
-
*
|
|
817
|
-
* Only valid on a polymorphic schema (created via `.withVariants()`).
|
|
818
|
-
*
|
|
819
|
-
* @param keys - Discriminator values to include (e.g. `['image', 'document']`).
|
|
820
|
-
* @returns `this` for chaining.
|
|
821
|
-
*
|
|
822
|
-
* @example
|
|
823
|
-
* ```ts
|
|
824
|
-
* const images = await query(db, FileSchema).selectVariants(['image']);
|
|
825
|
-
* // images: Array<{ id; name; type: 'image'; width; height; format }>
|
|
826
|
-
* ```
|
|
827
|
-
*/
|
|
828
|
-
selectVariants(keys: string[]): this;
|
|
829
|
-
/**
|
|
830
|
-
* Include soft-deleted rows in the results.
|
|
831
|
-
*
|
|
832
|
-
* By default, schemas with `.softDelete()` automatically filter out
|
|
833
|
-
* rows where `deleted_at IS NOT NULL`. Call `.withDeleted()` to
|
|
834
|
-
* include them.
|
|
835
|
-
*
|
|
836
|
-
* @returns `this` for chaining.
|
|
837
|
-
*/
|
|
108
|
+
delete(): Promise<number>;
|
|
838
109
|
withDeleted(): this;
|
|
839
|
-
/**
|
|
840
|
-
* Return only soft-deleted rows (`WHERE deleted_at IS NOT NULL`).
|
|
841
|
-
*
|
|
842
|
-
* @returns `this` for chaining.
|
|
843
|
-
*/
|
|
844
110
|
onlyDeleted(): this;
|
|
845
|
-
/**
|
|
846
|
-
* Permanently delete rows matching the current WHERE clause, bypassing
|
|
847
|
-
* the soft-delete mechanism.
|
|
848
|
-
*
|
|
849
|
-
* @returns The number of rows deleted.
|
|
850
|
-
*/
|
|
851
111
|
hardDelete(): Promise<number>;
|
|
852
|
-
/**
|
|
853
|
-
* Restore soft-deleted rows by setting `deleted_at = NULL`.
|
|
854
|
-
*
|
|
855
|
-
* @returns The restored rows.
|
|
856
|
-
*/
|
|
857
112
|
restore(): Promise<TResult[]>;
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
*
|
|
867
|
-
* @example
|
|
868
|
-
* ```ts
|
|
869
|
-
* const page = await query(db, Post)
|
|
870
|
-
* .where(t => t.status, 'published')
|
|
871
|
-
* .paginate({ page: 2, pageSize: 20 });
|
|
872
|
-
* // page.data, page.total, page.totalPages, page.hasNextPage, ...
|
|
873
|
-
* ```
|
|
874
|
-
*/
|
|
875
|
-
paginate(opts: {
|
|
876
|
-
page: number;
|
|
877
|
-
pageSize: number;
|
|
878
|
-
}): Promise<PaginationResult<TResult>>;
|
|
879
|
-
/**
|
|
880
|
-
* Execute a cursor-based (keyset) paginated query.
|
|
881
|
-
*
|
|
882
|
-
* More efficient than offset pagination for large datasets. Fetches one
|
|
883
|
-
* extra row to determine whether more data exists.
|
|
884
|
-
*
|
|
885
|
-
* @param opts - `{ cursor, limit, column?, direction? }`.
|
|
886
|
-
* @returns A {@link CursorPaginationResult} with data, next cursor, and
|
|
887
|
-
* `hasMore` flag.
|
|
888
|
-
*
|
|
889
|
-
* @example
|
|
890
|
-
* ```ts
|
|
891
|
-
* const page = await query(db, Post)
|
|
892
|
-
* .orderBy(t => t.createdAt, 'desc')
|
|
893
|
-
* .paginateAfter({ cursor: lastCreatedAt, limit: 20 });
|
|
894
|
-
* ```
|
|
895
|
-
*/
|
|
896
|
-
paginateAfter(opts: {
|
|
897
|
-
cursor?: any;
|
|
898
|
-
limit: number;
|
|
899
|
-
column?: ColumnRef<TLocalSchema>;
|
|
900
|
-
direction?: 'asc' | 'desc';
|
|
901
|
-
}): Promise<CursorPaginationResult<TResult>>;
|
|
902
|
-
/**
|
|
903
|
-
* Add a raw SQL expression to the SELECT clause.
|
|
904
|
-
*
|
|
905
|
-
* @param sql - Raw SQL (e.g. `'*, ts_rank(vector, query) AS rank'`).
|
|
906
|
-
* @param bindings - Optional parameter bindings.
|
|
907
|
-
* @returns `this` for chaining.
|
|
908
|
-
*/
|
|
909
|
-
selectRaw(sql: string, bindings?: any[]): this;
|
|
910
|
-
/**
|
|
911
|
-
* Return the raw SQL string that would be executed, for debugging.
|
|
912
|
-
* Does not execute the query against the database.
|
|
913
|
-
*/
|
|
113
|
+
joinOne<TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TFieldName extends string, TRequired extends boolean = true>(spec: JoinOneSpec<TLocalSchema, TForeignSchema, TFieldName, TRequired>): SchemaQueryBuilder<TLocalSchema, import('./types.js').WithJoinedOne<TResult, TFieldName, TForeignSchema, TRequired>>;
|
|
114
|
+
joinMany<TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TFieldName extends string>(spec: JoinManySpec<TLocalSchema, TForeignSchema, TFieldName>): SchemaQueryBuilder<TLocalSchema, import('./types.js').WithJoinedMany<TResult, TFieldName, TForeignSchema>>;
|
|
115
|
+
include(relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): this;
|
|
116
|
+
includeVariant(variantKey: string, relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): this;
|
|
117
|
+
whereVariant(key: string, column: string, operator: string, value: any): this;
|
|
118
|
+
selectVariants(keys: string[]): this;
|
|
119
|
+
apply(fn: (builder: Knex.QueryBuilder) => void): this;
|
|
120
|
+
transacting(trx: Knex.Transaction): SchemaQueryBuilder<TLocalSchema, TResult>;
|
|
914
121
|
toQuery(): string;
|
|
915
|
-
/**
|
|
916
|
-
* Returns the underlying Knex query builder. Useful when passing this
|
|
917
|
-
* query as a `foreignQuery` in `.joinOne()` / `.joinMany()`, or any context
|
|
918
|
-
* that expects a raw `Knex.QueryBuilder`.
|
|
919
|
-
*/
|
|
920
122
|
toKnexQuery(): Knex.QueryBuilder;
|
|
921
|
-
/**
|
|
922
|
-
* Alias for {@link toQuery} — returns the raw SQL string.
|
|
923
|
-
*/
|
|
924
123
|
toString(): string;
|
|
925
|
-
/**
|
|
926
|
-
* Execute the query and return all matching rows, mapped back to schema
|
|
927
|
-
* property names.
|
|
928
|
-
*
|
|
929
|
-
* @returns A promise that resolves to an array of result objects typed as
|
|
930
|
-
* `TResult[]`.
|
|
931
|
-
*
|
|
932
|
-
* @example
|
|
933
|
-
* ```ts
|
|
934
|
-
* const users = await query(db, UserSchema).execute();
|
|
935
|
-
* ```
|
|
936
|
-
*/
|
|
937
124
|
execute(): Promise<TResult[]>;
|
|
938
|
-
/**
|
|
939
|
-
* Execute the query and return only the first row, or `undefined` if no
|
|
940
|
-
* rows match.
|
|
941
|
-
*
|
|
942
|
-
* @example
|
|
943
|
-
* ```ts
|
|
944
|
-
* const user = await query(db, UserSchema).where(t => t.id, id).first();
|
|
945
|
-
* if (user) { /* ... *\/ }
|
|
946
|
-
* ```
|
|
947
|
-
*/
|
|
948
125
|
first(): Promise<TResult | undefined>;
|
|
949
|
-
/**
|
|
950
|
-
* Execute the query and return an array of values for a single column.
|
|
951
|
-
*
|
|
952
|
-
* @param column - Column reference (property accessor or string key) for
|
|
953
|
-
* the column whose values should be returned.
|
|
954
|
-
* @returns A promise resolving to an array of values for that column.
|
|
955
|
-
*
|
|
956
|
-
* @example
|
|
957
|
-
* ```ts
|
|
958
|
-
* const names = await query(db, UserSchema).pluck(t => t.name);
|
|
959
|
-
* // names: string[]
|
|
960
|
-
* ```
|
|
961
|
-
*/
|
|
962
126
|
pluck<K extends keyof TResult & string>(column: ColumnRef<TLocalSchema>): Promise<TResult[K][]>;
|
|
963
|
-
/**
|
|
964
|
-
* Thenable implementation — allows the builder to be awaited directly
|
|
965
|
-
* without calling {@link execute} explicitly.
|
|
966
|
-
*
|
|
967
|
-
* @example
|
|
968
|
-
* ```ts
|
|
969
|
-
* const users = await query(db, UserSchema).where(t => t.name, 'Alice');
|
|
970
|
-
* // Equivalent to: await query(db, UserSchema).where(...).execute()
|
|
971
|
-
* ```
|
|
972
|
-
*/
|
|
973
127
|
then<TReturn1 = TResult[], TReturn2 = never>(onfulfilled?: ((value: TResult[]) => TReturn1 | PromiseLike<TReturn1>) | null, onrejected?: ((reason: any) => TReturn2 | PromiseLike<TReturn2>) | null): Promise<TReturn1 | TReturn2>;
|
|
974
128
|
}
|
|
975
|
-
/**
|
|
976
|
-
* Create a typed {@link SchemaQueryBuilder} for the table described by `schema`.
|
|
977
|
-
*
|
|
978
|
-
* The schema must have a table name configured via `.hasTableName()`.
|
|
979
|
-
* Column name mappings set via `.hasColumnName()` are applied automatically
|
|
980
|
-
* to all query methods. The returned builder is thenable — you can `await` it
|
|
981
|
-
* directly to execute the query and get `TResult[]`.
|
|
982
|
-
*
|
|
983
|
-
* @param knex - A configured Knex instance.
|
|
984
|
-
* @param schema - The `ObjectSchemaBuilder` describing the table.
|
|
985
|
-
* @returns A new {@link SchemaQueryBuilder} ready for chaining.
|
|
986
|
-
*
|
|
987
|
-
* @example
|
|
988
|
-
* ```ts
|
|
989
|
-
* import knex from 'knex';
|
|
990
|
-
* import { query, object, string, number } from '@cleverbrush/knex-schema';
|
|
991
|
-
*
|
|
992
|
-
* const UserSchema = object({ id: number(), name: string() }).hasTableName('users');
|
|
993
|
-
* const db = knex({ client: 'pg', connection: process.env.DB_URL });
|
|
994
|
-
*
|
|
995
|
-
* const users = await query(db, UserSchema).where(t => t.name, 'like', 'A%');
|
|
996
|
-
* ```
|
|
997
|
-
*/
|
|
998
129
|
export declare function query<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(knex: Knex, schema: TLocalSchema): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
|
|
999
|
-
/**
|
|
1000
|
-
* Create a typed {@link SchemaQueryBuilder} from an existing Knex query builder.
|
|
1001
|
-
*
|
|
1002
|
-
* Use this overload when you need to supply a pre-configured base query —
|
|
1003
|
-
* for example one that already has a sub-query, CTE, or a schema scope applied.
|
|
1004
|
-
*
|
|
1005
|
-
* @param knex - A configured Knex instance.
|
|
1006
|
-
* @param schema - The `ObjectSchemaBuilder` describing the table.
|
|
1007
|
-
* @param baseQuery - An existing `Knex.QueryBuilder` to use as the base.
|
|
1008
|
-
* @returns A new {@link SchemaQueryBuilder} wrapping `baseQuery`.
|
|
1009
|
-
*
|
|
1010
|
-
* @example
|
|
1011
|
-
* ```ts
|
|
1012
|
-
* // Use a scoped base query (e.g. soft-delete filter applied globally)
|
|
1013
|
-
* const base = db('users').where('deleted_at', null);
|
|
1014
|
-
* const activeUsers = await query(db, UserSchema, base).where(t => t.age, '>', 18);
|
|
1015
|
-
* ```
|
|
1016
|
-
*/
|
|
1017
130
|
export declare function query<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(knex: Knex, schema: TLocalSchema, baseQuery: Knex.QueryBuilder): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
|
|
1018
|
-
/** Bound query function returned by {@link createQuery}. */
|
|
1019
131
|
export interface BoundQuery {
|
|
1020
132
|
<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(schema: TLocalSchema): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
|
|
1021
133
|
<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(schema: TLocalSchema, baseQuery: Knex.QueryBuilder): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
|
|
1022
|
-
/**
|
|
1023
|
-
* Return a version of this bound factory whose queries all run within the
|
|
1024
|
-
* given Knex transaction. Equivalent to calling `.transacting(trx)` on
|
|
1025
|
-
* each individual builder, but more convenient when every query in a block
|
|
1026
|
-
* must share the same transaction.
|
|
1027
|
-
*
|
|
1028
|
-
* @example
|
|
1029
|
-
* ```ts
|
|
1030
|
-
* const db = createQuery(knex);
|
|
1031
|
-
*
|
|
1032
|
-
* await knex.transaction(async trx => {
|
|
1033
|
-
* const dbTrx = db.withTransaction(trx);
|
|
1034
|
-
* const user = await dbTrx(UserSchema).insert({ name: 'Alice' });
|
|
1035
|
-
* await dbTrx(PostSchema).insert({ authorId: user.id, title: 'Hello' });
|
|
1036
|
-
* });
|
|
1037
|
-
* ```
|
|
1038
|
-
*/
|
|
1039
134
|
withTransaction(trx: Knex.Transaction): BoundQuery;
|
|
1040
|
-
/**
|
|
1041
|
-
* Start a Knex transaction and run `callback` inside it, passing a
|
|
1042
|
-
* transaction-bound `BoundQuery` factory as the argument. The transaction
|
|
1043
|
-
* is committed when the callback resolves and rolled back if it rejects.
|
|
1044
|
-
*
|
|
1045
|
-
* This is the callback-style counterpart to {@link withTransaction} — you
|
|
1046
|
-
* don't need to obtain a `Knex.Transaction` object yourself.
|
|
1047
|
-
*
|
|
1048
|
-
* @param callback - An async function that receives a transaction-bound
|
|
1049
|
-
* `BoundQuery` and returns a value. The returned value is forwarded as
|
|
1050
|
-
* the resolved value of the outer `Promise`.
|
|
1051
|
-
* @returns A `Promise` that resolves with the value returned by `callback`.
|
|
1052
|
-
*
|
|
1053
|
-
* @example
|
|
1054
|
-
* ```ts
|
|
1055
|
-
* const db = createQuery(knex);
|
|
1056
|
-
*
|
|
1057
|
-
* const user = await db.transaction(async dbTrx => {
|
|
1058
|
-
* const newUser = await dbTrx(UserSchema).insert({ name: 'Alice' });
|
|
1059
|
-
* await dbTrx(PostSchema).insert({ authorId: newUser.id, title: 'Hello' });
|
|
1060
|
-
* return newUser;
|
|
1061
|
-
* });
|
|
1062
|
-
* ```
|
|
1063
|
-
*/
|
|
1064
135
|
transaction<T>(callback: (db: BoundQuery) => Promise<T>): Promise<T>;
|
|
1065
136
|
}
|
|
1066
|
-
/**
|
|
1067
|
-
* Bind a Knex instance once and get back a `query(schema)` function that
|
|
1068
|
-
* doesn't require repeating the knex argument on every call.
|
|
1069
|
-
*
|
|
1070
|
-
* @param knex - A configured Knex instance.
|
|
1071
|
-
* @returns A bound query factory: `(schema, baseQuery?) => SchemaQueryBuilder`.
|
|
1072
|
-
*
|
|
1073
|
-
* @example
|
|
1074
|
-
* ```ts
|
|
1075
|
-
* import Knex from 'knex';
|
|
1076
|
-
* import { createQuery } from '@cleverbrush/knex-schema';
|
|
1077
|
-
*
|
|
1078
|
-
* const knex = Knex({ client: 'pg', connection: process.env.DB_URL });
|
|
1079
|
-
* const query = createQuery(knex);
|
|
1080
|
-
*
|
|
1081
|
-
* // No knex argument needed from here on
|
|
1082
|
-
* const users = await query(UserSchema).where(t => t.role, '=', 'admin');
|
|
1083
|
-
* const post = await query(PostSchema).where(t => t.id, '=', 42).first();
|
|
1084
|
-
*
|
|
1085
|
-
* // Optional base query (e.g. soft-delete scope applied globally)
|
|
1086
|
-
* const active = query(UserSchema, knex('users').where('deleted_at', null));
|
|
1087
|
-
* ```
|
|
1088
|
-
*/
|
|
1089
137
|
export declare function createQuery(knexInstance: Knex): BoundQuery;
|
|
1090
|
-
export {};
|