speexjs 0.2.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.
Files changed (67) hide show
  1. package/README.md +555 -0
  2. package/dist/cli/index.d.ts +1 -0
  3. package/dist/cli/index.js +1017 -0
  4. package/dist/cli/index.js.map +1 -0
  5. package/dist/client/index.d.ts +73 -0
  6. package/dist/client/index.js +927 -0
  7. package/dist/client/index.js.map +1 -0
  8. package/dist/client/signals/index.d.ts +62 -0
  9. package/dist/client/signals/index.js +248 -0
  10. package/dist/client/signals/index.js.map +1 -0
  11. package/dist/client/vdom/index.d.ts +50 -0
  12. package/dist/client/vdom/index.js +540 -0
  13. package/dist/client/vdom/index.js.map +1 -0
  14. package/dist/client/vdom/jsx-runtime.d.ts +9 -0
  15. package/dist/client/vdom/jsx-runtime.js +203 -0
  16. package/dist/client/vdom/jsx-runtime.js.map +1 -0
  17. package/dist/index-CMkhSDh7.d.ts +97 -0
  18. package/dist/index.d.ts +18 -0
  19. package/dist/index.js +6402 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/jsx-DGrnv8QB.d.ts +8 -0
  22. package/dist/response-Ca8KWK5_.d.ts +173 -0
  23. package/dist/rpc/index.d.ts +70 -0
  24. package/dist/rpc/index.js +136 -0
  25. package/dist/rpc/index.js.map +1 -0
  26. package/dist/schema/index.d.ts +231 -0
  27. package/dist/schema/index.js +1160 -0
  28. package/dist/schema/index.js.map +1 -0
  29. package/dist/server/auth/index.d.ts +61 -0
  30. package/dist/server/auth/index.js +462 -0
  31. package/dist/server/auth/index.js.map +1 -0
  32. package/dist/server/cache/index.d.ts +45 -0
  33. package/dist/server/cache/index.js +238 -0
  34. package/dist/server/cache/index.js.map +1 -0
  35. package/dist/server/container/index.d.ts +20 -0
  36. package/dist/server/container/index.js +62 -0
  37. package/dist/server/container/index.js.map +1 -0
  38. package/dist/server/controller/index.d.ts +37 -0
  39. package/dist/server/controller/index.js +139 -0
  40. package/dist/server/controller/index.js.map +1 -0
  41. package/dist/server/database/index.d.ts +461 -0
  42. package/dist/server/database/index.js +1977 -0
  43. package/dist/server/database/index.js.map +1 -0
  44. package/dist/server/events/index.d.ts +29 -0
  45. package/dist/server/events/index.js +159 -0
  46. package/dist/server/events/index.js.map +1 -0
  47. package/dist/server/gate/index.d.ts +36 -0
  48. package/dist/server/gate/index.js +169 -0
  49. package/dist/server/gate/index.js.map +1 -0
  50. package/dist/server/http/index.d.ts +45 -0
  51. package/dist/server/http/index.js +871 -0
  52. package/dist/server/http/index.js.map +1 -0
  53. package/dist/server/index.d.ts +79 -0
  54. package/dist/server/index.js +4185 -0
  55. package/dist/server/index.js.map +1 -0
  56. package/dist/server/middleware/index.d.ts +5 -0
  57. package/dist/server/middleware/index.js +416 -0
  58. package/dist/server/middleware/index.js.map +1 -0
  59. package/dist/server/router/index.d.ts +5 -0
  60. package/dist/server/router/index.js +231 -0
  61. package/dist/server/router/index.js.map +1 -0
  62. package/dist/server/storage/index.d.ts +66 -0
  63. package/dist/server/storage/index.js +244 -0
  64. package/dist/server/storage/index.js.map +1 -0
  65. package/dist/session-guard-CZeN87L9.d.ts +48 -0
  66. package/dist/types-CXH8hPei.d.ts +38 -0
  67. package/package.json +138 -0
