@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.
package/types.ts CHANGED
@@ -1,623 +1,623 @@
1
- import type { Database, SQLQueryBindings } from "bun:sqlite";
2
-
3
- /**
4
- * All SQLite data types including affinity types
5
- */
6
- export const SQLiteTypes = {
7
- // Standard SQLite types
8
- INTEGER: "INTEGER" as const,
9
- TEXT: "TEXT" as const,
10
- REAL: "REAL" as const,
11
- BLOB: "BLOB" as const,
12
- NUMERIC: "NUMERIC" as const,
13
-
14
- // Common type aliases and variations
15
- INT: "INT" as const,
16
- TINYINT: "TINYINT" as const,
17
- SMALLINT: "SMALLINT" as const,
18
- MEDIUMINT: "MEDIUMINT" as const,
19
- BIGINT: "BIGINT" as const,
20
-
21
- // Text variations
22
- VARCHAR: "VARCHAR" as const,
23
- CHAR: "CHAR" as const,
24
- CHARACTER: "CHARACTER" as const,
25
- NCHAR: "NCHAR" as const,
26
- NVARCHAR: "NVARCHAR" as const,
27
- CLOB: "CLOB" as const,
28
-
29
- // Numeric variations
30
- DOUBLE: "DOUBLE" as const,
31
- FLOAT: "FLOAT" as const,
32
- DECIMAL: "DECIMAL" as const,
33
-
34
- // Date/Time (stored as TEXT, INTEGER, or REAL)
35
- DATE: "DATE" as const,
36
- DATETIME: "DATETIME" as const,
37
- TIMESTAMP: "TIMESTAMP" as const,
38
- TIME: "TIME" as const,
39
-
40
- // Boolean (stored as INTEGER)
41
- BOOLEAN: "BOOLEAN" as const,
42
-
43
- // JSON (stored as TEXT)
44
- JSON: "JSON" as const,
45
- } as const;
46
-
47
- export type SQLiteType = (typeof SQLiteTypes)[keyof typeof SQLiteTypes];
48
-
49
- /**
50
- * SQLite built-in scalar functions
51
- */
52
- export const SQLiteFunctions = {
53
- // Date/Time functions
54
- DATE: (expr: string) => `DATE(${expr})`,
55
- TIME: (expr: string) => `TIME(${expr})`,
56
- DATETIME: (expr: string) => `DATETIME(${expr})`,
57
- JULIANDAY: (expr: string) => `JULIANDAY(${expr})`,
58
- STRFTIME: (format: string, expr: string) => `STRFTIME('${format}', ${expr})`,
59
-
60
- // String functions
61
- LENGTH: (expr: string) => `LENGTH(${expr})`,
62
- LOWER: (expr: string) => `LOWER(${expr})`,
63
- UPPER: (expr: string) => `UPPER(${expr})`,
64
- TRIM: (expr: string, chars?: string) =>
65
- chars ? `TRIM(${expr}, '${chars}')` : `TRIM(${expr})`,
66
- LTRIM: (expr: string, chars?: string) =>
67
- chars ? `LTRIM(${expr}, '${chars}')` : `LTRIM(${expr})`,
68
- RTRIM: (expr: string, chars?: string) =>
69
- chars ? `RTRIM(${expr}, '${chars}')` : `RTRIM(${expr})`,
70
- SUBSTR: (expr: string, start: number, length?: number) =>
71
- length
72
- ? `SUBSTR(${expr}, ${start}, ${length})`
73
- : `SUBSTR(${expr}, ${start})`,
74
- SUBSTRING: (expr: string, start: number, length?: number) =>
75
- length
76
- ? `SUBSTRING(${expr}, ${start}, ${length})`
77
- : `SUBSTRING(${expr}, ${start})`,
78
- REPLACE: (expr: string, old: string, replacement: string) =>
79
- `REPLACE(${expr}, '${old}', '${replacement}')`,
80
- PRINTF: (format: string, ...args: string[]) =>
81
- `PRINTF('${format}', ${args.join(", ")})`,
82
-
83
- // Math functions
84
- ABS: (expr: string) => `ABS(${expr})`,
85
- ROUND: (expr: string, digits?: number) =>
86
- digits !== undefined ? `ROUND(${expr}, ${digits})` : `ROUND(${expr})`,
87
- RANDOM: () => "RANDOM()",
88
- MIN: (...exprs: string[]) => `MIN(${exprs.join(", ")})`,
89
- MAX: (...exprs: string[]) => `MAX(${exprs.join(", ")})`,
90
-
91
- // Type conversion
92
- CAST: (expr: string, type: string) => `CAST(${expr} AS ${type})`,
93
- TYPEOF: (expr: string) => `TYPEOF(${expr})`,
94
-
95
- // Conditional
96
- COALESCE: (...exprs: string[]) => `COALESCE(${exprs.join(", ")})`,
97
- IFNULL: (expr: string, replacement: string) =>
98
- `IFNULL(${expr}, ${replacement})`,
99
- NULLIF: (expr1: string, expr2: string) => `NULLIF(${expr1}, ${expr2})`,
100
- IIF: (condition: string, trueValue: string, falseValue: string) =>
101
- `IIF(${condition}, ${trueValue}, ${falseValue})`,
102
-
103
- // Aggregate functions (for use in expressions)
104
- COUNT: (expr?: string) => (expr ? `COUNT(${expr})` : "COUNT(*)"),
105
- SUM: (expr: string) => `SUM(${expr})`,
106
- AVG: (expr: string) => `AVG(${expr})`,
107
- TOTAL: (expr: string) => `TOTAL(${expr})`,
108
- GROUP_CONCAT: (expr: string, separator?: string) =>
109
- separator
110
- ? `GROUP_CONCAT(${expr}, '${separator}')`
111
- : `GROUP_CONCAT(${expr})`,
112
-
113
- // JSON functions (SQLite 3.45+)
114
- JSON: (expr: string) => `JSON(${expr})`,
115
- JSON_EXTRACT: (json: string, path: string) =>
116
- `JSON_EXTRACT(${json}, '${path}')`,
117
- JSON_TYPE: (json: string, path?: string) =>
118
- path ? `JSON_TYPE(${json}, '${path}')` : `JSON_TYPE(${json})`,
119
- JSON_VALID: (expr: string) => `JSON_VALID(${expr})`,
120
- JSON_ARRAY: (...values: string[]) => `JSON_ARRAY(${values.join(", ")})`,
121
- JSON_OBJECT: (...pairs: string[]) => `JSON_OBJECT(${pairs.join(", ")})`,
122
- } as const;
123
-
124
- /**
125
- * SQLite keywords and special values
126
- */
127
- export const SQLiteKeywords = {
128
- // Special values
129
- NULL: "NULL" as const,
130
- CURRENT_TIME: "CURRENT_TIME" as const,
131
- CURRENT_DATE: "CURRENT_DATE" as const,
132
- CURRENT_TIMESTAMP: "CURRENT_TIMESTAMP" as const,
133
-
134
- // Boolean values (as integers)
135
- TRUE: "1" as const,
136
- FALSE: "0" as const,
137
-
138
- // Conflict resolution
139
- ROLLBACK: "ROLLBACK" as const,
140
- ABORT: "ABORT" as const,
141
- FAIL: "FAIL" as const,
142
- IGNORE: "IGNORE" as const,
143
- REPLACE: "REPLACE" as const,
144
- } as const;
145
-
146
- /**
147
- * Foreign key actions
148
- */
149
- export type ForeignKeyAction =
150
- | "CASCADE"
151
- | "SET NULL"
152
- | "RESTRICT"
153
- | "NO ACTION"
154
- | "SET DEFAULT";
155
-
156
- /**
157
- * Column constraint options with comprehensive support
158
- */
159
- export interface ColumnConstraints {
160
- /** Column is PRIMARY KEY */
161
- primaryKey?: boolean;
162
- /** Column has AUTOINCREMENT (only valid with INTEGER PRIMARY KEY) */
163
- autoincrement?: boolean;
164
- /** Column is NOT NULL */
165
- notNull?: boolean;
166
- /** Column has UNIQUE constraint */
167
- unique?: boolean;
168
- /** Default value - can be literal value, function call, or keyword */
169
- default?: string | number | boolean | null | DefaultExpression;
170
- /** Custom check constraint */
171
- check?: string;
172
- /** Collation sequence */
173
- collate?: "BINARY" | "NOCASE" | "RTRIM" | string;
174
- /** References another table (foreign key) */
175
- references?: {
176
- table: string;
177
- column: string;
178
- onDelete?: ForeignKeyAction;
179
- onUpdate?: ForeignKeyAction;
180
- };
181
- /** Generated column expression (GENERATED ALWAYS AS) */
182
- generated?: {
183
- expression: string;
184
- stored?: boolean; // true for STORED, false/undefined for VIRTUAL
185
- };
186
- /** Column comment (stored as metadata, not in schema) */
187
- comment?: string;
188
- }
189
-
190
- /**
191
- * Type-safe default value expressions
192
- */
193
- export type DefaultExpression = {
194
- _type: "expression";
195
- expression: string;
196
- };
197
-
198
- /**
199
- * Helper to create default expressions
200
- */
201
- export const defaultExpr = (expression: string): DefaultExpression => ({
202
- _type: "expression",
203
- expression,
204
- });
205
-
206
- /**
207
- * Type-safe column definition
208
- */
209
- export interface ColumnDefinition extends ColumnConstraints {
210
- /** SQLite data type */
211
- type: SQLiteType;
212
- /** Optional type parameters (e.g., VARCHAR(255)) */
213
- length?: number;
214
- /** Precision for DECIMAL/NUMERIC types */
215
- precision?: number;
216
- /** Scale for DECIMAL/NUMERIC types */
217
- scale?: number;
218
- }
219
-
220
- /**
221
- * Type-safe table schema definition
222
- */
223
- export type TableSchema = Record<string, ColumnDefinition>;
224
-
225
-
226
- export type TypedTableSchema<T extends string = string> = Record<T, ColumnDefinition>;
227
-
228
- /**
229
- * Table constraint types
230
- */
231
- export interface TableConstraints {
232
- /** PRIMARY KEY constraint on multiple columns */
233
- primaryKey?: string[];
234
- /** UNIQUE constraints */
235
- unique?: string[] | string[][];
236
- /** CHECK constraints */
237
- check?: string[];
238
- /** FOREIGN KEY constraints */
239
- foreignKeys?: Array<{
240
- columns: string[];
241
- references: {
242
- table: string;
243
- columns: string[];
244
- onDelete?: ForeignKeyAction;
245
- onUpdate?: ForeignKeyAction;
246
- };
247
- }>;
248
- }
249
-
250
- /**
251
- * Enhanced table options
252
- */
253
- export interface TableOptions<T> {
254
- /** Add IF NOT EXISTS clause */
255
- ifNotExists?: boolean;
256
- /** Create WITHOUT ROWID table */
257
- withoutRowId?: boolean;
258
- /** Table constraints */
259
- constraints?: TableConstraints;
260
- /** Temporary table */
261
- temporary?: boolean;
262
- /** Table comment */
263
- comment?: string;
264
-
265
- jsonConfig?: JsonColumnConfig<T>
266
- }
267
-
268
- /**
269
- * Comprehensive column helper functions with full type support
270
- */
271
- export const column = {
272
- /**
273
- * Create an INTEGER column with optional size specification
274
- */
275
- integer: (
276
- constraints?: ColumnConstraints & {
277
- size?: "TINYINT" | "SMALLINT" | "MEDIUMINT" | "BIGINT";
278
- },
279
- ): ColumnDefinition => ({
280
- type: constraints?.size || SQLiteTypes.INTEGER,
281
- ...constraints,
282
- }),
283
-
284
- /**
285
- * Create a TEXT column with optional length
286
- */
287
- text: (
288
- constraints?: ColumnConstraints & {
289
- length?: number;
290
- variant?: "VARCHAR" | "CHAR" | "CLOB" | "NCHAR" | "NVARCHAR";
291
- },
292
- ): ColumnDefinition => ({
293
- type: constraints?.variant || SQLiteTypes.TEXT,
294
- length: constraints?.length,
295
- ...constraints,
296
- }),
297
-
298
- /**
299
- * Create a REAL column
300
- */
301
- real: (
302
- constraints?: ColumnConstraints & { variant?: "DOUBLE" | "FLOAT" },
303
- ): ColumnDefinition => ({
304
- type: constraints?.variant || SQLiteTypes.REAL,
305
- ...constraints,
306
- }),
307
-
308
- /**
309
- * Create a BLOB column
310
- */
311
- blob: (constraints?: ColumnConstraints): ColumnDefinition => ({
312
- type: SQLiteTypes.BLOB,
313
- ...constraints,
314
- }),
315
-
316
- /**
317
- * Create a NUMERIC/DECIMAL column with precision and scale
318
- */
319
- numeric: (
320
- constraints?: ColumnConstraints & {
321
- precision?: number;
322
- scale?: number;
323
- variant?: "DECIMAL";
324
- },
325
- ): ColumnDefinition => ({
326
- type: constraints?.variant || SQLiteTypes.NUMERIC,
327
- precision: constraints?.precision,
328
- scale: constraints?.scale,
329
- ...constraints,
330
- }),
331
-
332
- /**
333
- * Create a DATE column (stored as TEXT)
334
- */
335
- date: (constraints?: ColumnConstraints): ColumnDefinition => ({
336
- type: SQLiteTypes.DATE,
337
- ...constraints,
338
- }),
339
-
340
- /**
341
- * Create a DATETIME column (stored as TEXT)
342
- */
343
- datetime: (constraints?: ColumnConstraints): ColumnDefinition => ({
344
- type: SQLiteTypes.DATETIME,
345
- ...constraints,
346
- }),
347
-
348
- /**
349
- * Create a TIMESTAMP column (stored as INTEGER by default)
350
- */
351
- timestamp: (
352
- constraints?: ColumnConstraints & { asText?: boolean },
353
- ): ColumnDefinition => ({
354
- type: constraints?.asText ? SQLiteTypes.TEXT : SQLiteTypes.INTEGER,
355
- ...constraints,
356
- }),
357
-
358
- /**
359
- * Create a TIME column (stored as TEXT)
360
- */
361
- time: (constraints?: ColumnConstraints): ColumnDefinition => ({
362
- type: SQLiteTypes.TIME,
363
- ...constraints,
364
- }),
365
-
366
- /**
367
- * Create a BOOLEAN column (stored as INTEGER)
368
- */
369
- boolean: (constraints?: ColumnConstraints): ColumnDefinition => ({
370
- type: SQLiteTypes.BOOLEAN,
371
- check: constraints?.check || "{{COLUMN}} IN (0, 1)", // Placeholder for column name
372
- ...constraints,
373
- }),
374
-
375
- /**
376
- * Create a JSON column (stored as TEXT)
377
- */
378
- json: (
379
- constraints: ColumnConstraints & { validateJson?: boolean },
380
- ): ColumnDefinition => ({
381
- type: SQLiteTypes.JSON,
382
- check: constraints?.validateJson
383
- ? "JSON_VALID({{COLUMN}})"
384
- : constraints?.check,
385
- ...constraints,
386
- }),
387
-
388
- /**
389
- * Create a VARCHAR column with specified length
390
- */
391
- varchar: (
392
- length: number,
393
- constraints?: ColumnConstraints,
394
- ): ColumnDefinition => ({
395
- type: SQLiteTypes.VARCHAR,
396
- length,
397
- ...constraints,
398
- }),
399
-
400
- /**
401
- * Create a CHAR column with specified length
402
- */
403
- char: (
404
- length: number,
405
- constraints?: ColumnConstraints,
406
- ): ColumnDefinition => ({
407
- type: SQLiteTypes.CHAR,
408
- length,
409
- ...constraints,
410
- }),
411
-
412
- /**
413
- * Create an auto-incrementing primary key column
414
- */
415
- id: (
416
- constraints?: Omit<
417
- ColumnConstraints,
418
- "primaryKey" | "autoincrement" | "notNull"
419
- >,
420
- ): ColumnDefinition => ({
421
- type: SQLiteTypes.INTEGER,
422
- primaryKey: true,
423
- autoincrement: true,
424
- notNull: true,
425
- ...constraints,
426
- }),
427
-
428
- /**
429
- * Create a UUID column (stored as TEXT)
430
- */
431
- uuid: (
432
- constraints?: ColumnConstraints & { generateDefault?: boolean },
433
- ): ColumnDefinition => ({
434
- type: SQLiteTypes.TEXT,
435
- length: 36,
436
- default: constraints?.generateDefault
437
- ? defaultExpr(
438
- "lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-4' || substr(lower(hex(randomblob(2))),2) || '-' || substr('89ab',abs(random()) % 4 + 1, 1) || substr(lower(hex(randomblob(2))),2) || '-' || lower(hex(randomblob(6)))",
439
- )
440
- : constraints?.default,
441
- ...constraints,
442
- }),
443
-
444
- /**
445
- * Create a created_at timestamp column
446
- */
447
- createdAt: (
448
- constraints?: Omit<ColumnConstraints, "default" | "notNull"> & {
449
- asText?: boolean;
450
- },
451
- ): ColumnDefinition => ({
452
- type: constraints?.asText ? SQLiteTypes.DATETIME : SQLiteTypes.INTEGER,
453
- notNull: true,
454
- default: constraints?.asText
455
- ? defaultExpr("datetime('now')")
456
- : defaultExpr("strftime('%s', 'now')"),
457
- ...constraints,
458
- }),
459
-
460
- /**
461
- * Create an updated_at timestamp column
462
- */
463
- updatedAt: (
464
- constraints?: Omit<ColumnConstraints, "default"> & { asText?: boolean },
465
- ): ColumnDefinition => ({
466
- type: constraints?.asText ? SQLiteTypes.DATETIME : SQLiteTypes.INTEGER,
467
- default: constraints?.asText
468
- ? defaultExpr("datetime('now')")
469
- : defaultExpr("strftime('%s', 'now')"),
470
- ...constraints,
471
- }),
472
-
473
- /**
474
- * Create a foreign key reference column
475
- */
476
- foreignKey: (
477
- refTable: string,
478
- refColumn = "id",
479
- constraints?: ColumnConstraints & {
480
- onDelete?: ForeignKeyAction;
481
- onUpdate?: ForeignKeyAction;
482
- type?: SQLiteType;
483
- },
484
- ): ColumnDefinition => ({
485
- type: constraints?.type || SQLiteTypes.INTEGER,
486
- references: {
487
- table: refTable,
488
- column: refColumn,
489
- onDelete: constraints?.onDelete,
490
- onUpdate: constraints?.onUpdate,
491
- },
492
- ...constraints,
493
- }),
494
-
495
- /**
496
- * Create an enum column (with CHECK constraint)
497
- */
498
- enum: (
499
- values: string[],
500
- constraints?: ColumnConstraints,
501
- ): ColumnDefinition => ({
502
- type: SQLiteTypes.TEXT,
503
- notNull: true,
504
- check: `{{COLUMN}} IN (${values.map((v) => `'${v}'`).join(", ")})`,
505
- ...constraints,
506
- }),
507
- };
508
-
509
- /**
510
- * SQL function helpers for use in defaults and expressions
511
- */
512
- export const sql = {
513
- // Current date/time
514
- now: () => defaultExpr("datetime('now')"),
515
- currentTime: () => defaultExpr("time('now')"),
516
- currentDate: () => defaultExpr("date('now')"),
517
- currentTimestamp: () => defaultExpr("datetime('now')"),
518
- unixTimestamp: () => defaultExpr("strftime('%s', 'now')"),
519
-
520
- // Functions
521
- ...SQLiteFunctions,
522
-
523
- // Raw expression
524
- raw: (expression: string) => defaultExpr(expression),
525
-
526
- // Literals
527
- null: () => null,
528
- true: () => 1,
529
- false: () => 0,
530
- };
531
-
532
- /**
533
- * Enhanced createTable method signature
534
- */
535
- export type CreateTableColumns = string | Record<string, string> | TableSchema;
536
-
537
- /**
538
- * Query builder state interface
539
- */
540
- export interface QueryBuilderState<T extends Record<string, unknown>> {
541
- db: Database; // Database instance from bun:sqlite
542
- tableName: string;
543
- whereConditions: string[];
544
- whereParams: SQLQueryBindings[];
545
- regexConditions: Array<{
546
- column: keyof T;
547
- regex: RegExp;
548
- }>;
549
- jsonColumns?: Array<keyof T>;
550
- }
551
-
552
- /**
553
- * Column names type for SELECT operations
554
- */
555
- export type ColumnNames<T> = ["*"] | Array<keyof T>;
556
-
557
- /**
558
- * Order direction for ORDER BY clauses
559
- */
560
- export type OrderDirection = "ASC" | "DESC";
561
-
562
- /**
563
- * WHERE condition object type
564
- */
565
- export type WhereCondition<T> = Partial<T>;
566
-
567
- /**
568
- * Regex condition object type
569
- */
570
- export type RegexCondition<T> = Partial<Record<keyof T, RegExp | string>>;
571
-
572
- /**
573
- * Insert result interface
574
- */
575
- export interface InsertResult {
576
- insertId: number;
577
- changes: number;
578
- }
579
-
580
- /**
581
- * Update result interface
582
- */
583
- export interface UpdateResult {
584
- changes: number;
585
- }
586
-
587
- /**
588
- * Delete result interface
589
- */
590
- export interface DeleteResult {
591
- changes: number;
592
- }
593
-
594
- /**
595
- * Insert options interface
596
- */
597
- export interface InsertOptions {
598
- orIgnore?: boolean;
599
- orReplace?: boolean;
600
- orAbort?: boolean;
601
- orFail?: boolean;
602
- orRollback?: boolean;
603
- }
604
-
605
- /**
606
- * JSON column configuration
607
- */
608
- export type JsonColumnConfig<T> = Array<keyof T>
609
-
610
- /**
611
- * Generic database row type
612
- */
613
- export type DatabaseRow = Record<string, unknown>;
614
-
615
- /**
616
- * SQL parameter type
617
- */
618
- export type SqlParameter = SQLQueryBindings;
619
-
620
- /**
621
- * Database row with unknown structure
622
- */
623
- export type DatabaseRowData = Record<string, SQLQueryBindings>;
1
+ import type { Database, SQLQueryBindings } from "bun:sqlite";
2
+
3
+ /**
4
+ * All SQLite data types including affinity types
5
+ */
6
+ export const SQLiteTypes = {
7
+ // Standard SQLite types
8
+ INTEGER: "INTEGER" as const,
9
+ TEXT: "TEXT" as const,
10
+ REAL: "REAL" as const,
11
+ BLOB: "BLOB" as const,
12
+ NUMERIC: "NUMERIC" as const,
13
+
14
+ // Common type aliases and variations
15
+ INT: "INT" as const,
16
+ TINYINT: "TINYINT" as const,
17
+ SMALLINT: "SMALLINT" as const,
18
+ MEDIUMINT: "MEDIUMINT" as const,
19
+ BIGINT: "BIGINT" as const,
20
+
21
+ // Text variations
22
+ VARCHAR: "VARCHAR" as const,
23
+ CHAR: "CHAR" as const,
24
+ CHARACTER: "CHARACTER" as const,
25
+ NCHAR: "NCHAR" as const,
26
+ NVARCHAR: "NVARCHAR" as const,
27
+ CLOB: "CLOB" as const,
28
+
29
+ // Numeric variations
30
+ DOUBLE: "DOUBLE" as const,
31
+ FLOAT: "FLOAT" as const,
32
+ DECIMAL: "DECIMAL" as const,
33
+
34
+ // Date/Time (stored as TEXT, INTEGER, or REAL)
35
+ DATE: "DATE" as const,
36
+ DATETIME: "DATETIME" as const,
37
+ TIMESTAMP: "TIMESTAMP" as const,
38
+ TIME: "TIME" as const,
39
+
40
+ // Boolean (stored as INTEGER)
41
+ BOOLEAN: "BOOLEAN" as const,
42
+
43
+ // JSON (stored as TEXT)
44
+ JSON: "JSON" as const,
45
+ } as const;
46
+
47
+ export type SQLiteType = (typeof SQLiteTypes)[keyof typeof SQLiteTypes];
48
+
49
+ /**
50
+ * SQLite built-in scalar functions
51
+ */
52
+ export const SQLiteFunctions = {
53
+ // Date/Time functions
54
+ DATE: (expr: string) => `DATE(${expr})`,
55
+ TIME: (expr: string) => `TIME(${expr})`,
56
+ DATETIME: (expr: string) => `DATETIME(${expr})`,
57
+ JULIANDAY: (expr: string) => `JULIANDAY(${expr})`,
58
+ STRFTIME: (format: string, expr: string) => `STRFTIME('${format}', ${expr})`,
59
+
60
+ // String functions
61
+ LENGTH: (expr: string) => `LENGTH(${expr})`,
62
+ LOWER: (expr: string) => `LOWER(${expr})`,
63
+ UPPER: (expr: string) => `UPPER(${expr})`,
64
+ TRIM: (expr: string, chars?: string) =>
65
+ chars ? `TRIM(${expr}, '${chars}')` : `TRIM(${expr})`,
66
+ LTRIM: (expr: string, chars?: string) =>
67
+ chars ? `LTRIM(${expr}, '${chars}')` : `LTRIM(${expr})`,
68
+ RTRIM: (expr: string, chars?: string) =>
69
+ chars ? `RTRIM(${expr}, '${chars}')` : `RTRIM(${expr})`,
70
+ SUBSTR: (expr: string, start: number, length?: number) =>
71
+ length
72
+ ? `SUBSTR(${expr}, ${start}, ${length})`
73
+ : `SUBSTR(${expr}, ${start})`,
74
+ SUBSTRING: (expr: string, start: number, length?: number) =>
75
+ length
76
+ ? `SUBSTRING(${expr}, ${start}, ${length})`
77
+ : `SUBSTRING(${expr}, ${start})`,
78
+ REPLACE: (expr: string, old: string, replacement: string) =>
79
+ `REPLACE(${expr}, '${old}', '${replacement}')`,
80
+ PRINTF: (format: string, ...args: string[]) =>
81
+ `PRINTF('${format}', ${args.join(", ")})`,
82
+
83
+ // Math functions
84
+ ABS: (expr: string) => `ABS(${expr})`,
85
+ ROUND: (expr: string, digits?: number) =>
86
+ digits !== undefined ? `ROUND(${expr}, ${digits})` : `ROUND(${expr})`,
87
+ RANDOM: () => "RANDOM()",
88
+ MIN: (...exprs: string[]) => `MIN(${exprs.join(", ")})`,
89
+ MAX: (...exprs: string[]) => `MAX(${exprs.join(", ")})`,
90
+
91
+ // Type conversion
92
+ CAST: (expr: string, type: string) => `CAST(${expr} AS ${type})`,
93
+ TYPEOF: (expr: string) => `TYPEOF(${expr})`,
94
+
95
+ // Conditional
96
+ COALESCE: (...exprs: string[]) => `COALESCE(${exprs.join(", ")})`,
97
+ IFNULL: (expr: string, replacement: string) =>
98
+ `IFNULL(${expr}, ${replacement})`,
99
+ NULLIF: (expr1: string, expr2: string) => `NULLIF(${expr1}, ${expr2})`,
100
+ IIF: (condition: string, trueValue: string, falseValue: string) =>
101
+ `IIF(${condition}, ${trueValue}, ${falseValue})`,
102
+
103
+ // Aggregate functions (for use in expressions)
104
+ COUNT: (expr?: string) => (expr ? `COUNT(${expr})` : "COUNT(*)"),
105
+ SUM: (expr: string) => `SUM(${expr})`,
106
+ AVG: (expr: string) => `AVG(${expr})`,
107
+ TOTAL: (expr: string) => `TOTAL(${expr})`,
108
+ GROUP_CONCAT: (expr: string, separator?: string) =>
109
+ separator
110
+ ? `GROUP_CONCAT(${expr}, '${separator}')`
111
+ : `GROUP_CONCAT(${expr})`,
112
+
113
+ // JSON functions (SQLite 3.45+)
114
+ JSON: (expr: string) => `JSON(${expr})`,
115
+ JSON_EXTRACT: (json: string, path: string) =>
116
+ `JSON_EXTRACT(${json}, '${path}')`,
117
+ JSON_TYPE: (json: string, path?: string) =>
118
+ path ? `JSON_TYPE(${json}, '${path}')` : `JSON_TYPE(${json})`,
119
+ JSON_VALID: (expr: string) => `JSON_VALID(${expr})`,
120
+ JSON_ARRAY: (...values: string[]) => `JSON_ARRAY(${values.join(", ")})`,
121
+ JSON_OBJECT: (...pairs: string[]) => `JSON_OBJECT(${pairs.join(", ")})`,
122
+ } as const;
123
+
124
+ /**
125
+ * SQLite keywords and special values
126
+ */
127
+ export const SQLiteKeywords = {
128
+ // Special values
129
+ NULL: "NULL" as const,
130
+ CURRENT_TIME: "CURRENT_TIME" as const,
131
+ CURRENT_DATE: "CURRENT_DATE" as const,
132
+ CURRENT_TIMESTAMP: "CURRENT_TIMESTAMP" as const,
133
+
134
+ // Boolean values (as integers)
135
+ TRUE: "1" as const,
136
+ FALSE: "0" as const,
137
+
138
+ // Conflict resolution
139
+ ROLLBACK: "ROLLBACK" as const,
140
+ ABORT: "ABORT" as const,
141
+ FAIL: "FAIL" as const,
142
+ IGNORE: "IGNORE" as const,
143
+ REPLACE: "REPLACE" as const,
144
+ } as const;
145
+
146
+ /**
147
+ * Foreign key actions
148
+ */
149
+ export type ForeignKeyAction =
150
+ | "CASCADE"
151
+ | "SET NULL"
152
+ | "RESTRICT"
153
+ | "NO ACTION"
154
+ | "SET DEFAULT";
155
+
156
+ /**
157
+ * Column constraint options with comprehensive support
158
+ */
159
+ export interface ColumnConstraints {
160
+ /** Column is PRIMARY KEY */
161
+ primaryKey?: boolean;
162
+ /** Column has AUTOINCREMENT (only valid with INTEGER PRIMARY KEY) */
163
+ autoincrement?: boolean;
164
+ /** Column is NOT NULL */
165
+ notNull?: boolean;
166
+ /** Column has UNIQUE constraint */
167
+ unique?: boolean;
168
+ /** Default value - can be literal value, function call, or keyword */
169
+ default?: string | number | boolean | null | DefaultExpression;
170
+ /** Custom check constraint */
171
+ check?: string;
172
+ /** Collation sequence */
173
+ collate?: "BINARY" | "NOCASE" | "RTRIM" | string;
174
+ /** References another table (foreign key) */
175
+ references?: {
176
+ table: string;
177
+ column: string;
178
+ onDelete?: ForeignKeyAction;
179
+ onUpdate?: ForeignKeyAction;
180
+ };
181
+ /** Generated column expression (GENERATED ALWAYS AS) */
182
+ generated?: {
183
+ expression: string;
184
+ stored?: boolean; // true for STORED, false/undefined for VIRTUAL
185
+ };
186
+ /** Column comment (stored as metadata, not in schema) */
187
+ comment?: string;
188
+ }
189
+
190
+ /**
191
+ * Type-safe default value expressions
192
+ */
193
+ export type DefaultExpression = {
194
+ _type: "expression";
195
+ expression: string;
196
+ };
197
+
198
+ /**
199
+ * Helper to create default expressions
200
+ */
201
+ export const defaultExpr = (expression: string): DefaultExpression => ({
202
+ _type: "expression",
203
+ expression,
204
+ });
205
+
206
+ /**
207
+ * Type-safe column definition
208
+ */
209
+ export interface ColumnDefinition extends ColumnConstraints {
210
+ /** SQLite data type */
211
+ type: SQLiteType;
212
+ /** Optional type parameters (e.g., VARCHAR(255)) */
213
+ length?: number;
214
+ /** Precision for DECIMAL/NUMERIC types */
215
+ precision?: number;
216
+ /** Scale for DECIMAL/NUMERIC types */
217
+ scale?: number;
218
+ }
219
+
220
+ /**
221
+ * Type-safe table schema definition
222
+ */
223
+ export type TableSchema = Record<string, ColumnDefinition>;
224
+
225
+
226
+ export type TypedTableSchema<T extends string = string> = Record<T, ColumnDefinition>;
227
+
228
+ /**
229
+ * Table constraint types
230
+ */
231
+ export interface TableConstraints {
232
+ /** PRIMARY KEY constraint on multiple columns */
233
+ primaryKey?: string[];
234
+ /** UNIQUE constraints */
235
+ unique?: string[] | string[][];
236
+ /** CHECK constraints */
237
+ check?: string[];
238
+ /** FOREIGN KEY constraints */
239
+ foreignKeys?: Array<{
240
+ columns: string[];
241
+ references: {
242
+ table: string;
243
+ columns: string[];
244
+ onDelete?: ForeignKeyAction;
245
+ onUpdate?: ForeignKeyAction;
246
+ };
247
+ }>;
248
+ }
249
+
250
+ /**
251
+ * Enhanced table options
252
+ */
253
+ export interface TableOptions<T> {
254
+ /** Add IF NOT EXISTS clause */
255
+ ifNotExists?: boolean;
256
+ /** Create WITHOUT ROWID table */
257
+ withoutRowId?: boolean;
258
+ /** Table constraints */
259
+ constraints?: TableConstraints;
260
+ /** Temporary table */
261
+ temporary?: boolean;
262
+ /** Table comment */
263
+ comment?: string;
264
+
265
+ jsonConfig?: JsonColumnConfig<T>
266
+ }
267
+
268
+ /**
269
+ * Comprehensive column helper functions with full type support
270
+ */
271
+ export const column = {
272
+ /**
273
+ * Create an INTEGER column with optional size specification
274
+ */
275
+ integer: (
276
+ constraints?: ColumnConstraints & {
277
+ size?: "TINYINT" | "SMALLINT" | "MEDIUMINT" | "BIGINT";
278
+ },
279
+ ): ColumnDefinition => ({
280
+ type: constraints?.size || SQLiteTypes.INTEGER,
281
+ ...constraints,
282
+ }),
283
+
284
+ /**
285
+ * Create a TEXT column with optional length
286
+ */
287
+ text: (
288
+ constraints?: ColumnConstraints & {
289
+ length?: number;
290
+ variant?: "VARCHAR" | "CHAR" | "CLOB" | "NCHAR" | "NVARCHAR";
291
+ },
292
+ ): ColumnDefinition => ({
293
+ type: constraints?.variant || SQLiteTypes.TEXT,
294
+ length: constraints?.length,
295
+ ...constraints,
296
+ }),
297
+
298
+ /**
299
+ * Create a REAL column
300
+ */
301
+ real: (
302
+ constraints?: ColumnConstraints & { variant?: "DOUBLE" | "FLOAT" },
303
+ ): ColumnDefinition => ({
304
+ type: constraints?.variant || SQLiteTypes.REAL,
305
+ ...constraints,
306
+ }),
307
+
308
+ /**
309
+ * Create a BLOB column
310
+ */
311
+ blob: (constraints?: ColumnConstraints): ColumnDefinition => ({
312
+ type: SQLiteTypes.BLOB,
313
+ ...constraints,
314
+ }),
315
+
316
+ /**
317
+ * Create a NUMERIC/DECIMAL column with precision and scale
318
+ */
319
+ numeric: (
320
+ constraints?: ColumnConstraints & {
321
+ precision?: number;
322
+ scale?: number;
323
+ variant?: "DECIMAL";
324
+ },
325
+ ): ColumnDefinition => ({
326
+ type: constraints?.variant || SQLiteTypes.NUMERIC,
327
+ precision: constraints?.precision,
328
+ scale: constraints?.scale,
329
+ ...constraints,
330
+ }),
331
+
332
+ /**
333
+ * Create a DATE column (stored as TEXT)
334
+ */
335
+ date: (constraints?: ColumnConstraints): ColumnDefinition => ({
336
+ type: SQLiteTypes.DATE,
337
+ ...constraints,
338
+ }),
339
+
340
+ /**
341
+ * Create a DATETIME column (stored as TEXT)
342
+ */
343
+ datetime: (constraints?: ColumnConstraints): ColumnDefinition => ({
344
+ type: SQLiteTypes.DATETIME,
345
+ ...constraints,
346
+ }),
347
+
348
+ /**
349
+ * Create a TIMESTAMP column (stored as INTEGER by default)
350
+ */
351
+ timestamp: (
352
+ constraints?: ColumnConstraints & { asText?: boolean },
353
+ ): ColumnDefinition => ({
354
+ type: constraints?.asText ? SQLiteTypes.TEXT : SQLiteTypes.INTEGER,
355
+ ...constraints,
356
+ }),
357
+
358
+ /**
359
+ * Create a TIME column (stored as TEXT)
360
+ */
361
+ time: (constraints?: ColumnConstraints): ColumnDefinition => ({
362
+ type: SQLiteTypes.TIME,
363
+ ...constraints,
364
+ }),
365
+
366
+ /**
367
+ * Create a BOOLEAN column (stored as INTEGER)
368
+ */
369
+ boolean: (constraints?: ColumnConstraints): ColumnDefinition => ({
370
+ type: SQLiteTypes.BOOLEAN,
371
+ check: constraints?.check || "{{COLUMN}} IN (0, 1)", // Placeholder for column name
372
+ ...constraints,
373
+ }),
374
+
375
+ /**
376
+ * Create a JSON column (stored as TEXT)
377
+ */
378
+ json: (
379
+ constraints: ColumnConstraints & { validateJson?: boolean },
380
+ ): ColumnDefinition => ({
381
+ type: SQLiteTypes.JSON,
382
+ check: constraints?.validateJson
383
+ ? "JSON_VALID({{COLUMN}})"
384
+ : constraints?.check,
385
+ ...constraints,
386
+ }),
387
+
388
+ /**
389
+ * Create a VARCHAR column with specified length
390
+ */
391
+ varchar: (
392
+ length: number,
393
+ constraints?: ColumnConstraints,
394
+ ): ColumnDefinition => ({
395
+ type: SQLiteTypes.VARCHAR,
396
+ length,
397
+ ...constraints,
398
+ }),
399
+
400
+ /**
401
+ * Create a CHAR column with specified length
402
+ */
403
+ char: (
404
+ length: number,
405
+ constraints?: ColumnConstraints,
406
+ ): ColumnDefinition => ({
407
+ type: SQLiteTypes.CHAR,
408
+ length,
409
+ ...constraints,
410
+ }),
411
+
412
+ /**
413
+ * Create an auto-incrementing primary key column
414
+ */
415
+ id: (
416
+ constraints?: Omit<
417
+ ColumnConstraints,
418
+ "primaryKey" | "autoincrement" | "notNull"
419
+ >,
420
+ ): ColumnDefinition => ({
421
+ type: SQLiteTypes.INTEGER,
422
+ primaryKey: true,
423
+ autoincrement: true,
424
+ notNull: true,
425
+ ...constraints,
426
+ }),
427
+
428
+ /**
429
+ * Create a UUID column (stored as TEXT)
430
+ */
431
+ uuid: (
432
+ constraints?: ColumnConstraints & { generateDefault?: boolean },
433
+ ): ColumnDefinition => ({
434
+ type: SQLiteTypes.TEXT,
435
+ length: 36,
436
+ default: constraints?.generateDefault
437
+ ? defaultExpr(
438
+ "lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-4' || substr(lower(hex(randomblob(2))),2) || '-' || substr('89ab',abs(random()) % 4 + 1, 1) || substr(lower(hex(randomblob(2))),2) || '-' || lower(hex(randomblob(6)))",
439
+ )
440
+ : constraints?.default,
441
+ ...constraints,
442
+ }),
443
+
444
+ /**
445
+ * Create a created_at timestamp column
446
+ */
447
+ createdAt: (
448
+ constraints?: Omit<ColumnConstraints, "default" | "notNull"> & {
449
+ asText?: boolean;
450
+ },
451
+ ): ColumnDefinition => ({
452
+ type: constraints?.asText ? SQLiteTypes.DATETIME : SQLiteTypes.INTEGER,
453
+ notNull: true,
454
+ default: constraints?.asText
455
+ ? defaultExpr("datetime('now')")
456
+ : defaultExpr("strftime('%s', 'now')"),
457
+ ...constraints,
458
+ }),
459
+
460
+ /**
461
+ * Create an updated_at timestamp column
462
+ */
463
+ updatedAt: (
464
+ constraints?: Omit<ColumnConstraints, "default"> & { asText?: boolean },
465
+ ): ColumnDefinition => ({
466
+ type: constraints?.asText ? SQLiteTypes.DATETIME : SQLiteTypes.INTEGER,
467
+ default: constraints?.asText
468
+ ? defaultExpr("datetime('now')")
469
+ : defaultExpr("strftime('%s', 'now')"),
470
+ ...constraints,
471
+ }),
472
+
473
+ /**
474
+ * Create a foreign key reference column
475
+ */
476
+ foreignKey: (
477
+ refTable: string,
478
+ refColumn = "id",
479
+ constraints?: ColumnConstraints & {
480
+ onDelete?: ForeignKeyAction;
481
+ onUpdate?: ForeignKeyAction;
482
+ type?: SQLiteType;
483
+ },
484
+ ): ColumnDefinition => ({
485
+ type: constraints?.type || SQLiteTypes.INTEGER,
486
+ references: {
487
+ table: refTable,
488
+ column: refColumn,
489
+ onDelete: constraints?.onDelete,
490
+ onUpdate: constraints?.onUpdate,
491
+ },
492
+ ...constraints,
493
+ }),
494
+
495
+ /**
496
+ * Create an enum column (with CHECK constraint)
497
+ */
498
+ enum: (
499
+ values: string[],
500
+ constraints?: ColumnConstraints,
501
+ ): ColumnDefinition => ({
502
+ type: SQLiteTypes.TEXT,
503
+ notNull: true,
504
+ check: `{{COLUMN}} IN (${values.map((v) => `'${v}'`).join(", ")})`,
505
+ ...constraints,
506
+ }),
507
+ };
508
+
509
+ /**
510
+ * SQL function helpers for use in defaults and expressions
511
+ */
512
+ export const sql = {
513
+ // Current date/time
514
+ now: () => defaultExpr("datetime('now')"),
515
+ currentTime: () => defaultExpr("time('now')"),
516
+ currentDate: () => defaultExpr("date('now')"),
517
+ currentTimestamp: () => defaultExpr("datetime('now')"),
518
+ unixTimestamp: () => defaultExpr("strftime('%s', 'now')"),
519
+
520
+ // Functions
521
+ ...SQLiteFunctions,
522
+
523
+ // Raw expression
524
+ raw: (expression: string) => defaultExpr(expression),
525
+
526
+ // Literals
527
+ null: () => null,
528
+ true: () => 1,
529
+ false: () => 0,
530
+ };
531
+
532
+ /**
533
+ * Enhanced createTable method signature
534
+ */
535
+ export type CreateTableColumns = string | Record<string, string> | TableSchema;
536
+
537
+ /**
538
+ * Query builder state interface
539
+ */
540
+ export interface QueryBuilderState<T extends Record<string, unknown>> {
541
+ db: Database; // Database instance from bun:sqlite
542
+ tableName: string;
543
+ whereConditions: string[];
544
+ whereParams: SQLQueryBindings[];
545
+ regexConditions: Array<{
546
+ column: keyof T;
547
+ regex: RegExp;
548
+ }>;
549
+ jsonColumns?: Array<keyof T>;
550
+ }
551
+
552
+ /**
553
+ * Column names type for SELECT operations
554
+ */
555
+ export type ColumnNames<T> = ["*"] | Array<keyof T>;
556
+
557
+ /**
558
+ * Order direction for ORDER BY clauses
559
+ */
560
+ export type OrderDirection = "ASC" | "DESC";
561
+
562
+ /**
563
+ * WHERE condition object type
564
+ */
565
+ export type WhereCondition<T> = Partial<T>;
566
+
567
+ /**
568
+ * Regex condition object type
569
+ */
570
+ export type RegexCondition<T> = Partial<Record<keyof T, RegExp | string>>;
571
+
572
+ /**
573
+ * Insert result interface
574
+ */
575
+ export interface InsertResult {
576
+ insertId: number;
577
+ changes: number;
578
+ }
579
+
580
+ /**
581
+ * Update result interface
582
+ */
583
+ export interface UpdateResult {
584
+ changes: number;
585
+ }
586
+
587
+ /**
588
+ * Delete result interface
589
+ */
590
+ export interface DeleteResult {
591
+ changes: number;
592
+ }
593
+
594
+ /**
595
+ * Insert options interface
596
+ */
597
+ export interface InsertOptions {
598
+ orIgnore?: boolean;
599
+ orReplace?: boolean;
600
+ orAbort?: boolean;
601
+ orFail?: boolean;
602
+ orRollback?: boolean;
603
+ }
604
+
605
+ /**
606
+ * JSON column configuration
607
+ */
608
+ export type JsonColumnConfig<T> = Array<keyof T>
609
+
610
+ /**
611
+ * Generic database row type
612
+ */
613
+ export type DatabaseRow = Record<string, unknown>;
614
+
615
+ /**
616
+ * SQL parameter type
617
+ */
618
+ export type SqlParameter = SQLQueryBindings;
619
+
620
+ /**
621
+ * Database row with unknown structure
622
+ */
623
+ export type DatabaseRowData = Record<string, SQLQueryBindings>;