workers-qb 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -45
- package/dist/index.d.mts +596 -8
- package/dist/index.d.ts +596 -8
- package/dist/index.js +1074 -105
- package/dist/index.mjs +1067 -105
- package/docs/advanced-queries.md +526 -0
- package/package.json +7 -5
package/dist/index.d.mts
CHANGED
|
@@ -16,7 +16,18 @@ declare enum ConflictTypes {
|
|
|
16
16
|
declare enum JoinTypes {
|
|
17
17
|
INNER = "INNER",
|
|
18
18
|
LEFT = "LEFT",
|
|
19
|
-
CROSS = "CROSS"
|
|
19
|
+
CROSS = "CROSS",
|
|
20
|
+
RIGHT = "RIGHT",
|
|
21
|
+
FULL = "FULL",
|
|
22
|
+
NATURAL = "NATURAL"
|
|
23
|
+
}
|
|
24
|
+
declare enum SetOperationType {
|
|
25
|
+
UNION = "UNION",
|
|
26
|
+
UNION_ALL = "UNION ALL",
|
|
27
|
+
INTERSECT = "INTERSECT",
|
|
28
|
+
INTERSECT_ALL = "INTERSECT ALL",
|
|
29
|
+
EXCEPT = "EXCEPT",
|
|
30
|
+
EXCEPT_ALL = "EXCEPT ALL"
|
|
20
31
|
}
|
|
21
32
|
|
|
22
33
|
/**
|
|
@@ -88,8 +99,8 @@ type SchemaAware<S extends TableSchema, Strict, Loose> = IsEmptySchema<S> extend
|
|
|
88
99
|
|
|
89
100
|
declare class Raw {
|
|
90
101
|
isRaw: boolean;
|
|
91
|
-
content:
|
|
92
|
-
constructor(content:
|
|
102
|
+
content: string;
|
|
103
|
+
constructor(content: string);
|
|
93
104
|
}
|
|
94
105
|
declare class Query<Result = any, IsAsync extends boolean = true> {
|
|
95
106
|
executeMethod: (query: Query<Result, IsAsync>) => MaybeAsync<IsAsync, Result>;
|
|
@@ -99,6 +110,28 @@ declare class Query<Result = any, IsAsync extends boolean = true> {
|
|
|
99
110
|
constructor(executeMethod: (query: Query<Result, IsAsync>) => MaybeAsync<IsAsync, Result>, query: string, args?: Primitive[], fetchType?: FetchTypes);
|
|
100
111
|
execute(): MaybeAsync<IsAsync, Result>;
|
|
101
112
|
toObject(): RawQuery;
|
|
113
|
+
/**
|
|
114
|
+
* Returns the SQL query string and parameters without executing.
|
|
115
|
+
* Useful for debugging and logging.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* const { sql, params } = qb.select('users').where('id = ?', 1).getQueryAll().toSQL()
|
|
119
|
+
* // sql: "SELECT * FROM users WHERE id = ?"
|
|
120
|
+
* // params: [1]
|
|
121
|
+
*/
|
|
122
|
+
toSQL(): {
|
|
123
|
+
sql: string;
|
|
124
|
+
params: Primitive[];
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Returns the SQL query with parameters interpolated for debugging purposes.
|
|
128
|
+
* WARNING: This should NEVER be used to execute queries as it bypasses parameterization.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* const debugSql = qb.select('users').where('id = ?', 1).getQueryAll().toDebugSQL()
|
|
132
|
+
* // "SELECT * FROM users WHERE id = 1"
|
|
133
|
+
*/
|
|
134
|
+
toDebugSQL(): string;
|
|
102
135
|
}
|
|
103
136
|
declare class QueryWithExtra<GenericResultWrapper, Result = any, IsAsync extends boolean = true> extends Query<Result, IsAsync> {
|
|
104
137
|
private countQuery;
|
|
@@ -107,6 +140,10 @@ declare class QueryWithExtra<GenericResultWrapper, Result = any, IsAsync extends
|
|
|
107
140
|
}
|
|
108
141
|
declare function trimQuery(query: string): string;
|
|
109
142
|
|
|
143
|
+
interface PaginateOptions {
|
|
144
|
+
page: number;
|
|
145
|
+
perPage: number;
|
|
146
|
+
}
|
|
110
147
|
interface SelectExecuteOptions {
|
|
111
148
|
lazy?: boolean;
|
|
112
149
|
}
|
|
@@ -119,9 +156,330 @@ declare class SelectBuilder<Schema extends TableSchema = {}, GenericResultWrappe
|
|
|
119
156
|
setDebugger(state: boolean): void;
|
|
120
157
|
tableName(tableName: SelectAll['tableName']): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
121
158
|
fields(fields: SelectAll['fields']): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
159
|
+
/**
|
|
160
|
+
* Enable DISTINCT selection to remove duplicate rows from results.
|
|
161
|
+
*
|
|
162
|
+
* @param columns - Optional array of columns for DISTINCT ON (PostgreSQL only).
|
|
163
|
+
* If not provided, applies simple DISTINCT.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* // Simple DISTINCT
|
|
167
|
+
* qb.select('users').distinct().execute()
|
|
168
|
+
* // SELECT DISTINCT * FROM users
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* // DISTINCT ON specific columns (PostgreSQL)
|
|
172
|
+
* qb.select('users').distinct(['department']).fields(['department', 'name']).execute()
|
|
173
|
+
* // SELECT DISTINCT ON (department) department, name FROM users
|
|
174
|
+
*/
|
|
175
|
+
distinct(columns?: Array<string>): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
122
176
|
where(conditions: string | Array<string>, params?: Primitive | Primitive[]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
177
|
+
/**
|
|
178
|
+
* Add an OR WHERE condition to the query.
|
|
179
|
+
* All previously added WHERE conditions are grouped together and ORed with the new condition.
|
|
180
|
+
* Subsequent `.where()` calls after `.orWhere()` are ANDed as independent conditions.
|
|
181
|
+
*
|
|
182
|
+
* @param conditions - The SQL condition string(s) (can use ? placeholders)
|
|
183
|
+
* @param params - The parameter(s) to bind to the ? placeholders
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* // Simple OR condition
|
|
187
|
+
* qb.select('users').where('status = ?', 'active').orWhere('status = ?', 'pending').execute()
|
|
188
|
+
* // SELECT * FROM users WHERE (status = ?) OR (status = ?)
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* // Multiple where conditions ORed together
|
|
192
|
+
* qb.select('users')
|
|
193
|
+
* .where('tenant_id = ?', 1)
|
|
194
|
+
* .where('status = ?', 'active')
|
|
195
|
+
* .orWhere('role = ?', 'superadmin')
|
|
196
|
+
* .execute()
|
|
197
|
+
* // SELECT * FROM users WHERE ((tenant_id = ?) AND (status = ?)) OR (role = ?)
|
|
198
|
+
*/
|
|
199
|
+
orWhere(conditions: string | Array<string>, params?: Primitive | Primitive[]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
123
200
|
whereIn<T extends string | Array<string>, P extends T extends Array<string> ? Primitive[][] : Primitive[]>(fields: T, values: P): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
201
|
+
/**
|
|
202
|
+
* Conditionally apply query modifications based on a runtime value.
|
|
203
|
+
* If condition is truthy, the callback is invoked with the current builder
|
|
204
|
+
* and its return value is used. If condition is falsy and an otherwise callback
|
|
205
|
+
* is provided, it is invoked instead. Otherwise, the builder is returned unchanged.
|
|
206
|
+
*
|
|
207
|
+
* @param condition - A value to check for truthiness
|
|
208
|
+
* @param callback - Function that receives the builder and returns a modified builder
|
|
209
|
+
* @param otherwise - Optional function applied when condition is falsy
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* qb.select('users')
|
|
213
|
+
* .when(nameFilter, q => q.where('name LIKE ?', [`%${nameFilter}%`]))
|
|
214
|
+
* .when(sortByDate, q => q.orderBy({ created_at: 'DESC' }))
|
|
215
|
+
* .execute()
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* // With otherwise callback
|
|
219
|
+
* qb.select('products')
|
|
220
|
+
* .when(
|
|
221
|
+
* inStock,
|
|
222
|
+
* q => q.where('stock > ?', 0),
|
|
223
|
+
* q => q.where('stock = ?', 0)
|
|
224
|
+
* )
|
|
225
|
+
* .execute()
|
|
226
|
+
*/
|
|
227
|
+
when<T>(condition: T | undefined | null | false | 0 | '', callback: (builder: SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>) => SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>, otherwise?: (builder: SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>) => SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
228
|
+
/**
|
|
229
|
+
* Add a WHERE column IS NULL condition.
|
|
230
|
+
*
|
|
231
|
+
* @param column - The column name to check for NULL
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* qb.select('users').whereNull('deleted_at').execute()
|
|
235
|
+
* // SELECT * FROM users WHERE deleted_at IS NULL
|
|
236
|
+
*/
|
|
237
|
+
whereNull(column: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
238
|
+
/**
|
|
239
|
+
* Add a WHERE column IS NOT NULL condition.
|
|
240
|
+
*
|
|
241
|
+
* @param column - The column name to check for NOT NULL
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* qb.select('users').whereNotNull('email_verified_at').execute()
|
|
245
|
+
* // SELECT * FROM users WHERE email_verified_at IS NOT NULL
|
|
246
|
+
*/
|
|
247
|
+
whereNotNull(column: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
248
|
+
/**
|
|
249
|
+
* Add a WHERE column BETWEEN min AND max condition.
|
|
250
|
+
*
|
|
251
|
+
* @param column - The column name
|
|
252
|
+
* @param range - Tuple of [min, max] values
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* qb.select('products').whereBetween('price', [10, 100]).execute()
|
|
256
|
+
* // SELECT * FROM products WHERE price BETWEEN ? AND ?
|
|
257
|
+
*/
|
|
258
|
+
whereBetween(column: string, range: [Primitive, Primitive]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
259
|
+
/**
|
|
260
|
+
* Add a WHERE column NOT BETWEEN min AND max condition.
|
|
261
|
+
*
|
|
262
|
+
* @param column - The column name
|
|
263
|
+
* @param range - Tuple of [min, max] values
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* qb.select('products').whereNotBetween('price', [10, 100]).execute()
|
|
267
|
+
* // SELECT * FROM products WHERE price NOT BETWEEN ? AND ?
|
|
268
|
+
*/
|
|
269
|
+
whereNotBetween(column: string, range: [Primitive, Primitive]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
270
|
+
/**
|
|
271
|
+
* Add an OR WHERE column IS NULL condition.
|
|
272
|
+
*
|
|
273
|
+
* @param column - The column name to check for NULL
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* qb.select('users').where('active = ?', true).orWhereNull('deleted_at').execute()
|
|
277
|
+
* // SELECT * FROM users WHERE (active = ?) OR (deleted_at IS NULL)
|
|
278
|
+
*/
|
|
279
|
+
orWhereNull(column: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
280
|
+
/**
|
|
281
|
+
* Add an OR WHERE column IS NOT NULL condition.
|
|
282
|
+
*
|
|
283
|
+
* @param column - The column name to check for NOT NULL
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* qb.select('users').whereNull('deleted_at').orWhereNotNull('verified_at').execute()
|
|
287
|
+
* // SELECT * FROM users WHERE (deleted_at IS NULL) OR (verified_at IS NOT NULL)
|
|
288
|
+
*/
|
|
289
|
+
orWhereNotNull(column: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
290
|
+
/**
|
|
291
|
+
* Add an OR WHERE column BETWEEN min AND max condition.
|
|
292
|
+
*
|
|
293
|
+
* @param column - The column name
|
|
294
|
+
* @param range - Tuple of [min, max] values
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* qb.select('products').where('active = ?', true).orWhereBetween('price', [10, 100]).execute()
|
|
298
|
+
* // SELECT * FROM products WHERE (active = ?) OR (price BETWEEN ? AND ?)
|
|
299
|
+
*/
|
|
300
|
+
orWhereBetween(column: string, range: [Primitive, Primitive]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
301
|
+
/**
|
|
302
|
+
* Add an OR WHERE column NOT BETWEEN min AND max condition.
|
|
303
|
+
*
|
|
304
|
+
* @param column - The column name
|
|
305
|
+
* @param range - Tuple of [min, max] values
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* qb.select('products').where('featured = ?', true).orWhereNotBetween('price', [10, 100]).execute()
|
|
309
|
+
* // SELECT * FROM products WHERE (featured = ?) OR (price NOT BETWEEN ? AND ?)
|
|
310
|
+
*/
|
|
311
|
+
orWhereNotBetween(column: string, range: [Primitive, Primitive]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
312
|
+
/**
|
|
313
|
+
* Add a WHERE column LIKE pattern condition.
|
|
314
|
+
*
|
|
315
|
+
* @param column - The column name
|
|
316
|
+
* @param pattern - The LIKE pattern (e.g., '%search%')
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* qb.select('users').whereLike('name', '%john%').execute()
|
|
320
|
+
* // SELECT * FROM users WHERE name LIKE ?
|
|
321
|
+
*/
|
|
322
|
+
whereLike(column: string, pattern: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
323
|
+
/**
|
|
324
|
+
* Add a WHERE column NOT LIKE pattern condition.
|
|
325
|
+
*
|
|
326
|
+
* @param column - The column name
|
|
327
|
+
* @param pattern - The LIKE pattern
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* qb.select('users').whereNotLike('email', '%@spam.com').execute()
|
|
331
|
+
* // SELECT * FROM users WHERE email NOT LIKE ?
|
|
332
|
+
*/
|
|
333
|
+
whereNotLike(column: string, pattern: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
334
|
+
/**
|
|
335
|
+
* Add an OR WHERE column LIKE pattern condition.
|
|
336
|
+
*
|
|
337
|
+
* @param column - The column name
|
|
338
|
+
* @param pattern - The LIKE pattern (e.g., '%search%')
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* qb.select('users').whereLike('name', '%john%').orWhereLike('email', '%john%').execute()
|
|
342
|
+
* // SELECT * FROM users WHERE (name LIKE ?) OR (email LIKE ?)
|
|
343
|
+
*/
|
|
344
|
+
orWhereLike(column: string, pattern: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
345
|
+
/**
|
|
346
|
+
* Add an OR WHERE column NOT LIKE pattern condition.
|
|
347
|
+
*
|
|
348
|
+
* @param column - The column name
|
|
349
|
+
* @param pattern - The LIKE pattern
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* qb.select('users').where('active = ?', true).orWhereNotLike('email', '%@spam.com').execute()
|
|
353
|
+
* // SELECT * FROM users WHERE (active = ?) OR (email NOT LIKE ?)
|
|
354
|
+
*/
|
|
355
|
+
orWhereNotLike(column: string, pattern: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
356
|
+
/**
|
|
357
|
+
* Add a WHERE column NOT IN (values) condition.
|
|
358
|
+
*
|
|
359
|
+
* @param fields - Column name(s) to check
|
|
360
|
+
* @param values - Values to exclude
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* qb.select('users').whereNotIn('status', ['banned', 'suspended']).execute()
|
|
364
|
+
* // SELECT * FROM users WHERE (status) NOT IN (VALUES (?), (?))
|
|
365
|
+
*/
|
|
366
|
+
whereNotIn<T extends string | Array<string>, P extends T extends Array<string> ? Primitive[][] : Primitive[]>(fields: T, values: P): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
124
367
|
join(join: SelectAll['join']): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
368
|
+
/**
|
|
369
|
+
* Add an INNER JOIN to the query.
|
|
370
|
+
*/
|
|
371
|
+
innerJoin(params: {
|
|
372
|
+
table: string;
|
|
373
|
+
on: string;
|
|
374
|
+
alias?: string;
|
|
375
|
+
}): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
376
|
+
/**
|
|
377
|
+
* Add a LEFT JOIN to the query.
|
|
378
|
+
*/
|
|
379
|
+
leftJoin(params: {
|
|
380
|
+
table: string;
|
|
381
|
+
on: string;
|
|
382
|
+
alias?: string;
|
|
383
|
+
}): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
384
|
+
/**
|
|
385
|
+
* Add a RIGHT JOIN to the query.
|
|
386
|
+
*/
|
|
387
|
+
rightJoin(params: {
|
|
388
|
+
table: string;
|
|
389
|
+
on: string;
|
|
390
|
+
alias?: string;
|
|
391
|
+
}): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
392
|
+
/**
|
|
393
|
+
* Add a FULL OUTER JOIN to the query.
|
|
394
|
+
*/
|
|
395
|
+
fullJoin(params: {
|
|
396
|
+
table: string;
|
|
397
|
+
on: string;
|
|
398
|
+
alias?: string;
|
|
399
|
+
}): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
400
|
+
/**
|
|
401
|
+
* Add a CROSS JOIN to the query.
|
|
402
|
+
*/
|
|
403
|
+
crossJoin(params: {
|
|
404
|
+
table: string;
|
|
405
|
+
alias?: string;
|
|
406
|
+
}): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
407
|
+
/**
|
|
408
|
+
* Add a NATURAL JOIN to the query.
|
|
409
|
+
* Natural joins automatically match columns with the same name.
|
|
410
|
+
*/
|
|
411
|
+
naturalJoin(table: string): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
412
|
+
/**
|
|
413
|
+
* Define a Common Table Expression (CTE) using the WITH clause.
|
|
414
|
+
* CTEs allow you to define named temporary result sets that can be referenced
|
|
415
|
+
* in the main query, making complex queries more readable.
|
|
416
|
+
*
|
|
417
|
+
* @param name - The name of the CTE
|
|
418
|
+
* @param query - The query that defines the CTE
|
|
419
|
+
* @param columns - Optional column names for the CTE
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* // Simple CTE
|
|
423
|
+
* qb.select('orders')
|
|
424
|
+
* .with('active_users', qb.select('users').where('status = ?', 'active'))
|
|
425
|
+
* .join({ table: 'active_users', on: 'orders.user_id = active_users.id' })
|
|
426
|
+
* .execute()
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* // Multiple CTEs
|
|
430
|
+
* qb.select('combined')
|
|
431
|
+
* .with('cte1', qb.select('table1').where('x = ?', 1))
|
|
432
|
+
* .with('cte2', qb.select('table2').where('y = ?', 2))
|
|
433
|
+
* .execute()
|
|
434
|
+
*/
|
|
435
|
+
with(name: string, query: SelectBuilder<any, any, any, any> | SelectAll, columns?: string[]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
436
|
+
/**
|
|
437
|
+
* Combine results with another query using UNION (removes duplicates).
|
|
438
|
+
*
|
|
439
|
+
* @param query - The query to union with
|
|
440
|
+
* @param all - If true, uses UNION ALL to keep duplicates
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* qb.select('active_users').fields(['id', 'name'])
|
|
444
|
+
* .union(qb.select('archived_users').fields(['id', 'name']))
|
|
445
|
+
* .execute()
|
|
446
|
+
*/
|
|
447
|
+
union(query: SelectBuilder<any, any, any, any> | SelectAll, all?: boolean): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
448
|
+
/**
|
|
449
|
+
* Combine results with another query using UNION ALL (keeps duplicates).
|
|
450
|
+
*
|
|
451
|
+
* @param query - The query to union with
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* qb.select('table1').fields(['id'])
|
|
455
|
+
* .unionAll(qb.select('table2').fields(['id']))
|
|
456
|
+
* .execute()
|
|
457
|
+
*/
|
|
458
|
+
unionAll(query: SelectBuilder<any, any, any, any> | SelectAll): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
459
|
+
/**
|
|
460
|
+
* Return only rows present in both queries using INTERSECT.
|
|
461
|
+
*
|
|
462
|
+
* @param query - The query to intersect with
|
|
463
|
+
* @param all - If true, uses INTERSECT ALL
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* qb.select('users').fields(['id'])
|
|
467
|
+
* .intersect(qb.select('admins').fields(['user_id']))
|
|
468
|
+
* .execute()
|
|
469
|
+
*/
|
|
470
|
+
intersect(query: SelectBuilder<any, any, any, any> | SelectAll, all?: boolean): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
471
|
+
/**
|
|
472
|
+
* Return rows from the first query that are not in the second query using EXCEPT.
|
|
473
|
+
*
|
|
474
|
+
* @param query - The query to except
|
|
475
|
+
* @param all - If true, uses EXCEPT ALL
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* qb.select('all_users').fields(['id'])
|
|
479
|
+
* .except(qb.select('blocked_users').fields(['user_id']))
|
|
480
|
+
* .execute()
|
|
481
|
+
*/
|
|
482
|
+
except(query: SelectBuilder<any, any, any, any> | SelectAll, all?: boolean): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
125
483
|
groupBy(groupBy: SelectAll['groupBy']): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
126
484
|
having(conditions: string | Array<string>, params?: Primitive | Primitive[]): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
127
485
|
orderBy(orderBy: SelectAll['orderBy']): SelectBuilder<Schema, GenericResultWrapper, GenericResult, IsAsync>;
|
|
@@ -140,7 +498,69 @@ declare class SelectBuilder<Schema extends TableSchema = {}, GenericResultWrappe
|
|
|
140
498
|
} ? true : false>;
|
|
141
499
|
one(): MaybeAsync<IsAsync, OneResult<GenericResultWrapper, GenericResult>>;
|
|
142
500
|
count(): MaybeAsync<IsAsync, CountResult<GenericResultWrapper>>;
|
|
501
|
+
/**
|
|
502
|
+
* Execute the query with pagination, returning results along with pagination metadata.
|
|
503
|
+
*
|
|
504
|
+
* @param options - Pagination options
|
|
505
|
+
* @param options.page - The page number (1-indexed)
|
|
506
|
+
* @param options.perPage - Number of results per page
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* const result = await qb.select('users')
|
|
510
|
+
* .where('active = ?', true)
|
|
511
|
+
* .paginate({ page: 2, perPage: 20 })
|
|
512
|
+
*
|
|
513
|
+
* // Returns:
|
|
514
|
+
* // {
|
|
515
|
+
* // results: [...],
|
|
516
|
+
* // pagination: {
|
|
517
|
+
* // page: 2,
|
|
518
|
+
* // perPage: 20,
|
|
519
|
+
* // total: 150,
|
|
520
|
+
* // totalPages: 8,
|
|
521
|
+
* // hasNext: true,
|
|
522
|
+
* // hasPrev: true
|
|
523
|
+
* // }
|
|
524
|
+
* // }
|
|
525
|
+
*/
|
|
526
|
+
paginate(options: PaginateOptions): MaybeAsync<IsAsync, PaginatedResult<GenericResultWrapper, GenericResult>>;
|
|
143
527
|
getOptions(): SelectAll;
|
|
528
|
+
/**
|
|
529
|
+
* Returns the SQL query string and parameters without executing.
|
|
530
|
+
* Useful for debugging and logging.
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* const { sql, params } = qb.select('users').where('id = ?', 1).toSQL()
|
|
534
|
+
* // sql: "SELECT * FROM users WHERE id = ?"
|
|
535
|
+
* // params: [1]
|
|
536
|
+
*/
|
|
537
|
+
toSQL(): {
|
|
538
|
+
sql: string;
|
|
539
|
+
params: Primitive[];
|
|
540
|
+
};
|
|
541
|
+
/**
|
|
542
|
+
* Returns the SQL query with parameters interpolated for debugging purposes.
|
|
543
|
+
* WARNING: This should NEVER be used to execute queries as it bypasses parameterization.
|
|
544
|
+
*
|
|
545
|
+
* @example
|
|
546
|
+
* const debugSql = qb.select('users').where('id = ?', 1).toDebugSQL()
|
|
547
|
+
* // "SELECT * FROM users WHERE id = 1"
|
|
548
|
+
*/
|
|
549
|
+
toDebugSQL(): string;
|
|
550
|
+
/**
|
|
551
|
+
* Get the query plan for this query using EXPLAIN.
|
|
552
|
+
* Returns the query plan as an array of rows showing how the database will execute the query.
|
|
553
|
+
*
|
|
554
|
+
* @example
|
|
555
|
+
* const plan = await qb.select('users').where('id = ?', 1).explain()
|
|
556
|
+
* // Returns query plan rows
|
|
557
|
+
*/
|
|
558
|
+
explain(): MaybeAsync<IsAsync, ArrayResult<GenericResultWrapper, {
|
|
559
|
+
id: number;
|
|
560
|
+
parent: number;
|
|
561
|
+
notused: number;
|
|
562
|
+
detail: string;
|
|
563
|
+
}, IsAsync>>;
|
|
144
564
|
}
|
|
145
565
|
|
|
146
566
|
type OmitIndexSignature<ObjectType> = {
|
|
@@ -161,8 +581,22 @@ type Primitive = null | string | number | boolean | bigint | ArrayBuffer | Raw |
|
|
|
161
581
|
type QueryLoggerMeta = {
|
|
162
582
|
duration?: number;
|
|
163
583
|
};
|
|
584
|
+
/**
|
|
585
|
+
* Hook called before a query is executed.
|
|
586
|
+
* Can modify the query or cancel execution by throwing.
|
|
587
|
+
*/
|
|
588
|
+
type BeforeQueryHook<IsAsync extends boolean = true> = (query: RawQuery, type: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE' | 'RAW') => MaybeAsync<IsAsync, RawQuery | void>;
|
|
589
|
+
/**
|
|
590
|
+
* Hook called after a query is executed.
|
|
591
|
+
* Can modify the result or perform side effects.
|
|
592
|
+
*/
|
|
593
|
+
type AfterQueryHook<IsAsync extends boolean = true> = (result: any, query: RawQuery, duration: number) => MaybeAsync<IsAsync, any>;
|
|
164
594
|
type QueryBuilderOptions<IsAsync extends boolean = true> = {
|
|
165
595
|
logger?: (query: RawQuery, meta: QueryLoggerMeta) => MaybeAsync<IsAsync, void>;
|
|
596
|
+
/** Hook called before each query execution */
|
|
597
|
+
beforeQuery?: BeforeQueryHook<IsAsync>;
|
|
598
|
+
/** Hook called after each query execution */
|
|
599
|
+
afterQuery?: AfterQueryHook<IsAsync>;
|
|
166
600
|
};
|
|
167
601
|
type DefaultObject = Record<string, Primitive>;
|
|
168
602
|
type DefaultReturnObject = Record<string, null | string | number | boolean | bigint | ArrayBuffer>;
|
|
@@ -187,6 +621,8 @@ type SelectOne = {
|
|
|
187
621
|
offset?: number;
|
|
188
622
|
subQueryPlaceholders?: Record<string, SelectAll>;
|
|
189
623
|
subQueryTokenNextId?: number;
|
|
624
|
+
/** Enable DISTINCT selection. Can be true for simple DISTINCT or an array of columns for DISTINCT ON */
|
|
625
|
+
distinct?: boolean | Array<string>;
|
|
190
626
|
};
|
|
191
627
|
type RawQuery = {
|
|
192
628
|
query: string;
|
|
@@ -200,9 +636,22 @@ type RawQueryFetchAll = Omit<RawQuery, 'fetchType'> & {
|
|
|
200
636
|
fetchType: FetchTypes.ALL;
|
|
201
637
|
};
|
|
202
638
|
type RawQueryWithoutFetching = Omit<RawQuery, 'fetchType'>;
|
|
639
|
+
type SetOperation = {
|
|
640
|
+
type: SetOperationType | string;
|
|
641
|
+
query: SelectAll;
|
|
642
|
+
};
|
|
643
|
+
type CTEDefinition = {
|
|
644
|
+
name: string;
|
|
645
|
+
query: SelectAll;
|
|
646
|
+
columns?: string[];
|
|
647
|
+
};
|
|
203
648
|
type SelectAll = SelectOne & {
|
|
204
649
|
limit?: number;
|
|
205
650
|
lazy?: boolean;
|
|
651
|
+
/** Set operations (UNION, INTERSECT, EXCEPT) to combine with this query */
|
|
652
|
+
setOperations?: SetOperation[];
|
|
653
|
+
/** Common Table Expressions (CTEs) for WITH clause */
|
|
654
|
+
cteDefinitions?: CTEDefinition[];
|
|
206
655
|
};
|
|
207
656
|
type ConflictUpsert = {
|
|
208
657
|
column: string | Array<string>;
|
|
@@ -293,6 +742,18 @@ type OneResult<ResultWrapper, Result> = Merge<ResultWrapper, {
|
|
|
293
742
|
type CountResult<GenericResultWrapper> = OneResult<GenericResultWrapper, {
|
|
294
743
|
total: number;
|
|
295
744
|
}>;
|
|
745
|
+
type PaginationMeta = {
|
|
746
|
+
page: number;
|
|
747
|
+
perPage: number;
|
|
748
|
+
total: number;
|
|
749
|
+
totalPages: number;
|
|
750
|
+
hasNext: boolean;
|
|
751
|
+
hasPrev: boolean;
|
|
752
|
+
};
|
|
753
|
+
type PaginatedResult<ResultWrapper, Result> = Merge<ResultWrapper, {
|
|
754
|
+
results?: Array<Result>;
|
|
755
|
+
pagination: PaginationMeta;
|
|
756
|
+
}>;
|
|
296
757
|
type AsyncType<T> = Promise<T>;
|
|
297
758
|
type SyncType<T> = T;
|
|
298
759
|
type MaybeAsync<IsAsync extends boolean, T> = IsAsync extends true ? AsyncType<T> : SyncType<T>;
|
|
@@ -354,15 +815,45 @@ type TypedDelete<S extends TableSchema, T extends TableName<S>> = {
|
|
|
354
815
|
*/
|
|
355
816
|
type InferResult<S extends TableSchema, T extends TableName<S>, F> = F extends '*' ? S[T] : F extends ColumnName<S, T>[] ? Pick<S[T], F[number]> : F extends ColumnName<S, T> ? Pick<S[T], F> : S[T];
|
|
356
817
|
|
|
818
|
+
type LoggerFunction = (query: RawQuery, meta: QueryLoggerMeta) => void | Promise<void>;
|
|
357
819
|
declare function defaultLogger(query: RawQuery, meta: QueryLoggerMeta): any;
|
|
358
|
-
declare function asyncLoggerWrapper<Async extends boolean = true>(query: Query<any, Async> | Query<any, Async>[], loggerFunction:
|
|
359
|
-
declare function syncLoggerWrapper<Async extends boolean = false>(query: Query<any, Async> | Query<any, Async>[], loggerFunction:
|
|
820
|
+
declare function asyncLoggerWrapper<Async extends boolean = true>(query: Query<any, Async> | Query<any, Async>[], loggerFunction: LoggerFunction | undefined, innerFunction: () => any): Promise<any>;
|
|
821
|
+
declare function syncLoggerWrapper<Async extends boolean = false>(query: Query<any, Async> | Query<any, Async>[], loggerFunction: LoggerFunction | undefined, innerFunction: () => any): any;
|
|
360
822
|
|
|
361
823
|
declare class QueryBuilder<Schema extends TableSchema = {}, GenericResultWrapper = unknown, IsAsync extends boolean = true> {
|
|
362
824
|
protected options: QueryBuilderOptions<IsAsync>;
|
|
363
825
|
loggerWrapper: typeof asyncLoggerWrapper;
|
|
364
826
|
constructor(options?: QueryBuilderOptions<IsAsync>);
|
|
365
827
|
setDebugger(state: boolean): void;
|
|
828
|
+
/**
|
|
829
|
+
* Register a hook to be called before each query execution.
|
|
830
|
+
* The hook can modify the query or throw to cancel execution.
|
|
831
|
+
*
|
|
832
|
+
* @param hook - The hook function to call before query execution
|
|
833
|
+
*
|
|
834
|
+
* @example
|
|
835
|
+
* qb.beforeQuery((query, type) => {
|
|
836
|
+
* // Add tenant filter to all SELECT/UPDATE/DELETE queries
|
|
837
|
+
* if (type !== 'INSERT' && type !== 'RAW') {
|
|
838
|
+
* query.query = query.query.replace('WHERE', `WHERE tenant_id = ${tenantId} AND`)
|
|
839
|
+
* }
|
|
840
|
+
* return query
|
|
841
|
+
* })
|
|
842
|
+
*/
|
|
843
|
+
beforeQuery(hook: BeforeQueryHook<IsAsync>): this;
|
|
844
|
+
/**
|
|
845
|
+
* Register a hook to be called after each query execution.
|
|
846
|
+
* The hook receives the result and can modify it or perform side effects.
|
|
847
|
+
*
|
|
848
|
+
* @param hook - The hook function to call after query execution
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* qb.afterQuery((result, query, duration) => {
|
|
852
|
+
* metrics.record(query.query, duration)
|
|
853
|
+
* return result
|
|
854
|
+
* })
|
|
855
|
+
*/
|
|
856
|
+
afterQuery(hook: AfterQueryHook<IsAsync>): this;
|
|
366
857
|
execute(query: Query<any, IsAsync>): MaybeAsync<IsAsync, any>;
|
|
367
858
|
batchExecute(queryArray: Query<any, IsAsync>[]): MaybeAsync<IsAsync, any[]>;
|
|
368
859
|
lazyExecute(query: Query<any, IsAsync>): IsAsync extends true ? Promise<AsyncIterable<any>> : Iterable<any>;
|
|
@@ -404,6 +895,7 @@ declare class QueryBuilder<Schema extends TableSchema = {}, GenericResultWrapper
|
|
|
404
895
|
protected _update(params: Update): string;
|
|
405
896
|
protected _delete(params: Delete): string;
|
|
406
897
|
protected _select(params: SelectAll, queryArgs?: any[]): string;
|
|
898
|
+
protected _distinct(value?: boolean | Array<string>): string;
|
|
407
899
|
protected _fields(value?: string | Array<string>): string;
|
|
408
900
|
protected _where(value: Where | undefined, context?: {
|
|
409
901
|
subQueryPlaceholders?: Record<string, SelectAll>;
|
|
@@ -472,7 +964,24 @@ declare class D1QB<Schema extends TableSchema = {}> extends QueryBuilder<Schema,
|
|
|
472
964
|
constructor(db: D1Database, options?: QueryBuilderOptions);
|
|
473
965
|
migrations(options: MigrationOptions): asyncMigrationsBuilder<D1Result>;
|
|
474
966
|
execute(query: Query): Promise<any>;
|
|
967
|
+
private _getQueryType;
|
|
475
968
|
batchExecute(queryArray: Query[]): Promise<any>;
|
|
969
|
+
/**
|
|
970
|
+
* Execute multiple queries atomically as a transaction.
|
|
971
|
+
* D1 uses batching for transactions - all queries succeed or all fail together.
|
|
972
|
+
*
|
|
973
|
+
* @param callback - A function that receives a transaction builder and returns queries to execute
|
|
974
|
+
* @returns Array of results from all queries in the transaction
|
|
975
|
+
*
|
|
976
|
+
* @example
|
|
977
|
+
* const results = await qb.transaction(async (tx) => {
|
|
978
|
+
* return [
|
|
979
|
+
* tx.insert({ tableName: 'orders', data: { user_id: 1, total: 100 } }),
|
|
980
|
+
* tx.update({ tableName: 'users', data: { balance: 50 }, where: { conditions: 'id = ?', params: [1] } }),
|
|
981
|
+
* ]
|
|
982
|
+
* })
|
|
983
|
+
*/
|
|
984
|
+
transaction<T extends Query<any, true>[]>(callback: (tx: D1QB<Schema>) => T | Promise<T>): Promise<any[]>;
|
|
476
985
|
}
|
|
477
986
|
|
|
478
987
|
interface SqlStorage {
|
|
@@ -487,17 +996,96 @@ declare class DOQB<Schema extends TableSchema = {}> extends QueryBuilder<Schema,
|
|
|
487
996
|
constructor(db: SqlStorage, options?: QueryBuilderOptions<false>);
|
|
488
997
|
migrations(options: MigrationOptions): syncMigrationsBuilder<DOResult>;
|
|
489
998
|
execute(query: Query<any, false>): any;
|
|
999
|
+
private _getQueryType;
|
|
490
1000
|
lazyExecute(query: Query<any, false>): Iterable<any>;
|
|
1001
|
+
/**
|
|
1002
|
+
* Execute multiple queries atomically as a transaction.
|
|
1003
|
+
* Uses SQLite's BEGIN/COMMIT/ROLLBACK for atomicity.
|
|
1004
|
+
* Note: This should be called within blockConcurrencyWhile for proper isolation in Durable Objects.
|
|
1005
|
+
*
|
|
1006
|
+
* @param callback - A function that receives the query builder and executes queries
|
|
1007
|
+
* @returns The return value of the callback
|
|
1008
|
+
*
|
|
1009
|
+
* @example
|
|
1010
|
+
* // Inside a Durable Object
|
|
1011
|
+
* this.ctx.blockConcurrencyWhile(() => {
|
|
1012
|
+
* qb.transaction((tx) => {
|
|
1013
|
+
* tx.insert({ tableName: 'orders', data: { user_id: 1, total: 100 } }).execute()
|
|
1014
|
+
* tx.update({ tableName: 'users', data: { balance: 50 }, where: { conditions: 'id = ?', params: [1] } }).execute()
|
|
1015
|
+
* })
|
|
1016
|
+
* })
|
|
1017
|
+
*/
|
|
1018
|
+
transaction<T>(callback: (tx: DOQB<Schema>) => T): T;
|
|
491
1019
|
}
|
|
492
1020
|
|
|
1021
|
+
declare class PGMigrationsBuilder extends asyncMigrationsBuilder<PGResult> {
|
|
1022
|
+
initialize(): Promise<void>;
|
|
1023
|
+
apply(): Promise<Array<{
|
|
1024
|
+
name: string;
|
|
1025
|
+
sql: string;
|
|
1026
|
+
}>>;
|
|
1027
|
+
}
|
|
493
1028
|
declare class PGQB<Schema extends TableSchema = {}> extends QueryBuilder<Schema, PGResult, true> {
|
|
494
1029
|
db: any;
|
|
495
|
-
_migrationsBuilder: typeof asyncMigrationsBuilder;
|
|
496
1030
|
constructor(db: any, options?: QueryBuilderOptions);
|
|
497
|
-
migrations(options: MigrationOptions):
|
|
1031
|
+
migrations(options: MigrationOptions): PGMigrationsBuilder;
|
|
498
1032
|
connect(): Promise<void>;
|
|
499
1033
|
close(): Promise<void>;
|
|
500
1034
|
execute(query: Query): Promise<any>;
|
|
501
1035
|
}
|
|
502
1036
|
|
|
503
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* Custom error class for Query Builder errors with enhanced context.
|
|
1039
|
+
* Provides helpful information about what went wrong and how to fix it.
|
|
1040
|
+
*/
|
|
1041
|
+
declare class QueryBuilderError extends Error {
|
|
1042
|
+
query?: string;
|
|
1043
|
+
expectedParams?: number;
|
|
1044
|
+
receivedParams?: number;
|
|
1045
|
+
hint?: string;
|
|
1046
|
+
clause?: string;
|
|
1047
|
+
constructor(message: string, options?: {
|
|
1048
|
+
query?: string;
|
|
1049
|
+
expectedParams?: number;
|
|
1050
|
+
receivedParams?: number;
|
|
1051
|
+
hint?: string;
|
|
1052
|
+
clause?: string;
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Error thrown when there's a parameter count mismatch.
|
|
1057
|
+
*/
|
|
1058
|
+
declare class ParameterMismatchError extends QueryBuilderError {
|
|
1059
|
+
constructor(options: {
|
|
1060
|
+
clause: string;
|
|
1061
|
+
query?: string;
|
|
1062
|
+
expectedParams: number;
|
|
1063
|
+
receivedParams: number;
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Error thrown when required data is missing.
|
|
1068
|
+
*/
|
|
1069
|
+
declare class MissingDataError extends QueryBuilderError {
|
|
1070
|
+
constructor(operation: string, field: string);
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Error thrown when an invalid configuration is detected.
|
|
1074
|
+
*/
|
|
1075
|
+
declare class InvalidConfigurationError extends QueryBuilderError {
|
|
1076
|
+
constructor(message: string, hint?: string);
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Error thrown when a subquery token is not found.
|
|
1080
|
+
*/
|
|
1081
|
+
declare class SubqueryTokenError extends QueryBuilderError {
|
|
1082
|
+
constructor(token: string);
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Error thrown when subquery context is missing.
|
|
1086
|
+
*/
|
|
1087
|
+
declare class MissingSubqueryContextError extends QueryBuilderError {
|
|
1088
|
+
constructor();
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
export { type AfterQueryHook, type ArrayResult, type AsyncType, type BeforeQueryHook, type CTEDefinition, type ColumnName, ConflictTypes, type ConflictUpsert, type CountResult, type D1Meta, D1QB, type D1Result, DOQB, type DOResult, type DefaultObject, type DefaultReturnObject, type Delete, type DeleteReturning, type DeleteWithoutReturning, FetchTypes, type FullArrayResult, type InferResult, type Insert, type InsertData, type InsertMultiple, type InsertOne, type InsertWithoutReturning, InvalidConfigurationError, type IsEmptySchema, type IterableResult, type Join, JoinTypes, type MaybeAsync, type Migration, type MigrationEntry, type MigrationOptions, MissingDataError, MissingSubqueryContextError, type OneResult, OrderTypes, PGQB, type PGResult, type PaginatedResult, type PaginationMeta, ParameterMismatchError, type Primitive, Query, QueryBuilder, QueryBuilderError, type QueryBuilderOptions, type QueryLoggerMeta, QueryWithExtra, Raw, type RawQuery, type RawQueryFetchAll, type RawQueryFetchOne, type RawQueryWithoutFetching, type SchemaAware, type SelectAll, type SelectColumns, type SelectOne, type SetOperation, SetOperationType, SubqueryTokenError, type SyncType, type TableName, type TableSchema, type TypedDelete, type TypedInsert, type TypedSelectAll, type TypedSelectOne, type TypedUpdate, type Update, type UpdateData, type UpdateReturning, type UpdateWithoutReturning, type Where, asyncLoggerWrapper, asyncMigrationsBuilder, defaultLogger, syncLoggerWrapper, syncMigrationsBuilder, trimQuery };
|