@@ -0,0 +1,1977 @@
1
+ // src/server/database/connection.ts
2
+ import { randomUUID } from "crypto";
3
+
4
+ // src/server/database/dialect.ts
5
+ var MysqlDialect = class {
6
+ wrapIdentifier(identifier) {
7
+ return `\`${identifier.replace(/`/g, "``")}\``;
8
+ }
9
+ makeParameter(_index) {
10
+ return "?";
11
+ }
12
+ compileLimitOffset(bindings, limit, offset) {
13
+ if (limit === null && offset === null) return "";
14
+ if (offset !== null) {
15
+ bindings.push(limit ?? 0, offset);
16
+ return " LIMIT ? OFFSET ?";
17
+ }
18
+ bindings.push(limit);
19
+ return " LIMIT ?";
20
+ }
21
+ compileInsertReturning(sql, _bindings, _idColumn) {
22
+ return `${sql}; SELECT LAST_INSERT_ID() as id`;
23
+ }
24
+ compileTruncate(tableName) {
25
+ return `TRUNCATE TABLE ${this.wrapIdentifier(tableName)}`;
26
+ }
27
+ compileCreateMigrationsTable() {
28
+ return `CREATE TABLE IF NOT EXISTS \`migrations\` (
29
+ \`id\` INT AUTO_INCREMENT PRIMARY KEY,
30
+ \`name\` VARCHAR(255) NOT NULL,
31
+ \`batch\` INT NOT NULL,
32
+ \`executed_at\` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
33
+ )`;
34
+ }
35
+ mapType(type, options) {
36
+ switch (type) {
37
+ case "id":
38
+ case "increments":
39
+ return "INT AUTO_INCREMENT PRIMARY KEY";
40
+ case "bigIncrements":
41
+ return "BIGINT AUTO_INCREMENT PRIMARY KEY";
42
+ case "string":
43
+ return `VARCHAR(${options.length ?? 255})`;
44
+ case "text":
45
+ return "TEXT";
46
+ case "integer":
47
+ return "INT";
48
+ case "bigInteger":
49
+ return "BIGINT";
50
+ case "tinyInteger":
51
+ return "TINYINT";
52
+ case "smallInteger":
53
+ return "SMALLINT";
54
+ case "boolean":
55
+ return "TINYINT(1)";
56
+ case "float":
57
+ return "FLOAT";
58
+ case "double":
59
+ return "DOUBLE";
60
+ case "decimal":
61
+ return `DECIMAL(${options.precision ?? 10},${options.scale ?? 0})`;
62
+ case "date":
63
+ return "DATE";
64
+ case "datetime":
65
+ return "DATETIME";
66
+ case "timestamp":
67
+ return "TIMESTAMP";
68
+ case "time":
69
+ return "TIME";
70
+ case "year":
71
+ return "YEAR";
72
+ case "json":
73
+ case "jsonb":
74
+ return "JSON";
75
+ case "binary":
76
+ return "BLOB";
77
+ case "uuid":
78
+ return "CHAR(36)";
79
+ case "foreignId":
80
+ return "INT UNSIGNED";
81
+ default:
82
+ return type;
83
+ }
84
+ }
85
+ compileColumn(options) {
86
+ let sql = `${this.wrapIdentifier(options.name)} ${this.mapType(options.type, options)}`;
87
+ if (options.unsigned && options.type !== "id" && options.type !== "increments" && options.type !== "bigIncrements" && options.type !== "foreignId")
88
+ sql += " UNSIGNED";
89
+ if (options.autoIncrement && options.type !== "id" && options.type !== "increments" && options.type !== "bigIncrements")
90
+ sql += " AUTO_INCREMENT";
91
+ if (options.defaultValue !== void 0 && options.defaultValue !== null) {
92
+ sql += ` DEFAULT ${this.formatDefault(options.defaultValue)}`;
93
+ } else if (!options.nullable && !options.autoIncrement && options.type !== "id" && options.type !== "increments" && options.type !== "bigIncrements") {
94
+ sql += " NOT NULL";
95
+ }
96
+ if (options.nullable) sql += " NULL";
97
+ if (options.primary) sql += " PRIMARY KEY";
98
+ if (options.unique) sql += " UNIQUE";
99
+ if (options.comment !== null)
100
+ sql += ` COMMENT '${options.comment.replace(/'/g, "\\'")}'`;
101
+ if (options.after !== null)
102
+ sql += ` AFTER ${this.wrapIdentifier(options.after)}`;
103
+ return sql;
104
+ }
105
+ compileModifyColumn(options) {
106
+ return `MODIFY COLUMN ${this.compileColumn(options)}`;
107
+ }
108
+ compileTableBlueprint(_tableName, columns, constraints) {
109
+ const parts = [
110
+ ...columns.map((c) => this.compileColumn(c)),
111
+ ...constraints
112
+ ];
113
+ return parts.join(",\n ");
114
+ }
115
+ compileAddColumns(_tableName, columns) {
116
+ return `ADD ${columns.map((c) => this.compileColumn(c)).join(", ADD ")}`;
117
+ }
118
+ compileDropColumns(_tableName, columns) {
119
+ return `DROP COLUMN ${columns.map((c) => this.wrapIdentifier(c)).join(", DROP COLUMN ")}`;
120
+ }
121
+ compileRenameColumn(_tableName, from, to) {
122
+ return `RENAME COLUMN ${this.wrapIdentifier(from)} TO ${this.wrapIdentifier(to)}`;
123
+ }
124
+ compileCreateTable(tableName, columns, constraints) {
125
+ const body = this.compileTableBlueprint(tableName, columns, constraints);
126
+ return `CREATE TABLE ${this.wrapIdentifier(tableName)} (
127
+ ${body}
128
+ )`;
129
+ }
130
+ compileRenameTable(from, to) {
131
+ return `RENAME TABLE ${this.wrapIdentifier(from)} TO ${this.wrapIdentifier(to)}`;
132
+ }
133
+ compileDropTable(tableName) {
134
+ return `DROP TABLE ${this.wrapIdentifier(tableName)}`;
135
+ }
136
+ compileDropTableIfExists(tableName) {
137
+ return `DROP TABLE IF EXISTS ${this.wrapIdentifier(tableName)}`;
138
+ }
139
+ compileHasTable(_tableName) {
140
+ return `SELECT COUNT(*) as \`count\` FROM \`information_schema\`.\`tables\` WHERE \`table_schema\` = DATABASE() AND \`table_name\` = ?`;
141
+ }
142
+ compileHasColumn(_tableName, _columnName) {
143
+ return `SELECT COUNT(*) as \`count\` FROM \`information_schema\`.\`columns\` WHERE \`table_schema\` = DATABASE() AND \`table_name\` = ? AND \`column_name\` = ?`;
144
+ }
145
+ compileInsert(sql) {
146
+ return sql;
147
+ }
148
+ formatDefault(value) {
149
+ if (typeof value === "string") {
150
+ if (value === "CURRENT_TIMESTAMP") return value;
151
+ return `'${value.replace(/'/g, "\\'")}'`;
152
+ }
153
+ if (value === null) return "NULL";
154
+ if (typeof value === "boolean") return value ? "1" : "0";
155
+ return String(value);
156
+ }
157
+ };
158
+ var SqliteDialect = class {
159
+ wrapIdentifier(identifier) {
160
+ return `"${identifier.replace(/"/g, '""')}"`;
161
+ }
162
+ makeParameter(_index) {
163
+ return "?";
164
+ }
165
+ compileLimitOffset(bindings, limit, offset) {
166
+ if (limit === null && offset === null) return "";
167
+ if (offset !== null) {
168
+ bindings.push(limit ?? 0, offset);
169
+ return " LIMIT ? OFFSET ?";
170
+ }
171
+ bindings.push(limit);
172
+ return " LIMIT ?";
173
+ }
174
+ compileInsertReturning(sql, _bindings, _idColumn) {
175
+ return `${sql}; SELECT last_insert_rowid() as id`;
176
+ }
177
+ compileTruncate(tableName) {
178
+ return `DELETE FROM ${this.wrapIdentifier(tableName)}`;
179
+ }
180
+ compileCreateMigrationsTable() {
181
+ return `CREATE TABLE IF NOT EXISTS "migrations" (
182
+ "id" INTEGER PRIMARY KEY AUTOINCREMENT,
183
+ "name" TEXT NOT NULL,
184
+ "batch" INTEGER NOT NULL,
185
+ "executed_at" TEXT DEFAULT CURRENT_TIMESTAMP
186
+ )`;
187
+ }
188
+ mapType(type, options) {
189
+ switch (type) {
190
+ case "id":
191
+ case "increments":
192
+ return "INTEGER PRIMARY KEY AUTOINCREMENT";
193
+ case "bigIncrements":
194
+ return "INTEGER PRIMARY KEY AUTOINCREMENT";
195
+ case "string":
196
+ return `VARCHAR(${options.length ?? 255})`;
197
+ case "text":
198
+ return "TEXT";
199
+ case "integer":
200
+ return "INTEGER";
201
+ case "bigInteger":
202
+ return "INTEGER";
203
+ case "tinyInteger":
204
+ return "INTEGER";
205
+ case "smallInteger":
206
+ return "INTEGER";
207
+ case "boolean":
208
+ return "INTEGER";
209
+ case "float":
210
+ return "REAL";
211
+ case "double":
212
+ return "REAL";
213
+ case "decimal":
214
+ return "REAL";
215
+ case "date":
216
+ return "TEXT";
217
+ case "datetime":
218
+ return "TEXT";
219
+ case "timestamp":
220
+ return "TEXT";
221
+ case "time":
222
+ return "TEXT";
223
+ case "year":
224
+ return "TEXT";
225
+ case "json":
226
+ case "jsonb":
227
+ return "TEXT";
228
+ case "binary":
229
+ return "BLOB";
230
+ case "uuid":
231
+ return "TEXT";
232
+ case "foreignId":
233
+ return "INTEGER";
234
+ default:
235
+ return type;
236
+ }
237
+ }
238
+ compileColumn(options) {
239
+ let sql = `${this.wrapIdentifier(options.name)} ${this.mapType(options.type, options)}`;
240
+ if (options.autoIncrement && options.type !== "id" && options.type !== "increments" && options.type !== "bigIncrements")
241
+ sql += " AUTOINCREMENT";
242
+ if (!options.nullable && options.defaultValue === void 0 && !options.autoIncrement && options.type !== "id" && options.type !== "increments" && options.type !== "bigIncrements")
243
+ sql += " NOT NULL";
244
+ if (options.nullable) sql += " NULL";
245
+ if (options.defaultValue !== void 0 && options.defaultValue !== null) {
246
+ sql += ` DEFAULT ${this.formatDefault(options.defaultValue)}`;
247
+ }
248
+ if (options.primary) sql += " PRIMARY KEY";
249
+ if (options.unique) sql += " UNIQUE";
250
+ return sql;
251
+ }
252
+ compileModifyColumn(options) {
253
+ return this.compileColumn(options);
254
+ }
255
+ compileTableBlueprint(_tableName, columns, constraints) {
256
+ const parts = [
257
+ ...columns.map((c) => this.compileColumn(c)),
258
+ ...constraints
259
+ ];
260
+ return parts.join(",\n ");
261
+ }
262
+ compileAddColumns(_tableName, columns) {
263
+ return `ADD COLUMN ${columns.map((c) => this.compileColumn(c)).join(", ADD COLUMN ")}`;
264
+ }
265
+ compileDropColumns(_tableName, columns) {
266
+ return `DROP COLUMN ${columns.map((c) => this.wrapIdentifier(c)).join(", DROP COLUMN ")}`;
267
+ }
268
+ compileRenameColumn(_tableName, from, to) {
269
+ return `RENAME COLUMN ${this.wrapIdentifier(from)} TO ${this.wrapIdentifier(to)}`;
270
+ }
271
+ compileCreateTable(tableName, columns, constraints) {
272
+ const body = this.compileTableBlueprint(tableName, columns, constraints);
273
+ return `CREATE TABLE ${this.wrapIdentifier(tableName)} (
274
+ ${body}
275
+ )`;
276
+ }
277
+ compileRenameTable(from, to) {
278
+ return `ALTER TABLE ${this.wrapIdentifier(from)} RENAME TO ${this.wrapIdentifier(to)}`;
279
+ }
280
+ compileDropTable(tableName) {
281
+ return `DROP TABLE ${this.wrapIdentifier(tableName)}`;
282
+ }
283
+ compileDropTableIfExists(tableName) {
284
+ return `DROP TABLE IF EXISTS ${this.wrapIdentifier(tableName)}`;
285
+ }
286
+ compileHasTable(_tableName) {
287
+ return `SELECT COUNT(*) as "count" FROM "sqlite_master" WHERE "type" = 'table' AND "name" = ?`;
288
+ }
289
+ compileHasColumn(_tableName, _columnName) {
290
+ return `PRAGMA table_info(${this.wrapIdentifier(_tableName)})`;
291
+ }
292
+ compileInsert(sql) {
293
+ return sql;
294
+ }
295
+ formatDefault(value) {
296
+ if (typeof value === "string") {
297
+ if (value === "CURRENT_TIMESTAMP") return value;
298
+ return `'${value.replace(/'/g, "''")}'`;
299
+ }
300
+ if (value === null) return "NULL";
301
+ if (typeof value === "boolean") return value ? "1" : "0";
302
+ return String(value);
303
+ }
304
+ };
305
+ var PostgresqlDialect = class {
306
+ wrapIdentifier(identifier) {
307
+ return `"${identifier.replace(/"/g, '""')}"`;
308
+ }
309
+ makeParameter(index) {
310
+ return `$${index + 1}`;
311
+ }
312
+ compileLimitOffset(bindings, limit, offset) {
313
+ if (limit === null && offset === null) return "";
314
+ const start = bindings.length;
315
+ if (offset !== null) {
316
+ bindings.push(limit ?? 0, offset);
317
+ return ` LIMIT $${start + 1} OFFSET $${start + 2}`;
318
+ }
319
+ bindings.push(limit);
320
+ return ` LIMIT $${start + 1}`;
321
+ }
322
+ compileInsertReturning(sql, _bindings, idColumn = "id") {
323
+ return `${sql} RETURNING ${this.wrapIdentifier(idColumn)}`;
324
+ }
325
+ compileTruncate(tableName) {
326
+ return `TRUNCATE TABLE ${this.wrapIdentifier(tableName)} RESTART IDENTITY CASCADE`;
327
+ }
328
+ compileCreateMigrationsTable() {
329
+ return `CREATE TABLE IF NOT EXISTS "migrations" (
330
+ "id" SERIAL PRIMARY KEY,
331
+ "name" VARCHAR(255) NOT NULL,
332
+ "batch" INTEGER NOT NULL,
333
+ "executed_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
334
+ )`;
335
+ }
336
+ mapType(type, options) {
337
+ switch (type) {
338
+ case "id":
339
+ case "increments":
340
+ return "SERIAL PRIMARY KEY";
341
+ case "bigIncrements":
342
+ return "BIGSERIAL PRIMARY KEY";
343
+ case "string":
344
+ return `VARCHAR(${options.length ?? 255})`;
345
+ case "text":
346
+ return "TEXT";
347
+ case "integer":
348
+ return "INTEGER";
349
+ case "bigInteger":
350
+ return "BIGINT";
351
+ case "tinyInteger":
352
+ return "SMALLINT";
353
+ case "smallInteger":
354
+ return "SMALLINT";
355
+ case "boolean":
356
+ return "BOOLEAN";
357
+ case "float":
358
+ return "REAL";
359
+ case "double":
360
+ return "DOUBLE PRECISION";
361
+ case "decimal":
362
+ return `DECIMAL(${options.precision ?? 10},${options.scale ?? 0})`;
363
+ case "date":
364
+ return "DATE";
365
+ case "datetime":
366
+ return "TIMESTAMP";
367
+ case "timestamp":
368
+ return "TIMESTAMP";
369
+ case "time":
370
+ return "TIME";
371
+ case "year":
372
+ return "INTEGER";
373
+ case "json":
374
+ return "JSON";
375
+ case "jsonb":
376
+ return "JSONB";
377
+ case "binary":
378
+ return "BYTEA";
379
+ case "uuid":
380
+ return "UUID";
381
+ case "foreignId":
382
+ return "INTEGER";
383
+ default:
384
+ return type;
385
+ }
386
+ }
387
+ compileColumn(options) {
388
+ let sql = `${this.wrapIdentifier(options.name)} ${this.mapType(options.type, options)}`;
389
+ if (!options.nullable && options.type !== "id" && options.type !== "increments" && options.type !== "bigIncrements")
390
+ sql += " NOT NULL";
391
+ if (options.nullable) sql += " NULL";
392
+ if (options.defaultValue !== void 0 && options.defaultValue !== null) {
393
+ sql += ` DEFAULT ${this.formatDefault(options.defaultValue)}`;
394
+ }
395
+ if (options.primary && options.type !== "id" && options.type !== "increments" && options.type !== "bigIncrements")
396
+ sql += " PRIMARY KEY";
397
+ if (options.unique) sql += " UNIQUE";
398
+ if (options.comment !== null)
399
+ sql += ` -- ${options.comment.replace(/--/g, "")}`;
400
+ return sql;
401
+ }
402
+ compileModifyColumn(options) {
403
+ return `ALTER COLUMN ${this.wrapIdentifier(options.name)} TYPE ${this.mapType(options.type, options)}`;
404
+ }
405
+ compileTableBlueprint(_tableName, columns, constraints) {
406
+ const parts = [
407
+ ...columns.map((c) => this.compileColumn(c)),
408
+ ...constraints
409
+ ];
410
+ return parts.join(",\n ");
411
+ }
412
+ compileAddColumns(_tableName, columns) {
413
+ return `ADD COLUMN ${columns.map((c) => this.compileColumn(c)).join(", ADD COLUMN ")}`;
414
+ }
415
+ compileDropColumns(_tableName, columns) {
416
+ return `DROP COLUMN ${columns.map((c) => this.wrapIdentifier(c)).join(", DROP COLUMN ")}`;
417
+ }
418
+ compileRenameColumn(_tableName, from, to) {
419
+ return `RENAME COLUMN ${this.wrapIdentifier(from)} TO ${this.wrapIdentifier(to)}`;
420
+ }
421
+ compileCreateTable(tableName, columns, constraints) {
422
+ const body = this.compileTableBlueprint(tableName, columns, constraints);
423
+ return `CREATE TABLE ${this.wrapIdentifier(tableName)} (
424
+ ${body}
425
+ )`;
426
+ }
427
+ compileRenameTable(from, to) {
428
+ return `ALTER TABLE ${this.wrapIdentifier(from)} RENAME TO ${this.wrapIdentifier(to)}`;
429
+ }
430
+ compileDropTable(_tableName) {
431
+ return `DROP TABLE IF EXISTS ${this.wrapIdentifier(_tableName)}`;
432
+ }
433
+ compileDropTableIfExists(tableName) {
434
+ return `DROP TABLE IF EXISTS ${this.wrapIdentifier(tableName)}`;
435
+ }
436
+ compileHasTable(_tableName) {
437
+ return `SELECT COUNT(*)::int as "count" FROM "information_schema"."tables" WHERE "table_schema" = 'public' AND "table_name" = $1`;
438
+ }
439
+ compileHasColumn(_tableName, _columnName) {
440
+ return `SELECT COUNT(*)::int as "count" FROM "information_schema"."columns" WHERE "table_schema" = 'public' AND "table_name" = $1 AND "column_name" = $2`;
441
+ }
442
+ compileInsert(sql) {
443
+ return sql;
444
+ }
445
+ formatDefault(value) {
446
+ if (typeof value === "string") {
447
+ if (value === "CURRENT_TIMESTAMP") return value;
448
+ return `'${value.replace(/'/g, "''")}'`;
449
+ }
450
+ if (value === null) return "NULL";
451
+ if (typeof value === "boolean") return value ? "true" : "false";
452
+ return String(value);
453
+ }
454
+ };
455
+ function createDialect(driver) {
456
+ switch (driver) {
457
+ case "mysql":
458
+ return new MysqlDialect();
459
+ case "sqlite":
460
+ return new SqliteDialect();
461
+ case "postgresql":
462
+ return new PostgresqlDialect();
463
+ default:
464
+ return new MysqlDialect();
465
+ }
466
+ }
467
+
468
+ // src/server/database/driver.ts
469
+ async function createDriver(config) {
470
+ const driverType = config.driver ?? "mysql";
471
+ switch (driverType) {
472
+ case "mysql":
473
+ return createMysqlDriver(config);
474
+ case "postgresql":
475
+ return createPostgresqlDriver(config);
476
+ case "sqlite":
477
+ return createSqliteDriver(config);
478
+ default:
479
+ return createMysqlDriver(config);
480
+ }
481
+ }
482
+ async function createMysqlDriver(config) {
483
+ let mysqlPackage;
484
+ try {
485
+ mysqlPackage = await import("mysql2/promise");
486
+ } catch {
487
+ throw new Error(
488
+ "MySQL driver (mysql2) is not installed. Run: npm install mysql2"
489
+ );
490
+ }
491
+ let connection = null;
492
+ const dialect = new MysqlDialect();
493
+ const driver = {
494
+ async connect() {
495
+ connection = await mysqlPackage.createConnection({
496
+ host: config.host ?? "127.0.0.1",
497
+ port: config.port ?? 3306,
498
+ user: config.username,
499
+ password: config.password,
500
+ database: config.database,
501
+ charset: config.charset ?? "utf8mb4"
502
+ });
503
+ },
504
+ async disconnect() {
505
+ if (connection !== null) {
506
+ await connection.end();
507
+ connection = null;
508
+ }
509
+ },
510
+ isConnected() {
511
+ return connection !== null;
512
+ },
513
+ async raw(sql, bindings) {
514
+ if (connection === null) {
515
+ throw new Error("Database not connected. Call connect() first.");
516
+ }
517
+ const [rows, fields] = await connection.execute(sql, bindings ?? []);
518
+ return { rows, fields };
519
+ },
520
+ async transaction(callback) {
521
+ if (connection === null) {
522
+ throw new Error("Database not connected. Call connect() first.");
523
+ }
524
+ await connection.beginTransaction();
525
+ try {
526
+ const result = await callback(driver);
527
+ await connection.commit();
528
+ return result;
529
+ } catch (err) {
530
+ await connection.rollback();
531
+ throw err;
532
+ }
533
+ },
534
+ getDialect() {
535
+ return dialect;
536
+ },
537
+ getDriver() {
538
+ return "mysql";
539
+ }
540
+ };
541
+ return driver;
542
+ }
543
+ async function createPostgresqlDriver(config) {
544
+ let pgPackage;
545
+ try {
546
+ pgPackage = await import("pg");
547
+ } catch {
548
+ throw new Error(
549
+ "PostgreSQL driver (pg) is not installed. Run: npm install pg"
550
+ );
551
+ }
552
+ let pool = null;
553
+ const dialect = new PostgresqlDialect();
554
+ const driver = {
555
+ async connect() {
556
+ const { Pool } = pgPackage;
557
+ pool = new Pool({
558
+ host: config.host ?? "127.0.0.1",
559
+ port: config.port ?? 5432,
560
+ user: config.username,
561
+ password: config.password,
562
+ database: config.database
563
+ });
564
+ await pool.query("SELECT 1");
565
+ },
566
+ async disconnect() {
567
+ if (pool !== null) {
568
+ await pool.end();
569
+ pool = null;
570
+ }
571
+ },
572
+ isConnected() {
573
+ return pool !== null;
574
+ },
575
+ async raw(sql, bindings) {
576
+ if (pool === null) {
577
+ throw new Error("Database not connected. Call connect() first.");
578
+ }
579
+ const result = await pool.query(sql, bindings ?? []);
580
+ return { rows: result.rows };
581
+ },
582
+ async transaction(callback) {
583
+ if (pool === null) {
584
+ throw new Error("Database not connected. Call connect() first.");
585
+ }
586
+ const client = await pool.connect();
587
+ try {
588
+ await client.query("BEGIN");
589
+ const trxDriver = {
590
+ ...driver,
591
+ async raw(sql, bindings) {
592
+ const result2 = await client.query(sql, bindings ?? []);
593
+ return { rows: result2.rows };
594
+ },
595
+ getDialect() {
596
+ return dialect;
597
+ },
598
+ getDriver() {
599
+ return "postgresql";
600
+ }
601
+ };
602
+ const result = await callback(trxDriver);
603
+ await client.query("COMMIT");
604
+ return result;
605
+ } catch (err) {
606
+ await client.query("ROLLBACK");
607
+ throw err;
608
+ } finally {
609
+ client.release();
610
+ }
611
+ },
612
+ getDialect() {
613
+ return dialect;
614
+ },
615
+ getDriver() {
616
+ return "postgresql";
617
+ }
618
+ };
619
+ return driver;
620
+ }
621
+ async function createSqliteDriver(config) {
622
+ let sqlitePackage;
623
+ try {
624
+ sqlitePackage = await import("better-sqlite3");
625
+ } catch {
626
+ throw new Error(
627
+ "SQLite driver (better-sqlite3) is not installed. Run: npm install better-sqlite3"
628
+ );
629
+ }
630
+ let db = null;
631
+ let connected = false;
632
+ const dialect = new SqliteDialect();
633
+ const driver = {
634
+ async connect() {
635
+ db = new sqlitePackage(config.database);
636
+ db.pragma("journal_mode = WAL");
637
+ connected = true;
638
+ },
639
+ async disconnect() {
640
+ if (db !== null) {
641
+ db.close();
642
+ db = null;
643
+ connected = false;
644
+ }
645
+ },
646
+ isConnected() {
647
+ return connected;
648
+ },
649
+ async raw(sql, bindings) {
650
+ if (db === null) {
651
+ throw new Error("Database not connected. Call connect() first.");
652
+ }
653
+ const trimmedSQL = sql.trim().toUpperCase();
654
+ const isQuery = trimmedSQL.startsWith("SELECT") || trimmedSQL.startsWith("WITH") || trimmedSQL.startsWith("PRAGMA");
655
+ const stmt = db.prepare(sql);
656
+ if (isQuery) {
657
+ const rows = bindings !== void 0 && bindings.length > 0 ? stmt.all(...bindings) : stmt.all();
658
+ return { rows };
659
+ }
660
+ if (bindings !== void 0 && bindings.length > 0) {
661
+ stmt.run(...bindings);
662
+ } else {
663
+ stmt.run();
664
+ }
665
+ return { rows: [] };
666
+ },
667
+ async transaction(callback) {
668
+ if (db === null) {
669
+ throw new Error("Database not connected. Call connect() first.");
670
+ }
671
+ const txn = db.transaction(async () => {
672
+ return await callback(driver);
673
+ });
674
+ return txn();
675
+ },
676
+ getDialect() {
677
+ return dialect;
678
+ },
679
+ getDriver() {
680
+ return "sqlite";
681
+ }
682
+ };
683
+ return driver;
684
+ }
685
+
686
+ // src/server/database/query.ts
687
+ var QueryBuilder = class _QueryBuilder {
688
+ connection;
689
+ tableName;
690
+ columns = ["*"];
691
+ distinctEnabled = false;
692
+ wheres = [];
693
+ joins = [];
694
+ orderBys = [];
695
+ havings = [];
696
+ groupBys = [];
697
+ limitValue = null;
698
+ offsetValue = null;
699
+ fromSubquery = null;
700
+ constructor(connection, tableName) {
701
+ this.connection = connection;
702
+ this.tableName = tableName;
703
+ }
704
+ select(...columns) {
705
+ this.columns = columns.length > 0 ? columns : ["*"];
706
+ return this;
707
+ }
708
+ addSelect(...columns) {
709
+ if (this.columns[0] === "*") {
710
+ this.columns = columns;
711
+ } else {
712
+ this.columns.push(...columns);
713
+ }
714
+ return this;
715
+ }
716
+ distinct() {
717
+ this.distinctEnabled = true;
718
+ return this;
719
+ }
720
+ from(table) {
721
+ this.fromSubquery = table;
722
+ return this;
723
+ }
724
+ where(column, operator, value) {
725
+ if (value === void 0) {
726
+ value = operator;
727
+ operator = "=";
728
+ }
729
+ this.wheres.push({
730
+ type: "basic",
731
+ column,
732
+ operator: String(operator),
733
+ value,
734
+ boolean: "and"
735
+ });
736
+ return this;
737
+ }
738
+ orWhere(column, operator, value) {
739
+ if (value === void 0) {
740
+ value = operator;
741
+ operator = "=";
742
+ }
743
+ this.wheres.push({
744
+ type: "basic",
745
+ column,
746
+ operator: String(operator),
747
+ value,
748
+ boolean: "or"
749
+ });
750
+ return this;
751
+ }
752
+ whereIn(column, values) {
753
+ this.wheres.push({ type: "in", column, values, boolean: "and" });
754
+ return this;
755
+ }
756
+ whereNotIn(column, values) {
757
+ this.wheres.push({ type: "notIn", column, values, boolean: "and" });
758
+ return this;
759
+ }
760
+ whereNull(column) {
761
+ this.wheres.push({ type: "null", column, boolean: "and" });
762
+ return this;
763
+ }
764
+ whereNotNull(column) {
765
+ this.wheres.push({ type: "notNull", column, boolean: "and" });
766
+ return this;
767
+ }
768
+ whereBetween(column, range) {
769
+ this.wheres.push({
770
+ type: "between",
771
+ column,
772
+ values: range,
773
+ boolean: "and"
774
+ });
775
+ return this;
776
+ }
777
+ whereNotBetween(column, range) {
778
+ this.wheres.push({
779
+ type: "notBetween",
780
+ column,
781
+ values: range,
782
+ boolean: "and"
783
+ });
784
+ return this;
785
+ }
786
+ whereLike(column, pattern) {
787
+ this.wheres.push({ type: "like", column, value: pattern, boolean: "and" });
788
+ return this;
789
+ }
790
+ orWhereLike(column, pattern) {
791
+ this.wheres.push({ type: "like", column, value: pattern, boolean: "or" });
792
+ return this;
793
+ }
794
+ whereGroup(callback) {
795
+ const subQuery = new _QueryBuilder(this.connection, this.tableName);
796
+ callback(subQuery);
797
+ this.wheres.push({
798
+ type: "nested",
799
+ nested: subQuery.wheres,
800
+ boolean: "and"
801
+ });
802
+ return this;
803
+ }
804
+ join(table, first, operator, second, type = "inner") {
805
+ this.joins.push({ table, first, operator, second, type });
806
+ return this;
807
+ }
808
+ leftJoin(table, first, operator, second) {
809
+ return this.join(table, first, operator, second, "left");
810
+ }
811
+ rightJoin(table, first, operator, second) {
812
+ return this.join(table, first, operator, second, "right");
813
+ }
814
+ crossJoin(table, first, operator, second) {
815
+ return this.join(table, first, operator, second, "cross");
816
+ }
817
+ orderBy(column, direction = "asc") {
818
+ this.orderBys.push({ column, direction });
819
+ return this;
820
+ }
821
+ orderByDesc(column) {
822
+ return this.orderBy(column, "desc");
823
+ }
824
+ latest(column = "created_at") {
825
+ return this.orderBy(column, "desc");
826
+ }
827
+ oldest(column = "created_at") {
828
+ return this.orderBy(column, "asc");
829
+ }
830
+ inRandomOrder() {
831
+ this.orderBys.push({ column: "RANDOM()", direction: "asc" });
832
+ return this;
833
+ }
834
+ limit(limit) {
835
+ this.limitValue = limit;
836
+ return this;
837
+ }
838
+ offset(offset) {
839
+ this.offsetValue = offset;
840
+ return this;
841
+ }
842
+ skip(skip) {
843
+ return this.offset(skip);
844
+ }
845
+ take(take) {
846
+ return this.limit(take);
847
+ }
848
+ groupBy(...columns) {
849
+ this.groupBys.push(...columns);
850
+ return this;
851
+ }
852
+ having(column, operator, value) {
853
+ this.havings.push({ column, operator, value });
854
+ return this;
855
+ }
856
+ async get() {
857
+ const { sql, bindings } = this.toSQL();
858
+ const result = await this.connection.raw(sql, bindings);
859
+ return result.rows;
860
+ }
861
+ async first() {
862
+ const qb = this.clone();
863
+ qb.limitValue = 1;
864
+ const { sql, bindings } = qb.toSQL();
865
+ const result = await this.connection.raw(sql, bindings);
866
+ return result.rows.length > 0 ? result.rows[0] : null;
867
+ }
868
+ async find(id) {
869
+ return this.where("id", id).first();
870
+ }
871
+ async pluck(column) {
872
+ const qb = this.clone();
873
+ qb.columns = [column];
874
+ const { sql, bindings } = qb.toSQL();
875
+ const result = await this.connection.raw(sql, bindings);
876
+ return result.rows.map((row) => row[column]);
877
+ }
878
+ async count(column = "*") {
879
+ const qb = this.clone();
880
+ qb.columns = [
881
+ `COUNT(${column === "*" ? "*" : this.wrap(column)}) as aggregate`
882
+ ];
883
+ qb.orderBys = [];
884
+ qb.limitValue = null;
885
+ qb.offsetValue = null;
886
+ const { sql, bindings } = qb.toSQL();
887
+ const result = await this.connection.raw(sql, bindings);
888
+ const row = result.rows[0];
889
+ if (!row) return 0;
890
+ return Number(row.aggregate ?? row.count ?? row["COUNT(*)"] ?? 0);
891
+ }
892
+ async exists() {
893
+ const count = await this.count();
894
+ return count > 0;
895
+ }
896
+ async doesntExist() {
897
+ return !await this.exists();
898
+ }
899
+ async max(column) {
900
+ return this.aggregate("MAX", column);
901
+ }
902
+ async min(column) {
903
+ return this.aggregate("MIN", column);
904
+ }
905
+ async sum(column) {
906
+ const result = await this.aggregate("SUM", column);
907
+ return result ?? 0;
908
+ }
909
+ async avg(column) {
910
+ const result = await this.aggregate("AVG", column);
911
+ return result ?? 0;
912
+ }
913
+ async paginate(perPage = 15, page = 1) {
914
+ const countQb = this.clone();
915
+ const total = await countQb.count();
916
+ const lastPage = Math.max(1, Math.ceil(total / perPage));
917
+ const currentPage = Math.max(1, Math.min(page, lastPage));
918
+ const fromVal = (currentPage - 1) * perPage + 1;
919
+ const toVal = Math.min(currentPage * perPage, total);
920
+ const qb = this.clone();
921
+ qb.limitValue = perPage;
922
+ qb.offsetValue = (currentPage - 1) * perPage;
923
+ const { sql, bindings } = qb.toSQL();
924
+ const result = await this.connection.raw(sql, bindings);
925
+ return {
926
+ data: result.rows,
927
+ currentPage,
928
+ perPage,
929
+ total,
930
+ lastPage,
931
+ from: total > 0 ? fromVal : 0,
932
+ to: total > 0 ? toVal : 0,
933
+ hasMore: currentPage < lastPage,
934
+ hasPrev: currentPage > 1,
935
+ isEmpty: total === 0
936
+ };
937
+ }
938
+ async insert(data) {
939
+ const { sql, bindings } = this.compileInsert(data);
940
+ const driverType = this.connection.getDriver();
941
+ if (driverType === "postgresql") {
942
+ const dialect = this.connection.getDialect();
943
+ const returningSQL = dialect.compileInsertReturning(sql, bindings);
944
+ const result2 = await this.connection.raw(returningSQL, bindings);
945
+ return result2.rows.length > 0 ? Number(result2.rows[0].id) ?? 0 : 0;
946
+ }
947
+ const result = await this.connection.raw(sql, bindings);
948
+ if (result.rows && result.rows.length > 0) {
949
+ return Number(result.rows[0].id) ?? result.rows[0].insertId ?? 0;
950
+ }
951
+ return 0;
952
+ }
953
+ async insertGetId(data) {
954
+ return this.insert(data);
955
+ }
956
+ async insertReturning(data) {
957
+ const { sql, bindings } = this.compileInsert(data);
958
+ const dialect = this.connection.getDialect();
959
+ const returningSQL = dialect.compileInsertReturning(sql, bindings);
960
+ const result = await this.connection.raw(returningSQL, bindings);
961
+ return result.rows.length > 0 ? result.rows[0] : null;
962
+ }
963
+ async update(data) {
964
+ const { sql, bindings } = this.compileUpdate(data);
965
+ const result = await this.connection.raw(sql, bindings);
966
+ const rows = result.rows;
967
+ if (rows.length > 0) {
968
+ const info = rows[0];
969
+ return info.affectedRows ?? info.changes ?? rows.length;
970
+ }
971
+ return 0;
972
+ }
973
+ async delete() {
974
+ const { sql, bindings } = this.compileDelete();
975
+ const result = await this.connection.raw(sql, bindings);
976
+ const rows = result.rows;
977
+ if (rows.length > 0) {
978
+ const info = rows[0];
979
+ return info.affectedRows ?? info.changes ?? rows.length;
980
+ }
981
+ return 0;
982
+ }
983
+ async truncate() {
984
+ const dialect = this.connection.getDialect();
985
+ const sql = dialect.compileTruncate(this.tableName);
986
+ await this.connection.raw(sql);
987
+ }
988
+ async chunk(size, callback) {
989
+ let page = 1;
990
+ let hasMore = true;
991
+ while (hasMore) {
992
+ const qb = this.clone();
993
+ qb.limitValue = size;
994
+ qb.offsetValue = (page - 1) * size;
995
+ const rows = await qb.get();
996
+ if (rows.length === 0) {
997
+ hasMore = false;
998
+ break;
999
+ }
1000
+ await callback(rows);
1001
+ if (rows.length < size) {
1002
+ hasMore = false;
1003
+ }
1004
+ page++;
1005
+ }
1006
+ }
1007
+ clone() {
1008
+ const qb = new _QueryBuilder(this.connection, this.tableName);
1009
+ qb.columns = [...this.columns];
1010
+ qb.distinctEnabled = this.distinctEnabled;
1011
+ qb.wheres = this.cloneWheres(this.wheres);
1012
+ qb.joins = [...this.joins];
1013
+ qb.orderBys = [...this.orderBys];
1014
+ qb.havings = [...this.havings];
1015
+ qb.groupBys = [...this.groupBys];
1016
+ qb.limitValue = this.limitValue;
1017
+ qb.offsetValue = this.offsetValue;
1018
+ qb.fromSubquery = this.fromSubquery;
1019
+ return qb;
1020
+ }
1021
+ toSQL() {
1022
+ const bindings = [];
1023
+ const dialect = this.connection.getDialect();
1024
+ const wrappedColumns = this.columns.map(
1025
+ (c) => c.includes("(") || c === "*" || c.includes(" as ") || c.includes(" AS ") ? c : dialect.wrapIdentifier(c)
1026
+ ).join(", ");
1027
+ const from = this.fromSubquery ?? this.tableName;
1028
+ const wrappedFrom = this.fromSubquery ?? dialect.wrapIdentifier(from);
1029
+ let sql = this.distinctEnabled ? `SELECT DISTINCT ${wrappedColumns} FROM ${wrappedFrom}` : `SELECT ${wrappedColumns} FROM ${wrappedFrom}`;
1030
+ const joinSQL = this.compileJoins(dialect);
1031
+ if (joinSQL) sql += joinSQL;
1032
+ const whereSQL = this.compileWheres(dialect, bindings);
1033
+ if (whereSQL) sql += whereSQL;
1034
+ if (this.groupBys.length > 0) {
1035
+ sql += ` GROUP BY ${this.groupBys.map((c) => dialect.wrapIdentifier(c)).join(", ")}`;
1036
+ }
1037
+ const havingSQL = this.compileHavings(dialect, bindings);
1038
+ if (havingSQL) sql += havingSQL;
1039
+ if (this.orderBys.length > 0) {
1040
+ sql += ` ORDER BY ${this.orderBys.map((o) => {
1041
+ const col = o.column === "RANDOM()" ? o.column : dialect.wrapIdentifier(o.column);
1042
+ return `${col} ${o.direction.toUpperCase()}`;
1043
+ }).join(", ")}`;
1044
+ }
1045
+ const limitOffsetSQL = dialect.compileLimitOffset(
1046
+ bindings,
1047
+ this.limitValue,
1048
+ this.offsetValue
1049
+ );
1050
+ if (limitOffsetSQL) sql += limitOffsetSQL;
1051
+ return { sql, bindings };
1052
+ }
1053
+ dd() {
1054
+ const { sql, bindings } = this.toSQL();
1055
+ const output = `SQL: ${sql}
1056
+ Bindings: ${JSON.stringify(bindings)}`;
1057
+ console.error(output);
1058
+ process.exit(1);
1059
+ }
1060
+ compileJoins(dialect) {
1061
+ if (this.joins.length === 0) return "";
1062
+ return " " + this.joins.map((j) => {
1063
+ const type = j.type.toUpperCase();
1064
+ return `${type} JOIN ${dialect.wrapIdentifier(j.table)} ON ${dialect.wrapIdentifier(j.first)} ${j.operator} ${this.wrap(j.second)}`;
1065
+ }).join(" ");
1066
+ }
1067
+ compileWheres(dialect, bindings) {
1068
+ if (this.wheres.length === 0) return "";
1069
+ const sql = this.compileWhereArray(this.wheres, dialect, bindings);
1070
+ return sql ? ` WHERE ${sql}` : "";
1071
+ }
1072
+ compileWhereArray(wheres, dialect, bindings) {
1073
+ if (wheres.length === 0) return "";
1074
+ const parts = [];
1075
+ for (const w of wheres) {
1076
+ const sql = this.compileSingleWhere(w, dialect, bindings);
1077
+ if (sql !== null) parts.push(sql);
1078
+ }
1079
+ if (parts.length === 0) return "";
1080
+ return parts.join(" AND ");
1081
+ }
1082
+ compileSingleWhere(w, dialect, bindings) {
1083
+ const col = w.column ? dialect.wrapIdentifier(w.column) : "";
1084
+ switch (w.type) {
1085
+ case "basic": {
1086
+ bindings.push(w.value);
1087
+ const operator = w.operator === "=" ? "=" : w.operator;
1088
+ return `${col} ${operator} ${dialect.makeParameter(bindings.length - 1)}`;
1089
+ }
1090
+ case "in": {
1091
+ const placeholders = w.values.map((v) => {
1092
+ bindings.push(v);
1093
+ return dialect.makeParameter(bindings.length - 1);
1094
+ }).join(", ");
1095
+ return `${col} IN (${placeholders})`;
1096
+ }
1097
+ case "notIn": {
1098
+ const placeholders = w.values.map((v) => {
1099
+ bindings.push(v);
1100
+ return dialect.makeParameter(bindings.length - 1);
1101
+ }).join(", ");
1102
+ return `${col} NOT IN (${placeholders})`;
1103
+ }
1104
+ case "null":
1105
+ return `${col} IS NULL`;
1106
+ case "notNull":
1107
+ return `${col} IS NOT NULL`;
1108
+ case "between": {
1109
+ bindings.push(w.values[0], w.values[1]);
1110
+ return `${col} BETWEEN ${dialect.makeParameter(bindings.length - 2)} AND ${dialect.makeParameter(bindings.length - 1)}`;
1111
+ }
1112
+ case "notBetween": {
1113
+ bindings.push(w.values[0], w.values[1]);
1114
+ return `${col} NOT BETWEEN ${dialect.makeParameter(bindings.length - 2)} AND ${dialect.makeParameter(bindings.length - 1)}`;
1115
+ }
1116
+ case "like": {
1117
+ bindings.push(w.value);
1118
+ return `${col} LIKE ${dialect.makeParameter(bindings.length - 1)}`;
1119
+ }
1120
+ case "nested": {
1121
+ const nestedSQL = this.compileNestedWhere(w.nested, dialect, bindings);
1122
+ return nestedSQL ? `(${nestedSQL})` : null;
1123
+ }
1124
+ default:
1125
+ return null;
1126
+ }
1127
+ }
1128
+ compileNestedWhere(wheres, dialect, bindings) {
1129
+ const parts = [];
1130
+ for (const w of wheres) {
1131
+ const sql = this.compileSingleWhere(w, dialect, bindings);
1132
+ if (sql !== null) {
1133
+ parts.push(sql);
1134
+ }
1135
+ }
1136
+ if (parts.length === 0) return "";
1137
+ return parts.join(" AND ");
1138
+ }
1139
+ compileHavings(dialect, bindings) {
1140
+ if (this.havings.length === 0) return "";
1141
+ const parts = this.havings.map((h) => {
1142
+ bindings.push(h.value);
1143
+ return `${dialect.wrapIdentifier(h.column)} ${h.operator} ${dialect.makeParameter(bindings.length - 1)}`;
1144
+ });
1145
+ return ` HAVING ${parts.join(" AND ")}`;
1146
+ }
1147
+ compileInsert(data) {
1148
+ const dialect = this.connection.getDialect();
1149
+ const columns = Object.keys(data);
1150
+ const values = Object.values(data);
1151
+ const bindings = [];
1152
+ const placeholders = values.map((v) => {
1153
+ bindings.push(v);
1154
+ return dialect.makeParameter(bindings.length - 1);
1155
+ }).join(", ");
1156
+ const sql = `INSERT INTO ${dialect.wrapIdentifier(this.tableName)} (${columns.map((c) => dialect.wrapIdentifier(c)).join(", ")}) VALUES (${placeholders})`;
1157
+ return { sql, bindings };
1158
+ }
1159
+ compileUpdate(data) {
1160
+ const dialect = this.connection.getDialect();
1161
+ const bindings = [];
1162
+ const sets = Object.entries(data).map(([key, value]) => {
1163
+ bindings.push(value);
1164
+ return `${dialect.wrapIdentifier(key)} = ${dialect.makeParameter(bindings.length - 1)}`;
1165
+ });
1166
+ let sql = `UPDATE ${dialect.wrapIdentifier(this.tableName)} SET ${sets.join(", ")}`;
1167
+ const whereSQL = this.compileWheres(dialect, bindings);
1168
+ if (whereSQL) sql += whereSQL;
1169
+ if (this.orderBys.length > 0) {
1170
+ sql += ` ORDER BY ${this.orderBys.map((o) => {
1171
+ const col = o.column === "RANDOM()" ? o.column : dialect.wrapIdentifier(o.column);
1172
+ return `${col} ${o.direction.toUpperCase()}`;
1173
+ }).join(", ")}`;
1174
+ }
1175
+ const limitOffsetSQL = dialect.compileLimitOffset(
1176
+ bindings,
1177
+ this.limitValue,
1178
+ this.offsetValue
1179
+ );
1180
+ if (limitOffsetSQL) sql += limitOffsetSQL;
1181
+ return { sql, bindings };
1182
+ }
1183
+ compileDelete() {
1184
+ const dialect = this.connection.getDialect();
1185
+ const bindings = [];
1186
+ let sql = `DELETE FROM ${dialect.wrapIdentifier(this.tableName)}`;
1187
+ const whereSQL = this.compileWheres(dialect, bindings);
1188
+ if (whereSQL) sql += whereSQL;
1189
+ if (this.orderBys.length > 0) {
1190
+ sql += ` ORDER BY ${this.orderBys.map((o) => {
1191
+ const col = o.column === "RANDOM()" ? o.column : dialect.wrapIdentifier(o.column);
1192
+ return `${col} ${o.direction.toUpperCase()}`;
1193
+ }).join(", ")}`;
1194
+ }
1195
+ const limitOffsetSQL = dialect.compileLimitOffset(
1196
+ bindings,
1197
+ this.limitValue,
1198
+ this.offsetValue
1199
+ );
1200
+ if (limitOffsetSQL) sql += limitOffsetSQL;
1201
+ return { sql, bindings };
1202
+ }
1203
+ async aggregate(fn, column) {
1204
+ const qb = this.clone();
1205
+ qb.columns = [`${fn}(${this.wrap(column)}) as aggregate`];
1206
+ qb.orderBys = [];
1207
+ qb.limitValue = null;
1208
+ qb.offsetValue = null;
1209
+ const { sql, bindings } = qb.toSQL();
1210
+ const result = await this.connection.raw(sql, bindings);
1211
+ const row = result.rows[0];
1212
+ if (!row) return null;
1213
+ const val = row.aggregate ?? row[`${fn}(${column})`];
1214
+ return val !== null && val !== void 0 ? Number(val) : null;
1215
+ }
1216
+ cloneWheres(wheres) {
1217
+ return wheres.map((w) => ({
1218
+ ...w,
1219
+ values: w.values ? [...w.values] : void 0,
1220
+ nested: w.nested ? this.cloneWheres(w.nested) : void 0
1221
+ }));
1222
+ }
1223
+ wrap(identifier) {
1224
+ if (identifier === "*" || identifier.includes("(")) return identifier;
1225
+ const dialect = this.connection.getDialect();
1226
+ return dialect.wrapIdentifier(identifier);
1227
+ }
1228
+ };
1229
+
1230
+ // src/server/database/connection.ts
1231
+ var DatabaseConnection = class _DatabaseConnection {
1232
+ config;
1233
+ driver = null;
1234
+ constructor(config) {
1235
+ this.config = {
1236
+ driver: "mysql",
1237
+ host: "127.0.0.1",
1238
+ charset: "utf8mb4",
1239
+ prefix: "",
1240
+ ...config
1241
+ };
1242
+ if (this.config.port === void 0) {
1243
+ if (this.config.driver === "mysql") this.config.port = 3306;
1244
+ else if (this.config.driver === "postgresql") this.config.port = 5432;
1245
+ }
1246
+ }
1247
+ async connect() {
1248
+ if (this.driver !== null) return;
1249
+ this.driver = await createDriver(this.config);
1250
+ await this.driver.connect();
1251
+ }
1252
+ async disconnect() {
1253
+ if (this.driver !== null) {
1254
+ await this.driver.disconnect();
1255
+ this.driver = null;
1256
+ }
1257
+ }
1258
+ async raw(sql, bindings) {
1259
+ this.ensureConnected();
1260
+ return this.driver.raw(sql, bindings);
1261
+ }
1262
+ table(tableName) {
1263
+ return new QueryBuilder(this, `${this.config.prefix ?? ""}${tableName}`);
1264
+ }
1265
+ isConnected() {
1266
+ return this.driver !== null && this.driver.isConnected();
1267
+ }
1268
+ getDriver() {
1269
+ return this.config.driver ?? "mysql";
1270
+ }
1271
+ getDialect() {
1272
+ this.ensureConnected();
1273
+ return this.driver.getDialect();
1274
+ }
1275
+ getPrefix() {
1276
+ return this.config.prefix ?? "";
1277
+ }
1278
+ getConfig() {
1279
+ return { ...this.config };
1280
+ }
1281
+ async transaction(callback) {
1282
+ this.ensureConnected();
1283
+ return this.driver.transaction(async (_driver) => {
1284
+ const trxConnection = new _DatabaseConnection(this.config);
1285
+ trxConnection["driver"] = this.driver;
1286
+ trxConnection.raw = async (sql, bindings) => {
1287
+ return this.driver.raw(sql, bindings);
1288
+ };
1289
+ return callback(trxConnection);
1290
+ });
1291
+ }
1292
+ static generateId() {
1293
+ return randomUUID();
1294
+ }
1295
+ ensureConnected() {
1296
+ if (this.driver === null || !this.driver.isConnected()) {
1297
+ throw new Error(
1298
+ "Database not connected. Call connect() before performing operations."
1299
+ );
1300
+ }
1301
+ }
1302
+ };
1303
+
1304
+ // src/server/database/migration.ts
1305
+ var SchemaBuilder = class {
1306
+ connection;
1307
+ constructor(connection) {
1308
+ this.connection = connection;
1309
+ }
1310
+ async createTable(tableName, callback) {
1311
+ const blueprint = new TableBlueprint(this.connection, "create");
1312
+ callback(blueprint);
1313
+ const dialect = this.connection.getDialect();
1314
+ const columns = blueprint.compileColumns();
1315
+ const constraints = blueprint.compileConstraints(dialect);
1316
+ const sql = dialect.compileCreateTable(tableName, columns, constraints);
1317
+ await this.connection.raw(sql);
1318
+ }
1319
+ async dropTable(tableName) {
1320
+ const dialect = this.connection.getDialect();
1321
+ const sql = dialect.compileDropTable(tableName);
1322
+ await this.connection.raw(sql);
1323
+ }
1324
+ async dropTableIfExists(tableName) {
1325
+ const dialect = this.connection.getDialect();
1326
+ const sql = dialect.compileDropTableIfExists(tableName);
1327
+ await this.connection.raw(sql);
1328
+ }
1329
+ async renameTable(from, to) {
1330
+ const dialect = this.connection.getDialect();
1331
+ const sql = dialect.compileRenameTable(from, to);
1332
+ await this.connection.raw(sql);
1333
+ }
1334
+ async alterTable(tableName, callback) {
1335
+ const blueprint = new TableBlueprint(this.connection, "alter");
1336
+ callback(blueprint);
1337
+ const dialect = this.connection.getDialect();
1338
+ if (blueprint.droppedColumns.length > 0) {
1339
+ const dropSQL = dialect.compileDropColumns(
1340
+ tableName,
1341
+ blueprint.droppedColumns
1342
+ );
1343
+ await this.connection.raw(
1344
+ `ALTER TABLE ${dialect.wrapIdentifier(tableName)} ${dropSQL}`
1345
+ );
1346
+ }
1347
+ if (blueprint.renamedColumns.length > 0) {
1348
+ for (const { from, to } of blueprint.renamedColumns) {
1349
+ const renameSQL = dialect.compileRenameColumn(tableName, from, to);
1350
+ await this.connection.raw(
1351
+ `ALTER TABLE ${dialect.wrapIdentifier(tableName)} ${renameSQL}`
1352
+ );
1353
+ }
1354
+ }
1355
+ const compiledColumns = blueprint.compileColumnDefinitions(dialect);
1356
+ if (compiledColumns.length > 0) {
1357
+ for (const colSQL of compiledColumns) {
1358
+ await this.connection.raw(
1359
+ `ALTER TABLE ${dialect.wrapIdentifier(tableName)} ${colSQL}`
1360
+ );
1361
+ }
1362
+ }
1363
+ }
1364
+ async hasTable(tableName) {
1365
+ const dialect = this.connection.getDialect();
1366
+ const sql = dialect.compileHasTable(tableName);
1367
+ const result = await this.connection.raw(sql, [tableName]);
1368
+ return this.parseCount(result) > 0;
1369
+ }
1370
+ async hasColumn(tableName, columnName) {
1371
+ const dialect = this.connection.getDialect();
1372
+ const driver = this.connection.getDriver();
1373
+ if (driver === "sqlite") {
1374
+ const sql2 = dialect.compileHasColumn(tableName, columnName);
1375
+ const result2 = await this.connection.raw(sql2);
1376
+ return result2.rows.some((row) => row.name === columnName);
1377
+ }
1378
+ const sql = dialect.compileHasColumn(tableName, columnName);
1379
+ const result = await this.connection.raw(sql, [tableName, columnName]);
1380
+ return this.parseCount(result) > 0;
1381
+ }
1382
+ parseCount(result) {
1383
+ if (result.rows.length === 0) return 0;
1384
+ const row = result.rows[0];
1385
+ return Number(row.count ?? row.Count ?? 0);
1386
+ }
1387
+ };
1388
+ var TableBlueprint = class {
1389
+ mode;
1390
+ columns = [];
1391
+ primaryKeys = [];
1392
+ uniqueKeys = [];
1393
+ indexKeys = [];
1394
+ foreignKeys = [];
1395
+ droppedColumns = [];
1396
+ renamedColumns = [];
1397
+ constructor(_connection, mode) {
1398
+ this.mode = mode;
1399
+ }
1400
+ id(name = "id") {
1401
+ const col = this.addColumn("id", name);
1402
+ col.autoIncrement();
1403
+ col.unsigned();
1404
+ return col;
1405
+ }
1406
+ increments(name = "id") {
1407
+ const col = this.addColumn("increments", name);
1408
+ col.autoIncrement();
1409
+ col.unsigned();
1410
+ return col;
1411
+ }
1412
+ bigIncrements(name = "id") {
1413
+ const col = this.addColumn("bigIncrements", name);
1414
+ col.autoIncrement();
1415
+ col.unsigned();
1416
+ return col;
1417
+ }
1418
+ string(name, length = 255) {
1419
+ const col = this.addColumn("string", name);
1420
+ col.setLength(length);
1421
+ return col;
1422
+ }
1423
+ text(name) {
1424
+ return this.addColumn("text", name);
1425
+ }
1426
+ integer(name) {
1427
+ return this.addColumn("integer", name);
1428
+ }
1429
+ bigInteger(name) {
1430
+ return this.addColumn("bigInteger", name);
1431
+ }
1432
+ tinyInteger(name) {
1433
+ return this.addColumn("tinyInteger", name);
1434
+ }
1435
+ smallInteger(name) {
1436
+ return this.addColumn("smallInteger", name);
1437
+ }
1438
+ boolean(name) {
1439
+ return this.addColumn("boolean", name);
1440
+ }
1441
+ float(name, _precision) {
1442
+ const col = this.addColumn("float", name);
1443
+ if (_precision !== void 0) col.setPrecision(_precision);
1444
+ return col;
1445
+ }
1446
+ double(name) {
1447
+ return this.addColumn("double", name);
1448
+ }
1449
+ decimal(name, precision = 10, scale = 0) {
1450
+ const col = this.addColumn("decimal", name);
1451
+ col.setPrecision(precision);
1452
+ col.setScale(scale);
1453
+ return col;
1454
+ }
1455
+ date(name) {
1456
+ return this.addColumn("date", name);
1457
+ }
1458
+ datetime(name) {
1459
+ return this.addColumn("datetime", name);
1460
+ }
1461
+ timestamp(name) {
1462
+ return this.addColumn("timestamp", name);
1463
+ }
1464
+ time(name) {
1465
+ return this.addColumn("time", name);
1466
+ }
1467
+ year(name) {
1468
+ return this.addColumn("year", name);
1469
+ }
1470
+ json(name) {
1471
+ return this.addColumn("json", name);
1472
+ }
1473
+ jsonb(name) {
1474
+ return this.addColumn("jsonb", name);
1475
+ }
1476
+ binary(name) {
1477
+ return this.addColumn("binary", name);
1478
+ }
1479
+ uuid(name = "uuid") {
1480
+ return this.addColumn("uuid", name);
1481
+ }
1482
+ enum(name, values) {
1483
+ const col = this.addColumn("enum", name);
1484
+ col.setValues(values);
1485
+ return col;
1486
+ }
1487
+ foreignId(name) {
1488
+ const col = this.addColumn("foreignId", name);
1489
+ col.unsigned();
1490
+ return col;
1491
+ }
1492
+ primary(...columns) {
1493
+ this.primaryKeys.push(...columns);
1494
+ }
1495
+ unique(...columns) {
1496
+ this.uniqueKeys.push(columns);
1497
+ }
1498
+ index(...columns) {
1499
+ this.indexKeys.push(columns);
1500
+ }
1501
+ foreign(column) {
1502
+ const fk = {
1503
+ column,
1504
+ references: "",
1505
+ on: "",
1506
+ onDelete: null,
1507
+ onUpdate: null
1508
+ };
1509
+ this.foreignKeys.push(fk);
1510
+ return new ForeignKeyDefinition(fk);
1511
+ }
1512
+ timestamps() {
1513
+ this.timestamp("created_at").nullable();
1514
+ this.timestamp("updated_at").nullable();
1515
+ }
1516
+ softDeletes() {
1517
+ this.timestamp("deleted_at").nullable();
1518
+ }
1519
+ rememberToken() {
1520
+ this.string("remember_token", 100).nullable();
1521
+ }
1522
+ dropColumn(column) {
1523
+ this.droppedColumns.push(column);
1524
+ }
1525
+ renameColumn(from, to) {
1526
+ this.renamedColumns.push({ from, to });
1527
+ }
1528
+ dropPrimary() {
1529
+ this.primaryKeys = [];
1530
+ }
1531
+ dropUnique(_indexName) {
1532
+ this.uniqueKeys = [];
1533
+ }
1534
+ dropIndex(_indexName) {
1535
+ this.indexKeys = [];
1536
+ }
1537
+ dropForeign(_indexName) {
1538
+ this.foreignKeys = [];
1539
+ }
1540
+ dropTimestamps() {
1541
+ this.droppedColumns.push("created_at", "updated_at");
1542
+ }
1543
+ dropSoftDeletes() {
1544
+ this.droppedColumns.push("deleted_at");
1545
+ }
1546
+ dropRememberToken() {
1547
+ this.droppedColumns.push("remember_token");
1548
+ }
1549
+ compileColumns() {
1550
+ return this.columns.filter((c) => this.mode === "create" || c.isNew).map((c) => c.compile());
1551
+ }
1552
+ compileConstraints(dialect) {
1553
+ const constraints = [];
1554
+ const wrap = (name) => dialect.wrapIdentifier(name);
1555
+ for (const pk of this.primaryKeys) {
1556
+ constraints.push(`PRIMARY KEY (${wrap(pk)})`);
1557
+ }
1558
+ for (const uk of this.uniqueKeys) {
1559
+ constraints.push(`UNIQUE (${uk.map((c) => wrap(c)).join(", ")})`);
1560
+ }
1561
+ for (const ik of this.indexKeys) {
1562
+ constraints.push(`INDEX (${ik.map((c) => wrap(c)).join(", ")})`);
1563
+ }
1564
+ for (const fk of this.foreignKeys) {
1565
+ let fkSQL = `FOREIGN KEY (${wrap(fk.column)}) REFERENCES ${wrap(fk.on)} (${wrap(fk.references)})`;
1566
+ if (fk.onDelete) fkSQL += ` ON DELETE ${fk.onDelete}`;
1567
+ if (fk.onUpdate) fkSQL += ` ON UPDATE ${fk.onUpdate}`;
1568
+ constraints.push(fkSQL);
1569
+ }
1570
+ return constraints;
1571
+ }
1572
+ compileColumnDefinitions(dialect) {
1573
+ return this.columns.filter((c) => c.isNew && this.mode === "alter").map((c) => dialect.compileAddColumns("", [c.compile()]));
1574
+ }
1575
+ addColumn(type, name) {
1576
+ const col = new ColumnDefinition(type, name);
1577
+ this.columns.push(col);
1578
+ return col;
1579
+ }
1580
+ };
1581
+ var ColumnDefinition = class {
1582
+ type;
1583
+ name;
1584
+ isNullable = false;
1585
+ defaultValue = void 0;
1586
+ isUnsigned = false;
1587
+ isUnique = false;
1588
+ isPrimary = false;
1589
+ isIndex = false;
1590
+ commentText = null;
1591
+ afterColumn = null;
1592
+ isFirst = false;
1593
+ isAutoIncrement = false;
1594
+ precisionValue = null;
1595
+ scaleValue = null;
1596
+ lengthValue = null;
1597
+ enumValues = null;
1598
+ isForeignId = false;
1599
+ isNew = true;
1600
+ constructor(type, name) {
1601
+ this.type = type;
1602
+ this.name = name;
1603
+ }
1604
+ nullable() {
1605
+ this.isNullable = true;
1606
+ return this;
1607
+ }
1608
+ default(value) {
1609
+ this.defaultValue = value;
1610
+ return this;
1611
+ }
1612
+ unsigned() {
1613
+ this.isUnsigned = true;
1614
+ return this;
1615
+ }
1616
+ unique() {
1617
+ this.isUnique = true;
1618
+ return this;
1619
+ }
1620
+ primary() {
1621
+ this.isPrimary = true;
1622
+ return this;
1623
+ }
1624
+ index() {
1625
+ this.isIndex = true;
1626
+ return this;
1627
+ }
1628
+ comment(text) {
1629
+ this.commentText = text;
1630
+ return this;
1631
+ }
1632
+ after(column) {
1633
+ this.afterColumn = column;
1634
+ return this;
1635
+ }
1636
+ first() {
1637
+ this.isFirst = true;
1638
+ return this;
1639
+ }
1640
+ autoIncrement() {
1641
+ this.isAutoIncrement = true;
1642
+ return this;
1643
+ }
1644
+ setValues(vals) {
1645
+ this.enumValues = vals;
1646
+ return this;
1647
+ }
1648
+ setLength(len) {
1649
+ this.lengthValue = len;
1650
+ return this;
1651
+ }
1652
+ setPrecision(precision) {
1653
+ this.precisionValue = precision;
1654
+ return this;
1655
+ }
1656
+ setScale(scale) {
1657
+ this.scaleValue = scale;
1658
+ return this;
1659
+ }
1660
+ compile() {
1661
+ return {
1662
+ name: this.name,
1663
+ type: this.type,
1664
+ nullable: this.isNullable,
1665
+ defaultValue: this.defaultValue,
1666
+ unsigned: this.isUnsigned,
1667
+ unique: this.isUnique,
1668
+ primary: this.isPrimary,
1669
+ index: this.isIndex,
1670
+ comment: this.commentText,
1671
+ after: this.afterColumn,
1672
+ first: this.isFirst,
1673
+ autoIncrement: this.isAutoIncrement,
1674
+ precision: this.precisionValue,
1675
+ scale: this.scaleValue,
1676
+ length: this.lengthValue,
1677
+ values: this.enumValues,
1678
+ isForeignId: this.isForeignId
1679
+ };
1680
+ }
1681
+ };
1682
+ var ForeignKeyDefinition = class {
1683
+ def;
1684
+ constructor(def) {
1685
+ this.def = def;
1686
+ }
1687
+ references(column) {
1688
+ this.def.references = column;
1689
+ return this;
1690
+ }
1691
+ on(table) {
1692
+ this.def.on = table;
1693
+ return this;
1694
+ }
1695
+ onDelete(action) {
1696
+ this.def.onDelete = action;
1697
+ return this;
1698
+ }
1699
+ onUpdate(action) {
1700
+ this.def.onUpdate = action;
1701
+ return this;
1702
+ }
1703
+ };
1704
+ var Migrator = class {
1705
+ connection;
1706
+ migrations = [];
1707
+ constructor(connection) {
1708
+ this.connection = connection;
1709
+ }
1710
+ addMigrations(migrations) {
1711
+ this.migrations.push(...migrations);
1712
+ }
1713
+ setMigrations(migrations) {
1714
+ this.migrations = migrations;
1715
+ }
1716
+ async run() {
1717
+ await this.ensureMigrationTable();
1718
+ const ran = await this.getRanMigrations();
1719
+ const ranNames = new Set(ran.map((r) => r.name));
1720
+ const pending = this.migrations.filter((m) => !ranNames.has(m.name));
1721
+ if (pending.length === 0) {
1722
+ console.log("Nothing to migrate.");
1723
+ return;
1724
+ }
1725
+ const nextBatch = await this.getNextBatchNumber();
1726
+ const schema = new SchemaBuilder(this.connection);
1727
+ for (const migration of pending) {
1728
+ console.log(`Migrating: ${migration.name}`);
1729
+ try {
1730
+ await migration.up(schema);
1731
+ await this.recordMigration(migration.name, nextBatch);
1732
+ console.log(`Migrated: ${migration.name}`);
1733
+ } catch (err) {
1734
+ console.error(`Migration failed: ${migration.name}`, err);
1735
+ throw err;
1736
+ }
1737
+ }
1738
+ }
1739
+ async rollback() {
1740
+ await this.ensureMigrationTable();
1741
+ const lastBatch = await this.getLastBatchNumber();
1742
+ if (lastBatch === 0) {
1743
+ console.log("Nothing to rollback.");
1744
+ return;
1745
+ }
1746
+ const lastBatchMigrations = await this.getMigrationsByBatch(lastBatch);
1747
+ const schema = new SchemaBuilder(this.connection);
1748
+ for (const migration of lastBatchMigrations.reverse()) {
1749
+ const def = this.migrations.find((m) => m.name === migration.name);
1750
+ if (def) {
1751
+ console.log(`Rolling back: ${migration.name}`);
1752
+ try {
1753
+ await def.down(schema);
1754
+ await this.removeMigration(migration.name);
1755
+ console.log(`Rolled back: ${migration.name}`);
1756
+ } catch (err) {
1757
+ console.error(`Rollback failed: ${migration.name}`, err);
1758
+ throw err;
1759
+ }
1760
+ }
1761
+ }
1762
+ }
1763
+ async reset() {
1764
+ await this.ensureMigrationTable();
1765
+ const allRan = await this.getRanMigrations();
1766
+ const schema = new SchemaBuilder(this.connection);
1767
+ for (const migration of allRan.reverse()) {
1768
+ const def = this.migrations.find((m) => m.name === migration.name);
1769
+ if (def) {
1770
+ console.log(`Resetting: ${migration.name}`);
1771
+ try {
1772
+ await def.down(schema);
1773
+ await this.removeMigration(migration.name);
1774
+ console.log(`Reset: ${migration.name}`);
1775
+ } catch (err) {
1776
+ console.error(`Reset failed: ${migration.name}`, err);
1777
+ throw err;
1778
+ }
1779
+ }
1780
+ }
1781
+ }
1782
+ async refresh() {
1783
+ await this.reset();
1784
+ await this.run();
1785
+ }
1786
+ async status() {
1787
+ await this.ensureMigrationTable();
1788
+ return this.getRanMigrations();
1789
+ }
1790
+ async ensureMigrationTable() {
1791
+ const dialect = this.connection.getDialect();
1792
+ const sql = dialect.compileCreateMigrationsTable();
1793
+ await this.connection.raw(sql);
1794
+ }
1795
+ async getRanMigrations() {
1796
+ const result = await this.connection.raw(
1797
+ "SELECT name, batch, executed_at as executedAt FROM migrations ORDER BY batch ASC, name ASC"
1798
+ );
1799
+ return result.rows.map((row) => ({
1800
+ name: String(row.name),
1801
+ batch: Number(row.batch),
1802
+ executedAt: String(row.executedAt ?? "")
1803
+ }));
1804
+ }
1805
+ async getNextBatchNumber() {
1806
+ const result = await this.connection.raw(
1807
+ "SELECT COALESCE(MAX(batch), 0) + 1 as next_batch FROM migrations"
1808
+ );
1809
+ return Number(result.rows[0]?.next_batch ?? 1);
1810
+ }
1811
+ async getLastBatchNumber() {
1812
+ const result = await this.connection.raw(
1813
+ "SELECT COALESCE(MAX(batch), 0) as last_batch FROM migrations"
1814
+ );
1815
+ return Number(result.rows[0]?.last_batch ?? 0);
1816
+ }
1817
+ async getMigrationsByBatch(batch) {
1818
+ const result = await this.connection.raw(
1819
+ "SELECT name, batch, executed_at as executedAt FROM migrations WHERE batch = ? ORDER BY name ASC",
1820
+ [batch]
1821
+ );
1822
+ return result.rows.map((row) => ({
1823
+ name: String(row.name),
1824
+ batch: Number(row.batch),
1825
+ executedAt: String(row.executedAt ?? "")
1826
+ }));
1827
+ }
1828
+ async recordMigration(name, batch) {
1829
+ await this.connection.raw(
1830
+ "INSERT INTO migrations (name, batch) VALUES (?, ?)",
1831
+ [name, batch]
1832
+ );
1833
+ }
1834
+ async removeMigration(name) {
1835
+ await this.connection.raw("DELETE FROM migrations WHERE name = ?", [name]);
1836
+ }
1837
+ };
1838
+
1839
+ // src/server/database/pagination.ts
1840
+ var Pagination = class _Pagination {
1841
+ data;
1842
+ currentPage;
1843
+ perPage;
1844
+ total;
1845
+ lastPage;
1846
+ from;
1847
+ to;
1848
+ constructor(result) {
1849
+ this.data = result.data;
1850
+ this.currentPage = result.currentPage;
1851
+ this.perPage = result.perPage;
1852
+ this.total = result.total;
1853
+ this.lastPage = result.lastPage;
1854
+ this.from = result.from;
1855
+ this.to = result.to;
1856
+ }
1857
+ get hasMore() {
1858
+ return this.currentPage < this.lastPage;
1859
+ }
1860
+ get hasPrev() {
1861
+ return this.currentPage > 1;
1862
+ }
1863
+ get isEmpty() {
1864
+ return this.data.length === 0;
1865
+ }
1866
+ nextPage() {
1867
+ if (!this.hasMore) return null;
1868
+ return {
1869
+ page: this.currentPage + 1,
1870
+ perPage: this.perPage,
1871
+ url: null
1872
+ };
1873
+ }
1874
+ prevPage() {
1875
+ if (!this.hasPrev) return null;
1876
+ return {
1877
+ page: this.currentPage - 1,
1878
+ perPage: this.perPage,
1879
+ url: null
1880
+ };
1881
+ }
1882
+ toJSON() {
1883
+ return {
1884
+ data: this.data,
1885
+ pagination: {
1886
+ currentPage: this.currentPage,
1887
+ perPage: this.perPage,
1888
+ total: this.total,
1889
+ lastPage: this.lastPage,
1890
+ from: this.from,
1891
+ to: this.to,
1892
+ hasMore: this.hasMore,
1893
+ hasPrev: this.hasPrev,
1894
+ isEmpty: this.isEmpty
1895
+ }
1896
+ };
1897
+ }
1898
+ map(fn) {
1899
+ return new _Pagination({
1900
+ ...this,
1901
+ data: this.data.map(fn)
1902
+ });
1903
+ }
1904
+ items() {
1905
+ return this.data;
1906
+ }
1907
+ static from(result) {
1908
+ return new _Pagination(result);
1909
+ }
1910
+ };
1911
+
1912
+ // src/server/database/seeder.ts
1913
+ var Seeder = class {
1914
+ connection;
1915
+ constructor(connection) {
1916
+ this.connection = connection;
1917
+ }
1918
+ async call(seederClass) {
1919
+ await seederClass.run(this.connection);
1920
+ }
1921
+ async insert(table, data) {
1922
+ if (data.length === 0) return;
1923
+ const dialect = this.connection.getDialect();
1924
+ const firstRow = data[0];
1925
+ if (!firstRow) return;
1926
+ const columns = Object.keys(firstRow);
1927
+ const wrappedColumns = columns.map((c) => dialect.wrapIdentifier(c)).join(", ");
1928
+ const batchSize = 100;
1929
+ for (let i = 0; i < data.length; i += batchSize) {
1930
+ const batch = data.slice(i, i + batchSize);
1931
+ const placeholders = [];
1932
+ const bindings = [];
1933
+ for (const row of batch) {
1934
+ const rowPlaceholders = columns.map((col) => {
1935
+ bindings.push(row[col]);
1936
+ return dialect.makeParameter(bindings.length - 1);
1937
+ });
1938
+ placeholders.push(`(${rowPlaceholders.join(", ")})`);
1939
+ }
1940
+ const sql = `INSERT INTO ${dialect.wrapIdentifier(table)} (${wrappedColumns}) VALUES ${placeholders.join(", ")}`;
1941
+ await this.connection.raw(sql, bindings);
1942
+ }
1943
+ }
1944
+ async truncate(table) {
1945
+ const dialect = this.connection.getDialect();
1946
+ const driver = this.connection.getDriver();
1947
+ if (driver === "sqlite") {
1948
+ await this.connection.raw(`DELETE FROM ${dialect.wrapIdentifier(table)}`);
1949
+ } else if (driver === "postgresql") {
1950
+ await this.connection.raw(dialect.compileTruncate(table));
1951
+ } else {
1952
+ await this.connection.raw("SET FOREIGN_KEY_CHECKS = 0");
1953
+ await this.connection.raw(dialect.compileTruncate(table));
1954
+ await this.connection.raw("SET FOREIGN_KEY_CHECKS = 1");
1955
+ }
1956
+ }
1957
+ async run() {
1958
+ throw new Error("Seeder.run() must be overridden by subclasses");
1959
+ }
1960
+ };
1961
+ export {
1962
+ ColumnDefinition,
1963
+ DatabaseConnection,
1964
+ ForeignKeyDefinition,
1965
+ Migrator,
1966
+ MysqlDialect,
1967
+ Pagination,
1968
+ PostgresqlDialect,
1969
+ QueryBuilder,
1970
+ SchemaBuilder,
1971
+ Seeder,
1972
+ SqliteDialect,
1973
+ TableBlueprint,
1974
+ createDialect,
1975
+ createDriver
1976
+ };
1977
+ //# sourceMappingURL=index.js.map