@bungres/kit 0.5.0 → 0.6.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/dist/cli.js +331 -146
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/studio.d.ts.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/ensure-db.d.ts.map +1 -1
- package/dist/index.js +56 -18
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -73,6 +73,7 @@ function createTableFactory(casing) {
|
|
|
73
73
|
var table = createTableFactory("snake");
|
|
74
74
|
var snakeCase = { table: createTableFactory("snake") };
|
|
75
75
|
var camelCase = { table: createTableFactory("camel") };
|
|
76
|
+
var noCasing = { table: createTableFactory("none") };
|
|
76
77
|
// ../bungres-orm/src/schema/columns.ts
|
|
77
78
|
function buildColumn(dataType, nameOrOpts, opts) {
|
|
78
79
|
let name = "";
|
|
@@ -167,14 +168,14 @@ function sqlJoin(chunks, separator = ", ") {
|
|
|
167
168
|
function rawSql(query) {
|
|
168
169
|
return { sql: query, params: [] };
|
|
169
170
|
}
|
|
170
|
-
|
|
171
|
-
var colName = (c) => {
|
|
171
|
+
function colName(c) {
|
|
172
172
|
if (typeof c === "string")
|
|
173
173
|
return `"${c}"`;
|
|
174
174
|
if (isSQLChunk(c))
|
|
175
175
|
return c.sql;
|
|
176
176
|
return c.tableName ? `${c.tableName}."${c.name}"` : `"${c.name}"`;
|
|
177
|
-
}
|
|
177
|
+
}
|
|
178
|
+
// ../bungres-orm/src/core/conditions.ts
|
|
178
179
|
function isColumnConfig(val) {
|
|
179
180
|
return val !== null && typeof val === "object" && "name" in val && "dataType" in val;
|
|
180
181
|
}
|
|
@@ -231,6 +232,14 @@ var inArray = (column, values) => {
|
|
|
231
232
|
const placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
|
|
232
233
|
return { sql: `${colName(column)} = ANY(ARRAY[${placeholders}])`, params };
|
|
233
234
|
};
|
|
235
|
+
var notInArray = (column, values) => {
|
|
236
|
+
if (values.length === 0)
|
|
237
|
+
return rawSql("TRUE");
|
|
238
|
+
const params = values;
|
|
239
|
+
const placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
|
|
240
|
+
return { sql: `${colName(column)} != ALL(ARRAY[${placeholders}])`, params };
|
|
241
|
+
};
|
|
242
|
+
var between = (column, min, max) => sql`${rawSql(colName(column))} BETWEEN ${min} AND ${max}`;
|
|
234
243
|
var and = (...conditions) => sqlJoin(conditions, " AND ");
|
|
235
244
|
var or = (...conditions) => {
|
|
236
245
|
const joined = sqlJoin(conditions, " OR ");
|
|
@@ -281,6 +290,10 @@ function parseWhereObject(tableConfig, whereObj) {
|
|
|
281
290
|
conditions.push(lte(columnArg, opVal.lte));
|
|
282
291
|
if (opVal.in !== undefined)
|
|
283
292
|
conditions.push(inArray(columnArg, opVal.in));
|
|
293
|
+
if (opVal.notIn !== undefined)
|
|
294
|
+
conditions.push(notInArray(columnArg, opVal.notIn));
|
|
295
|
+
if (opVal.between !== undefined)
|
|
296
|
+
conditions.push(between(columnArg, opVal.between[0], opVal.between[1]));
|
|
284
297
|
if (opVal.like !== undefined)
|
|
285
298
|
conditions.push(like(columnArg, opVal.like));
|
|
286
299
|
if (opVal.ilike !== undefined)
|
|
@@ -361,6 +374,9 @@ class DeleteBuilder {
|
|
|
361
374
|
if (this._returning) {
|
|
362
375
|
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(getTableConfig(this._table).columns).map((c) => `"${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
363
376
|
}
|
|
377
|
+
if (this._comment) {
|
|
378
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
379
|
+
}
|
|
364
380
|
return { sql: query, params };
|
|
365
381
|
}
|
|
366
382
|
}
|
|
@@ -471,7 +487,7 @@ class InsertBuilder {
|
|
|
471
487
|
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(tConfig.columns).map((c) => `"${tConfig.columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${tConfig.columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
472
488
|
}
|
|
473
489
|
if (this._comment) {
|
|
474
|
-
query += ` /* ${this._comment} */`;
|
|
490
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
475
491
|
}
|
|
476
492
|
return { sql: query, params };
|
|
477
493
|
}
|
|
@@ -668,7 +684,7 @@ class SelectBuilder {
|
|
|
668
684
|
query += ` OFFSET $${params.length}`;
|
|
669
685
|
}
|
|
670
686
|
if (this._comment) {
|
|
671
|
-
query += ` /* ${this._comment} */`;
|
|
687
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
672
688
|
}
|
|
673
689
|
return { sql: query, params };
|
|
674
690
|
}
|
|
@@ -768,10 +784,22 @@ class UpdateBuilder {
|
|
|
768
784
|
if (this._returning) {
|
|
769
785
|
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(getTableConfig(this._table).columns).map((c) => `"${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
770
786
|
}
|
|
787
|
+
if (this._comment) {
|
|
788
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
789
|
+
}
|
|
771
790
|
return { sql: query, params };
|
|
772
791
|
}
|
|
773
792
|
}
|
|
774
793
|
// ../bungres-orm/src/builders/relational.ts
|
|
794
|
+
function getPkColumn(tableConfig) {
|
|
795
|
+
if (tableConfig.primaryKeys?.length > 0)
|
|
796
|
+
return tableConfig.primaryKeys[0];
|
|
797
|
+
for (const [, col2] of Object.entries(tableConfig.columns)) {
|
|
798
|
+
if (col2.primaryKey)
|
|
799
|
+
return col2.name;
|
|
800
|
+
}
|
|
801
|
+
return "id";
|
|
802
|
+
}
|
|
775
803
|
var _relationsCache = new WeakMap;
|
|
776
804
|
|
|
777
805
|
class RelationalQueryBuilder {
|
|
@@ -922,14 +950,17 @@ class RelationalQueryBuilder {
|
|
|
922
950
|
if (relations.ones[relKey]) {
|
|
923
951
|
const rel = relations.ones[relKey];
|
|
924
952
|
const subAlias = `${alias}_${relKey}`;
|
|
925
|
-
const
|
|
953
|
+
const targetConfig = this._schema[rel.targetTable][TableConfigSymbol];
|
|
954
|
+
const targetPk = getPkColumn(targetConfig);
|
|
955
|
+
const joinCond = `"${subAlias}"."${targetPk}" = "${alias}"."${rel.sourceColumn}"`;
|
|
926
956
|
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, joinCond);
|
|
927
957
|
const subSql = `SELECT ${subQuery.sql} ${subQuery.from}`;
|
|
928
958
|
jsonFields.push(`'${relKey}', (${subSql})`);
|
|
929
959
|
} else if (relations.manys[relKey]) {
|
|
930
960
|
const rel = relations.manys[relKey];
|
|
931
961
|
const subAlias = `${alias}_${relKey}`;
|
|
932
|
-
const
|
|
962
|
+
const thisPk = getPkColumn(tableConfig);
|
|
963
|
+
const joinCond = `"${subAlias}"."${rel.targetColumn}" = "${alias}"."${thisPk}"`;
|
|
933
964
|
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, joinCond);
|
|
934
965
|
const aggAlias = `${subAlias}_agg`;
|
|
935
966
|
const aggSql = `
|
|
@@ -948,9 +979,9 @@ class RelationalQueryBuilder {
|
|
|
948
979
|
const junctionTableConfig = this._schema[rel.junctionTable][TableConfigSymbol];
|
|
949
980
|
const fromExtra = `
|
|
950
981
|
INNER JOIN ${junctionTableConfig.qualifiedName} AS "${junctionAlias}"
|
|
951
|
-
ON "${junctionAlias}"."${rel.joinTargetColumn}" = "${subAlias}"."${targetTableConfig
|
|
982
|
+
ON "${junctionAlias}"."${rel.joinTargetColumn}" = "${subAlias}"."${getPkColumn(targetTableConfig)}"
|
|
952
983
|
`;
|
|
953
|
-
const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${alias}"."${tableConfig
|
|
984
|
+
const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${alias}"."${getPkColumn(tableConfig)}"`;
|
|
954
985
|
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, whereExtra, fromExtra);
|
|
955
986
|
const aggSql = `
|
|
956
987
|
SELECT COALESCE(json_agg(_sub.obj), '[]'::json)
|
|
@@ -1331,9 +1362,9 @@ function isTable(value) {
|
|
|
1331
1362
|
}
|
|
1332
1363
|
|
|
1333
1364
|
// src/utils/colors.ts
|
|
1334
|
-
function colorize(
|
|
1365
|
+
function colorize(text, color) {
|
|
1335
1366
|
const code2 = Bun.color(color, "ansi");
|
|
1336
|
-
return code2 ? `${code2}${
|
|
1367
|
+
return code2 ? `${code2}${text}\x1B[0m` : text;
|
|
1337
1368
|
}
|
|
1338
1369
|
|
|
1339
1370
|
// src/commands/drop.ts
|
|
@@ -1614,6 +1645,14 @@ function diffColumn(prev, next) {
|
|
|
1614
1645
|
const col2 = `"${next.name}"`;
|
|
1615
1646
|
if (prev.dataType !== next.dataType) {
|
|
1616
1647
|
changes.push(`ALTER COLUMN ${col2} TYPE ${next.dataType.toUpperCase()} USING ${col2}::${next.dataType}`);
|
|
1648
|
+
} else {
|
|
1649
|
+
const prevLen = prev.length;
|
|
1650
|
+
const nextLen = next.length;
|
|
1651
|
+
if (prevLen !== nextLen && (next.dataType === "varchar" || next.dataType === "char")) {
|
|
1652
|
+
const typeName = next.dataType === "varchar" ? "VARCHAR" : "CHAR";
|
|
1653
|
+
const typeStr = nextLen ? `${typeName}(${nextLen})` : typeName;
|
|
1654
|
+
changes.push(`ALTER COLUMN ${col2} TYPE ${typeStr}`);
|
|
1655
|
+
}
|
|
1617
1656
|
}
|
|
1618
1657
|
if (!prev.notNull && next.notNull) {
|
|
1619
1658
|
changes.push(`ALTER COLUMN ${col2} SET NOT NULL`);
|
|
@@ -1680,8 +1719,6 @@ async function runGenerate(config2, name) {
|
|
|
1680
1719
|
if (isFirstMigration) {
|
|
1681
1720
|
const sorted = topoSort(schemas2);
|
|
1682
1721
|
statements = [
|
|
1683
|
-
`CREATE EXTENSION IF NOT EXISTS "pgcrypto";`,
|
|
1684
|
-
``,
|
|
1685
1722
|
...sorted.flatMap((entry) => [
|
|
1686
1723
|
`-- ${entry.exportName}`,
|
|
1687
1724
|
generateCreateTable(entry.config, true),
|
|
@@ -2099,13 +2136,15 @@ async function runPush(config2, opts = {}) {
|
|
|
2099
2136
|
}
|
|
2100
2137
|
const sql2 = new Bun.SQL(config2.dbUrl);
|
|
2101
2138
|
try {
|
|
2139
|
+
await sql2.unsafe(`CREATE SCHEMA IF NOT EXISTS "${config2.migrationsSchema}";`);
|
|
2140
|
+
const qualifiedPush = `"${config2.migrationsSchema}"."__bungres_push"`;
|
|
2102
2141
|
await sql2.unsafe(`
|
|
2103
|
-
CREATE TABLE IF NOT EXISTS
|
|
2142
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedPush} (
|
|
2104
2143
|
id SERIAL PRIMARY KEY,
|
|
2105
2144
|
snapshot JSONB NOT NULL
|
|
2106
2145
|
);
|
|
2107
2146
|
`);
|
|
2108
|
-
const rows = await sql2.unsafe(`SELECT snapshot FROM
|
|
2147
|
+
const rows = await sql2.unsafe(`SELECT snapshot FROM ${qualifiedPush} ORDER BY id DESC LIMIT 1;`);
|
|
2109
2148
|
let prevSnapshot = {};
|
|
2110
2149
|
if (rows.length > 0) {
|
|
2111
2150
|
prevSnapshot = typeof rows[0].snapshot === "string" ? JSON.parse(rows[0].snapshot) : rows[0].snapshot;
|
|
@@ -2140,14 +2179,13 @@ Are you sure you want to push these changes? Type YES to continue: `);
|
|
|
2140
2179
|
}
|
|
2141
2180
|
console.log(`
|
|
2142
2181
|
Pushing changes...`);
|
|
2143
|
-
await sql2.unsafe(`CREATE EXTENSION IF NOT EXISTS "pgcrypto";`);
|
|
2144
2182
|
for (const stmt of diff.statements) {
|
|
2145
2183
|
if (config2.verbose) {
|
|
2146
2184
|
console.log(`-- ${stmt}`);
|
|
2147
2185
|
}
|
|
2148
2186
|
await sql2.unsafe(stmt);
|
|
2149
2187
|
}
|
|
2150
|
-
await sql2.unsafe(`INSERT INTO
|
|
2188
|
+
await sql2.unsafe(`INSERT INTO ${qualifiedPush} (snapshot) VALUES ($1);`, [JSON.stringify(currentSnapshot)]);
|
|
2151
2189
|
console.log(`
|
|
2152
2190
|
Push complete.`);
|
|
2153
2191
|
} finally {
|
|
@@ -2281,15 +2319,32 @@ async function runStudio(config2) {
|
|
|
2281
2319
|
async fetch(req) {
|
|
2282
2320
|
const url = new URL(req.url);
|
|
2283
2321
|
if (req.method === "GET" && url.pathname === "/api/tables") {
|
|
2284
|
-
const tables = schemas2.map((s) =>
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2322
|
+
const tables = schemas2.map((s) => {
|
|
2323
|
+
const fkColumns = new Set;
|
|
2324
|
+
if (s.config.foreignKeys) {
|
|
2325
|
+
s.config.foreignKeys.forEach((fk) => {
|
|
2326
|
+
fk.columns.forEach((col2) => fkColumns.add(col2));
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
const columns2 = Object.entries(s.config.columns).map(([key, col2]) => {
|
|
2330
|
+
const fk = col2.references ? {
|
|
2331
|
+
table: col2.references.table,
|
|
2332
|
+
column: col2.references.column
|
|
2333
|
+
} : fkColumns.has(col2.name) ? { isForeignKey: true } : null;
|
|
2334
|
+
return {
|
|
2335
|
+
name: col2.name,
|
|
2336
|
+
type: col2.dataType,
|
|
2337
|
+
primaryKey: col2.primaryKey,
|
|
2338
|
+
foreignKey: fk
|
|
2339
|
+
};
|
|
2340
|
+
});
|
|
2341
|
+
return {
|
|
2342
|
+
name: s.config.name,
|
|
2343
|
+
exportName: s.exportName,
|
|
2344
|
+
columns: columns2,
|
|
2345
|
+
foreignKeys: s.config.foreignKeys || []
|
|
2346
|
+
};
|
|
2347
|
+
});
|
|
2293
2348
|
return new Response(JSON.stringify(tables), {
|
|
2294
2349
|
headers: { "Content-Type": "application/json" }
|
|
2295
2350
|
});
|
|
@@ -2367,15 +2422,16 @@ var htmlTemplate = `
|
|
|
2367
2422
|
<style>
|
|
2368
2423
|
:root {
|
|
2369
2424
|
--bg-color: #09090b;
|
|
2370
|
-
--panel-bg:
|
|
2425
|
+
--panel-bg: #18181b;
|
|
2371
2426
|
--border-color: #27272a;
|
|
2372
|
-
--text-main: #
|
|
2427
|
+
--text-main: #fafafa;
|
|
2373
2428
|
--text-muted: #a1a1aa;
|
|
2374
2429
|
--accent-color: #8b5cf6;
|
|
2375
2430
|
--accent-hover: #7c3aed;
|
|
2376
|
-
--header-bg:
|
|
2377
|
-
--row-hover:
|
|
2378
|
-
--
|
|
2431
|
+
--header-bg: #09090b;
|
|
2432
|
+
--row-hover: #27272a;
|
|
2433
|
+
--input-bg: #18181b;
|
|
2434
|
+
--muted-bg: #27272a;
|
|
2379
2435
|
|
|
2380
2436
|
--type-number: #f472b6;
|
|
2381
2437
|
--type-string: #60a5fa;
|
|
@@ -2400,45 +2456,39 @@ var htmlTemplate = `
|
|
|
2400
2456
|
|
|
2401
2457
|
/* Sidebar */
|
|
2402
2458
|
.sidebar {
|
|
2403
|
-
width:
|
|
2459
|
+
width: 240px;
|
|
2404
2460
|
background-color: var(--panel-bg);
|
|
2405
|
-
backdrop-filter: blur(12px);
|
|
2406
|
-
-webkit-backdrop-filter: blur(12px);
|
|
2407
2461
|
border-right: 1px solid var(--border-color);
|
|
2408
2462
|
display: flex;
|
|
2409
2463
|
flex-direction: column;
|
|
2410
|
-
box-shadow: 4px 0 24px rgba(0,0,0,0.2);
|
|
2411
2464
|
z-index: 20;
|
|
2412
2465
|
}
|
|
2413
2466
|
|
|
2414
2467
|
.sidebar-header {
|
|
2415
|
-
padding:
|
|
2416
|
-
border-bottom: 1px solid var(--
|
|
2468
|
+
padding: 16px;
|
|
2469
|
+
border-bottom: 1px solid var(--border-color);
|
|
2417
2470
|
display: flex;
|
|
2418
2471
|
align-items: center;
|
|
2419
|
-
gap:
|
|
2420
|
-
background:
|
|
2472
|
+
gap: 8px;
|
|
2473
|
+
background-color: var(--panel-bg);
|
|
2421
2474
|
}
|
|
2422
2475
|
|
|
2423
2476
|
.sidebar-header h1 {
|
|
2424
2477
|
margin: 0;
|
|
2425
|
-
font-size:
|
|
2478
|
+
font-size: 14px;
|
|
2426
2479
|
font-weight: 600;
|
|
2427
|
-
|
|
2428
|
-
-
|
|
2429
|
-
-webkit-text-fill-color: transparent;
|
|
2430
|
-
letter-spacing: -0.5px;
|
|
2480
|
+
color: var(--text-main);
|
|
2481
|
+
letter-spacing: -0.25px;
|
|
2431
2482
|
}
|
|
2432
2483
|
|
|
2433
2484
|
.sidebar-header svg {
|
|
2434
2485
|
color: var(--accent-color);
|
|
2435
|
-
filter: drop-shadow(0 0 8px rgba(139, 92, 246, 0.5));
|
|
2436
2486
|
}
|
|
2437
2487
|
|
|
2438
2488
|
.table-list {
|
|
2439
2489
|
flex: 1;
|
|
2440
2490
|
overflow-y: auto;
|
|
2441
|
-
padding:
|
|
2491
|
+
padding: 8px;
|
|
2442
2492
|
list-style: none;
|
|
2443
2493
|
margin: 0;
|
|
2444
2494
|
}
|
|
@@ -2452,39 +2502,36 @@ var htmlTemplate = `
|
|
|
2452
2502
|
}
|
|
2453
2503
|
|
|
2454
2504
|
.table-item {
|
|
2455
|
-
padding: 12px
|
|
2505
|
+
padding: 8px 12px;
|
|
2456
2506
|
cursor: pointer;
|
|
2457
|
-
font-size:
|
|
2507
|
+
font-size: 13px;
|
|
2458
2508
|
font-weight: 500;
|
|
2459
2509
|
color: var(--text-muted);
|
|
2460
|
-
border-radius:
|
|
2461
|
-
transition: all 0.
|
|
2510
|
+
border-radius: 6px;
|
|
2511
|
+
transition: all 0.15s ease;
|
|
2462
2512
|
display: flex;
|
|
2463
2513
|
align-items: center;
|
|
2464
|
-
gap:
|
|
2465
|
-
margin-bottom:
|
|
2514
|
+
gap: 8px;
|
|
2515
|
+
margin-bottom: 2px;
|
|
2466
2516
|
border: 1px solid transparent;
|
|
2467
2517
|
}
|
|
2468
2518
|
|
|
2469
2519
|
.table-item:hover {
|
|
2470
|
-
background-color:
|
|
2520
|
+
background-color: var(--muted-bg);
|
|
2471
2521
|
color: var(--text-main);
|
|
2472
|
-
transform: translateX(4px);
|
|
2473
2522
|
}
|
|
2474
2523
|
|
|
2475
2524
|
.table-item.active {
|
|
2476
|
-
background-color:
|
|
2525
|
+
background-color: var(--accent-color);
|
|
2477
2526
|
color: #fff;
|
|
2478
|
-
border:
|
|
2479
|
-
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.1);
|
|
2527
|
+
border-color: var(--accent-color);
|
|
2480
2528
|
}
|
|
2481
2529
|
|
|
2482
2530
|
.table-item svg {
|
|
2483
|
-
|
|
2531
|
+
flex-shrink: 0;
|
|
2484
2532
|
}
|
|
2485
2533
|
.table-item.active svg {
|
|
2486
|
-
color:
|
|
2487
|
-
transform: scale(1.1);
|
|
2534
|
+
color: #fff;
|
|
2488
2535
|
}
|
|
2489
2536
|
|
|
2490
2537
|
/* Main Content */
|
|
@@ -2496,31 +2543,29 @@ var htmlTemplate = `
|
|
|
2496
2543
|
}
|
|
2497
2544
|
|
|
2498
2545
|
.main-header {
|
|
2499
|
-
height:
|
|
2500
|
-
padding: 0
|
|
2546
|
+
height: 56px;
|
|
2547
|
+
padding: 0 16px;
|
|
2501
2548
|
border-bottom: 1px solid var(--border-color);
|
|
2502
2549
|
display: flex;
|
|
2503
2550
|
align-items: center;
|
|
2504
2551
|
justify-content: space-between;
|
|
2505
2552
|
background-color: var(--header-bg);
|
|
2506
|
-
backdrop-filter: blur(12px);
|
|
2507
|
-
-webkit-backdrop-filter: blur(12px);
|
|
2508
2553
|
z-index: 10;
|
|
2509
2554
|
}
|
|
2510
2555
|
|
|
2511
2556
|
.main-header h2 {
|
|
2512
2557
|
margin: 0;
|
|
2513
|
-
font-size:
|
|
2558
|
+
font-size: 14px;
|
|
2514
2559
|
font-weight: 600;
|
|
2515
|
-
color:
|
|
2516
|
-
letter-spacing: -0.
|
|
2560
|
+
color: var(--text-main);
|
|
2561
|
+
letter-spacing: -0.25px;
|
|
2517
2562
|
display: flex;
|
|
2518
2563
|
align-items: center;
|
|
2519
|
-
gap:
|
|
2564
|
+
gap: 8px;
|
|
2520
2565
|
}
|
|
2521
2566
|
|
|
2522
2567
|
.btn {
|
|
2523
|
-
background-color:
|
|
2568
|
+
background-color: var(--input-bg);
|
|
2524
2569
|
border: 1px solid var(--border-color);
|
|
2525
2570
|
color: var(--text-main);
|
|
2526
2571
|
padding: 6px 12px;
|
|
@@ -2529,14 +2574,14 @@ var htmlTemplate = `
|
|
|
2529
2574
|
font-weight: 500;
|
|
2530
2575
|
font-family: 'Outfit', sans-serif;
|
|
2531
2576
|
cursor: pointer;
|
|
2532
|
-
transition: all 0.
|
|
2577
|
+
transition: all 0.15s ease;
|
|
2533
2578
|
display: flex;
|
|
2534
2579
|
align-items: center;
|
|
2535
|
-
gap:
|
|
2580
|
+
gap: 6px;
|
|
2536
2581
|
}
|
|
2537
2582
|
|
|
2538
2583
|
.btn:hover:not(:disabled) {
|
|
2539
|
-
background-color:
|
|
2584
|
+
background-color: var(--muted-bg);
|
|
2540
2585
|
}
|
|
2541
2586
|
|
|
2542
2587
|
.btn:active:not(:disabled) {
|
|
@@ -2544,7 +2589,7 @@ var htmlTemplate = `
|
|
|
2544
2589
|
}
|
|
2545
2590
|
|
|
2546
2591
|
.btn:disabled {
|
|
2547
|
-
opacity: 0.
|
|
2592
|
+
opacity: 0.5;
|
|
2548
2593
|
cursor: not-allowed;
|
|
2549
2594
|
}
|
|
2550
2595
|
|
|
@@ -2559,14 +2604,20 @@ var htmlTemplate = `
|
|
|
2559
2604
|
|
|
2560
2605
|
/* Data Table */
|
|
2561
2606
|
.data-grid-container {
|
|
2562
|
-
background-color:
|
|
2607
|
+
background-color: var(--bg-color);
|
|
2563
2608
|
border: 1px solid var(--border-color);
|
|
2564
2609
|
border-radius: 0;
|
|
2565
|
-
overflow:
|
|
2566
|
-
|
|
2567
|
-
backdrop-filter: blur(8px);
|
|
2568
|
-
max-height: 100%;
|
|
2610
|
+
overflow: hidden;
|
|
2611
|
+
height: 100%;
|
|
2569
2612
|
width: 100%;
|
|
2613
|
+
display: flex;
|
|
2614
|
+
flex-direction: column;
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
.data-grid-container > .table-wrapper {
|
|
2618
|
+
flex: 1;
|
|
2619
|
+
overflow: auto;
|
|
2620
|
+
min-height: 0;
|
|
2570
2621
|
}
|
|
2571
2622
|
|
|
2572
2623
|
.data-grid-container::-webkit-scrollbar {
|
|
@@ -2581,6 +2632,7 @@ var htmlTemplate = `
|
|
|
2581
2632
|
border-radius: 4px;
|
|
2582
2633
|
}
|
|
2583
2634
|
|
|
2635
|
+
|
|
2584
2636
|
table {
|
|
2585
2637
|
width: auto;
|
|
2586
2638
|
border-collapse: separate;
|
|
@@ -2591,11 +2643,11 @@ var htmlTemplate = `
|
|
|
2591
2643
|
}
|
|
2592
2644
|
|
|
2593
2645
|
th {
|
|
2594
|
-
background-color:
|
|
2595
|
-
backdrop-filter: blur(4px);
|
|
2646
|
+
background-color: var(--panel-bg);
|
|
2596
2647
|
color: var(--text-main);
|
|
2597
2648
|
font-weight: 500;
|
|
2598
|
-
|
|
2649
|
+
font-size: 12px;
|
|
2650
|
+
padding: 10px 16px;
|
|
2599
2651
|
border-bottom: 1px solid var(--border-color);
|
|
2600
2652
|
border-right: 1px solid var(--border-color);
|
|
2601
2653
|
white-space: nowrap;
|
|
@@ -2603,24 +2655,16 @@ var htmlTemplate = `
|
|
|
2603
2655
|
top: 0;
|
|
2604
2656
|
z-index: 10;
|
|
2605
2657
|
}
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
th::after {
|
|
2609
|
-
content: '';
|
|
2610
|
-
position: absolute;
|
|
2611
|
-
bottom: -1px; left: 0; right: 0;
|
|
2612
|
-
height: 1px;
|
|
2613
|
-
background: var(--border-color);
|
|
2614
|
-
}
|
|
2615
2658
|
|
|
2616
2659
|
.col-header {
|
|
2617
2660
|
display: flex;
|
|
2618
2661
|
flex-direction: column;
|
|
2619
|
-
gap:
|
|
2662
|
+
gap: 2px;
|
|
2620
2663
|
}
|
|
2621
2664
|
|
|
2622
2665
|
.col-name {
|
|
2623
2666
|
font-weight: 600;
|
|
2667
|
+
font-size: 13px;
|
|
2624
2668
|
display: flex;
|
|
2625
2669
|
align-items: center;
|
|
2626
2670
|
gap: 6px;
|
|
@@ -2628,22 +2672,35 @@ var htmlTemplate = `
|
|
|
2628
2672
|
|
|
2629
2673
|
.pk-badge {
|
|
2630
2674
|
font-size: 10px;
|
|
2631
|
-
background: rgba(251, 191, 36, 0.
|
|
2675
|
+
background: rgba(251, 191, 36, 0.15);
|
|
2632
2676
|
color: #fbbf24;
|
|
2633
|
-
padding: 2px
|
|
2677
|
+
padding: 2px 5px;
|
|
2634
2678
|
border-radius: 4px;
|
|
2635
|
-
font-weight:
|
|
2636
|
-
letter-spacing: 0.
|
|
2679
|
+
font-weight: 500;
|
|
2680
|
+
letter-spacing: 0.25px;
|
|
2681
|
+
border: 1px solid rgba(251, 191, 36, 0.3);
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
.fk-badge {
|
|
2685
|
+
font-size: 10px;
|
|
2686
|
+
background: rgba(96, 165, 250, 0.15);
|
|
2687
|
+
color: #60a5fa;
|
|
2688
|
+
padding: 2px 5px;
|
|
2689
|
+
border-radius: 4px;
|
|
2690
|
+
font-weight: 500;
|
|
2691
|
+
letter-spacing: 0.25px;
|
|
2692
|
+
border: 1px solid rgba(96, 165, 250, 0.3);
|
|
2637
2693
|
}
|
|
2638
2694
|
|
|
2639
2695
|
.col-type {
|
|
2640
|
-
font-size:
|
|
2696
|
+
font-size: 11px;
|
|
2641
2697
|
color: var(--text-muted);
|
|
2642
|
-
font-family: monospace;
|
|
2698
|
+
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
2699
|
+
text-transform: uppercase;
|
|
2643
2700
|
}
|
|
2644
2701
|
|
|
2645
2702
|
td {
|
|
2646
|
-
padding:
|
|
2703
|
+
padding: 10px 16px;
|
|
2647
2704
|
border-bottom: 1px solid var(--border-color);
|
|
2648
2705
|
border-right: 1px solid var(--border-color);
|
|
2649
2706
|
color: var(--text-main);
|
|
@@ -2651,13 +2708,11 @@ var htmlTemplate = `
|
|
|
2651
2708
|
overflow: hidden;
|
|
2652
2709
|
text-overflow: ellipsis;
|
|
2653
2710
|
white-space: nowrap;
|
|
2654
|
-
transition: background-color 0.
|
|
2711
|
+
transition: background-color 0.15s ease;
|
|
2712
|
+
font-size: 13px;
|
|
2655
2713
|
}
|
|
2656
2714
|
|
|
2657
2715
|
|
|
2658
|
-
tr:last-child td {
|
|
2659
|
-
border-bottom: none;
|
|
2660
|
-
}
|
|
2661
2716
|
|
|
2662
2717
|
tr:hover td {
|
|
2663
2718
|
background-color: var(--row-hover);
|
|
@@ -2717,45 +2772,45 @@ var htmlTemplate = `
|
|
|
2717
2772
|
display: flex;
|
|
2718
2773
|
align-items: center;
|
|
2719
2774
|
justify-content: space-between;
|
|
2720
|
-
padding: 16px
|
|
2721
|
-
background-color:
|
|
2775
|
+
padding: 12px 16px;
|
|
2776
|
+
background-color: var(--panel-bg);
|
|
2722
2777
|
border-top: 1px solid var(--border-color);
|
|
2723
|
-
font-size:
|
|
2778
|
+
font-size: 13px;
|
|
2724
2779
|
color: var(--text-muted);
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2780
|
+
width: fit-content;
|
|
2781
|
+
min-width: 100%;
|
|
2782
|
+
flex-shrink: 0;
|
|
2728
2783
|
}
|
|
2729
2784
|
|
|
2730
2785
|
.pagination-info {
|
|
2731
2786
|
display: flex;
|
|
2732
2787
|
align-items: center;
|
|
2733
|
-
gap:
|
|
2788
|
+
gap: 12px;
|
|
2734
2789
|
}
|
|
2735
2790
|
|
|
2736
2791
|
.pagination-controls {
|
|
2737
2792
|
display: flex;
|
|
2738
2793
|
align-items: center;
|
|
2739
|
-
gap:
|
|
2794
|
+
gap: 6px;
|
|
2740
2795
|
}
|
|
2741
2796
|
|
|
2742
2797
|
.pagination-btn {
|
|
2743
|
-
background-color:
|
|
2798
|
+
background-color: var(--input-bg);
|
|
2744
2799
|
border: 1px solid var(--border-color);
|
|
2745
2800
|
color: var(--text-main);
|
|
2746
2801
|
padding: 6px 12px;
|
|
2747
2802
|
border-radius: 6px;
|
|
2748
2803
|
cursor: pointer;
|
|
2749
2804
|
font-size: 13px;
|
|
2750
|
-
transition: all 0.
|
|
2805
|
+
transition: all 0.15s ease;
|
|
2751
2806
|
}
|
|
2752
2807
|
|
|
2753
2808
|
.pagination-btn:hover:not(:disabled) {
|
|
2754
|
-
background-color:
|
|
2809
|
+
background-color: var(--muted-bg);
|
|
2755
2810
|
}
|
|
2756
2811
|
|
|
2757
2812
|
.pagination-btn:disabled {
|
|
2758
|
-
opacity: 0.
|
|
2813
|
+
opacity: 0.5;
|
|
2759
2814
|
cursor: not-allowed;
|
|
2760
2815
|
}
|
|
2761
2816
|
|
|
@@ -2765,7 +2820,7 @@ var htmlTemplate = `
|
|
|
2765
2820
|
}
|
|
2766
2821
|
|
|
2767
2822
|
.page-input {
|
|
2768
|
-
background-color:
|
|
2823
|
+
background-color: var(--input-bg);
|
|
2769
2824
|
border: 1px solid var(--border-color);
|
|
2770
2825
|
color: var(--text-main);
|
|
2771
2826
|
padding: 6px 8px;
|
|
@@ -2774,6 +2829,20 @@ var htmlTemplate = `
|
|
|
2774
2829
|
text-align: center;
|
|
2775
2830
|
font-size: 13px;
|
|
2776
2831
|
}
|
|
2832
|
+
|
|
2833
|
+
.page-size-select {
|
|
2834
|
+
background-color: var(--input-bg);
|
|
2835
|
+
border: 1px solid var(--border-color);
|
|
2836
|
+
color: var(--text-main);
|
|
2837
|
+
padding: 6px 8px;
|
|
2838
|
+
border-radius: 6px;
|
|
2839
|
+
font-size: 13px;
|
|
2840
|
+
cursor: pointer;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
.page-size-select:hover {
|
|
2844
|
+
background-color: var(--muted-bg);
|
|
2845
|
+
}
|
|
2777
2846
|
</style>
|
|
2778
2847
|
</head>
|
|
2779
2848
|
<body>
|
|
@@ -2830,7 +2899,7 @@ var htmlTemplate = `
|
|
|
2830
2899
|
let currentPage = 1;
|
|
2831
2900
|
let totalPages = 1;
|
|
2832
2901
|
let totalRecords = 0;
|
|
2833
|
-
let pageSize =
|
|
2902
|
+
let pageSize = 25;
|
|
2834
2903
|
|
|
2835
2904
|
// Format values for the data grid
|
|
2836
2905
|
function formatValue(val) {
|
|
@@ -2910,21 +2979,29 @@ var htmlTemplate = `
|
|
|
2910
2979
|
document.getElementById('refresh-btn').disabled = false;
|
|
2911
2980
|
|
|
2912
2981
|
const container = document.getElementById('data-container');
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
<
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2982
|
+
const existingTable = container.querySelector('.data-grid-container');
|
|
2983
|
+
|
|
2984
|
+
if (existingTable) {
|
|
2985
|
+
// Show loading overlay instead of replacing content
|
|
2986
|
+
existingTable.style.opacity = '0.5';
|
|
2987
|
+
existingTable.style.pointerEvents = 'none';
|
|
2988
|
+
} else {
|
|
2989
|
+
container.innerHTML = \`
|
|
2990
|
+
<div class="empty-state">
|
|
2991
|
+
<svg class="spinning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2992
|
+
<line x1="12" y1="2" x2="12" y2="6"></line>
|
|
2993
|
+
<line x1="12" y1="18" x2="12" y2="22"></line>
|
|
2994
|
+
<line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line>
|
|
2995
|
+
<line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line>
|
|
2996
|
+
<line x1="2" y1="12" x2="6" y2="12"></line>
|
|
2997
|
+
<line x1="18" y1="12" x2="22" y2="12"></line>
|
|
2998
|
+
<line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line>
|
|
2999
|
+
<line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>
|
|
3000
|
+
</svg>
|
|
3001
|
+
<p>Loading data...</p>
|
|
3002
|
+
</div>
|
|
3003
|
+
\`;
|
|
3004
|
+
}
|
|
2928
3005
|
|
|
2929
3006
|
try {
|
|
2930
3007
|
const res = await fetch(\`/api/tables/\${name}/data?page=\${page}&limit=\${pageSize}\`);
|
|
@@ -2967,13 +3044,32 @@ var htmlTemplate = `
|
|
|
2967
3044
|
});
|
|
2968
3045
|
}
|
|
2969
3046
|
|
|
2970
|
-
columns = Array.from(allKeys).map(key =>
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
3047
|
+
columns = Array.from(allKeys).map(key => {
|
|
3048
|
+
const schemaCol = schemaColMap[key];
|
|
3049
|
+
let type = 'text';
|
|
3050
|
+
|
|
3051
|
+
// First try to get type from schema
|
|
3052
|
+
if (schemaCol && schemaCol.type) {
|
|
3053
|
+
type = schemaCol.type;
|
|
3054
|
+
} else if (rows[0] && rows[0][key] !== undefined) {
|
|
3055
|
+
// Fallback to type detection from actual value
|
|
3056
|
+
const val = rows[0][key];
|
|
3057
|
+
if (typeof val === 'number') type = 'integer';
|
|
3058
|
+
else if (typeof val === 'boolean') type = 'boolean';
|
|
3059
|
+
else if (val instanceof Date) type = 'timestamptz';
|
|
3060
|
+
else if (typeof val === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(val)) type = 'uuid';
|
|
3061
|
+
else type = 'text';
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
return {
|
|
3065
|
+
name: key,
|
|
3066
|
+
type,
|
|
3067
|
+
primaryKey: schemaCol ? schemaCol.primaryKey : false,
|
|
3068
|
+
foreignKey: schemaCol ? schemaCol.foreignKey : null
|
|
3069
|
+
};
|
|
3070
|
+
});
|
|
2975
3071
|
|
|
2976
|
-
let html = '<div class="data-grid-container"><table><thead><tr>';
|
|
3072
|
+
let html = '<div class="data-grid-container"><div class="table-wrapper"><table><thead><tr>';
|
|
2977
3073
|
columns.forEach(col => {
|
|
2978
3074
|
html += \`
|
|
2979
3075
|
<th>
|
|
@@ -2981,6 +3077,7 @@ var htmlTemplate = `
|
|
|
2981
3077
|
<div class="col-name">
|
|
2982
3078
|
\${col.name}
|
|
2983
3079
|
\${col.primaryKey ? '<span class="pk-badge">PK</span>' : ''}
|
|
3080
|
+
\${col.foreignKey ? '<span class="fk-badge">FK</span>' : ''}
|
|
2984
3081
|
</div>
|
|
2985
3082
|
<div class="col-type">\${col.type}</div>
|
|
2986
3083
|
</div>
|
|
@@ -2999,12 +3096,22 @@ var htmlTemplate = `
|
|
|
2999
3096
|
|
|
3000
3097
|
html += '</tbody></table>';
|
|
3001
3098
|
|
|
3002
|
-
// Add pagination
|
|
3099
|
+
// Add pagination inside the table wrapper to match table width
|
|
3003
3100
|
html += renderPagination();
|
|
3004
3101
|
|
|
3005
|
-
html += '</div>';
|
|
3102
|
+
html += '</div></div>';
|
|
3006
3103
|
container.innerHTML = html;
|
|
3007
3104
|
|
|
3105
|
+
// Fade in the new content
|
|
3106
|
+
const newTable = container.querySelector('.data-grid-container');
|
|
3107
|
+
if (newTable) {
|
|
3108
|
+
newTable.style.opacity = '0';
|
|
3109
|
+
requestAnimationFrame(() => {
|
|
3110
|
+
newTable.style.transition = 'opacity 0.15s ease';
|
|
3111
|
+
newTable.style.opacity = '1';
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3008
3115
|
} catch (e) {
|
|
3009
3116
|
container.innerHTML = \`
|
|
3010
3117
|
<div class="empty-state">
|
|
@@ -3026,18 +3133,27 @@ var htmlTemplate = `
|
|
|
3026
3133
|
|
|
3027
3134
|
let html = '<div class="pagination">';
|
|
3028
3135
|
html += '<div class="pagination-info">';
|
|
3029
|
-
html += \`<span
|
|
3030
|
-
html += \`<span
|
|
3031
|
-
html += \`<span>Showing \${startRecord}-\${endRecord}</span>\`;
|
|
3136
|
+
html += \`<span>\${totalRecords} records</span>\`;
|
|
3137
|
+
html += \`<span>\${startRecord}-\${endRecord}</span>\`;
|
|
3032
3138
|
html += '</div>';
|
|
3033
3139
|
|
|
3034
3140
|
html += '<div class="pagination-controls">';
|
|
3035
3141
|
|
|
3142
|
+
// Page size selector
|
|
3143
|
+
html += '<select class="page-size-select" onchange="changePageSize(this.value)">';
|
|
3144
|
+
[10, 25, 50, 100].forEach(size => {
|
|
3145
|
+
html += \`<option value="\${size}" \${pageSize === size ? 'selected' : ''}>\${size}</option>\`;
|
|
3146
|
+
});
|
|
3147
|
+
html += '</select>';
|
|
3148
|
+
|
|
3036
3149
|
// Previous button
|
|
3037
|
-
html += \`<button class="pagination-btn" onclick="changePage(\${currentPage - 1})" \${currentPage === 1 ? 'disabled' : ''}
|
|
3150
|
+
html += \`<button class="pagination-btn" onclick="changePage(\${currentPage - 1})" \${currentPage === 1 ? 'disabled' : ''}>\u2190</button>\`;
|
|
3151
|
+
|
|
3152
|
+
// Page indicator
|
|
3153
|
+
html += \`<span style="min-width: 60px; text-align: center;">\${currentPage} / \${totalPages}</span>\`;
|
|
3038
3154
|
|
|
3039
3155
|
// Next button
|
|
3040
|
-
html += \`<button class="pagination-btn" onclick="changePage(\${currentPage + 1})" \${currentPage === totalPages ? 'disabled' : ''}
|
|
3156
|
+
html += \`<button class="pagination-btn" onclick="changePage(\${currentPage + 1})" \${currentPage === totalPages ? 'disabled' : ''}>\u2192</button>\`;
|
|
3041
3157
|
|
|
3042
3158
|
html += '</div>';
|
|
3043
3159
|
html += '</div>';
|
|
@@ -3045,6 +3161,12 @@ var htmlTemplate = `
|
|
|
3045
3161
|
return html;
|
|
3046
3162
|
}
|
|
3047
3163
|
|
|
3164
|
+
function changePageSize(newSize) {
|
|
3165
|
+
pageSize = parseInt(newSize, 10);
|
|
3166
|
+
currentPage = 1;
|
|
3167
|
+
selectTable(currentTable, currentPage);
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3048
3170
|
function changePage(page) {
|
|
3049
3171
|
if (page < 1 || page > totalPages) return;
|
|
3050
3172
|
selectTable(currentTable, page);
|
|
@@ -3172,7 +3294,7 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
3172
3294
|
migrationsSchema: userConfig.migrations?.schema ?? "bungres",
|
|
3173
3295
|
breakpoints: userConfig.breakpoints ?? true,
|
|
3174
3296
|
strict: userConfig.strict ?? false,
|
|
3175
|
-
outDir: "./src/db/generated",
|
|
3297
|
+
outDir: userConfig.outDir ?? "./src/db/generated",
|
|
3176
3298
|
verbose: userConfig.verbose ?? false
|
|
3177
3299
|
};
|
|
3178
3300
|
}
|
|
@@ -3189,6 +3311,9 @@ async function ensureDatabase2(dbUrl) {
|
|
|
3189
3311
|
try {
|
|
3190
3312
|
const parsed = new URL(dbUrl);
|
|
3191
3313
|
const dbName = parsed.pathname.slice(1);
|
|
3314
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_$]*$/.test(dbName)) {
|
|
3315
|
+
throw new Error(`Invalid database name: "${dbName}"`);
|
|
3316
|
+
}
|
|
3192
3317
|
parsed.pathname = "/postgres";
|
|
3193
3318
|
const fallbackUrl = parsed.toString();
|
|
3194
3319
|
const fallback = new Bun.SQL(fallbackUrl);
|
|
@@ -3206,9 +3331,69 @@ async function ensureDatabase2(dbUrl) {
|
|
|
3206
3331
|
}
|
|
3207
3332
|
}
|
|
3208
3333
|
}
|
|
3334
|
+
// package.json
|
|
3335
|
+
var package_default = {
|
|
3336
|
+
name: "@bungres/kit",
|
|
3337
|
+
version: "0.6.0",
|
|
3338
|
+
description: "CLI toolkit for @bungres/orm \u2014 migrate, push, generate, pull",
|
|
3339
|
+
license: "MIT",
|
|
3340
|
+
engines: {
|
|
3341
|
+
node: ">=24.0.0",
|
|
3342
|
+
bun: ">=1.3.0"
|
|
3343
|
+
},
|
|
3344
|
+
type: "module",
|
|
3345
|
+
bin: {
|
|
3346
|
+
bungres: "./dist/cli.js"
|
|
3347
|
+
},
|
|
3348
|
+
main: "./dist/index.js",
|
|
3349
|
+
types: "./dist/index.d.ts",
|
|
3350
|
+
exports: {
|
|
3351
|
+
".": {
|
|
3352
|
+
bun: "./src/index.ts",
|
|
3353
|
+
import: "./dist/index.js",
|
|
3354
|
+
types: "./dist/index.d.ts"
|
|
3355
|
+
}
|
|
3356
|
+
},
|
|
3357
|
+
files: [
|
|
3358
|
+
"dist",
|
|
3359
|
+
"README.md",
|
|
3360
|
+
"LICENSE"
|
|
3361
|
+
],
|
|
3362
|
+
author: "aniket khote",
|
|
3363
|
+
repository: {
|
|
3364
|
+
type: "git",
|
|
3365
|
+
url: "https://github.com/bungres/bungres.git",
|
|
3366
|
+
directory: "packages/bungres-kit"
|
|
3367
|
+
},
|
|
3368
|
+
bugs: {
|
|
3369
|
+
url: "https://github.com/bungres/bungres/issues"
|
|
3370
|
+
},
|
|
3371
|
+
homepage: "https://github.com/bungres/bungres#readme",
|
|
3372
|
+
keywords: [
|
|
3373
|
+
"bun",
|
|
3374
|
+
"postgres",
|
|
3375
|
+
"orm",
|
|
3376
|
+
"cli",
|
|
3377
|
+
"migration",
|
|
3378
|
+
"generator"
|
|
3379
|
+
],
|
|
3380
|
+
scripts: {
|
|
3381
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
3382
|
+
build: "bun build ./src/cli.ts ./src/index.ts --outdir ./dist --target bun --format esm && npm run build:types",
|
|
3383
|
+
dev: "bun --watch src/cli.ts",
|
|
3384
|
+
test: "bun test"
|
|
3385
|
+
},
|
|
3386
|
+
dependencies: {
|
|
3387
|
+
"@bungres/orm": "workspace:*"
|
|
3388
|
+
},
|
|
3389
|
+
devDependencies: {
|
|
3390
|
+
"bun-types": "latest",
|
|
3391
|
+
typescript: "latest"
|
|
3392
|
+
}
|
|
3393
|
+
};
|
|
3209
3394
|
|
|
3210
3395
|
// src/cli.ts
|
|
3211
|
-
var VERSION =
|
|
3396
|
+
var VERSION = package_default.version;
|
|
3212
3397
|
var HELP = `
|
|
3213
3398
|
${colorize("\uD83D\uDC18 Bungres ORM CLI", "cyan")} v${VERSION}
|
|
3214
3399
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAgBnD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAgBnD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CA+Ff"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAUnD,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":"push.d.ts","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAUnD,wBAAsB,OAAO,CAC3B,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,IAAI,CAAC,CAqFf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studio.d.ts","sourceRoot":"","sources":["../../src/commands/studio.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAQnD,wBAAsB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"studio.d.ts","sourceRoot":"","sources":["../../src/commands/studio.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAQnD,wBAAsB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAyIrE"}
|
package/dist/config.d.ts
CHANGED
|
@@ -53,6 +53,11 @@ export interface BungresKitConfig {
|
|
|
53
53
|
* Default: false
|
|
54
54
|
*/
|
|
55
55
|
strict?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Output directory for `bungres pull` generated TypeScript.
|
|
58
|
+
* Default: "./src/db/generated"
|
|
59
|
+
*/
|
|
60
|
+
outDir?: string;
|
|
56
61
|
/** Print every SQL statement executed. Default: false */
|
|
57
62
|
verbose?: boolean;
|
|
58
63
|
}
|
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;;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"}
|
|
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;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,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/ensure-db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure-db.d.ts","sourceRoot":"","sources":["../src/ensure-db.ts"],"names":[],"mappings":"AAAA,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"ensure-db.d.ts","sourceRoot":"","sources":["../src/ensure-db.ts"],"names":[],"mappings":"AAAA,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCjE"}
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
34
34
|
migrationsSchema: userConfig.migrations?.schema ?? "bungres",
|
|
35
35
|
breakpoints: userConfig.breakpoints ?? true,
|
|
36
36
|
strict: userConfig.strict ?? false,
|
|
37
|
-
outDir: "./src/db/generated",
|
|
37
|
+
outDir: userConfig.outDir ?? "./src/db/generated",
|
|
38
38
|
verbose: userConfig.verbose ?? false
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -110,6 +110,7 @@ function createTableFactory(casing) {
|
|
|
110
110
|
var table = createTableFactory("snake");
|
|
111
111
|
var snakeCase = { table: createTableFactory("snake") };
|
|
112
112
|
var camelCase = { table: createTableFactory("camel") };
|
|
113
|
+
var noCasing = { table: createTableFactory("none") };
|
|
113
114
|
// ../bungres-orm/src/schema/columns.ts
|
|
114
115
|
function buildColumn(dataType, nameOrOpts, opts) {
|
|
115
116
|
let name = "";
|
|
@@ -204,14 +205,14 @@ function sqlJoin(chunks, separator = ", ") {
|
|
|
204
205
|
function rawSql(query) {
|
|
205
206
|
return { sql: query, params: [] };
|
|
206
207
|
}
|
|
207
|
-
|
|
208
|
-
var colName = (c) => {
|
|
208
|
+
function colName(c) {
|
|
209
209
|
if (typeof c === "string")
|
|
210
210
|
return `"${c}"`;
|
|
211
211
|
if (isSQLChunk(c))
|
|
212
212
|
return c.sql;
|
|
213
213
|
return c.tableName ? `${c.tableName}."${c.name}"` : `"${c.name}"`;
|
|
214
|
-
}
|
|
214
|
+
}
|
|
215
|
+
// ../bungres-orm/src/core/conditions.ts
|
|
215
216
|
function isColumnConfig(val) {
|
|
216
217
|
return val !== null && typeof val === "object" && "name" in val && "dataType" in val;
|
|
217
218
|
}
|
|
@@ -268,6 +269,14 @@ var inArray = (column, values) => {
|
|
|
268
269
|
const placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
|
|
269
270
|
return { sql: `${colName(column)} = ANY(ARRAY[${placeholders}])`, params };
|
|
270
271
|
};
|
|
272
|
+
var notInArray = (column, values) => {
|
|
273
|
+
if (values.length === 0)
|
|
274
|
+
return rawSql("TRUE");
|
|
275
|
+
const params = values;
|
|
276
|
+
const placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
|
|
277
|
+
return { sql: `${colName(column)} != ALL(ARRAY[${placeholders}])`, params };
|
|
278
|
+
};
|
|
279
|
+
var between = (column, min, max) => sql`${rawSql(colName(column))} BETWEEN ${min} AND ${max}`;
|
|
271
280
|
var and = (...conditions) => sqlJoin(conditions, " AND ");
|
|
272
281
|
var or = (...conditions) => {
|
|
273
282
|
const joined = sqlJoin(conditions, " OR ");
|
|
@@ -318,6 +327,10 @@ function parseWhereObject(tableConfig, whereObj) {
|
|
|
318
327
|
conditions.push(lte(columnArg, opVal.lte));
|
|
319
328
|
if (opVal.in !== undefined)
|
|
320
329
|
conditions.push(inArray(columnArg, opVal.in));
|
|
330
|
+
if (opVal.notIn !== undefined)
|
|
331
|
+
conditions.push(notInArray(columnArg, opVal.notIn));
|
|
332
|
+
if (opVal.between !== undefined)
|
|
333
|
+
conditions.push(between(columnArg, opVal.between[0], opVal.between[1]));
|
|
321
334
|
if (opVal.like !== undefined)
|
|
322
335
|
conditions.push(like(columnArg, opVal.like));
|
|
323
336
|
if (opVal.ilike !== undefined)
|
|
@@ -398,6 +411,9 @@ class DeleteBuilder {
|
|
|
398
411
|
if (this._returning) {
|
|
399
412
|
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(getTableConfig(this._table).columns).map((c) => `"${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
400
413
|
}
|
|
414
|
+
if (this._comment) {
|
|
415
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
416
|
+
}
|
|
401
417
|
return { sql: query, params };
|
|
402
418
|
}
|
|
403
419
|
}
|
|
@@ -508,7 +524,7 @@ class InsertBuilder {
|
|
|
508
524
|
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(tConfig.columns).map((c) => `"${tConfig.columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${tConfig.columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
509
525
|
}
|
|
510
526
|
if (this._comment) {
|
|
511
|
-
query += ` /* ${this._comment} */`;
|
|
527
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
512
528
|
}
|
|
513
529
|
return { sql: query, params };
|
|
514
530
|
}
|
|
@@ -705,7 +721,7 @@ class SelectBuilder {
|
|
|
705
721
|
query += ` OFFSET $${params.length}`;
|
|
706
722
|
}
|
|
707
723
|
if (this._comment) {
|
|
708
|
-
query += ` /* ${this._comment} */`;
|
|
724
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
709
725
|
}
|
|
710
726
|
return { sql: query, params };
|
|
711
727
|
}
|
|
@@ -805,10 +821,22 @@ class UpdateBuilder {
|
|
|
805
821
|
if (this._returning) {
|
|
806
822
|
query += " RETURNING " + (this._returning[0] === "*" ? Object.keys(getTableConfig(this._table).columns).map((c) => `"${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ") : this._returning.map((c) => `"${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`).join(", "));
|
|
807
823
|
}
|
|
824
|
+
if (this._comment) {
|
|
825
|
+
query += ` /* ${this._comment.replace(/\*\//g, "")} */`;
|
|
826
|
+
}
|
|
808
827
|
return { sql: query, params };
|
|
809
828
|
}
|
|
810
829
|
}
|
|
811
830
|
// ../bungres-orm/src/builders/relational.ts
|
|
831
|
+
function getPkColumn(tableConfig) {
|
|
832
|
+
if (tableConfig.primaryKeys?.length > 0)
|
|
833
|
+
return tableConfig.primaryKeys[0];
|
|
834
|
+
for (const [, col2] of Object.entries(tableConfig.columns)) {
|
|
835
|
+
if (col2.primaryKey)
|
|
836
|
+
return col2.name;
|
|
837
|
+
}
|
|
838
|
+
return "id";
|
|
839
|
+
}
|
|
812
840
|
var _relationsCache = new WeakMap;
|
|
813
841
|
|
|
814
842
|
class RelationalQueryBuilder {
|
|
@@ -959,14 +987,17 @@ class RelationalQueryBuilder {
|
|
|
959
987
|
if (relations.ones[relKey]) {
|
|
960
988
|
const rel = relations.ones[relKey];
|
|
961
989
|
const subAlias = `${alias}_${relKey}`;
|
|
962
|
-
const
|
|
990
|
+
const targetConfig = this._schema[rel.targetTable][TableConfigSymbol];
|
|
991
|
+
const targetPk = getPkColumn(targetConfig);
|
|
992
|
+
const joinCond = `"${subAlias}"."${targetPk}" = "${alias}"."${rel.sourceColumn}"`;
|
|
963
993
|
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, joinCond);
|
|
964
994
|
const subSql = `SELECT ${subQuery.sql} ${subQuery.from}`;
|
|
965
995
|
jsonFields.push(`'${relKey}', (${subSql})`);
|
|
966
996
|
} else if (relations.manys[relKey]) {
|
|
967
997
|
const rel = relations.manys[relKey];
|
|
968
998
|
const subAlias = `${alias}_${relKey}`;
|
|
969
|
-
const
|
|
999
|
+
const thisPk = getPkColumn(tableConfig);
|
|
1000
|
+
const joinCond = `"${subAlias}"."${rel.targetColumn}" = "${alias}"."${thisPk}"`;
|
|
970
1001
|
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, joinCond);
|
|
971
1002
|
const aggAlias = `${subAlias}_agg`;
|
|
972
1003
|
const aggSql = `
|
|
@@ -985,9 +1016,9 @@ class RelationalQueryBuilder {
|
|
|
985
1016
|
const junctionTableConfig = this._schema[rel.junctionTable][TableConfigSymbol];
|
|
986
1017
|
const fromExtra = `
|
|
987
1018
|
INNER JOIN ${junctionTableConfig.qualifiedName} AS "${junctionAlias}"
|
|
988
|
-
ON "${junctionAlias}"."${rel.joinTargetColumn}" = "${subAlias}"."${targetTableConfig
|
|
1019
|
+
ON "${junctionAlias}"."${rel.joinTargetColumn}" = "${subAlias}"."${getPkColumn(targetTableConfig)}"
|
|
989
1020
|
`;
|
|
990
|
-
const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${alias}"."${tableConfig
|
|
1021
|
+
const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${alias}"."${getPkColumn(tableConfig)}"`;
|
|
991
1022
|
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, whereExtra, fromExtra);
|
|
992
1023
|
const aggSql = `
|
|
993
1024
|
SELECT COALESCE(json_agg(_sub.obj), '[]'::json)
|
|
@@ -1500,6 +1531,14 @@ function diffColumn(prev, next) {
|
|
|
1500
1531
|
const col2 = `"${next.name}"`;
|
|
1501
1532
|
if (prev.dataType !== next.dataType) {
|
|
1502
1533
|
changes.push(`ALTER COLUMN ${col2} TYPE ${next.dataType.toUpperCase()} USING ${col2}::${next.dataType}`);
|
|
1534
|
+
} else {
|
|
1535
|
+
const prevLen = prev.length;
|
|
1536
|
+
const nextLen = next.length;
|
|
1537
|
+
if (prevLen !== nextLen && (next.dataType === "varchar" || next.dataType === "char")) {
|
|
1538
|
+
const typeName = next.dataType === "varchar" ? "VARCHAR" : "CHAR";
|
|
1539
|
+
const typeStr = nextLen ? `${typeName}(${nextLen})` : typeName;
|
|
1540
|
+
changes.push(`ALTER COLUMN ${col2} TYPE ${typeStr}`);
|
|
1541
|
+
}
|
|
1503
1542
|
}
|
|
1504
1543
|
if (!prev.notNull && next.notNull) {
|
|
1505
1544
|
changes.push(`ALTER COLUMN ${col2} SET NOT NULL`);
|
|
@@ -1544,13 +1583,15 @@ async function runPush(config, opts = {}) {
|
|
|
1544
1583
|
}
|
|
1545
1584
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
1546
1585
|
try {
|
|
1586
|
+
await sql2.unsafe(`CREATE SCHEMA IF NOT EXISTS "${config.migrationsSchema}";`);
|
|
1587
|
+
const qualifiedPush = `"${config.migrationsSchema}"."__bungres_push"`;
|
|
1547
1588
|
await sql2.unsafe(`
|
|
1548
|
-
CREATE TABLE IF NOT EXISTS
|
|
1589
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedPush} (
|
|
1549
1590
|
id SERIAL PRIMARY KEY,
|
|
1550
1591
|
snapshot JSONB NOT NULL
|
|
1551
1592
|
);
|
|
1552
1593
|
`);
|
|
1553
|
-
const rows = await sql2.unsafe(`SELECT snapshot FROM
|
|
1594
|
+
const rows = await sql2.unsafe(`SELECT snapshot FROM ${qualifiedPush} ORDER BY id DESC LIMIT 1;`);
|
|
1554
1595
|
let prevSnapshot = {};
|
|
1555
1596
|
if (rows.length > 0) {
|
|
1556
1597
|
prevSnapshot = typeof rows[0].snapshot === "string" ? JSON.parse(rows[0].snapshot) : rows[0].snapshot;
|
|
@@ -1585,14 +1626,13 @@ Are you sure you want to push these changes? Type YES to continue: `);
|
|
|
1585
1626
|
}
|
|
1586
1627
|
console.log(`
|
|
1587
1628
|
Pushing changes...`);
|
|
1588
|
-
await sql2.unsafe(`CREATE EXTENSION IF NOT EXISTS "pgcrypto";`);
|
|
1589
1629
|
for (const stmt of diff.statements) {
|
|
1590
1630
|
if (config.verbose) {
|
|
1591
1631
|
console.log(`-- ${stmt}`);
|
|
1592
1632
|
}
|
|
1593
1633
|
await sql2.unsafe(stmt);
|
|
1594
1634
|
}
|
|
1595
|
-
await sql2.unsafe(`INSERT INTO
|
|
1635
|
+
await sql2.unsafe(`INSERT INTO ${qualifiedPush} (snapshot) VALUES ($1);`, [JSON.stringify(currentSnapshot)]);
|
|
1596
1636
|
console.log(`
|
|
1597
1637
|
Push complete.`);
|
|
1598
1638
|
} finally {
|
|
@@ -1608,9 +1648,9 @@ async function readLine() {
|
|
|
1608
1648
|
import { join as join3, resolve as resolve3 } from "path";
|
|
1609
1649
|
|
|
1610
1650
|
// src/utils/colors.ts
|
|
1611
|
-
function colorize(
|
|
1651
|
+
function colorize(text, color) {
|
|
1612
1652
|
const code = Bun.color(color, "ansi");
|
|
1613
|
-
return code ? `${code}${
|
|
1653
|
+
return code ? `${code}${text}\x1B[0m` : text;
|
|
1614
1654
|
}
|
|
1615
1655
|
|
|
1616
1656
|
// src/commands/generate.ts
|
|
@@ -1645,8 +1685,6 @@ async function runGenerate(config, name) {
|
|
|
1645
1685
|
if (isFirstMigration) {
|
|
1646
1686
|
const sorted = topoSort(schemas);
|
|
1647
1687
|
statements = [
|
|
1648
|
-
`CREATE EXTENSION IF NOT EXISTS "pgcrypto";`,
|
|
1649
|
-
``,
|
|
1650
1688
|
...sorted.flatMap((entry) => [
|
|
1651
1689
|
`-- ${entry.exportName}`,
|
|
1652
1690
|
generateCreateTable(entry.config, true),
|