@revojs/storage 0.1.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,842 @@
1
+ import { defineContext, getContext, setContext } from "revojs";
2
+ //#region src/index.ts
3
+ var Parameter = class {
4
+ value;
5
+ constructor(value) {
6
+ this.value = value;
7
+ }
8
+ };
9
+ var Sql = class Sql {
10
+ $chunks;
11
+ constructor(...chunks) {
12
+ this.$chunks = chunks;
13
+ }
14
+ push(...chunks) {
15
+ chunks.forEach((chunk) => {
16
+ if (chunk instanceof Sql && this.$chunks.at(-1) instanceof Sql) this.$chunks.push(" ");
17
+ this.$chunks.push(chunk);
18
+ });
19
+ return this;
20
+ }
21
+ toQuery() {
22
+ const queries = this.$chunks.map((chunk) => {
23
+ if (typeof chunk === "string") return {
24
+ sql: chunk,
25
+ parameters: []
26
+ };
27
+ if (chunk instanceof Parameter) return {
28
+ sql: "?",
29
+ parameters: [chunk.value]
30
+ };
31
+ if (chunk instanceof Sql || chunk instanceof Table || chunk instanceof Column) return chunk.toSql().toQuery();
32
+ return {
33
+ sql: "?",
34
+ parameters: [chunk]
35
+ };
36
+ });
37
+ return {
38
+ sql: queries.map((query) => query.sql).join(""),
39
+ parameters: queries.flatMap((query) => query.parameters)
40
+ };
41
+ }
42
+ toSql() {
43
+ return this;
44
+ }
45
+ };
46
+ var Statement = class extends Sql {
47
+ $session;
48
+ $fields;
49
+ constructor(session, value, ...chunks) {
50
+ super(...chunks);
51
+ this.$session = session;
52
+ this.$fields = Object.entries(value instanceof Table ? value.$columns : value);
53
+ }
54
+ async then(onfulfilled, onrejected) {
55
+ let value;
56
+ try {
57
+ value = (await this.$session.all(this.toQuery())).map((row) => this.mapRow(row));
58
+ } catch (error) {
59
+ if (onrejected) return onrejected(error);
60
+ throw error;
61
+ }
62
+ return onfulfilled ? onfulfilled(value) : value;
63
+ }
64
+ mapRow(row) {
65
+ const result = {};
66
+ this.$fields.forEach(([key, column], index) => {
67
+ const value = row[index];
68
+ result[key] = value === null ? null : column.fromDriverValue(value);
69
+ });
70
+ return result;
71
+ }
72
+ };
73
+ var SelectStatement = class extends Statement {
74
+ $value;
75
+ $selection;
76
+ $baseNullable = false;
77
+ $joins = new Array();
78
+ constructor(session, value) {
79
+ super(session, value);
80
+ this.$value = value;
81
+ this.$selection = combine(this.$fields.map(([, column]) => column), ", ");
82
+ this.push(sql`SELECT ${this.$selection}`);
83
+ }
84
+ from(table) {
85
+ this.push(sql`FROM ${table}`);
86
+ return this;
87
+ }
88
+ leftJoin(table, on) {
89
+ this.push(sql`LEFT JOIN ${table} ON ${on}`);
90
+ if (this.$value instanceof Table) {
91
+ this.$selection.push(", ", combine(Object.values(table.$columns), ", "));
92
+ this.$joins.push({
93
+ table,
94
+ nullable: true
95
+ });
96
+ }
97
+ return this;
98
+ }
99
+ rightJoin(table, on) {
100
+ this.push(sql`RIGHT JOIN ${table} ON ${on}`);
101
+ if (this.$value instanceof Table) {
102
+ this.$selection.push(", ", combine(Object.values(table.$columns), ", "));
103
+ this.$baseNullable = true;
104
+ this.$joins.forEach((join) => join.nullable = true);
105
+ this.$joins.push({
106
+ table,
107
+ nullable: false
108
+ });
109
+ }
110
+ return this;
111
+ }
112
+ innerJoin(table, on) {
113
+ this.push(sql`INNER JOIN ${table} ON ${on}`);
114
+ if (this.$value instanceof Table) {
115
+ this.$selection.push(", ", combine(Object.values(table.$columns), ", "));
116
+ this.$joins.push({
117
+ table,
118
+ nullable: false
119
+ });
120
+ }
121
+ return this;
122
+ }
123
+ crossJoin(table) {
124
+ this.push(sql`CROSS JOIN ${table}`);
125
+ if (this.$value instanceof Table) {
126
+ this.$selection.push(", ", combine(Object.values(table.$columns), ", "));
127
+ this.$joins.push({
128
+ table,
129
+ nullable: false
130
+ });
131
+ }
132
+ return this;
133
+ }
134
+ where(chunk) {
135
+ this.push(sql`WHERE ${chunk}`);
136
+ return this;
137
+ }
138
+ groupBy(...columns) {
139
+ this.push(sql`GROUP BY ${combine(columns, ", ")}`);
140
+ return this;
141
+ }
142
+ having(chunk) {
143
+ this.push(sql`HAVING ${chunk}`);
144
+ return this;
145
+ }
146
+ orderBy(...chunks) {
147
+ this.push(sql`ORDER BY ${combine(chunks, ", ")}`);
148
+ return this;
149
+ }
150
+ limit(count) {
151
+ this.push(sql`LIMIT ${new Parameter(count)}`);
152
+ return this;
153
+ }
154
+ offset(count) {
155
+ this.push(sql`OFFSET ${new Parameter(count)}`);
156
+ return this;
157
+ }
158
+ mapRow(row) {
159
+ if (!(this.$value instanceof Table) || this.$joins.length === 0) return super.mapRow(row);
160
+ const result = {};
161
+ let offset = 0;
162
+ for (const { table, nullable } of [{
163
+ table: this.$value,
164
+ nullable: this.$baseNullable
165
+ }, ...this.$joins]) {
166
+ const fields = Object.entries(table.$columns);
167
+ const values = row.slice(offset, offset + fields.length);
168
+ if (nullable && values.every((value) => value === null)) {
169
+ result[table.$name] = null;
170
+ offset += fields.length;
171
+ continue;
172
+ }
173
+ result[table.$name] = Object.fromEntries(fields.map(([key, column], index) => [key, values[index] === null ? null : column.fromDriverValue(values[index])]));
174
+ offset += fields.length;
175
+ }
176
+ return result;
177
+ }
178
+ };
179
+ var InsertStatement = class extends Statement {
180
+ $table;
181
+ constructor(session, table) {
182
+ super(session, table, sql`INSERT INTO ${table}`);
183
+ this.$table = table;
184
+ }
185
+ values(value) {
186
+ const columns = this.$table.$columns;
187
+ const rows = Array.isArray(value) ? value : [value];
188
+ const keys = Object.entries(columns).filter(([key, column]) => column.$defaultValue !== void 0 || rows.some((row) => Object.hasOwn(row, key))).map(([key]) => key);
189
+ this.push(sql`(${combine(keys.map((key) => columns[key].toSqlName()), ", ")}) VALUES ${combine(rows.map((row) => sql`(${combine(keys.map((key) => {
190
+ const column = columns[key];
191
+ const rowValue = row[key];
192
+ if (rowValue !== void 0) return toParameter(column, rowValue);
193
+ return toParameter(column, typeof column.$defaultValue === "function" ? column.$defaultValue() : column.$defaultValue ?? null);
194
+ }), ", ")})`), ", ")}`);
195
+ return this;
196
+ }
197
+ onConflictDoNothing() {
198
+ this.push(sql`ON CONFLICT DO NOTHING`);
199
+ return this;
200
+ }
201
+ returning() {
202
+ this.push(sql`RETURNING ${combine(this.$fields.map(([, column]) => column.toSqlName()), ", ")}`);
203
+ return this;
204
+ }
205
+ };
206
+ var UpdateStatement = class extends Statement {
207
+ $table;
208
+ constructor(session, table) {
209
+ super(session, table, sql`UPDATE ${table} SET`);
210
+ this.$table = table;
211
+ }
212
+ set(value) {
213
+ const columns = this.$table.$columns;
214
+ this.push(combine(Object.entries(value).map(([key, chunk]) => sql`${columns[key].toSqlName()} = ${toParameter(columns[key], chunk ?? null)}`), ", "));
215
+ return this;
216
+ }
217
+ where(chunk) {
218
+ this.push(sql`WHERE ${chunk}`);
219
+ return this;
220
+ }
221
+ returning() {
222
+ this.push(sql`RETURNING ${combine(this.$fields.map(([, column]) => column.toSqlName()), ", ")}`);
223
+ return this;
224
+ }
225
+ };
226
+ var DeleteStatement = class extends Statement {
227
+ $table;
228
+ constructor(session, table) {
229
+ super(session, table, sql`DELETE FROM ${table}`);
230
+ this.$table = table;
231
+ }
232
+ where(chunk) {
233
+ this.push(sql`WHERE ${chunk}`);
234
+ return this;
235
+ }
236
+ returning() {
237
+ this.push(sql`RETURNING ${combine(this.$fields.map(([, column]) => column.toSqlName()), ", ")}`);
238
+ return this;
239
+ }
240
+ };
241
+ var PreparedQuery = class {
242
+ $query;
243
+ constructor(query) {
244
+ this.$query = query;
245
+ }
246
+ getQuery() {
247
+ return this.$query;
248
+ }
249
+ };
250
+ var Session = class {
251
+ run(query) {
252
+ return this.prepareQuery(query).run(query.parameters);
253
+ }
254
+ all(query) {
255
+ return this.prepareQuery(query).all(query.parameters);
256
+ }
257
+ get(query) {
258
+ return this.prepareQuery(query).get(query.parameters);
259
+ }
260
+ values(query) {
261
+ return this.prepareQuery(query).values(query.parameters);
262
+ }
263
+ };
264
+ var Migration = class {
265
+ toSql(changes, current) {
266
+ if (current.dialect !== this.$dialect) throw new Error(`Unable to create ${this.$dialect} migration for ${current.dialect} metadata`);
267
+ return this.render({
268
+ changes,
269
+ current
270
+ });
271
+ }
272
+ render({ changes }) {
273
+ return changes.flatMap((change) => this.renderChange(change));
274
+ }
275
+ diff(previous, current) {
276
+ if (previous && previous.dialect !== current.dialect) throw new Error(`Storage dialect changed from "${previous.dialect}" to "${current.dialect}"`);
277
+ const changes = new Array();
278
+ const previousTables = new Map((previous?.tables ?? []).map((table) => [table.name, table]));
279
+ const currentTables = new Map(current.tables.map((table) => [table.name, table]));
280
+ for (const [name, table] of currentTables) {
281
+ const previousTable = previousTables.get(name);
282
+ if (!previousTable) {
283
+ changes.push({
284
+ kind: "createTable",
285
+ table
286
+ });
287
+ for (const definition of table.definitions) if (definition.kind === "index" || definition.kind === "uniqueIndex") changes.push({
288
+ kind: "createIndex",
289
+ table: table.name,
290
+ index: definition
291
+ });
292
+ continue;
293
+ }
294
+ const previousDefinitions = this.splitDefinitions(previousTable.definitions);
295
+ const currentDefinitions = this.splitDefinitions(table.definitions);
296
+ const previousColumns = new Map(Object.entries(previousTable.columns));
297
+ const currentColumns = new Map(Object.entries(table.columns));
298
+ changes.push(...this.diffValues(previousColumns, currentColumns, {
299
+ create: (column) => ({
300
+ kind: "createColumn",
301
+ table: name,
302
+ column
303
+ }),
304
+ update: (previous, column) => ({
305
+ kind: "updateColumn",
306
+ table: name,
307
+ before: previous,
308
+ after: column
309
+ }),
310
+ delete: (column) => ({
311
+ kind: "deleteColumn",
312
+ table: name,
313
+ column
314
+ })
315
+ }));
316
+ changes.push(...this.diffValues(previousDefinitions.constraints, currentDefinitions.constraints, {
317
+ create: (constraint) => ({
318
+ kind: "createConstraint",
319
+ table: name,
320
+ constraint
321
+ }),
322
+ delete: (constraint) => ({
323
+ kind: "deleteConstraint",
324
+ table: name,
325
+ constraint
326
+ })
327
+ }));
328
+ changes.push(...this.diffValues(previousDefinitions.indexes, currentDefinitions.indexes, {
329
+ create: (index) => ({
330
+ kind: "createIndex",
331
+ table: name,
332
+ index
333
+ }),
334
+ delete: (index) => ({
335
+ kind: "deleteIndex",
336
+ table: name,
337
+ index
338
+ })
339
+ }));
340
+ }
341
+ for (const [name, table] of previousTables) if (!currentTables.has(name)) changes.push({
342
+ kind: "deleteTable",
343
+ table
344
+ });
345
+ return changes;
346
+ }
347
+ diffValues(before, after, factory) {
348
+ const changes = new Array();
349
+ for (const [key, value] of before) if (!after.has(key)) changes.push(factory.delete(value));
350
+ for (const [key, value] of after) {
351
+ const previous = before.get(key);
352
+ if (previous === void 0) changes.push(factory.create(value));
353
+ else if (!this.equals(previous, value)) {
354
+ if (factory.update) changes.push(factory.update(previous, value));
355
+ else changes.push(factory.delete(previous), factory.create(value));
356
+ }
357
+ }
358
+ return changes;
359
+ }
360
+ splitDefinitions(definitions) {
361
+ const constraints = /* @__PURE__ */ new Map();
362
+ const indexes = /* @__PURE__ */ new Map();
363
+ for (const definition of definitions) if (definition.kind === "index" || definition.kind === "uniqueIndex") indexes.set(this.definitionFingerprint(definition), definition);
364
+ else constraints.set(this.definitionFingerprint(definition), definition);
365
+ return {
366
+ constraints,
367
+ indexes
368
+ };
369
+ }
370
+ definitionFingerprint(definition) {
371
+ if (definition.kind === "check") return `${definition.kind}:${definition.sql}:${JSON.stringify(definition.parameters)}`;
372
+ if (definition.kind === "foreignKey") return `${definition.kind}:${definition.columns.join(",")}:${definition.foreignTable}:${definition.foreignColumns.join(",")}:${definition.onDelete}:${definition.onUpdate}`;
373
+ return `${definition.kind}:${definition.columns.join(",")}`;
374
+ }
375
+ renderChange(change) {
376
+ switch (change.kind) {
377
+ case "createTable": return this.toCreateTableChange(change);
378
+ case "deleteTable": return this.toDeleteTableChange(change);
379
+ case "createColumn": return this.toCreateColumnChange(change);
380
+ case "updateColumn": return this.toUpdateColumnChange(change);
381
+ case "deleteColumn": return this.toDeleteColumnChange(change);
382
+ case "createConstraint": return this.toCreateConstraintChange(change);
383
+ case "deleteConstraint": return this.toDeleteConstraintChange(change);
384
+ case "createIndex": return this.toCreateIndexChange(change);
385
+ case "deleteIndex": return this.toDeleteIndexChange(change);
386
+ }
387
+ }
388
+ toCreateTableChange(change, name = change.table.name) {
389
+ const definitions = new Array();
390
+ for (const column of Object.values(change.table.columns)) {
391
+ definitions.push(...this.toCreateColumnChange({
392
+ kind: "createColumn",
393
+ table: change.table.name,
394
+ column
395
+ }, true));
396
+ for (const constraint of this.columnConstraints(column)) definitions.push(...this.toCreateConstraintChange({
397
+ kind: "createConstraint",
398
+ table: change.table.name,
399
+ constraint
400
+ }, true));
401
+ }
402
+ for (const definition of change.table.definitions) if (definition.kind !== "index" && definition.kind !== "uniqueIndex") definitions.push(...this.toCreateConstraintChange({
403
+ kind: "createConstraint",
404
+ table: change.table.name,
405
+ constraint: definition
406
+ }, true));
407
+ return [`CREATE TABLE ${this.quoteIdentifier(name)} (\n${definitions.map((definition) => ` ${definition}`).join(",\n")}\n);`];
408
+ }
409
+ toDeleteTableChange(change) {
410
+ return [`DROP TABLE ${this.quoteIdentifier(change.table.name)};`];
411
+ }
412
+ toCreateColumnChange(change, inline = false) {
413
+ const definition = `${this.quoteIdentifier(change.column.name)} ${change.column.type}${change.column.notNull ? " NOT NULL" : ""}`;
414
+ if (inline) return [definition];
415
+ const statements = [this.alterTable(change.table, `ADD COLUMN ${definition}`)];
416
+ for (const constraint of this.columnConstraints(change.column)) statements.push(...this.toCreateConstraintChange({
417
+ kind: "createConstraint",
418
+ table: change.table,
419
+ constraint
420
+ }));
421
+ return statements;
422
+ }
423
+ toUpdateColumnChange(change) {
424
+ const statements = new Array();
425
+ if (change.before.type !== change.after.type) statements.push(this.alterTable(change.table, `ALTER COLUMN ${this.quoteIdentifier(change.after.name)} TYPE ${change.after.type}`));
426
+ if (change.before.notNull !== change.after.notNull) statements.push(this.alterTable(change.table, `ALTER COLUMN ${this.quoteIdentifier(change.after.name)} ${change.after.notNull ? "SET" : "DROP"} NOT NULL`));
427
+ statements.push(...this.updateColumnConstraints(change.table, change.before, change.after));
428
+ return statements;
429
+ }
430
+ toDeleteColumnChange(change) {
431
+ const statements = new Array();
432
+ for (const constraint of this.columnConstraints(change.column)) statements.push(...this.toDeleteConstraintChange({
433
+ kind: "deleteConstraint",
434
+ table: change.table,
435
+ constraint
436
+ }));
437
+ statements.push(this.alterTable(change.table, `DROP COLUMN ${this.quoteIdentifier(change.column.name)}`));
438
+ return statements;
439
+ }
440
+ toCreateConstraintChange(change, inline = false) {
441
+ const constraint = change.constraint;
442
+ const name = this.quoteIdentifier(this.constraintName(change.table, constraint));
443
+ let definition;
444
+ if (constraint.kind === "check") {
445
+ let index = 0;
446
+ const sql = constraint.sql.replaceAll("?", () => {
447
+ if (index >= constraint.parameters.length) throw new Error("Check constraint parameter count does not match its SQL placeholders");
448
+ return this.serializeLiteral(constraint.parameters[index++]);
449
+ });
450
+ if (index !== constraint.parameters.length) throw new Error("Check constraint parameter count does not match its SQL placeholders");
451
+ definition = `CONSTRAINT ${name} CHECK (${sql})`;
452
+ } else {
453
+ const columns = this.quoteIdentifiers(constraint.columns);
454
+ if (constraint.kind === "primaryKey") definition = `CONSTRAINT ${name} PRIMARY KEY (${columns})`;
455
+ else if (constraint.kind === "unique") definition = `CONSTRAINT ${name} UNIQUE (${columns})`;
456
+ else {
457
+ let actions = "";
458
+ if (constraint.onDelete) actions += ` ON DELETE ${constraint.onDelete.toUpperCase()}`;
459
+ if (constraint.onUpdate) actions += ` ON UPDATE ${constraint.onUpdate.toUpperCase()}`;
460
+ definition = `CONSTRAINT ${name} FOREIGN KEY (${columns}) REFERENCES ${this.quoteIdentifier(constraint.foreignTable)} (${this.quoteIdentifiers(constraint.foreignColumns)})${actions}`;
461
+ }
462
+ }
463
+ return inline ? [definition] : [this.alterTable(change.table, `ADD ${definition}`)];
464
+ }
465
+ toDeleteConstraintChange(change) {
466
+ return [this.alterTable(change.table, `DROP CONSTRAINT ${this.quoteIdentifier(this.constraintName(change.table, change.constraint))}`)];
467
+ }
468
+ toCreateIndexChange(change) {
469
+ return [`CREATE ${change.index.kind === "uniqueIndex" ? "UNIQUE " : ""}INDEX ${this.quoteIdentifier(this.indexName(change.table, change.index))} ON ${this.quoteIdentifier(change.table)} (${this.quoteIdentifiers(change.index.columns)});`];
470
+ }
471
+ toDeleteIndexChange(change) {
472
+ return [`DROP INDEX ${this.quoteIdentifier(this.indexName(change.table, change.index))};`];
473
+ }
474
+ columnConstraints(column) {
475
+ const constraints = new Array();
476
+ if (column.primaryKey) constraints.push({
477
+ kind: "primaryKey",
478
+ columns: [column.name]
479
+ });
480
+ if (column.unique) constraints.push({
481
+ kind: "unique",
482
+ columns: [column.name]
483
+ });
484
+ if (column.references) constraints.push({
485
+ kind: "foreignKey",
486
+ columns: [column.name],
487
+ foreignTable: column.references.table,
488
+ foreignColumns: [column.references.column],
489
+ onDelete: column.references.onDelete,
490
+ onUpdate: column.references.onUpdate
491
+ });
492
+ return constraints;
493
+ }
494
+ updateColumnConstraints(table, before, after) {
495
+ const statements = new Array();
496
+ const beforeConstraints = new Map(this.columnConstraints(before).map((constraint) => [constraint.kind, constraint]));
497
+ const afterConstraints = new Map(this.columnConstraints(after).map((constraint) => [constraint.kind, constraint]));
498
+ for (const [kind, constraint] of beforeConstraints) {
499
+ const next = afterConstraints.get(kind);
500
+ if (!next || !this.equals(constraint, next)) statements.push(...this.toDeleteConstraintChange({
501
+ kind: "deleteConstraint",
502
+ table,
503
+ constraint
504
+ }));
505
+ }
506
+ for (const [kind, constraint] of afterConstraints) {
507
+ const previous = beforeConstraints.get(kind);
508
+ if (!previous || !this.equals(previous, constraint)) statements.push(...this.toCreateConstraintChange({
509
+ kind: "createConstraint",
510
+ table,
511
+ constraint
512
+ }));
513
+ }
514
+ return statements;
515
+ }
516
+ constraintName(table, constraint) {
517
+ if (constraint.kind === "check") return this.generatedName([
518
+ table,
519
+ this.hash(`${constraint.sql}:${JSON.stringify(constraint.parameters)}`),
520
+ "check"
521
+ ]);
522
+ return this.generatedName([
523
+ table,
524
+ ...constraint.columns,
525
+ constraint.kind
526
+ ]);
527
+ }
528
+ indexName(table, index) {
529
+ return this.generatedName([
530
+ table,
531
+ ...index.columns,
532
+ index.kind
533
+ ]);
534
+ }
535
+ generatedName(parts) {
536
+ const value = parts.join("_").replaceAll(/[^a-zA-Z0-9_]/g, "_");
537
+ return value.length <= 54 ? value : `${value.slice(0, 45)}_${this.hash(value)}`;
538
+ }
539
+ hash(value) {
540
+ let result = 2166136261;
541
+ for (const character of value) {
542
+ result ^= character.charCodeAt(0);
543
+ result = Math.imul(result, 16777619);
544
+ }
545
+ return (result >>> 0).toString(16).padStart(8, "0");
546
+ }
547
+ quoteIdentifiers(values) {
548
+ return values.map((value) => this.quoteIdentifier(value)).join(", ");
549
+ }
550
+ alterTable(table, value) {
551
+ return `ALTER TABLE ${this.quoteIdentifier(table)} ${value};`;
552
+ }
553
+ equals(left, right) {
554
+ return JSON.stringify(left) === JSON.stringify(right);
555
+ }
556
+ serializeLiteral(value) {
557
+ if (value === null) return "NULL";
558
+ if (typeof value === "number") {
559
+ if (!Number.isFinite(value)) throw new Error("Unable to serialize non-finite check constraint number");
560
+ return String(value);
561
+ }
562
+ if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
563
+ return `'${value.replaceAll("'", "''")}'`;
564
+ }
565
+ };
566
+ var Database = class {
567
+ $schema;
568
+ $session;
569
+ get $dialect() {
570
+ return this.$migration.$dialect;
571
+ }
572
+ constructor(session, schema) {
573
+ this.$session = session;
574
+ this.$schema = schema;
575
+ }
576
+ toMeta() {
577
+ return {
578
+ dialect: this.$dialect,
579
+ tables: Object.values(this.$schema).map((table) => table.toMeta())
580
+ };
581
+ }
582
+ };
583
+ var Table = class {
584
+ $name;
585
+ $columns;
586
+ $definitions;
587
+ constructor(name, columns, definitions) {
588
+ this.$name = name;
589
+ this.$columns = columns;
590
+ this.$definitions = definitions;
591
+ for (const column of Object.values(columns)) column.$table = this;
592
+ }
593
+ toMeta() {
594
+ return {
595
+ name: this.$name,
596
+ columns: Object.fromEntries(Object.values(this.$columns).map((column) => [column.$name, column.toMeta()])),
597
+ definitions: this.$definitions.map((definition) => definition.toMeta())
598
+ };
599
+ }
600
+ toSql() {
601
+ return new Sql(`"${this.$name}"`);
602
+ }
603
+ };
604
+ var Column = class {
605
+ $name;
606
+ $table;
607
+ $notNull;
608
+ $primaryKey;
609
+ $unique;
610
+ $defaultValue;
611
+ $references;
612
+ $onDelete;
613
+ $onUpdate;
614
+ constructor(name) {
615
+ this.$name = name;
616
+ this.$notNull = false;
617
+ this.$primaryKey = false;
618
+ this.$unique = false;
619
+ }
620
+ default(defaultValue) {
621
+ this.$defaultValue = defaultValue;
622
+ return this;
623
+ }
624
+ notNull() {
625
+ this.$notNull = true;
626
+ return this;
627
+ }
628
+ unique() {
629
+ this.$unique = true;
630
+ return this;
631
+ }
632
+ primaryKey() {
633
+ this.$primaryKey = true;
634
+ return this;
635
+ }
636
+ references(references, actions) {
637
+ this.$references = references;
638
+ this.$onDelete = actions?.onDelete;
639
+ this.$onUpdate = actions?.onUpdate;
640
+ return this;
641
+ }
642
+ fromDriverValue(value) {
643
+ return value;
644
+ }
645
+ toDriverValue(value) {
646
+ return value;
647
+ }
648
+ toSql() {
649
+ return this.$table ? new Sql(this.$table, ".", this.toSqlName()) : this.toSqlName();
650
+ }
651
+ toSqlName() {
652
+ return new Sql(`"${this.$name}"`);
653
+ }
654
+ toMeta() {
655
+ const foreignColumn = this.$references?.();
656
+ if (foreignColumn && !foreignColumn.$table) throw new Error(`Referenced column "${foreignColumn.$name}" does not belong to a table`);
657
+ return {
658
+ name: this.$name,
659
+ type: this.toSqlType(),
660
+ notNull: this.$notNull,
661
+ primaryKey: this.$primaryKey,
662
+ unique: this.$unique,
663
+ references: foreignColumn ? {
664
+ table: foreignColumn.$table.$name,
665
+ column: foreignColumn.$name,
666
+ onDelete: this.$onDelete,
667
+ onUpdate: this.$onUpdate
668
+ } : void 0
669
+ };
670
+ }
671
+ };
672
+ var UniqueConstraint = class {
673
+ $columns;
674
+ constructor(...columns) {
675
+ this.$columns = columns;
676
+ }
677
+ on(...columns) {
678
+ this.$columns = columns;
679
+ return this;
680
+ }
681
+ toMeta() {
682
+ return {
683
+ kind: "unique",
684
+ columns: this.$columns.map((column) => column.$name)
685
+ };
686
+ }
687
+ };
688
+ var CheckConstraint = class {
689
+ $value;
690
+ $query;
691
+ constructor(value) {
692
+ this.$value = value;
693
+ this.$query = value.toQuery();
694
+ }
695
+ toMeta() {
696
+ return {
697
+ kind: "check",
698
+ sql: this.$query.sql,
699
+ parameters: this.$query.parameters.map((parameter) => {
700
+ if (typeof parameter === "bigint") return parameter.toString();
701
+ if (typeof parameter === "symbol") throw new Error("Unable to serialize symbol parameters");
702
+ return parameter ?? null;
703
+ })
704
+ };
705
+ }
706
+ };
707
+ var PrimaryKeyConstraint = class {
708
+ $columns;
709
+ constructor(...columns) {
710
+ this.$columns = columns;
711
+ }
712
+ toMeta() {
713
+ return {
714
+ kind: "primaryKey",
715
+ columns: this.$columns.map((column) => column.$name)
716
+ };
717
+ }
718
+ };
719
+ var ForeignKeyConstraint = class {
720
+ $columns;
721
+ $foreignColumns;
722
+ constructor(columns, foreignColumns) {
723
+ this.$columns = columns;
724
+ this.$foreignColumns = foreignColumns;
725
+ }
726
+ toMeta() {
727
+ const foreignTables = new Set(this.$foreignColumns.map((column) => column.$table?.$name));
728
+ if (foreignTables.size !== 1 || foreignTables.has(void 0)) throw new Error("Foreign key columns must belong to the same table");
729
+ return {
730
+ kind: "foreignKey",
731
+ columns: this.$columns.map((column) => column.$name),
732
+ foreignTable: [...foreignTables][0],
733
+ foreignColumns: this.$foreignColumns.map((column) => column.$name)
734
+ };
735
+ }
736
+ };
737
+ var Index = class {
738
+ $columns;
739
+ constructor(...columns) {
740
+ this.$columns = columns;
741
+ }
742
+ on(...columns) {
743
+ this.$columns = columns;
744
+ return this;
745
+ }
746
+ toMeta() {
747
+ return {
748
+ kind: "index",
749
+ columns: this.$columns.map((column) => column.$name)
750
+ };
751
+ }
752
+ };
753
+ var UniqueIndex = class {
754
+ $columns;
755
+ constructor(...columns) {
756
+ this.$columns = columns;
757
+ }
758
+ on(...columns) {
759
+ this.$columns = columns;
760
+ return this;
761
+ }
762
+ toMeta() {
763
+ return {
764
+ kind: "uniqueIndex",
765
+ columns: this.$columns.map((column) => column.$name)
766
+ };
767
+ }
768
+ };
769
+ function toParameter(column, value) {
770
+ if (value instanceof Parameter || value instanceof Sql || value instanceof Table || value instanceof Column) return value;
771
+ return new Parameter(column.toDriverValue(value));
772
+ }
773
+ function combine(chunks, separator) {
774
+ const result = [];
775
+ chunks.forEach((chunk, index) => {
776
+ if (index > 0) result.push(separator);
777
+ result.push(chunk);
778
+ });
779
+ return new Sql(...result);
780
+ }
781
+ function sql(tokens, ...values) {
782
+ const chunks = [tokens[0]];
783
+ values.forEach((value, index) => {
784
+ chunks.push(value === void 0 ? null : value, tokens[index + 1]);
785
+ });
786
+ return new Sql(...chunks);
787
+ }
788
+ function equals(column, right) {
789
+ return sql`${column} = ${toParameter(column, right)}`;
790
+ }
791
+ function greater(column, right) {
792
+ return sql`${column} > ${toParameter(column, right)}`;
793
+ }
794
+ function greaterEquals(column, right) {
795
+ return sql`${column} >= ${toParameter(column, right)}`;
796
+ }
797
+ function lower(column, right) {
798
+ return sql`${column} < ${toParameter(column, right)}`;
799
+ }
800
+ function lowerEquals(column, right) {
801
+ return sql`${column} <= ${toParameter(column, right)}`;
802
+ }
803
+ function like(column, right) {
804
+ return sql`${column} LIKE ${toParameter(column, right)}`;
805
+ }
806
+ function contains(column, values) {
807
+ return sql`${column} IN (${combine(values.map((value) => toParameter(column, value)), ", ")})`;
808
+ }
809
+ function nullish(chunk) {
810
+ return sql`${chunk} IS NULL`;
811
+ }
812
+ function not(chunk) {
813
+ return sql`NOT ${chunk}`;
814
+ }
815
+ function exists(chunk) {
816
+ return sql`EXISTS (${chunk})`;
817
+ }
818
+ function between(column, from, to) {
819
+ return sql`${column} BETWEEN ${toParameter(column, from)} AND ${toParameter(column, to)}`;
820
+ }
821
+ function and(...chunks) {
822
+ return sql`(${combine(chunks, " AND ")})`;
823
+ }
824
+ function or(...chunks) {
825
+ return sql`(${combine(chunks, " OR ")})`;
826
+ }
827
+ function asc(chunk) {
828
+ return sql`${chunk} ASC`;
829
+ }
830
+ function desc(chunk) {
831
+ return sql`${chunk} DESC`;
832
+ }
833
+ function useStorage(scope, scopeName) {
834
+ const storages = getContext(scope, STORAGE_CONTEXT);
835
+ const storage = storages[scopeName] ?? {};
836
+ storages[scopeName] = storage;
837
+ setContext(scope, STORAGE_CONTEXT, storages);
838
+ return storage;
839
+ }
840
+ var STORAGE_CONTEXT = defineContext("STORAGE_CONTEXT");
841
+ //#endregion
842
+ export { CheckConstraint, Column, Database, DeleteStatement, ForeignKeyConstraint, Index, InsertStatement, Migration, Parameter, PreparedQuery, PrimaryKeyConstraint, STORAGE_CONTEXT, SelectStatement, Session, Sql, Statement, Table, UniqueConstraint, UniqueIndex, UpdateStatement, and, asc, between, combine, contains, desc, equals, exists, greater, greaterEquals, like, lower, lowerEquals, not, nullish, or, sql, toParameter, useStorage };