@palbase/backend 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Palbase
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/db/index.ts
21
+ var db_exports = {};
22
+ __export(db_exports, {
23
+ boolean: () => boolean,
24
+ defineSchema: () => defineSchema,
25
+ enumType: () => enumType,
26
+ generateDiffMigration: () => generateDiffMigration,
27
+ generateMigration: () => generateMigration,
28
+ integer: () => integer,
29
+ jsonb: () => jsonb,
30
+ table: () => table,
31
+ text: () => text,
32
+ timestamp: () => timestamp,
33
+ uuid: () => uuid
34
+ });
35
+ module.exports = __toCommonJS(db_exports);
36
+
37
+ // src/db/schema.ts
38
+ function table(name, columns) {
39
+ return { name, columns };
40
+ }
41
+ function defineSchema(tables) {
42
+ return { tables };
43
+ }
44
+
45
+ // src/db/columns.ts
46
+ var ColumnBuilder = class {
47
+ _def;
48
+ constructor(type) {
49
+ this._def = {
50
+ type,
51
+ nullable: false,
52
+ primaryKey: false
53
+ };
54
+ }
55
+ /** Mark this column as the primary key. */
56
+ primaryKey() {
57
+ this._def.primaryKey = true;
58
+ return this;
59
+ }
60
+ /** Mark this column as NOT NULL (default). */
61
+ notNull() {
62
+ this._def.nullable = false;
63
+ return this;
64
+ }
65
+ /** Allow NULL values. */
66
+ nullable() {
67
+ this._def.nullable = true;
68
+ return this;
69
+ }
70
+ /** Set a default value. */
71
+ default(value) {
72
+ this._def.defaultValue = value;
73
+ return this;
74
+ }
75
+ /** UUID: generate a random default (gen_random_uuid()). */
76
+ defaultRandom() {
77
+ this._def.defaultRandom = true;
78
+ return this;
79
+ }
80
+ /** Timestamp: default to now(). */
81
+ defaultNow() {
82
+ this._def.defaultNow = true;
83
+ return this;
84
+ }
85
+ /** Add a foreign key reference. */
86
+ references(table2, column) {
87
+ this._def.references = { table: table2, column };
88
+ return this;
89
+ }
90
+ /** Set the ON DELETE action for a foreign key reference. */
91
+ onDelete(action) {
92
+ this._def.onDeleteAction = action;
93
+ return this;
94
+ }
95
+ };
96
+ function uuid() {
97
+ return new ColumnBuilder("uuid");
98
+ }
99
+ function text() {
100
+ return new ColumnBuilder("text");
101
+ }
102
+ function integer() {
103
+ return new ColumnBuilder("integer");
104
+ }
105
+ function boolean() {
106
+ return new ColumnBuilder("boolean");
107
+ }
108
+ function timestamp() {
109
+ return new ColumnBuilder("timestamp");
110
+ }
111
+ function jsonb() {
112
+ return new ColumnBuilder("jsonb");
113
+ }
114
+ function enumType(name, values) {
115
+ const builder = new ColumnBuilder("enum");
116
+ builder._def.enumName = name;
117
+ builder._def.enumValues = values;
118
+ return builder;
119
+ }
120
+
121
+ // src/db/generator.ts
122
+ function columnTypeToSQL(col) {
123
+ switch (col.type) {
124
+ case "uuid":
125
+ return "UUID";
126
+ case "text":
127
+ return "TEXT";
128
+ case "integer":
129
+ return "INTEGER";
130
+ case "boolean":
131
+ return "BOOLEAN";
132
+ case "timestamp":
133
+ return "TIMESTAMPTZ";
134
+ case "jsonb":
135
+ return "JSONB";
136
+ case "enum":
137
+ return col.enumName ?? "TEXT";
138
+ default:
139
+ return "TEXT";
140
+ }
141
+ }
142
+ function defaultClause(col) {
143
+ if (col.defaultRandom) {
144
+ return " DEFAULT gen_random_uuid()";
145
+ }
146
+ if (col.defaultNow) {
147
+ return " DEFAULT now()";
148
+ }
149
+ if (col.defaultValue !== void 0) {
150
+ if (typeof col.defaultValue === "string") {
151
+ const escaped = col.defaultValue.replace(/'/g, "''");
152
+ return ` DEFAULT '${escaped}'`;
153
+ }
154
+ if (typeof col.defaultValue === "boolean") {
155
+ return ` DEFAULT ${col.defaultValue ? "true" : "false"}`;
156
+ }
157
+ if (typeof col.defaultValue === "object" && col.defaultValue !== null) {
158
+ const escaped = JSON.stringify(col.defaultValue).replace(/'/g, "''");
159
+ return ` DEFAULT '${escaped}'::jsonb`;
160
+ }
161
+ return ` DEFAULT ${col.defaultValue}`;
162
+ }
163
+ return "";
164
+ }
165
+ function onDeleteSQL(action) {
166
+ switch (action) {
167
+ case "cascade":
168
+ return "CASCADE";
169
+ case "set null":
170
+ return "SET NULL";
171
+ case "restrict":
172
+ return "RESTRICT";
173
+ case "no action":
174
+ return "NO ACTION";
175
+ }
176
+ }
177
+ function generateEnumTypes(tables) {
178
+ const enums = /* @__PURE__ */ new Map();
179
+ for (const tableDef of Object.values(tables)) {
180
+ for (const col of Object.values(tableDef.columns)) {
181
+ if (col._def.type === "enum" && col._def.enumName && col._def.enumValues) {
182
+ enums.set(col._def.enumName, col._def.enumValues);
183
+ }
184
+ }
185
+ }
186
+ return Array.from(enums.entries()).map(([name, values]) => {
187
+ const vals = values.map((v) => `'${v.replace(/'/g, "''")}'`).join(", ");
188
+ return `CREATE TYPE ${name} AS ENUM (${vals});`;
189
+ });
190
+ }
191
+ function generateCreateTable(tableDef) {
192
+ const lines = [];
193
+ for (const [colName, colBuilder] of Object.entries(tableDef.columns)) {
194
+ const col = colBuilder._def;
195
+ let line = ` ${colName} ${columnTypeToSQL(col)}`;
196
+ if (col.primaryKey) {
197
+ line += " PRIMARY KEY";
198
+ }
199
+ if (!col.nullable && !col.primaryKey) {
200
+ line += " NOT NULL";
201
+ }
202
+ line += defaultClause(col);
203
+ if (col.references) {
204
+ line += ` REFERENCES ${col.references.table}(${col.references.column})`;
205
+ if (col.onDeleteAction) {
206
+ line += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;
207
+ }
208
+ }
209
+ lines.push(line);
210
+ }
211
+ return `CREATE TABLE ${tableDef.name} (
212
+ ${lines.join(",\n")}
213
+ );`;
214
+ }
215
+ function generateDropTable(tableDef) {
216
+ return `DROP TABLE IF EXISTS ${tableDef.name};`;
217
+ }
218
+ function generateDropEnumTypes(tables) {
219
+ const enums = /* @__PURE__ */ new Set();
220
+ for (const tableDef of Object.values(tables)) {
221
+ for (const col of Object.values(tableDef.columns)) {
222
+ if (col._def.type === "enum" && col._def.enumName) {
223
+ enums.add(col._def.enumName);
224
+ }
225
+ }
226
+ }
227
+ return Array.from(enums).map((name) => `DROP TYPE IF EXISTS ${name};`);
228
+ }
229
+ function generateMigration(schema) {
230
+ const upParts = [];
231
+ const downParts = [];
232
+ const enumTypes = generateEnumTypes(schema.tables);
233
+ upParts.push(...enumTypes);
234
+ for (const tableDef of Object.values(schema.tables)) {
235
+ upParts.push(generateCreateTable(tableDef));
236
+ }
237
+ const tableNames = Object.values(schema.tables);
238
+ for (let i = tableNames.length - 1; i >= 0; i--) {
239
+ downParts.push(generateDropTable(tableNames[i]));
240
+ }
241
+ downParts.push(...generateDropEnumTypes(schema.tables));
242
+ return {
243
+ up: upParts.join("\n\n"),
244
+ down: downParts.join("\n\n")
245
+ };
246
+ }
247
+ function diffSchemas(oldSchema, newSchema) {
248
+ const addedTables = [];
249
+ const droppedTables = [];
250
+ const columnDiffs = [];
251
+ const oldTableNames = new Set(Object.keys(oldSchema.tables));
252
+ const newTableNames = new Set(Object.keys(newSchema.tables));
253
+ for (const name of newTableNames) {
254
+ if (!oldTableNames.has(name)) {
255
+ addedTables.push(newSchema.tables[name]);
256
+ }
257
+ }
258
+ for (const name of oldTableNames) {
259
+ if (!newTableNames.has(name)) {
260
+ droppedTables.push(oldSchema.tables[name]);
261
+ }
262
+ }
263
+ for (const name of newTableNames) {
264
+ if (!oldTableNames.has(name)) continue;
265
+ const oldTable = oldSchema.tables[name];
266
+ const newTable = newSchema.tables[name];
267
+ const oldCols = new Set(Object.keys(oldTable.columns));
268
+ const newCols = new Set(Object.keys(newTable.columns));
269
+ for (const col of newCols) {
270
+ if (!oldCols.has(col)) {
271
+ columnDiffs.push({
272
+ type: "add",
273
+ table: newTable.name,
274
+ column: col,
275
+ def: newTable.columns[col]._def
276
+ });
277
+ }
278
+ }
279
+ for (const col of oldCols) {
280
+ if (!newCols.has(col)) {
281
+ columnDiffs.push({
282
+ type: "drop",
283
+ table: oldTable.name,
284
+ column: col,
285
+ oldDef: oldTable.columns[col]._def
286
+ });
287
+ }
288
+ }
289
+ }
290
+ return { addedTables, droppedTables, columnDiffs };
291
+ }
292
+ function generateAddColumn(table2, column, col) {
293
+ let sql = `ALTER TABLE ${table2} ADD COLUMN ${column} ${columnTypeToSQL(col)}`;
294
+ if (!col.nullable) {
295
+ sql += " NOT NULL";
296
+ }
297
+ sql += defaultClause(col);
298
+ if (col.references) {
299
+ sql += ` REFERENCES ${col.references.table}(${col.references.column})`;
300
+ if (col.onDeleteAction) {
301
+ sql += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;
302
+ }
303
+ }
304
+ return `${sql};`;
305
+ }
306
+ function generateDropColumn(table2, column) {
307
+ return `ALTER TABLE ${table2} DROP COLUMN ${column};`;
308
+ }
309
+ function generateDiffMigration(oldSchema, newSchema) {
310
+ const { addedTables, droppedTables, columnDiffs } = diffSchemas(oldSchema, newSchema);
311
+ if (addedTables.length === 0 && droppedTables.length === 0 && columnDiffs.length === 0) {
312
+ return null;
313
+ }
314
+ const upParts = [];
315
+ const downParts = [];
316
+ const newEnums = generateEnumTypes(
317
+ Object.fromEntries(addedTables.map((t) => [t.name, t]))
318
+ );
319
+ upParts.push(...newEnums);
320
+ for (const table2 of addedTables) {
321
+ upParts.push(generateCreateTable(table2));
322
+ downParts.push(generateDropTable(table2));
323
+ }
324
+ for (const table2 of droppedTables) {
325
+ upParts.push(generateDropTable(table2));
326
+ downParts.push(generateCreateTable(table2));
327
+ }
328
+ for (const diff of columnDiffs) {
329
+ if (diff.type === "add" && diff.def) {
330
+ upParts.push(generateAddColumn(diff.table, diff.column, diff.def));
331
+ downParts.push(generateDropColumn(diff.table, diff.column));
332
+ } else if (diff.type === "drop") {
333
+ upParts.push(generateDropColumn(diff.table, diff.column));
334
+ if (diff.oldDef) {
335
+ downParts.push(generateAddColumn(diff.table, diff.column, diff.oldDef));
336
+ }
337
+ }
338
+ }
339
+ const droppedEnums = generateDropEnumTypes(
340
+ Object.fromEntries(droppedTables.map((t) => [t.name, t]))
341
+ );
342
+ downParts.push(...droppedEnums);
343
+ return {
344
+ up: upParts.join("\n\n"),
345
+ down: downParts.join("\n\n")
346
+ };
347
+ }
348
+ // Annotate the CommonJS export names for ESM import in node:
349
+ 0 && (module.exports = {
350
+ boolean,
351
+ defineSchema,
352
+ enumType,
353
+ generateDiffMigration,
354
+ generateMigration,
355
+ integer,
356
+ jsonb,
357
+ table,
358
+ text,
359
+ timestamp,
360
+ uuid
361
+ });
362
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/db/index.ts","../../src/db/schema.ts","../../src/db/columns.ts","../../src/db/generator.ts"],"sourcesContent":["export { defineSchema, table } from \"./schema.js\";\nexport type { TableDef, SchemaDef } from \"./schema.js\";\nexport {\n uuid,\n text,\n integer,\n boolean,\n timestamp,\n jsonb,\n enumType,\n} from \"./columns.js\";\nexport type { ColumnDef, ColumnType, OnDeleteAction, ColumnBuilder } from \"./columns.js\";\nexport { generateMigration, generateDiffMigration } from \"./generator.js\";\nexport type { MigrationResult } from \"./generator.js\";\n","import type { ColumnBuilder } from \"./columns.js\";\n\n/** A table definition with its columns. */\nexport interface TableDef {\n name: string;\n columns: Record<string, ColumnBuilder>;\n}\n\n/** A schema definition containing multiple tables. */\nexport interface SchemaDef<T extends Record<string, TableDef> = Record<string, TableDef>> {\n tables: T;\n}\n\n/** Define a table with a name and columns. */\nexport function table(name: string, columns: Record<string, ColumnBuilder>): TableDef {\n return { name, columns };\n}\n\n/** Define a schema containing multiple tables. */\nexport function defineSchema<T extends Record<string, TableDef>>(tables: T): SchemaDef<T> {\n return { tables };\n}\n","/** On delete action for foreign key references. */\nexport type OnDeleteAction = \"cascade\" | \"set null\" | \"restrict\" | \"no action\";\n\n/** Column type identifiers. */\nexport type ColumnType = \"uuid\" | \"text\" | \"integer\" | \"boolean\" | \"timestamp\" | \"jsonb\" | \"enum\";\n\n/** Base column definition shared by all column types. */\nexport interface ColumnDef {\n type: ColumnType;\n nullable: boolean;\n primaryKey: boolean;\n defaultValue?: unknown;\n defaultRandom?: boolean;\n defaultNow?: boolean;\n references?: { table: string; column: string };\n onDeleteAction?: OnDeleteAction;\n enumName?: string;\n enumValues?: string[];\n}\n\n/** Fluent column builder. Methods return `this` for chaining. */\nclass ColumnBuilder {\n readonly _def: ColumnDef;\n\n constructor(type: ColumnType) {\n this._def = {\n type,\n nullable: false,\n primaryKey: false,\n };\n }\n\n /** Mark this column as the primary key. */\n primaryKey(): this {\n this._def.primaryKey = true;\n return this;\n }\n\n /** Mark this column as NOT NULL (default). */\n notNull(): this {\n this._def.nullable = false;\n return this;\n }\n\n /** Allow NULL values. */\n nullable(): this {\n this._def.nullable = true;\n return this;\n }\n\n /** Set a default value. */\n default(value: unknown): this {\n this._def.defaultValue = value;\n return this;\n }\n\n /** UUID: generate a random default (gen_random_uuid()). */\n defaultRandom(): this {\n this._def.defaultRandom = true;\n return this;\n }\n\n /** Timestamp: default to now(). */\n defaultNow(): this {\n this._def.defaultNow = true;\n return this;\n }\n\n /** Add a foreign key reference. */\n references(table: string, column: string): this {\n this._def.references = { table, column };\n return this;\n }\n\n /** Set the ON DELETE action for a foreign key reference. */\n onDelete(action: OnDeleteAction): this {\n this._def.onDeleteAction = action;\n return this;\n }\n}\n\n/** Create a UUID column. */\nexport function uuid(): ColumnBuilder {\n return new ColumnBuilder(\"uuid\");\n}\n\n/** Create a TEXT column. */\nexport function text(): ColumnBuilder {\n return new ColumnBuilder(\"text\");\n}\n\n/** Create an INTEGER column. */\nexport function integer(): ColumnBuilder {\n return new ColumnBuilder(\"integer\");\n}\n\n/** Create a BOOLEAN column. */\nexport function boolean(): ColumnBuilder {\n return new ColumnBuilder(\"boolean\");\n}\n\n/** Create a TIMESTAMP column. */\nexport function timestamp(): ColumnBuilder {\n return new ColumnBuilder(\"timestamp\");\n}\n\n/** Create a JSONB column. */\nexport function jsonb(): ColumnBuilder {\n return new ColumnBuilder(\"jsonb\");\n}\n\n/** Create an ENUM column. */\nexport function enumType(name: string, values: string[]): ColumnBuilder {\n const builder = new ColumnBuilder(\"enum\");\n builder._def.enumName = name;\n builder._def.enumValues = values;\n return builder;\n}\n\nexport { ColumnBuilder };\n","import type { ColumnDef, OnDeleteAction } from \"./columns.js\";\nimport type { SchemaDef, TableDef } from \"./schema.js\";\n\n/** Maps column types to their PostgreSQL SQL equivalents. */\nfunction columnTypeToSQL(col: ColumnDef): string {\n switch (col.type) {\n case \"uuid\":\n return \"UUID\";\n case \"text\":\n return \"TEXT\";\n case \"integer\":\n return \"INTEGER\";\n case \"boolean\":\n return \"BOOLEAN\";\n case \"timestamp\":\n return \"TIMESTAMPTZ\";\n case \"jsonb\":\n return \"JSONB\";\n case \"enum\":\n return col.enumName ?? \"TEXT\";\n default:\n return \"TEXT\";\n }\n}\n\n/** Generates the DEFAULT clause for a column. */\nfunction defaultClause(col: ColumnDef): string {\n if (col.defaultRandom) {\n return \" DEFAULT gen_random_uuid()\";\n }\n if (col.defaultNow) {\n return \" DEFAULT now()\";\n }\n if (col.defaultValue !== undefined) {\n if (typeof col.defaultValue === \"string\") {\n // Escape single quotes in string defaults\n const escaped = col.defaultValue.replace(/'/g, \"''\");\n return ` DEFAULT '${escaped}'`;\n }\n if (typeof col.defaultValue === \"boolean\") {\n return ` DEFAULT ${col.defaultValue ? \"true\" : \"false\"}`;\n }\n if (typeof col.defaultValue === \"object\" && col.defaultValue !== null) {\n const escaped = JSON.stringify(col.defaultValue).replace(/'/g, \"''\");\n return ` DEFAULT '${escaped}'::jsonb`;\n }\n return ` DEFAULT ${col.defaultValue}`;\n }\n return \"\";\n}\n\n/** Maps OnDeleteAction to SQL. */\nfunction onDeleteSQL(action: OnDeleteAction): string {\n switch (action) {\n case \"cascade\":\n return \"CASCADE\";\n case \"set null\":\n return \"SET NULL\";\n case \"restrict\":\n return \"RESTRICT\";\n case \"no action\":\n return \"NO ACTION\";\n }\n}\n\n/** Generates CREATE TYPE statements for enum columns. */\nfunction generateEnumTypes(tables: Record<string, TableDef>): string[] {\n const enums = new Map<string, string[]>();\n for (const tableDef of Object.values(tables)) {\n for (const col of Object.values(tableDef.columns)) {\n if (col._def.type === \"enum\" && col._def.enumName && col._def.enumValues) {\n enums.set(col._def.enumName, col._def.enumValues);\n }\n }\n }\n\n return Array.from(enums.entries()).map(([name, values]) => {\n const vals = values.map((v) => `'${v.replace(/'/g, \"''\")}'`).join(\", \");\n return `CREATE TYPE ${name} AS ENUM (${vals});`;\n });\n}\n\n/** Generates a CREATE TABLE statement for a single table. */\nfunction generateCreateTable(tableDef: TableDef): string {\n const lines: string[] = [];\n\n for (const [colName, colBuilder] of Object.entries(tableDef.columns)) {\n const col = colBuilder._def;\n let line = ` ${colName} ${columnTypeToSQL(col)}`;\n\n if (col.primaryKey) {\n line += \" PRIMARY KEY\";\n }\n\n if (!col.nullable && !col.primaryKey) {\n line += \" NOT NULL\";\n }\n\n line += defaultClause(col);\n\n if (col.references) {\n line += ` REFERENCES ${col.references.table}(${col.references.column})`;\n if (col.onDeleteAction) {\n line += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;\n }\n }\n\n lines.push(line);\n }\n\n return `CREATE TABLE ${tableDef.name} (\\n${lines.join(\",\\n\")}\\n);`;\n}\n\n/** Generates a DROP TABLE statement (for down migration). */\nfunction generateDropTable(tableDef: TableDef): string {\n return `DROP TABLE IF EXISTS ${tableDef.name};`;\n}\n\n/** Generates DROP TYPE statements for enum columns (for down migration). */\nfunction generateDropEnumTypes(tables: Record<string, TableDef>): string[] {\n const enums = new Set<string>();\n for (const tableDef of Object.values(tables)) {\n for (const col of Object.values(tableDef.columns)) {\n if (col._def.type === \"enum\" && col._def.enumName) {\n enums.add(col._def.enumName);\n }\n }\n }\n return Array.from(enums).map((name) => `DROP TYPE IF EXISTS ${name};`);\n}\n\n/** Result of migration generation. */\nexport interface MigrationResult {\n up: string;\n down: string;\n}\n\n/**\n * Generates a full migration (up + down) from a schema definition.\n * Used for initial schema creation.\n */\nexport function generateMigration(schema: SchemaDef): MigrationResult {\n const upParts: string[] = [];\n const downParts: string[] = [];\n\n // Enum types first (up) / last (down)\n const enumTypes = generateEnumTypes(schema.tables);\n upParts.push(...enumTypes);\n\n // Tables\n for (const tableDef of Object.values(schema.tables)) {\n upParts.push(generateCreateTable(tableDef));\n }\n\n // Down: reverse order — drop tables first, then types\n const tableNames = Object.values(schema.tables);\n for (let i = tableNames.length - 1; i >= 0; i--) {\n downParts.push(generateDropTable(tableNames[i]!));\n }\n downParts.push(...generateDropEnumTypes(schema.tables));\n\n return {\n up: upParts.join(\"\\n\\n\"),\n down: downParts.join(\"\\n\\n\"),\n };\n}\n\n/** Column diff operation. */\ninterface ColumnDiff {\n type: \"add\" | \"drop\" | \"alter\";\n table: string;\n column: string;\n def?: ColumnDef;\n oldDef?: ColumnDef;\n}\n\n/** Computes column-level diffs between two schemas. */\nfunction diffSchemas(\n oldSchema: SchemaDef,\n newSchema: SchemaDef,\n): { addedTables: TableDef[]; droppedTables: TableDef[]; columnDiffs: ColumnDiff[] } {\n const addedTables: TableDef[] = [];\n const droppedTables: TableDef[] = [];\n const columnDiffs: ColumnDiff[] = [];\n\n const oldTableNames = new Set(Object.keys(oldSchema.tables));\n const newTableNames = new Set(Object.keys(newSchema.tables));\n\n // New tables\n for (const name of newTableNames) {\n if (!oldTableNames.has(name)) {\n addedTables.push(newSchema.tables[name]!);\n }\n }\n\n // Dropped tables\n for (const name of oldTableNames) {\n if (!newTableNames.has(name)) {\n droppedTables.push(oldSchema.tables[name]!);\n }\n }\n\n // Column-level diffs for existing tables\n for (const name of newTableNames) {\n if (!oldTableNames.has(name)) continue;\n\n const oldTable = oldSchema.tables[name]!;\n const newTable = newSchema.tables[name]!;\n const oldCols = new Set(Object.keys(oldTable.columns));\n const newCols = new Set(Object.keys(newTable.columns));\n\n for (const col of newCols) {\n if (!oldCols.has(col)) {\n columnDiffs.push({\n type: \"add\",\n table: newTable.name,\n column: col,\n def: newTable.columns[col]!._def,\n });\n }\n }\n\n for (const col of oldCols) {\n if (!newCols.has(col)) {\n columnDiffs.push({\n type: \"drop\",\n table: oldTable.name,\n column: col,\n oldDef: oldTable.columns[col]!._def,\n });\n }\n }\n }\n\n return { addedTables, droppedTables, columnDiffs };\n}\n\n/** Generates an ALTER TABLE ADD COLUMN statement. */\nfunction generateAddColumn(table: string, column: string, col: ColumnDef): string {\n let sql = `ALTER TABLE ${table} ADD COLUMN ${column} ${columnTypeToSQL(col)}`;\n if (!col.nullable) {\n sql += \" NOT NULL\";\n }\n sql += defaultClause(col);\n if (col.references) {\n sql += ` REFERENCES ${col.references.table}(${col.references.column})`;\n if (col.onDeleteAction) {\n sql += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;\n }\n }\n return `${sql};`;\n}\n\n/** Generates an ALTER TABLE DROP COLUMN statement. */\nfunction generateDropColumn(table: string, column: string): string {\n return `ALTER TABLE ${table} DROP COLUMN ${column};`;\n}\n\n/**\n * Generates a diff migration between two schemas.\n * Returns null if there are no changes.\n */\nexport function generateDiffMigration(\n oldSchema: SchemaDef,\n newSchema: SchemaDef,\n): MigrationResult | null {\n const { addedTables, droppedTables, columnDiffs } = diffSchemas(oldSchema, newSchema);\n\n if (addedTables.length === 0 && droppedTables.length === 0 && columnDiffs.length === 0) {\n return null;\n }\n\n const upParts: string[] = [];\n const downParts: string[] = [];\n\n // New enum types from added tables\n const newEnums = generateEnumTypes(\n Object.fromEntries(addedTables.map((t) => [t.name, t])),\n );\n upParts.push(...newEnums);\n\n // New tables\n for (const table of addedTables) {\n upParts.push(generateCreateTable(table));\n downParts.push(generateDropTable(table));\n }\n\n // Dropped tables\n for (const table of droppedTables) {\n upParts.push(generateDropTable(table));\n downParts.push(generateCreateTable(table));\n }\n\n // Column diffs\n for (const diff of columnDiffs) {\n if (diff.type === \"add\" && diff.def) {\n upParts.push(generateAddColumn(diff.table, diff.column, diff.def));\n downParts.push(generateDropColumn(diff.table, diff.column));\n } else if (diff.type === \"drop\") {\n upParts.push(generateDropColumn(diff.table, diff.column));\n if (diff.oldDef) {\n downParts.push(generateAddColumn(diff.table, diff.column, diff.oldDef));\n }\n }\n }\n\n // Drop enum types from dropped tables (down)\n const droppedEnums = generateDropEnumTypes(\n Object.fromEntries(droppedTables.map((t) => [t.name, t])),\n );\n downParts.push(...droppedEnums);\n\n return {\n up: upParts.join(\"\\n\\n\"),\n down: downParts.join(\"\\n\\n\"),\n };\n}\n"],"mappings":"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","names":["table","table"]}
@@ -0,0 +1,87 @@
1
+ /** On delete action for foreign key references. */
2
+ type OnDeleteAction = "cascade" | "set null" | "restrict" | "no action";
3
+ /** Column type identifiers. */
4
+ type ColumnType = "uuid" | "text" | "integer" | "boolean" | "timestamp" | "jsonb" | "enum";
5
+ /** Base column definition shared by all column types. */
6
+ interface ColumnDef {
7
+ type: ColumnType;
8
+ nullable: boolean;
9
+ primaryKey: boolean;
10
+ defaultValue?: unknown;
11
+ defaultRandom?: boolean;
12
+ defaultNow?: boolean;
13
+ references?: {
14
+ table: string;
15
+ column: string;
16
+ };
17
+ onDeleteAction?: OnDeleteAction;
18
+ enumName?: string;
19
+ enumValues?: string[];
20
+ }
21
+ /** Fluent column builder. Methods return `this` for chaining. */
22
+ declare class ColumnBuilder {
23
+ readonly _def: ColumnDef;
24
+ constructor(type: ColumnType);
25
+ /** Mark this column as the primary key. */
26
+ primaryKey(): this;
27
+ /** Mark this column as NOT NULL (default). */
28
+ notNull(): this;
29
+ /** Allow NULL values. */
30
+ nullable(): this;
31
+ /** Set a default value. */
32
+ default(value: unknown): this;
33
+ /** UUID: generate a random default (gen_random_uuid()). */
34
+ defaultRandom(): this;
35
+ /** Timestamp: default to now(). */
36
+ defaultNow(): this;
37
+ /** Add a foreign key reference. */
38
+ references(table: string, column: string): this;
39
+ /** Set the ON DELETE action for a foreign key reference. */
40
+ onDelete(action: OnDeleteAction): this;
41
+ }
42
+ /** Create a UUID column. */
43
+ declare function uuid(): ColumnBuilder;
44
+ /** Create a TEXT column. */
45
+ declare function text(): ColumnBuilder;
46
+ /** Create an INTEGER column. */
47
+ declare function integer(): ColumnBuilder;
48
+ /** Create a BOOLEAN column. */
49
+ declare function boolean(): ColumnBuilder;
50
+ /** Create a TIMESTAMP column. */
51
+ declare function timestamp(): ColumnBuilder;
52
+ /** Create a JSONB column. */
53
+ declare function jsonb(): ColumnBuilder;
54
+ /** Create an ENUM column. */
55
+ declare function enumType(name: string, values: string[]): ColumnBuilder;
56
+
57
+ /** A table definition with its columns. */
58
+ interface TableDef {
59
+ name: string;
60
+ columns: Record<string, ColumnBuilder>;
61
+ }
62
+ /** A schema definition containing multiple tables. */
63
+ interface SchemaDef<T extends Record<string, TableDef> = Record<string, TableDef>> {
64
+ tables: T;
65
+ }
66
+ /** Define a table with a name and columns. */
67
+ declare function table(name: string, columns: Record<string, ColumnBuilder>): TableDef;
68
+ /** Define a schema containing multiple tables. */
69
+ declare function defineSchema<T extends Record<string, TableDef>>(tables: T): SchemaDef<T>;
70
+
71
+ /** Result of migration generation. */
72
+ interface MigrationResult {
73
+ up: string;
74
+ down: string;
75
+ }
76
+ /**
77
+ * Generates a full migration (up + down) from a schema definition.
78
+ * Used for initial schema creation.
79
+ */
80
+ declare function generateMigration(schema: SchemaDef): MigrationResult;
81
+ /**
82
+ * Generates a diff migration between two schemas.
83
+ * Returns null if there are no changes.
84
+ */
85
+ declare function generateDiffMigration(oldSchema: SchemaDef, newSchema: SchemaDef): MigrationResult | null;
86
+
87
+ export { ColumnBuilder, type ColumnDef, type ColumnType, type MigrationResult, type OnDeleteAction, type SchemaDef, type TableDef, boolean, defineSchema, enumType, generateDiffMigration, generateMigration, integer, jsonb, table, text, timestamp, uuid };
@@ -0,0 +1,87 @@
1
+ /** On delete action for foreign key references. */
2
+ type OnDeleteAction = "cascade" | "set null" | "restrict" | "no action";
3
+ /** Column type identifiers. */
4
+ type ColumnType = "uuid" | "text" | "integer" | "boolean" | "timestamp" | "jsonb" | "enum";
5
+ /** Base column definition shared by all column types. */
6
+ interface ColumnDef {
7
+ type: ColumnType;
8
+ nullable: boolean;
9
+ primaryKey: boolean;
10
+ defaultValue?: unknown;
11
+ defaultRandom?: boolean;
12
+ defaultNow?: boolean;
13
+ references?: {
14
+ table: string;
15
+ column: string;
16
+ };
17
+ onDeleteAction?: OnDeleteAction;
18
+ enumName?: string;
19
+ enumValues?: string[];
20
+ }
21
+ /** Fluent column builder. Methods return `this` for chaining. */
22
+ declare class ColumnBuilder {
23
+ readonly _def: ColumnDef;
24
+ constructor(type: ColumnType);
25
+ /** Mark this column as the primary key. */
26
+ primaryKey(): this;
27
+ /** Mark this column as NOT NULL (default). */
28
+ notNull(): this;
29
+ /** Allow NULL values. */
30
+ nullable(): this;
31
+ /** Set a default value. */
32
+ default(value: unknown): this;
33
+ /** UUID: generate a random default (gen_random_uuid()). */
34
+ defaultRandom(): this;
35
+ /** Timestamp: default to now(). */
36
+ defaultNow(): this;
37
+ /** Add a foreign key reference. */
38
+ references(table: string, column: string): this;
39
+ /** Set the ON DELETE action for a foreign key reference. */
40
+ onDelete(action: OnDeleteAction): this;
41
+ }
42
+ /** Create a UUID column. */
43
+ declare function uuid(): ColumnBuilder;
44
+ /** Create a TEXT column. */
45
+ declare function text(): ColumnBuilder;
46
+ /** Create an INTEGER column. */
47
+ declare function integer(): ColumnBuilder;
48
+ /** Create a BOOLEAN column. */
49
+ declare function boolean(): ColumnBuilder;
50
+ /** Create a TIMESTAMP column. */
51
+ declare function timestamp(): ColumnBuilder;
52
+ /** Create a JSONB column. */
53
+ declare function jsonb(): ColumnBuilder;
54
+ /** Create an ENUM column. */
55
+ declare function enumType(name: string, values: string[]): ColumnBuilder;
56
+
57
+ /** A table definition with its columns. */
58
+ interface TableDef {
59
+ name: string;
60
+ columns: Record<string, ColumnBuilder>;
61
+ }
62
+ /** A schema definition containing multiple tables. */
63
+ interface SchemaDef<T extends Record<string, TableDef> = Record<string, TableDef>> {
64
+ tables: T;
65
+ }
66
+ /** Define a table with a name and columns. */
67
+ declare function table(name: string, columns: Record<string, ColumnBuilder>): TableDef;
68
+ /** Define a schema containing multiple tables. */
69
+ declare function defineSchema<T extends Record<string, TableDef>>(tables: T): SchemaDef<T>;
70
+
71
+ /** Result of migration generation. */
72
+ interface MigrationResult {
73
+ up: string;
74
+ down: string;
75
+ }
76
+ /**
77
+ * Generates a full migration (up + down) from a schema definition.
78
+ * Used for initial schema creation.
79
+ */
80
+ declare function generateMigration(schema: SchemaDef): MigrationResult;
81
+ /**
82
+ * Generates a diff migration between two schemas.
83
+ * Returns null if there are no changes.
84
+ */
85
+ declare function generateDiffMigration(oldSchema: SchemaDef, newSchema: SchemaDef): MigrationResult | null;
86
+
87
+ export { ColumnBuilder, type ColumnDef, type ColumnType, type MigrationResult, type OnDeleteAction, type SchemaDef, type TableDef, boolean, defineSchema, enumType, generateDiffMigration, generateMigration, integer, jsonb, table, text, timestamp, uuid };