@dockstat/sqlite-wrapper 1.2.7 → 1.2.8

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.
@@ -1,431 +1,431 @@
1
- import type { Database, SQLQueryBindings } from "bun:sqlite";
2
- import type {
3
- ColumnNames,
4
- WhereCondition,
5
- RegexCondition,
6
- InsertResult,
7
- UpdateResult,
8
- DeleteResult,
9
- InsertOptions,
10
- JsonColumnConfig,
11
- QueryBuilderState,
12
- } from "../types";
13
- import { SelectQueryBuilder } from "./select";
14
- import { InsertQueryBuilder } from "./insert";
15
- import { UpdateQueryBuilder } from "./update";
16
- import { DeleteQueryBuilder } from "./delete";
17
-
18
- /**
19
- * Main QueryBuilder class that combines all functionality using composition.
20
- * This class provides a unified interface for SELECT, INSERT, UPDATE, and DELETE operations.
21
- *
22
- * Each operation type is implemented in a separate module for better maintainability:
23
- * - SELECT: column selection, ordering, limiting, result execution
24
- * - INSERT: single/bulk inserts with conflict resolution
25
- * - UPDATE: safe updates with mandatory WHERE conditions
26
- * - DELETE: safe deletes with mandatory WHERE conditions
27
- * - WHERE: shared conditional logic across all operations
28
- */
29
- export class QueryBuilder<T extends Record<string, unknown>> {
30
- private selectBuilder: SelectQueryBuilder<T>;
31
- private insertBuilder: InsertQueryBuilder<T>;
32
- private updateBuilder: UpdateQueryBuilder<T>;
33
- private deleteBuilder: DeleteQueryBuilder<T>;
34
-
35
- constructor(
36
- db: Database,
37
- tableName: string,
38
- jsonConfig?: JsonColumnConfig<T>,
39
- ) {
40
- // Create instances of each specialized builder
41
- this.selectBuilder = new SelectQueryBuilder<T>(db, tableName, jsonConfig);
42
- this.insertBuilder = new InsertQueryBuilder<T>(db, tableName, jsonConfig);
43
- this.updateBuilder = new UpdateQueryBuilder<T>(db, tableName, jsonConfig);
44
- this.deleteBuilder = new DeleteQueryBuilder<T>(db, tableName, jsonConfig);
45
-
46
- // Ensure all builders share the same state for WHERE conditions
47
- this.syncBuilderStates();
48
- }
49
-
50
- /**
51
- * Synchronize the state between all builders so WHERE conditions are shared.
52
- */
53
- private syncBuilderStates(): void {
54
- const masterState = (
55
- this.selectBuilder as unknown as { state: QueryBuilderState<T> }
56
- ).state;
57
- (this.insertBuilder as unknown as { state: QueryBuilderState<T> }).state =
58
- masterState;
59
- (this.updateBuilder as unknown as { state: QueryBuilderState<T> }).state =
60
- masterState;
61
- (this.deleteBuilder as unknown as { state: QueryBuilderState<T> }).state =
62
- masterState;
63
- }
64
-
65
- // ===== WHERE METHODS (delegated to selectBuilder) =====
66
-
67
- /**
68
- * Add simple equality conditions to the WHERE clause.
69
- */
70
- where(conditions: WhereCondition<T>): this {
71
- this.selectBuilder.where(conditions);
72
- return this;
73
- }
74
-
75
- /**
76
- * Add regex conditions (applied client-side).
77
- */
78
- whereRgx(conditions: RegexCondition<T>): this {
79
- this.selectBuilder.whereRgx(conditions);
80
- return this;
81
- }
82
-
83
- /**
84
- * Add a raw SQL WHERE fragment with parameter binding.
85
- */
86
- whereExpr(expr: string, params: SQLQueryBindings[] = []): this {
87
- this.selectBuilder.whereExpr(expr, params);
88
- return this;
89
- }
90
-
91
- /**
92
- * Alias for whereExpr.
93
- */
94
- whereRaw(expr: string, params: SQLQueryBindings[] = []): this {
95
- this.selectBuilder.whereRaw(expr, params);
96
- return this;
97
- }
98
-
99
- /**
100
- * Add an IN clause with proper parameter binding.
101
- */
102
- whereIn(column: keyof T, values: SQLQueryBindings[]): this {
103
- this.selectBuilder.whereIn(column, values);
104
- return this;
105
- }
106
-
107
- /**
108
- * Add a NOT IN clause with proper parameter binding.
109
- */
110
- whereNotIn(column: keyof T, values: SQLQueryBindings[]): this {
111
- this.selectBuilder.whereNotIn(column, values);
112
- return this;
113
- }
114
-
115
- /**
116
- * Add a comparison operator condition.
117
- */
118
- whereOp(column: keyof T, op: string, value: SQLQueryBindings): this {
119
- this.selectBuilder.whereOp(column, op, value);
120
- return this;
121
- }
122
-
123
- /**
124
- * Add a BETWEEN condition.
125
- */
126
- whereBetween(
127
- column: keyof T,
128
- min: SQLQueryBindings,
129
- max: SQLQueryBindings,
130
- ): this {
131
- this.selectBuilder.whereBetween(column, min, max);
132
- return this;
133
- }
134
-
135
- /**
136
- * Add a NOT BETWEEN condition.
137
- */
138
- whereNotBetween(
139
- column: keyof T,
140
- min: SQLQueryBindings,
141
- max: SQLQueryBindings,
142
- ): this {
143
- this.selectBuilder.whereNotBetween(column, min, max);
144
- return this;
145
- }
146
-
147
- /**
148
- * Add an IS NULL condition.
149
- */
150
- whereNull(column: keyof T): this {
151
- this.selectBuilder.whereNull(column);
152
- return this;
153
- }
154
-
155
- /**
156
- * Add an IS NOT NULL condition.
157
- */
158
- whereNotNull(column: keyof T): this {
159
- this.selectBuilder.whereNotNull(column);
160
- return this;
161
- }
162
-
163
- // ===== SELECT METHODS (delegated to selectBuilder) =====
164
-
165
- /**
166
- * Specify which columns to select.
167
- */
168
- select(columns: ColumnNames<T>): this {
169
- this.selectBuilder.select(columns);
170
- return this;
171
- }
172
-
173
- /**
174
- * Add ORDER BY clause.
175
- */
176
- orderBy(column: keyof T): this {
177
- this.selectBuilder.orderBy(column);
178
- return this;
179
- }
180
-
181
- /**
182
- * Set order direction to descending.
183
- */
184
- desc(): this {
185
- this.selectBuilder.desc();
186
- return this;
187
- }
188
-
189
- /**
190
- * Set order direction to ascending.
191
- */
192
- asc(): this {
193
- this.selectBuilder.asc();
194
- return this;
195
- }
196
-
197
- /**
198
- * Add LIMIT clause.
199
- */
200
- limit(amount: number): this {
201
- this.selectBuilder.limit(amount);
202
- return this;
203
- }
204
-
205
- /**
206
- * Add OFFSET clause.
207
- */
208
- offset(start: number): this {
209
- this.selectBuilder.offset(start);
210
- return this;
211
- }
212
-
213
- // ===== SELECT EXECUTION METHODS (delegated to selectBuilder) =====
214
-
215
- /**
216
- * Execute the query and return all matching rows.
217
- */
218
- all(): T[] {
219
- return this.selectBuilder.all();
220
- }
221
-
222
- /**
223
- * Execute the query and return the first matching row, or null.
224
- */
225
- get(): T | null {
226
- return this.selectBuilder.get();
227
- }
228
-
229
- /**
230
- * Execute the query and return the first matching row, or null.
231
- */
232
- first(): T | null {
233
- return this.selectBuilder.first();
234
- }
235
-
236
- /**
237
- * Execute a COUNT query and return the number of matching rows.
238
- */
239
- count(): number {
240
- return this.selectBuilder.count();
241
- }
242
-
243
- /**
244
- * Check if any rows match the current conditions.
245
- */
246
- exists(): boolean {
247
- return this.selectBuilder.exists();
248
- }
249
-
250
- /**
251
- * Execute the query and return a single column value from the first row.
252
- */
253
- value<K extends keyof T>(column: K): T[K] | null {
254
- return this.selectBuilder.value(column);
255
- }
256
-
257
- /**
258
- * Execute the query and return an array of values from a single column.
259
- */
260
- pluck<K extends keyof T>(column: K): T[K][] {
261
- return this.selectBuilder.pluck(column);
262
- }
263
-
264
- // ===== INSERT METHODS (delegated to insertBuilder) =====
265
-
266
- /**
267
- * Insert a single row or multiple rows into the table.
268
- */
269
- insert(
270
- data: Partial<T> | Partial<T>[],
271
- options?: InsertOptions,
272
- ): InsertResult {
273
- return this.insertBuilder.insert(data, options);
274
- }
275
-
276
- /**
277
- * Insert with OR IGNORE conflict resolution.
278
- */
279
- insertOrIgnore(data: Partial<T> | Partial<T>[]): InsertResult {
280
- return this.insertBuilder.insertOrIgnore(data);
281
- }
282
-
283
- /**
284
- * Insert with OR REPLACE conflict resolution.
285
- */
286
- insertOrReplace(data: Partial<T> | Partial<T>[]): InsertResult {
287
- return this.insertBuilder.insertOrReplace(data);
288
- }
289
-
290
- /**
291
- * Insert with OR ABORT conflict resolution.
292
- */
293
- insertOrAbort(data: Partial<T> | Partial<T>[]): InsertResult {
294
- return this.insertBuilder.insertOrAbort(data);
295
- }
296
-
297
- /**
298
- * Insert with OR FAIL conflict resolution.
299
- */
300
- insertOrFail(data: Partial<T> | Partial<T>[]): InsertResult {
301
- return this.insertBuilder.insertOrFail(data);
302
- }
303
-
304
- /**
305
- * Insert with OR ROLLBACK conflict resolution.
306
- */
307
- insertOrRollback(data: Partial<T> | Partial<T>[]): InsertResult {
308
- return this.insertBuilder.insertOrRollback(data);
309
- }
310
-
311
- /**
312
- * Insert and get the inserted row back.
313
- */
314
- insertAndGet(data: Partial<T>, options?: InsertOptions): T | null {
315
- return this.insertBuilder.insertAndGet(data, options);
316
- }
317
-
318
- /**
319
- * Batch insert with transaction support.
320
- */
321
- insertBatch(rows: Partial<T>[], options?: InsertOptions): InsertResult {
322
- return this.insertBuilder.insertBatch(rows, options);
323
- }
324
-
325
- // ===== UPDATE METHODS (delegated to updateBuilder) =====
326
-
327
- /**
328
- * Update rows matching the WHERE conditions.
329
- */
330
- update(data: Partial<T>): UpdateResult {
331
- return this.updateBuilder.update(data);
332
- }
333
-
334
- /**
335
- * Update or insert (upsert) using INSERT OR REPLACE.
336
- */
337
- upsert(data: Partial<T>): UpdateResult {
338
- return this.updateBuilder.upsert(data);
339
- }
340
-
341
- /**
342
- * Increment a numeric column by a specified amount.
343
- */
344
- increment(column: keyof T, amount = 1): UpdateResult {
345
- return this.updateBuilder.increment(column, amount);
346
- }
347
-
348
- /**
349
- * Decrement a numeric column by a specified amount.
350
- */
351
- decrement(column: keyof T, amount = 1): UpdateResult {
352
- return this.updateBuilder.decrement(column, amount);
353
- }
354
-
355
- /**
356
- * Update and get the updated rows back.
357
- */
358
- updateAndGet(data: Partial<T>): T[] {
359
- return this.updateBuilder.updateAndGet(data);
360
- }
361
-
362
- /**
363
- * Batch update multiple rows with different values.
364
- */
365
- updateBatch(
366
- updates: Array<{ where: Partial<T>; data: Partial<T> }>,
367
- ): UpdateResult {
368
- return this.updateBuilder.updateBatch(updates);
369
- }
370
-
371
- // ===== DELETE METHODS (delegated to deleteBuilder) =====
372
-
373
- /**
374
- * Delete rows matching the WHERE conditions.
375
- */
376
- delete(): DeleteResult {
377
- return this.deleteBuilder.delete();
378
- }
379
-
380
- /**
381
- * Delete and get the deleted rows back.
382
- */
383
- deleteAndGet(): T[] {
384
- return this.deleteBuilder.deleteAndGet();
385
- }
386
-
387
- /**
388
- * Soft delete - mark rows as deleted instead of physically removing them.
389
- */
390
- softDelete(
391
- deletedColumn: keyof T = "deleted_at" as keyof T,
392
- deletedValue: SQLQueryBindings = Math.floor(Date.now() / 1000),
393
- ): DeleteResult {
394
- return this.deleteBuilder.softDelete(deletedColumn, deletedValue);
395
- }
396
-
397
- /**
398
- * Restore soft deleted rows.
399
- */
400
- restore(deletedColumn: keyof T = "deleted_at" as keyof T): DeleteResult {
401
- return this.deleteBuilder.restore(deletedColumn);
402
- }
403
-
404
- /**
405
- * Batch delete multiple sets of rows.
406
- */
407
- deleteBatch(conditions: Array<Partial<T>>): DeleteResult {
408
- return this.deleteBuilder.deleteBatch(conditions);
409
- }
410
-
411
- /**
412
- * Truncate the entire table (delete all rows).
413
- */
414
- truncate(): DeleteResult {
415
- return this.deleteBuilder.truncate();
416
- }
417
-
418
- /**
419
- * Delete rows older than a specified timestamp.
420
- */
421
- deleteOlderThan(timestampColumn: keyof T, olderThan: number): DeleteResult {
422
- return this.deleteBuilder.deleteOlderThan(timestampColumn, olderThan);
423
- }
424
-
425
- /**
426
- * Delete duplicate rows based on specified columns.
427
- */
428
- deleteDuplicates(columns: Array<keyof T>): DeleteResult {
429
- return this.deleteBuilder.deleteDuplicates(columns);
430
- }
431
- }
1
+ import type { Database, SQLQueryBindings } from "bun:sqlite";
2
+ import type {
3
+ ColumnNames,
4
+ WhereCondition,
5
+ RegexCondition,
6
+ InsertResult,
7
+ UpdateResult,
8
+ DeleteResult,
9
+ InsertOptions,
10
+ JsonColumnConfig,
11
+ QueryBuilderState,
12
+ } from "../types";
13
+ import { SelectQueryBuilder } from "./select";
14
+ import { InsertQueryBuilder } from "./insert";
15
+ import { UpdateQueryBuilder } from "./update";
16
+ import { DeleteQueryBuilder } from "./delete";
17
+
18
+ /**
19
+ * Main QueryBuilder class that combines all functionality using composition.
20
+ * This class provides a unified interface for SELECT, INSERT, UPDATE, and DELETE operations.
21
+ *
22
+ * Each operation type is implemented in a separate module for better maintainability:
23
+ * - SELECT: column selection, ordering, limiting, result execution
24
+ * - INSERT: single/bulk inserts with conflict resolution
25
+ * - UPDATE: safe updates with mandatory WHERE conditions
26
+ * - DELETE: safe deletes with mandatory WHERE conditions
27
+ * - WHERE: shared conditional logic across all operations
28
+ */
29
+ export class QueryBuilder<T extends Record<string, unknown>> {
30
+ private selectBuilder: SelectQueryBuilder<T>;
31
+ private insertBuilder: InsertQueryBuilder<T>;
32
+ private updateBuilder: UpdateQueryBuilder<T>;
33
+ private deleteBuilder: DeleteQueryBuilder<T>;
34
+
35
+ constructor(
36
+ db: Database,
37
+ tableName: string,
38
+ jsonConfig?: JsonColumnConfig<T>,
39
+ ) {
40
+ // Create instances of each specialized builder
41
+ this.selectBuilder = new SelectQueryBuilder<T>(db, tableName, jsonConfig);
42
+ this.insertBuilder = new InsertQueryBuilder<T>(db, tableName, jsonConfig);
43
+ this.updateBuilder = new UpdateQueryBuilder<T>(db, tableName, jsonConfig);
44
+ this.deleteBuilder = new DeleteQueryBuilder<T>(db, tableName, jsonConfig);
45
+
46
+ // Ensure all builders share the same state for WHERE conditions
47
+ this.syncBuilderStates();
48
+ }
49
+
50
+ /**
51
+ * Synchronize the state between all builders so WHERE conditions are shared.
52
+ */
53
+ private syncBuilderStates(): void {
54
+ const masterState = (
55
+ this.selectBuilder as unknown as { state: QueryBuilderState<T> }
56
+ ).state;
57
+ (this.insertBuilder as unknown as { state: QueryBuilderState<T> }).state =
58
+ masterState;
59
+ (this.updateBuilder as unknown as { state: QueryBuilderState<T> }).state =
60
+ masterState;
61
+ (this.deleteBuilder as unknown as { state: QueryBuilderState<T> }).state =
62
+ masterState;
63
+ }
64
+
65
+ // ===== WHERE METHODS (delegated to selectBuilder) =====
66
+
67
+ /**
68
+ * Add simple equality conditions to the WHERE clause.
69
+ */
70
+ where(conditions: WhereCondition<T>): this {
71
+ this.selectBuilder.where(conditions);
72
+ return this;
73
+ }
74
+
75
+ /**
76
+ * Add regex conditions (applied client-side).
77
+ */
78
+ whereRgx(conditions: RegexCondition<T>): this {
79
+ this.selectBuilder.whereRgx(conditions);
80
+ return this;
81
+ }
82
+
83
+ /**
84
+ * Add a raw SQL WHERE fragment with parameter binding.
85
+ */
86
+ whereExpr(expr: string, params: SQLQueryBindings[] = []): this {
87
+ this.selectBuilder.whereExpr(expr, params);
88
+ return this;
89
+ }
90
+
91
+ /**
92
+ * Alias for whereExpr.
93
+ */
94
+ whereRaw(expr: string, params: SQLQueryBindings[] = []): this {
95
+ this.selectBuilder.whereRaw(expr, params);
96
+ return this;
97
+ }
98
+
99
+ /**
100
+ * Add an IN clause with proper parameter binding.
101
+ */
102
+ whereIn(column: keyof T, values: SQLQueryBindings[]): this {
103
+ this.selectBuilder.whereIn(column, values);
104
+ return this;
105
+ }
106
+
107
+ /**
108
+ * Add a NOT IN clause with proper parameter binding.
109
+ */
110
+ whereNotIn(column: keyof T, values: SQLQueryBindings[]): this {
111
+ this.selectBuilder.whereNotIn(column, values);
112
+ return this;
113
+ }
114
+
115
+ /**
116
+ * Add a comparison operator condition.
117
+ */
118
+ whereOp(column: keyof T, op: string, value: SQLQueryBindings): this {
119
+ this.selectBuilder.whereOp(column, op, value);
120
+ return this;
121
+ }
122
+
123
+ /**
124
+ * Add a BETWEEN condition.
125
+ */
126
+ whereBetween(
127
+ column: keyof T,
128
+ min: SQLQueryBindings,
129
+ max: SQLQueryBindings,
130
+ ): this {
131
+ this.selectBuilder.whereBetween(column, min, max);
132
+ return this;
133
+ }
134
+
135
+ /**
136
+ * Add a NOT BETWEEN condition.
137
+ */
138
+ whereNotBetween(
139
+ column: keyof T,
140
+ min: SQLQueryBindings,
141
+ max: SQLQueryBindings,
142
+ ): this {
143
+ this.selectBuilder.whereNotBetween(column, min, max);
144
+ return this;
145
+ }
146
+
147
+ /**
148
+ * Add an IS NULL condition.
149
+ */
150
+ whereNull(column: keyof T): this {
151
+ this.selectBuilder.whereNull(column);
152
+ return this;
153
+ }
154
+
155
+ /**
156
+ * Add an IS NOT NULL condition.
157
+ */
158
+ whereNotNull(column: keyof T): this {
159
+ this.selectBuilder.whereNotNull(column);
160
+ return this;
161
+ }
162
+
163
+ // ===== SELECT METHODS (delegated to selectBuilder) =====
164
+
165
+ /**
166
+ * Specify which columns to select.
167
+ */
168
+ select(columns: ColumnNames<T>): this {
169
+ this.selectBuilder.select(columns);
170
+ return this;
171
+ }
172
+
173
+ /**
174
+ * Add ORDER BY clause.
175
+ */
176
+ orderBy(column: keyof T): this {
177
+ this.selectBuilder.orderBy(column);
178
+ return this;
179
+ }
180
+
181
+ /**
182
+ * Set order direction to descending.
183
+ */
184
+ desc(): this {
185
+ this.selectBuilder.desc();
186
+ return this;
187
+ }
188
+
189
+ /**
190
+ * Set order direction to ascending.
191
+ */
192
+ asc(): this {
193
+ this.selectBuilder.asc();
194
+ return this;
195
+ }
196
+
197
+ /**
198
+ * Add LIMIT clause.
199
+ */
200
+ limit(amount: number): this {
201
+ this.selectBuilder.limit(amount);
202
+ return this;
203
+ }
204
+
205
+ /**
206
+ * Add OFFSET clause.
207
+ */
208
+ offset(start: number): this {
209
+ this.selectBuilder.offset(start);
210
+ return this;
211
+ }
212
+
213
+ // ===== SELECT EXECUTION METHODS (delegated to selectBuilder) =====
214
+
215
+ /**
216
+ * Execute the query and return all matching rows.
217
+ */
218
+ all(): T[] {
219
+ return this.selectBuilder.all();
220
+ }
221
+
222
+ /**
223
+ * Execute the query and return the first matching row, or null.
224
+ */
225
+ get(): T | null {
226
+ return this.selectBuilder.get();
227
+ }
228
+
229
+ /**
230
+ * Execute the query and return the first matching row, or null.
231
+ */
232
+ first(): T | null {
233
+ return this.selectBuilder.first();
234
+ }
235
+
236
+ /**
237
+ * Execute a COUNT query and return the number of matching rows.
238
+ */
239
+ count(): number {
240
+ return this.selectBuilder.count();
241
+ }
242
+
243
+ /**
244
+ * Check if any rows match the current conditions.
245
+ */
246
+ exists(): boolean {
247
+ return this.selectBuilder.exists();
248
+ }
249
+
250
+ /**
251
+ * Execute the query and return a single column value from the first row.
252
+ */
253
+ value<K extends keyof T>(column: K): T[K] | null {
254
+ return this.selectBuilder.value(column);
255
+ }
256
+
257
+ /**
258
+ * Execute the query and return an array of values from a single column.
259
+ */
260
+ pluck<K extends keyof T>(column: K): T[K][] {
261
+ return this.selectBuilder.pluck(column);
262
+ }
263
+
264
+ // ===== INSERT METHODS (delegated to insertBuilder) =====
265
+
266
+ /**
267
+ * Insert a single row or multiple rows into the table.
268
+ */
269
+ insert(
270
+ data: Partial<T> | Partial<T>[],
271
+ options?: InsertOptions,
272
+ ): InsertResult {
273
+ return this.insertBuilder.insert(data, options);
274
+ }
275
+
276
+ /**
277
+ * Insert with OR IGNORE conflict resolution.
278
+ */
279
+ insertOrIgnore(data: Partial<T> | Partial<T>[]): InsertResult {
280
+ return this.insertBuilder.insertOrIgnore(data);
281
+ }
282
+
283
+ /**
284
+ * Insert with OR REPLACE conflict resolution.
285
+ */
286
+ insertOrReplace(data: Partial<T> | Partial<T>[]): InsertResult {
287
+ return this.insertBuilder.insertOrReplace(data);
288
+ }
289
+
290
+ /**
291
+ * Insert with OR ABORT conflict resolution.
292
+ */
293
+ insertOrAbort(data: Partial<T> | Partial<T>[]): InsertResult {
294
+ return this.insertBuilder.insertOrAbort(data);
295
+ }
296
+
297
+ /**
298
+ * Insert with OR FAIL conflict resolution.
299
+ */
300
+ insertOrFail(data: Partial<T> | Partial<T>[]): InsertResult {
301
+ return this.insertBuilder.insertOrFail(data);
302
+ }
303
+
304
+ /**
305
+ * Insert with OR ROLLBACK conflict resolution.
306
+ */
307
+ insertOrRollback(data: Partial<T> | Partial<T>[]): InsertResult {
308
+ return this.insertBuilder.insertOrRollback(data);
309
+ }
310
+
311
+ /**
312
+ * Insert and get the inserted row back.
313
+ */
314
+ insertAndGet(data: Partial<T>, options?: InsertOptions): T | null {
315
+ return this.insertBuilder.insertAndGet(data, options);
316
+ }
317
+
318
+ /**
319
+ * Batch insert with transaction support.
320
+ */
321
+ insertBatch(rows: Partial<T>[], options?: InsertOptions): InsertResult {
322
+ return this.insertBuilder.insertBatch(rows, options);
323
+ }
324
+
325
+ // ===== UPDATE METHODS (delegated to updateBuilder) =====
326
+
327
+ /**
328
+ * Update rows matching the WHERE conditions.
329
+ */
330
+ update(data: Partial<T>): UpdateResult {
331
+ return this.updateBuilder.update(data);
332
+ }
333
+
334
+ /**
335
+ * Update or insert (upsert) using INSERT OR REPLACE.
336
+ */
337
+ upsert(data: Partial<T>): UpdateResult {
338
+ return this.updateBuilder.upsert(data);
339
+ }
340
+
341
+ /**
342
+ * Increment a numeric column by a specified amount.
343
+ */
344
+ increment(column: keyof T, amount = 1): UpdateResult {
345
+ return this.updateBuilder.increment(column, amount);
346
+ }
347
+
348
+ /**
349
+ * Decrement a numeric column by a specified amount.
350
+ */
351
+ decrement(column: keyof T, amount = 1): UpdateResult {
352
+ return this.updateBuilder.decrement(column, amount);
353
+ }
354
+
355
+ /**
356
+ * Update and get the updated rows back.
357
+ */
358
+ updateAndGet(data: Partial<T>): T[] {
359
+ return this.updateBuilder.updateAndGet(data);
360
+ }
361
+
362
+ /**
363
+ * Batch update multiple rows with different values.
364
+ */
365
+ updateBatch(
366
+ updates: Array<{ where: Partial<T>; data: Partial<T> }>,
367
+ ): UpdateResult {
368
+ return this.updateBuilder.updateBatch(updates);
369
+ }
370
+
371
+ // ===== DELETE METHODS (delegated to deleteBuilder) =====
372
+
373
+ /**
374
+ * Delete rows matching the WHERE conditions.
375
+ */
376
+ delete(): DeleteResult {
377
+ return this.deleteBuilder.delete();
378
+ }
379
+
380
+ /**
381
+ * Delete and get the deleted rows back.
382
+ */
383
+ deleteAndGet(): T[] {
384
+ return this.deleteBuilder.deleteAndGet();
385
+ }
386
+
387
+ /**
388
+ * Soft delete - mark rows as deleted instead of physically removing them.
389
+ */
390
+ softDelete(
391
+ deletedColumn: keyof T = "deleted_at" as keyof T,
392
+ deletedValue: SQLQueryBindings = Math.floor(Date.now() / 1000),
393
+ ): DeleteResult {
394
+ return this.deleteBuilder.softDelete(deletedColumn, deletedValue);
395
+ }
396
+
397
+ /**
398
+ * Restore soft deleted rows.
399
+ */
400
+ restore(deletedColumn: keyof T = "deleted_at" as keyof T): DeleteResult {
401
+ return this.deleteBuilder.restore(deletedColumn);
402
+ }
403
+
404
+ /**
405
+ * Batch delete multiple sets of rows.
406
+ */
407
+ deleteBatch(conditions: Array<Partial<T>>): DeleteResult {
408
+ return this.deleteBuilder.deleteBatch(conditions);
409
+ }
410
+
411
+ /**
412
+ * Truncate the entire table (delete all rows).
413
+ */
414
+ truncate(): DeleteResult {
415
+ return this.deleteBuilder.truncate();
416
+ }
417
+
418
+ /**
419
+ * Delete rows older than a specified timestamp.
420
+ */
421
+ deleteOlderThan(timestampColumn: keyof T, olderThan: number): DeleteResult {
422
+ return this.deleteBuilder.deleteOlderThan(timestampColumn, olderThan);
423
+ }
424
+
425
+ /**
426
+ * Delete duplicate rows based on specified columns.
427
+ */
428
+ deleteDuplicates(columns: Array<keyof T>): DeleteResult {
429
+ return this.deleteBuilder.deleteDuplicates(columns);
430
+ }
431
+ }