@bungres/kit 0.4.0 → 0.5.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/README.md +4 -2
- package/dist/cli.js +62 -48
- package/dist/commands/drop.d.ts.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/config.d.ts +32 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/index.js +53 -39
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @bungres/kit
|
|
2
2
|
|
|
3
|
-
CLI toolkit for [`@bungres/orm`](https://www.npmjs.com/package/@bungres/orm) — generate, migrate, push, pull, status, and drop your database schema with ease. 🐘✨
|
|
3
|
+
CLI toolkit for [`@bungres/orm`](https://www.npmjs.com/package/@bungres/orm) — initialize, generate, migrate, push, pull, status, and drop your database schema with ease. 🐘✨
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
@@ -25,7 +25,7 @@ export default defineConfig({
|
|
|
25
25
|
schema: "./src/db/schema.ts",
|
|
26
26
|
out: "./bungres", // Directory for migrations & generated files
|
|
27
27
|
dbCredentials: {
|
|
28
|
-
url:
|
|
28
|
+
url: Bun.env.DATABASE_URL!,
|
|
29
29
|
},
|
|
30
30
|
});
|
|
31
31
|
```
|
|
@@ -40,6 +40,7 @@ bun run bungres --help
|
|
|
40
40
|
|
|
41
41
|
| Command | Description |
|
|
42
42
|
|---|---|
|
|
43
|
+
| `bungres init` | Initialize bungres project with config file and db folder structure |
|
|
43
44
|
| `bungres generate` | Write a timestamped `.sql` migration file from your schema |
|
|
44
45
|
| `bungres migrate` | Run pending `.sql` files, track applied in `__bungres_migrations` |
|
|
45
46
|
| `bungres push` | Apply schema directly to DB — no files (great for dev/prototyping) |
|
|
@@ -55,6 +56,7 @@ bun run bungres --help
|
|
|
55
56
|
### Usage Examples
|
|
56
57
|
|
|
57
58
|
```bash
|
|
59
|
+
bun run bungres init
|
|
58
60
|
bun run bungres generate
|
|
59
61
|
bun run bungres migrate
|
|
60
62
|
bun run bungres push
|
package/dist/cli.js
CHANGED
|
@@ -70,7 +70,7 @@ function createTableFactory(casing) {
|
|
|
70
70
|
return Object.assign(tableObj, columnConfigs);
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
-
var table = createTableFactory("
|
|
73
|
+
var table = createTableFactory("snake");
|
|
74
74
|
var snakeCase = { table: createTableFactory("snake") };
|
|
75
75
|
var camelCase = { table: createTableFactory("camel") };
|
|
76
76
|
// ../bungres-orm/src/schema/columns.ts
|
|
@@ -1162,7 +1162,7 @@ class BungresTransaction {
|
|
|
1162
1162
|
return Array.from(result2);
|
|
1163
1163
|
}
|
|
1164
1164
|
}
|
|
1165
|
-
function
|
|
1165
|
+
function bungres(config2) {
|
|
1166
1166
|
const db2 = new BungresDB(config2);
|
|
1167
1167
|
if (typeof config2 === "object" && config2.schema) {
|
|
1168
1168
|
const schema = config2.schema;
|
|
@@ -1345,14 +1345,19 @@ async function runDrop(config2, opts = {}) {
|
|
|
1345
1345
|
}
|
|
1346
1346
|
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
1347
1347
|
try {
|
|
1348
|
-
const
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
const
|
|
1348
|
+
const userSchema = config2.dbSchema;
|
|
1349
|
+
const existingUserTablesResult = await sql2.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = $1`, [userSchema]);
|
|
1350
|
+
const existingTableNames = new Set(existingUserTablesResult.map((r) => r.table_name));
|
|
1351
|
+
const migTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
1352
|
+
SELECT 1 FROM information_schema.tables
|
|
1353
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
1354
|
+
) AS exists`, [config2.migrationsSchema, config2.migrationsTable]);
|
|
1355
|
+
const migrationTableExists = migTableCheck[0]?.exists ?? false;
|
|
1356
|
+
const pushTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
1357
|
+
SELECT 1 FROM information_schema.tables
|
|
1358
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
1359
|
+
) AS exists`, [config2.migrationsSchema, "__bungres_push"]);
|
|
1360
|
+
const pushTableExists = pushTableCheck[0]?.exists ?? false;
|
|
1356
1361
|
const tablesToDrop = schemas2.filter((s) => existingTableNames.has(s.config.name));
|
|
1357
1362
|
if (tablesToDrop.length === 0 && !migrationTableExists && !pushTableExists) {
|
|
1358
1363
|
console.log("No tables to drop (they either don't exist or were already dropped).");
|
|
@@ -1360,10 +1365,10 @@ async function runDrop(config2, opts = {}) {
|
|
|
1360
1365
|
}
|
|
1361
1366
|
const tableNamesToPrint = tablesToDrop.map((s) => (s.config.schema ? s.config.schema + "." : "") + s.config.name);
|
|
1362
1367
|
if (migrationTableExists) {
|
|
1363
|
-
tableNamesToPrint.push(
|
|
1368
|
+
tableNamesToPrint.push(`${config2.migrationsSchema}.${config2.migrationsTable}`);
|
|
1364
1369
|
}
|
|
1365
1370
|
if (pushTableExists) {
|
|
1366
|
-
tableNamesToPrint.push(
|
|
1371
|
+
tableNamesToPrint.push(`${config2.migrationsSchema}.__bungres_push`);
|
|
1367
1372
|
}
|
|
1368
1373
|
if (!opts.force) {
|
|
1369
1374
|
console.warn(colorize(`
|
|
@@ -1387,12 +1392,13 @@ Are you sure? Type YES to continue: `, "cyan"));
|
|
|
1387
1392
|
console.log(colorize(` \u2713 dropped ${entry.config.name}`, "green"));
|
|
1388
1393
|
}
|
|
1389
1394
|
if (migrationTableExists) {
|
|
1390
|
-
|
|
1391
|
-
|
|
1395
|
+
const qualifiedMigTable = `"${config2.migrationsSchema}"."${config2.migrationsTable}"`;
|
|
1396
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS ${qualifiedMigTable} CASCADE`);
|
|
1397
|
+
console.log(colorize(` \u2713 dropped ${config2.migrationsSchema}.${config2.migrationsTable}`, "green"));
|
|
1392
1398
|
}
|
|
1393
1399
|
if (pushTableExists) {
|
|
1394
|
-
await sql2.unsafe(
|
|
1395
|
-
console.log(colorize(` \u2713 dropped __bungres_push`, "green"));
|
|
1400
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS "${config2.migrationsSchema}"."__bungres_push" CASCADE`);
|
|
1401
|
+
console.log(colorize(` \u2713 dropped ${config2.migrationsSchema}.__bungres_push`, "green"));
|
|
1396
1402
|
}
|
|
1397
1403
|
console.log(colorize(`
|
|
1398
1404
|
Drop complete.`, "green"));
|
|
@@ -1403,19 +1409,22 @@ Drop complete.`, "green"));
|
|
|
1403
1409
|
|
|
1404
1410
|
// src/commands/migrate.ts
|
|
1405
1411
|
import { join as join2, resolve as resolve2 } from "path";
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1412
|
+
async function runMigrate(config2) {
|
|
1413
|
+
const migrationsDir = resolve2(config2.out);
|
|
1414
|
+
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
1415
|
+
const table2 = config2.migrationsTable;
|
|
1416
|
+
const schema = config2.migrationsSchema;
|
|
1417
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
1418
|
+
const createSchema = `CREATE SCHEMA IF NOT EXISTS "${schema}";`;
|
|
1419
|
+
const createMigrationsTable = `
|
|
1420
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
|
|
1409
1421
|
id SERIAL PRIMARY KEY,
|
|
1410
1422
|
name TEXT NOT NULL UNIQUE,
|
|
1411
1423
|
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
1412
|
-
);
|
|
1413
|
-
`.trim();
|
|
1414
|
-
async function runMigrate(config2) {
|
|
1415
|
-
const migrationsDir = resolve2(config2.migrationsDir);
|
|
1416
|
-
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
1424
|
+
);`.trim();
|
|
1417
1425
|
try {
|
|
1418
|
-
await sql2.unsafe(
|
|
1426
|
+
await sql2.unsafe(createSchema);
|
|
1427
|
+
await sql2.unsafe(createMigrationsTable);
|
|
1419
1428
|
const glob = new Bun.Glob("*.sql");
|
|
1420
1429
|
const files = [];
|
|
1421
1430
|
for await (const file of glob.scan({ cwd: migrationsDir, absolute: false })) {
|
|
@@ -1427,7 +1436,7 @@ async function runMigrate(config2) {
|
|
|
1427
1436
|
console.log(colorize("Run `bungres generate` first.", "yellow"));
|
|
1428
1437
|
return;
|
|
1429
1438
|
}
|
|
1430
|
-
const applied = await sql2.unsafe(`SELECT name FROM
|
|
1439
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable}`);
|
|
1431
1440
|
const appliedSet = new Set(applied.map((r) => r.name));
|
|
1432
1441
|
const pending = files.filter((f) => !appliedSet.has(f));
|
|
1433
1442
|
if (pending.length === 0) {
|
|
@@ -1445,11 +1454,11 @@ ${content}
|
|
|
1445
1454
|
`);
|
|
1446
1455
|
}
|
|
1447
1456
|
await sql2.transaction(async (txSql) => {
|
|
1448
|
-
const statements = content.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1457
|
+
const statements = config2.breakpoints ? content.split(/-->statement-breakpoint/g).flatMap((chunk) => chunk.split(";").map((s) => s.trim()).filter(Boolean)) : content.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1449
1458
|
for (const stmt of statements) {
|
|
1450
1459
|
await txSql.unsafe(stmt + ";");
|
|
1451
1460
|
}
|
|
1452
|
-
await txSql.unsafe(`INSERT INTO
|
|
1461
|
+
await txSql.unsafe(`INSERT INTO ${qualifiedTable} (name) VALUES ($1)`, [file]);
|
|
1453
1462
|
});
|
|
1454
1463
|
console.log(colorize(` \u2713 ${file}`, "green"));
|
|
1455
1464
|
}
|
|
@@ -1648,7 +1657,7 @@ async function runGenerate(config2, name) {
|
|
|
1648
1657
|
console.warn(colorize("No table definitions found. Check your schema glob pattern.", "yellow"));
|
|
1649
1658
|
return;
|
|
1650
1659
|
}
|
|
1651
|
-
const migrationsDir = resolve3(config2.
|
|
1660
|
+
const migrationsDir = resolve3(config2.out);
|
|
1652
1661
|
await Bun.$`mkdir -p ${migrationsDir}`.quiet();
|
|
1653
1662
|
const currentSnapshot = Object.fromEntries(schemas2.map((s) => [s.config.name, s.config]));
|
|
1654
1663
|
const snapshotPath = join3(migrationsDir, SNAPSHOT_FILE);
|
|
@@ -1764,7 +1773,7 @@ export default defineConfig({
|
|
|
1764
1773
|
schema: "./src/db/schema.ts",
|
|
1765
1774
|
out: "./bungres",
|
|
1766
1775
|
dbCredentials: {
|
|
1767
|
-
url:
|
|
1776
|
+
url: process.env.DATABASE_URL!,
|
|
1768
1777
|
},
|
|
1769
1778
|
});
|
|
1770
1779
|
`;
|
|
@@ -1779,12 +1788,12 @@ export default defineConfig({
|
|
|
1779
1788
|
uuid,
|
|
1780
1789
|
varchar,
|
|
1781
1790
|
timestamptz,
|
|
1782
|
-
|
|
1791
|
+
table,
|
|
1783
1792
|
unique,
|
|
1784
1793
|
index
|
|
1785
1794
|
} from "@bungres/orm";
|
|
1786
1795
|
|
|
1787
|
-
export const users =
|
|
1796
|
+
export const users = table("users", {
|
|
1788
1797
|
id: uuid({ primaryKey: true }),
|
|
1789
1798
|
name: varchar({ length: 255, notNull: true }),
|
|
1790
1799
|
email: varchar({ length: 255, notNull: true }),
|
|
@@ -1800,12 +1809,12 @@ export const users = snakeCase.table("users", {
|
|
|
1800
1809
|
} catch (e) {
|
|
1801
1810
|
console.error("Failed to create schema file:", e);
|
|
1802
1811
|
}
|
|
1803
|
-
const clientContent = `import {
|
|
1812
|
+
const clientContent = `import { bungres } from "@bungres/orm";
|
|
1804
1813
|
import * as schema from "./schema";
|
|
1805
1814
|
|
|
1806
1815
|
const url = Bun.env.DATABASE_URL || "postgres://postgres:postgres@localhost:5432/postgres";
|
|
1807
1816
|
|
|
1808
|
-
export const db =
|
|
1817
|
+
export const db = bungres({ url, schema });
|
|
1809
1818
|
`;
|
|
1810
1819
|
try {
|
|
1811
1820
|
await Bun.write(join4(dbDir, "client.ts"), clientContent);
|
|
@@ -1921,7 +1930,7 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
1921
1930
|
`// Generated at: ${new Date().toISOString()}`,
|
|
1922
1931
|
``,
|
|
1923
1932
|
`import {`,
|
|
1924
|
-
`
|
|
1933
|
+
` table,`,
|
|
1925
1934
|
` text, varchar, char, integer, bigint, smallint,`,
|
|
1926
1935
|
` serial, bigserial, boolean, real, doublePrecision,`,
|
|
1927
1936
|
` numeric, decimal, json, jsonb,`,
|
|
@@ -1933,7 +1942,7 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
1933
1942
|
];
|
|
1934
1943
|
for (const [, table2] of tableMap) {
|
|
1935
1944
|
const varName = toCamelCase(table2.tableName);
|
|
1936
|
-
lines.push(`export const ${varName} =
|
|
1945
|
+
lines.push(`export const ${varName} = table("${table2.tableName}", {`);
|
|
1937
1946
|
for (const col2 of table2.columns) {
|
|
1938
1947
|
const colExpr = buildColumnExpression(col2);
|
|
1939
1948
|
lines.push(` ${toCamelCase(col2.name)}: ${colExpr},`);
|
|
@@ -2193,7 +2202,7 @@ Running seeder: ${config2.seed}...`, "cyan"));
|
|
|
2193
2202
|
cwd: process.cwd(),
|
|
2194
2203
|
stdout: "inherit",
|
|
2195
2204
|
stderr: "inherit",
|
|
2196
|
-
env: { ...
|
|
2205
|
+
env: { ...Bun.env, DATABASE_URL: config2.dbUrl }
|
|
2197
2206
|
});
|
|
2198
2207
|
const exitCode = await proc.exited;
|
|
2199
2208
|
if (exitCode === 0) {
|
|
@@ -2208,15 +2217,17 @@ Seed failed with exit code ${exitCode}.`);
|
|
|
2208
2217
|
|
|
2209
2218
|
// src/commands/status.ts
|
|
2210
2219
|
import { resolve as resolve6 } from "path";
|
|
2211
|
-
var MIGRATIONS_TABLE2 = "__bungres_migrations";
|
|
2212
2220
|
async function runStatus(config2) {
|
|
2213
|
-
const migrationsDir = resolve6(config2.
|
|
2221
|
+
const migrationsDir = resolve6(config2.out);
|
|
2214
2222
|
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
2223
|
+
const table2 = config2.migrationsTable;
|
|
2224
|
+
const schema = config2.migrationsSchema;
|
|
2225
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
2215
2226
|
try {
|
|
2216
2227
|
const tableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
2217
2228
|
SELECT 1 FROM information_schema.tables
|
|
2218
|
-
WHERE table_name = $
|
|
2219
|
-
) AS exists`, [
|
|
2229
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
2230
|
+
) AS exists`, [schema, table2]);
|
|
2220
2231
|
const trackingExists = tableCheck[0]?.exists ?? false;
|
|
2221
2232
|
const glob = new Bun.Glob("*.sql");
|
|
2222
2233
|
const files = [];
|
|
@@ -2230,7 +2241,7 @@ async function runStatus(config2) {
|
|
|
2230
2241
|
}
|
|
2231
2242
|
let appliedSet = new Set;
|
|
2232
2243
|
if (trackingExists) {
|
|
2233
|
-
const applied = await sql2.unsafe(`SELECT name FROM
|
|
2244
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable} ORDER BY applied_at`);
|
|
2234
2245
|
appliedSet = new Set(applied.map((r) => r.name));
|
|
2235
2246
|
}
|
|
2236
2247
|
console.log(colorize(`
|
|
@@ -2263,8 +2274,8 @@ async function runStudio(config2) {
|
|
|
2263
2274
|
for (const s of schemas2) {
|
|
2264
2275
|
schemaObj2[s.exportName] = s.table;
|
|
2265
2276
|
}
|
|
2266
|
-
const db2 =
|
|
2267
|
-
const port =
|
|
2277
|
+
const db2 = bungres({ url: config2.dbUrl, schema: schemaObj2 });
|
|
2278
|
+
const port = Bun.env.PORT ? parseInt(Bun.env.PORT, 10) : 5555;
|
|
2268
2279
|
const server = Bun.serve({
|
|
2269
2280
|
port,
|
|
2270
2281
|
async fetch(req) {
|
|
@@ -3069,7 +3080,7 @@ async function runTusky(config) {
|
|
|
3069
3080
|
for (const s of schemas) {
|
|
3070
3081
|
schemaObj[s.exportName] = s.table;
|
|
3071
3082
|
}
|
|
3072
|
-
const db =
|
|
3083
|
+
const db = bungres({ url: config.dbUrl, schema: schemaObj });
|
|
3073
3084
|
console.log("=========================================");
|
|
3074
3085
|
console.log("\uD83D\uDC18 Welcome to Bungres REPL (Tusky)");
|
|
3075
3086
|
console.log("=========================================");
|
|
@@ -3127,7 +3138,7 @@ Example query: await db.select().from(users)`);
|
|
|
3127
3138
|
}
|
|
3128
3139
|
|
|
3129
3140
|
// src/config.ts
|
|
3130
|
-
import {
|
|
3141
|
+
import { join as join6, resolve as resolve7 } from "path";
|
|
3131
3142
|
var CONFIG_FILES = [
|
|
3132
3143
|
"bungres.config.ts",
|
|
3133
3144
|
"bungres.config.js",
|
|
@@ -3144,7 +3155,7 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
3144
3155
|
break;
|
|
3145
3156
|
}
|
|
3146
3157
|
}
|
|
3147
|
-
const dbUrl = userConfig.dbCredentials?.url ??
|
|
3158
|
+
const dbUrl = userConfig.dbCredentials?.url ?? Bun.env.DATABASE_URL ?? Bun.env.POSTGRES_URL ?? "";
|
|
3148
3159
|
if (!dbUrl) {
|
|
3149
3160
|
console.error(`bungres: No database URL found.
|
|
3150
3161
|
Add dbCredentials.url to bungres.config.ts or set DATABASE_URL.`);
|
|
@@ -3157,7 +3168,10 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
3157
3168
|
out,
|
|
3158
3169
|
dbUrl,
|
|
3159
3170
|
dbSchema: userConfig.dbSchema ?? "public",
|
|
3160
|
-
|
|
3171
|
+
migrationsTable: userConfig.migrations?.table ?? "__bungres_migrations",
|
|
3172
|
+
migrationsSchema: userConfig.migrations?.schema ?? "bungres",
|
|
3173
|
+
breakpoints: userConfig.breakpoints ?? true,
|
|
3174
|
+
strict: userConfig.strict ?? false,
|
|
3161
3175
|
outDir: "./src/db/generated",
|
|
3162
3176
|
verbose: userConfig.verbose ?? false
|
|
3163
3177
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drop.d.ts","sourceRoot":"","sources":["../../src/commands/drop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AASnD,wBAAsB,OAAO,CAC3B,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"drop.d.ts","sourceRoot":"","sources":["../../src/commands/drop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AASnD,wBAAsB,OAAO,CAC3B,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,IAAI,CAAC,CA8Ff"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAOnD,wBAAsB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAOnD,wBAAsB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDrE"}
|
package/dist/config.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface BungresKitConfig {
|
|
|
11
11
|
seed?: string;
|
|
12
12
|
/**
|
|
13
13
|
* Output directory for generated migration .sql files.
|
|
14
|
-
*
|
|
14
|
+
* Default: "./migrations"
|
|
15
15
|
*/
|
|
16
16
|
out?: string;
|
|
17
17
|
/**
|
|
@@ -26,6 +26,33 @@ export interface BungresKitConfig {
|
|
|
26
26
|
* Default: "public"
|
|
27
27
|
*/
|
|
28
28
|
dbSchema?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Migrations tracking options.
|
|
31
|
+
*/
|
|
32
|
+
migrations?: {
|
|
33
|
+
/**
|
|
34
|
+
* Name of the table used to track applied migrations.
|
|
35
|
+
* Default: "__bungres_migrations"
|
|
36
|
+
*/
|
|
37
|
+
table?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Postgres schema where the migrations tracking table lives.
|
|
40
|
+
* Default: "bungres"
|
|
41
|
+
*/
|
|
42
|
+
schema?: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* When true, split generated SQL at `-->statement-breakpoint` comments
|
|
46
|
+
* and execute each statement individually inside a transaction.
|
|
47
|
+
* Default: true
|
|
48
|
+
*/
|
|
49
|
+
breakpoints?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* When true, commands like `push` and `drop` will prompt for confirmation
|
|
52
|
+
* before making destructive changes.
|
|
53
|
+
* Default: false
|
|
54
|
+
*/
|
|
55
|
+
strict?: boolean;
|
|
29
56
|
/** Print every SQL statement executed. Default: false */
|
|
30
57
|
verbose?: boolean;
|
|
31
58
|
}
|
|
@@ -35,8 +62,10 @@ export interface ResolvedConfig {
|
|
|
35
62
|
out: string;
|
|
36
63
|
dbUrl: string;
|
|
37
64
|
dbSchema: string;
|
|
38
|
-
|
|
39
|
-
|
|
65
|
+
migrationsTable: string;
|
|
66
|
+
migrationsSchema: string;
|
|
67
|
+
breakpoints: boolean;
|
|
68
|
+
strict: boolean;
|
|
40
69
|
outDir: string;
|
|
41
70
|
verbose: boolean;
|
|
42
71
|
}
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,aAAa,CAAC,EAAE;QACd,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IAEF;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,aAAa,CAAC,EAAE;QACd,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IAEF;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE;QACX;;;WAGG;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QACf;;;WAGG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AASD,wBAAsB,UAAU,CAAC,GAAG,SAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CA0C7E"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/config.ts
|
|
3
|
-
import {
|
|
3
|
+
import { join, resolve } from "path";
|
|
4
4
|
var CONFIG_FILES = [
|
|
5
5
|
"bungres.config.ts",
|
|
6
6
|
"bungres.config.js",
|
|
@@ -17,7 +17,7 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
17
17
|
break;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
const dbUrl = userConfig.dbCredentials?.url ??
|
|
20
|
+
const dbUrl = userConfig.dbCredentials?.url ?? Bun.env.DATABASE_URL ?? Bun.env.POSTGRES_URL ?? "";
|
|
21
21
|
if (!dbUrl) {
|
|
22
22
|
console.error(`bungres: No database URL found.
|
|
23
23
|
Add dbCredentials.url to bungres.config.ts or set DATABASE_URL.`);
|
|
@@ -30,7 +30,10 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
30
30
|
out,
|
|
31
31
|
dbUrl,
|
|
32
32
|
dbSchema: userConfig.dbSchema ?? "public",
|
|
33
|
-
|
|
33
|
+
migrationsTable: userConfig.migrations?.table ?? "__bungres_migrations",
|
|
34
|
+
migrationsSchema: userConfig.migrations?.schema ?? "bungres",
|
|
35
|
+
breakpoints: userConfig.breakpoints ?? true,
|
|
36
|
+
strict: userConfig.strict ?? false,
|
|
34
37
|
outDir: "./src/db/generated",
|
|
35
38
|
verbose: userConfig.verbose ?? false
|
|
36
39
|
};
|
|
@@ -104,7 +107,7 @@ function createTableFactory(casing) {
|
|
|
104
107
|
return Object.assign(tableObj, columnConfigs);
|
|
105
108
|
};
|
|
106
109
|
}
|
|
107
|
-
var table = createTableFactory("
|
|
110
|
+
var table = createTableFactory("snake");
|
|
108
111
|
var snakeCase = { table: createTableFactory("snake") };
|
|
109
112
|
var camelCase = { table: createTableFactory("camel") };
|
|
110
113
|
// ../bungres-orm/src/schema/columns.ts
|
|
@@ -1196,7 +1199,7 @@ class BungresTransaction {
|
|
|
1196
1199
|
return Array.from(result);
|
|
1197
1200
|
}
|
|
1198
1201
|
}
|
|
1199
|
-
function
|
|
1202
|
+
function bungres(config) {
|
|
1200
1203
|
const db = new BungresDB(config);
|
|
1201
1204
|
if (typeof config === "object" && config.schema) {
|
|
1202
1205
|
const schema = config.schema;
|
|
@@ -1619,7 +1622,7 @@ async function runGenerate(config, name) {
|
|
|
1619
1622
|
console.warn(colorize("No table definitions found. Check your schema glob pattern.", "yellow"));
|
|
1620
1623
|
return;
|
|
1621
1624
|
}
|
|
1622
|
-
const migrationsDir = resolve3(config.
|
|
1625
|
+
const migrationsDir = resolve3(config.out);
|
|
1623
1626
|
await Bun.$`mkdir -p ${migrationsDir}`.quiet();
|
|
1624
1627
|
const currentSnapshot = Object.fromEntries(schemas.map((s) => [s.config.name, s.config]));
|
|
1625
1628
|
const snapshotPath = join3(migrationsDir, SNAPSHOT_FILE);
|
|
@@ -1712,19 +1715,22 @@ function topoSort(schemas) {
|
|
|
1712
1715
|
}
|
|
1713
1716
|
// src/commands/migrate.ts
|
|
1714
1717
|
import { join as join4, resolve as resolve4 } from "path";
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
+
async function runMigrate(config) {
|
|
1719
|
+
const migrationsDir = resolve4(config.out);
|
|
1720
|
+
const sql2 = new Bun.SQL(config.dbUrl);
|
|
1721
|
+
const table2 = config.migrationsTable;
|
|
1722
|
+
const schema = config.migrationsSchema;
|
|
1723
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
1724
|
+
const createSchema = `CREATE SCHEMA IF NOT EXISTS "${schema}";`;
|
|
1725
|
+
const createMigrationsTable = `
|
|
1726
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
|
|
1718
1727
|
id SERIAL PRIMARY KEY,
|
|
1719
1728
|
name TEXT NOT NULL UNIQUE,
|
|
1720
1729
|
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
1721
|
-
);
|
|
1722
|
-
`.trim();
|
|
1723
|
-
async function runMigrate(config) {
|
|
1724
|
-
const migrationsDir = resolve4(config.migrationsDir);
|
|
1725
|
-
const sql2 = new Bun.SQL(config.dbUrl);
|
|
1730
|
+
);`.trim();
|
|
1726
1731
|
try {
|
|
1727
|
-
await sql2.unsafe(
|
|
1732
|
+
await sql2.unsafe(createSchema);
|
|
1733
|
+
await sql2.unsafe(createMigrationsTable);
|
|
1728
1734
|
const glob = new Bun.Glob("*.sql");
|
|
1729
1735
|
const files = [];
|
|
1730
1736
|
for await (const file of glob.scan({ cwd: migrationsDir, absolute: false })) {
|
|
@@ -1736,7 +1742,7 @@ async function runMigrate(config) {
|
|
|
1736
1742
|
console.log(colorize("Run `bungres generate` first.", "yellow"));
|
|
1737
1743
|
return;
|
|
1738
1744
|
}
|
|
1739
|
-
const applied = await sql2.unsafe(`SELECT name FROM
|
|
1745
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable}`);
|
|
1740
1746
|
const appliedSet = new Set(applied.map((r) => r.name));
|
|
1741
1747
|
const pending = files.filter((f) => !appliedSet.has(f));
|
|
1742
1748
|
if (pending.length === 0) {
|
|
@@ -1754,11 +1760,11 @@ ${content}
|
|
|
1754
1760
|
`);
|
|
1755
1761
|
}
|
|
1756
1762
|
await sql2.transaction(async (txSql) => {
|
|
1757
|
-
const statements = content.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1763
|
+
const statements = config.breakpoints ? content.split(/-->statement-breakpoint/g).flatMap((chunk) => chunk.split(";").map((s) => s.trim()).filter(Boolean)) : content.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1758
1764
|
for (const stmt of statements) {
|
|
1759
1765
|
await txSql.unsafe(stmt + ";");
|
|
1760
1766
|
}
|
|
1761
|
-
await txSql.unsafe(`INSERT INTO
|
|
1767
|
+
await txSql.unsafe(`INSERT INTO ${qualifiedTable} (name) VALUES ($1)`, [file]);
|
|
1762
1768
|
});
|
|
1763
1769
|
console.log(colorize(` \u2713 ${file}`, "green"));
|
|
1764
1770
|
}
|
|
@@ -1866,7 +1872,7 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
1866
1872
|
`// Generated at: ${new Date().toISOString()}`,
|
|
1867
1873
|
``,
|
|
1868
1874
|
`import {`,
|
|
1869
|
-
`
|
|
1875
|
+
` table,`,
|
|
1870
1876
|
` text, varchar, char, integer, bigint, smallint,`,
|
|
1871
1877
|
` serial, bigserial, boolean, real, doublePrecision,`,
|
|
1872
1878
|
` numeric, decimal, json, jsonb,`,
|
|
@@ -1878,7 +1884,7 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
1878
1884
|
];
|
|
1879
1885
|
for (const [, table2] of tableMap) {
|
|
1880
1886
|
const varName = toCamelCase(table2.tableName);
|
|
1881
|
-
lines.push(`export const ${varName} =
|
|
1887
|
+
lines.push(`export const ${varName} = table("${table2.tableName}", {`);
|
|
1882
1888
|
for (const col2 of table2.columns) {
|
|
1883
1889
|
const colExpr = buildColumnExpression(col2);
|
|
1884
1890
|
lines.push(` ${toCamelCase(col2.name)}: ${colExpr},`);
|
|
@@ -2025,15 +2031,17 @@ function toCamelCase(str) {
|
|
|
2025
2031
|
}
|
|
2026
2032
|
// src/commands/status.ts
|
|
2027
2033
|
import { resolve as resolve6 } from "path";
|
|
2028
|
-
var MIGRATIONS_TABLE2 = "__bungres_migrations";
|
|
2029
2034
|
async function runStatus(config) {
|
|
2030
|
-
const migrationsDir = resolve6(config.
|
|
2035
|
+
const migrationsDir = resolve6(config.out);
|
|
2031
2036
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
2037
|
+
const table2 = config.migrationsTable;
|
|
2038
|
+
const schema = config.migrationsSchema;
|
|
2039
|
+
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
2032
2040
|
try {
|
|
2033
2041
|
const tableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
2034
2042
|
SELECT 1 FROM information_schema.tables
|
|
2035
|
-
WHERE table_name = $
|
|
2036
|
-
) AS exists`, [
|
|
2043
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
2044
|
+
) AS exists`, [schema, table2]);
|
|
2037
2045
|
const trackingExists = tableCheck[0]?.exists ?? false;
|
|
2038
2046
|
const glob = new Bun.Glob("*.sql");
|
|
2039
2047
|
const files = [];
|
|
@@ -2047,7 +2055,7 @@ async function runStatus(config) {
|
|
|
2047
2055
|
}
|
|
2048
2056
|
let appliedSet = new Set;
|
|
2049
2057
|
if (trackingExists) {
|
|
2050
|
-
const applied = await sql2.unsafe(`SELECT name FROM
|
|
2058
|
+
const applied = await sql2.unsafe(`SELECT name FROM ${qualifiedTable} ORDER BY applied_at`);
|
|
2051
2059
|
appliedSet = new Set(applied.map((r) => r.name));
|
|
2052
2060
|
}
|
|
2053
2061
|
console.log(colorize(`
|
|
@@ -2077,14 +2085,19 @@ async function runDrop(config, opts = {}) {
|
|
|
2077
2085
|
}
|
|
2078
2086
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
2079
2087
|
try {
|
|
2080
|
-
const
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
const
|
|
2088
|
+
const userSchema = config.dbSchema;
|
|
2089
|
+
const existingUserTablesResult = await sql2.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = $1`, [userSchema]);
|
|
2090
|
+
const existingTableNames = new Set(existingUserTablesResult.map((r) => r.table_name));
|
|
2091
|
+
const migTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
2092
|
+
SELECT 1 FROM information_schema.tables
|
|
2093
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
2094
|
+
) AS exists`, [config.migrationsSchema, config.migrationsTable]);
|
|
2095
|
+
const migrationTableExists = migTableCheck[0]?.exists ?? false;
|
|
2096
|
+
const pushTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
2097
|
+
SELECT 1 FROM information_schema.tables
|
|
2098
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
2099
|
+
) AS exists`, [config.migrationsSchema, "__bungres_push"]);
|
|
2100
|
+
const pushTableExists = pushTableCheck[0]?.exists ?? false;
|
|
2088
2101
|
const tablesToDrop = schemas.filter((s) => existingTableNames.has(s.config.name));
|
|
2089
2102
|
if (tablesToDrop.length === 0 && !migrationTableExists && !pushTableExists) {
|
|
2090
2103
|
console.log("No tables to drop (they either don't exist or were already dropped).");
|
|
@@ -2092,10 +2105,10 @@ async function runDrop(config, opts = {}) {
|
|
|
2092
2105
|
}
|
|
2093
2106
|
const tableNamesToPrint = tablesToDrop.map((s) => (s.config.schema ? s.config.schema + "." : "") + s.config.name);
|
|
2094
2107
|
if (migrationTableExists) {
|
|
2095
|
-
tableNamesToPrint.push(
|
|
2108
|
+
tableNamesToPrint.push(`${config.migrationsSchema}.${config.migrationsTable}`);
|
|
2096
2109
|
}
|
|
2097
2110
|
if (pushTableExists) {
|
|
2098
|
-
tableNamesToPrint.push(
|
|
2111
|
+
tableNamesToPrint.push(`${config.migrationsSchema}.__bungres_push`);
|
|
2099
2112
|
}
|
|
2100
2113
|
if (!opts.force) {
|
|
2101
2114
|
console.warn(colorize(`
|
|
@@ -2119,12 +2132,13 @@ Are you sure? Type YES to continue: `, "cyan"));
|
|
|
2119
2132
|
console.log(colorize(` \u2713 dropped ${entry.config.name}`, "green"));
|
|
2120
2133
|
}
|
|
2121
2134
|
if (migrationTableExists) {
|
|
2122
|
-
|
|
2123
|
-
|
|
2135
|
+
const qualifiedMigTable = `"${config.migrationsSchema}"."${config.migrationsTable}"`;
|
|
2136
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS ${qualifiedMigTable} CASCADE`);
|
|
2137
|
+
console.log(colorize(` \u2713 dropped ${config.migrationsSchema}.${config.migrationsTable}`, "green"));
|
|
2124
2138
|
}
|
|
2125
2139
|
if (pushTableExists) {
|
|
2126
|
-
await sql2.unsafe(
|
|
2127
|
-
console.log(colorize(` \u2713 dropped __bungres_push`, "green"));
|
|
2140
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS "${config.migrationsSchema}"."__bungres_push" CASCADE`);
|
|
2141
|
+
console.log(colorize(` \u2713 dropped ${config.migrationsSchema}.__bungres_push`, "green"));
|
|
2128
2142
|
}
|
|
2129
2143
|
console.log(colorize(`
|
|
2130
2144
|
Drop complete.`, "green"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bungres/kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "CLI toolkit for @bungres/orm — migrate, push, generate, pull",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
31
31
|
"url": "https://github.com/bungres/bungres.git",
|
|
32
|
-
"directory": "packages
|
|
32
|
+
"directory": "packages/bungres-kit"
|
|
33
33
|
},
|
|
34
34
|
"bugs": {
|
|
35
35
|
"url": "https://github.com/bungres/bungres/issues"
|