@bungres/kit 1.1.0 → 1.1.2
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 +17 -16
- package/dist/cli.js +3620 -3088
- package/dist/commands/drop.d.ts.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/refresh.d.ts.map +1 -1
- package/dist/commands/rollback.d.ts.map +1 -1
- package/dist/commands/seed.d.ts.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/studio.d.ts.map +1 -1
- package/dist/commands/template.d.ts.map +1 -1
- package/dist/commands/tusky.d.ts.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.js +473 -232
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -168,14 +168,25 @@ var CONFIG_FILES = [
|
|
|
168
168
|
"bungres.config.mts",
|
|
169
169
|
"bungres.config.mjs"
|
|
170
170
|
];
|
|
171
|
-
async function loadConfig(cwd = process.cwd()) {
|
|
171
|
+
async function loadConfig(cwd = process.cwd(), explicitConfigPath) {
|
|
172
172
|
let userConfig = {};
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
if (await Bun.file(
|
|
176
|
-
const mod = await import(
|
|
173
|
+
if (explicitConfigPath) {
|
|
174
|
+
const fullPath = resolve(cwd, explicitConfigPath);
|
|
175
|
+
if (await Bun.file(fullPath).exists()) {
|
|
176
|
+
const mod = await import(fullPath);
|
|
177
177
|
userConfig = mod.default ?? mod;
|
|
178
|
-
|
|
178
|
+
} else {
|
|
179
|
+
console.error(`bungres: Config file not found at ${fullPath}`);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
for (const file of CONFIG_FILES) {
|
|
184
|
+
const configPath = join(cwd, file);
|
|
185
|
+
if (await Bun.file(configPath).exists()) {
|
|
186
|
+
const mod = await import(resolve(configPath));
|
|
187
|
+
userConfig = mod.default ?? mod;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
179
190
|
}
|
|
180
191
|
}
|
|
181
192
|
const dbUrl = userConfig.dbCredentials?.url ?? Bun.env.DATABASE_URL ?? Bun.env.POSTGRES_URL ?? "";
|
|
@@ -256,7 +267,7 @@ function createTableFactory(casing) {
|
|
|
256
267
|
const tableObj = {
|
|
257
268
|
[TableConfigSymbol]: {
|
|
258
269
|
name,
|
|
259
|
-
schema,
|
|
270
|
+
...schema ? { schema } : {},
|
|
260
271
|
columns: columnConfigs,
|
|
261
272
|
indexes,
|
|
262
273
|
checks,
|
|
@@ -268,10 +279,10 @@ function createTableFactory(casing) {
|
|
|
268
279
|
return Object.assign(tableObj, columnConfigs);
|
|
269
280
|
};
|
|
270
281
|
}
|
|
271
|
-
var
|
|
272
|
-
var snakeCase = {
|
|
273
|
-
var camelCase = {
|
|
274
|
-
var noCasing = {
|
|
282
|
+
var pgTable = createTableFactory("snake");
|
|
283
|
+
var snakeCase = { pgTable: createTableFactory("snake") };
|
|
284
|
+
var camelCase = { pgTable: createTableFactory("camel") };
|
|
285
|
+
var noCasing = { pgTable: createTableFactory("none") };
|
|
275
286
|
function buildColumn(dataType, nameOrOpts, opts) {
|
|
276
287
|
let name = "";
|
|
277
288
|
let options = opts;
|
|
@@ -298,8 +309,8 @@ function buildColumn(dataType, nameOrOpts, opts) {
|
|
|
298
309
|
...options?.check !== undefined ? { check: options.check } : {}
|
|
299
310
|
};
|
|
300
311
|
return Object.assign(config, {
|
|
301
|
-
as(
|
|
302
|
-
return Object.assign({}, this, { alias });
|
|
312
|
+
as(alias2) {
|
|
313
|
+
return Object.assign({}, this, { alias: alias2 });
|
|
303
314
|
},
|
|
304
315
|
array() {
|
|
305
316
|
return Object.assign({}, this, { dataType: `${this.dataType}[]` });
|
|
@@ -336,6 +347,41 @@ var textArray = col("text[]");
|
|
|
336
347
|
var integerArray = col("integer[]");
|
|
337
348
|
var varcharArray = col("varchar[]");
|
|
338
349
|
var uuidArray = col("uuid[]");
|
|
350
|
+
function shiftParams(sql, paramsLength, offset) {
|
|
351
|
+
if (paramsLength === 0)
|
|
352
|
+
return sql;
|
|
353
|
+
let result = "";
|
|
354
|
+
let inString = false;
|
|
355
|
+
let inIdent = false;
|
|
356
|
+
let i = 0;
|
|
357
|
+
while (i < sql.length) {
|
|
358
|
+
if (sql[i] === "'" && !inIdent) {
|
|
359
|
+
inString = !inString;
|
|
360
|
+
result += sql[i];
|
|
361
|
+
i++;
|
|
362
|
+
} else if (sql[i] === '"' && !inString) {
|
|
363
|
+
inIdent = !inIdent;
|
|
364
|
+
result += sql[i];
|
|
365
|
+
i++;
|
|
366
|
+
} else if (!inString && !inIdent && sql[i] === "$") {
|
|
367
|
+
const match = sql.slice(i).match(/^\$(\d+)/);
|
|
368
|
+
if (match) {
|
|
369
|
+
const num = parseInt(match[1], 10);
|
|
370
|
+
if (num >= 1 && num <= paramsLength) {
|
|
371
|
+
result += `$${num + offset}`;
|
|
372
|
+
i += match[0].length;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
result += sql[i];
|
|
377
|
+
i++;
|
|
378
|
+
} else {
|
|
379
|
+
result += sql[i];
|
|
380
|
+
i++;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
339
385
|
function sql(strings, ...values) {
|
|
340
386
|
let query = "";
|
|
341
387
|
const params = [];
|
|
@@ -345,7 +391,7 @@ function sql(strings, ...values) {
|
|
|
345
391
|
const val = values[i];
|
|
346
392
|
if (isSQLChunk(val)) {
|
|
347
393
|
const offset = params.length;
|
|
348
|
-
query += val.sql
|
|
394
|
+
query += shiftParams(val.sql, val.params.length, offset);
|
|
349
395
|
params.push(...val.params);
|
|
350
396
|
} else {
|
|
351
397
|
params.push(val);
|
|
@@ -363,7 +409,7 @@ function sqlJoin(chunks, separator = ", ") {
|
|
|
363
409
|
const parts = [];
|
|
364
410
|
for (const chunk of chunks) {
|
|
365
411
|
const offset = params.length;
|
|
366
|
-
parts.push(chunk.sql
|
|
412
|
+
parts.push(shiftParams(chunk.sql, chunk.params.length, offset));
|
|
367
413
|
params.push(...chunk.params);
|
|
368
414
|
}
|
|
369
415
|
return { sql: parts.join(separator), params };
|
|
@@ -371,6 +417,19 @@ function sqlJoin(chunks, separator = ", ") {
|
|
|
371
417
|
function rawSql(query) {
|
|
372
418
|
return { sql: query, params: [] };
|
|
373
419
|
}
|
|
420
|
+
function toPgArray(val) {
|
|
421
|
+
const formatted = val.map((item) => {
|
|
422
|
+
if (item === null || item === undefined)
|
|
423
|
+
return "NULL";
|
|
424
|
+
if (typeof item === "number" || typeof item === "boolean")
|
|
425
|
+
return String(item);
|
|
426
|
+
if (Array.isArray(item))
|
|
427
|
+
return toPgArray(item);
|
|
428
|
+
const str = String(item).replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
429
|
+
return `"${str}"`;
|
|
430
|
+
});
|
|
431
|
+
return `{${formatted.join(",")}}`;
|
|
432
|
+
}
|
|
374
433
|
function colName(c) {
|
|
375
434
|
if (typeof c === "string")
|
|
376
435
|
return `"${c}"`;
|
|
@@ -428,18 +487,26 @@ var ilike = (column, pattern) => sql`${rawSql(colName(column))} ILIKE ${pattern}
|
|
|
428
487
|
var isNull = (column) => rawSql(`${colName(column)} IS NULL`);
|
|
429
488
|
var isNotNull = (column) => rawSql(`${colName(column)} IS NOT NULL`);
|
|
430
489
|
var inArray = (column, values) => {
|
|
431
|
-
if (values
|
|
490
|
+
if (typeof values === "object" && values !== null && "toSQL" in values) {
|
|
491
|
+
return sql`${rawSql(colName(column))} IN (${values.toSQL()})`;
|
|
492
|
+
}
|
|
493
|
+
const arr = values;
|
|
494
|
+
if (arr.length === 0)
|
|
432
495
|
return rawSql("FALSE");
|
|
433
|
-
const params =
|
|
434
|
-
const placeholders =
|
|
435
|
-
return { sql: `${colName(column)}
|
|
496
|
+
const params = arr;
|
|
497
|
+
const placeholders = arr.map((_, i) => `$${i + 1}`).join(", ");
|
|
498
|
+
return { sql: `${colName(column)} IN (${placeholders})`, params };
|
|
436
499
|
};
|
|
437
500
|
var notInArray = (column, values) => {
|
|
438
|
-
if (values
|
|
501
|
+
if (typeof values === "object" && values !== null && "toSQL" in values) {
|
|
502
|
+
return sql`${rawSql(colName(column))} NOT IN (${values.toSQL()})`;
|
|
503
|
+
}
|
|
504
|
+
const arr = values;
|
|
505
|
+
if (arr.length === 0)
|
|
439
506
|
return rawSql("TRUE");
|
|
440
|
-
const params =
|
|
441
|
-
const placeholders =
|
|
442
|
-
return { sql: `${colName(column)}
|
|
507
|
+
const params = arr;
|
|
508
|
+
const placeholders = arr.map((_, i) => `$${i + 1}`).join(", ");
|
|
509
|
+
return { sql: `${colName(column)} NOT IN (${placeholders})`, params };
|
|
443
510
|
};
|
|
444
511
|
var between = (column, min, max) => sql`${rawSql(colName(column))} BETWEEN ${min} AND ${max}`;
|
|
445
512
|
var and = (...conditions) => sqlJoin(conditions, " AND ");
|
|
@@ -453,29 +520,29 @@ var not = (condition) => ({
|
|
|
453
520
|
});
|
|
454
521
|
var asc = (column) => sql`${rawSql(colName(column))} ASC`;
|
|
455
522
|
var desc = (column) => sql`${rawSql(colName(column))} DESC`;
|
|
456
|
-
function parseWhereObject(tableConfig, whereObj) {
|
|
523
|
+
function parseWhereObject(tableConfig, whereObj, alias2) {
|
|
457
524
|
const conditions = [];
|
|
458
525
|
for (const [key, val] of Object.entries(whereObj)) {
|
|
459
526
|
if (val === undefined)
|
|
460
527
|
continue;
|
|
461
528
|
if (key === "OR") {
|
|
462
|
-
const orConditions = val.map((o) => parseWhereObject(tableConfig, o));
|
|
529
|
+
const orConditions = val.map((o) => parseWhereObject(tableConfig, o, alias2));
|
|
463
530
|
if (orConditions.length > 0)
|
|
464
531
|
conditions.push(or(...orConditions));
|
|
465
532
|
continue;
|
|
466
533
|
}
|
|
467
534
|
if (key === "AND") {
|
|
468
|
-
const andConditions = val.map((o) => parseWhereObject(tableConfig, o));
|
|
535
|
+
const andConditions = val.map((o) => parseWhereObject(tableConfig, o, alias2));
|
|
469
536
|
if (andConditions.length > 0)
|
|
470
537
|
conditions.push(and(...andConditions));
|
|
471
538
|
continue;
|
|
472
539
|
}
|
|
473
540
|
if (key === "NOT") {
|
|
474
|
-
conditions.push(not(parseWhereObject(tableConfig, val)));
|
|
541
|
+
conditions.push(not(parseWhereObject(tableConfig, val, alias2)));
|
|
475
542
|
continue;
|
|
476
543
|
}
|
|
477
544
|
const colConfig = tableConfig.columns[key];
|
|
478
|
-
const columnArg = colConfig
|
|
545
|
+
const columnArg = colConfig ? alias2 ? { ...colConfig, tableName: alias2 } : colConfig : alias2 ? { name: key, tableName: alias2 } : key;
|
|
479
546
|
if (val !== null && typeof val === "object" && !Array.isArray(val) && !(val instanceof Date) && !(val instanceof Uint8Array)) {
|
|
480
547
|
const opVal = val;
|
|
481
548
|
if (opVal.eq !== undefined)
|
|
@@ -517,13 +584,13 @@ function parseWhereObject(tableConfig, whereObj) {
|
|
|
517
584
|
}
|
|
518
585
|
return and(...conditions);
|
|
519
586
|
}
|
|
520
|
-
function parseOrderByObject(tableConfig, orderByObj) {
|
|
587
|
+
function parseOrderByObject(tableConfig, orderByObj, alias2) {
|
|
521
588
|
const parts = [];
|
|
522
589
|
for (const [key, dir] of Object.entries(orderByObj)) {
|
|
523
590
|
if (dir === undefined)
|
|
524
591
|
continue;
|
|
525
592
|
const colConfig = tableConfig.columns[key];
|
|
526
|
-
const columnArg = colConfig
|
|
593
|
+
const columnArg = colConfig ? alias2 ? { ...colConfig, tableName: alias2 } : colConfig : alias2 ? { name: key, tableName: alias2 } : key;
|
|
527
594
|
if (dir === "asc")
|
|
528
595
|
parts.push(asc(columnArg));
|
|
529
596
|
else if (dir === "desc")
|
|
@@ -538,8 +605,8 @@ class DeleteBuilder {
|
|
|
538
605
|
_returning;
|
|
539
606
|
_comment;
|
|
540
607
|
_with = [];
|
|
541
|
-
constructor(
|
|
542
|
-
this._table =
|
|
608
|
+
constructor(table, executor) {
|
|
609
|
+
this._table = table;
|
|
543
610
|
this._executor = executor;
|
|
544
611
|
}
|
|
545
612
|
then(onfulfilled, onrejected) {
|
|
@@ -607,8 +674,8 @@ class InsertBuilder {
|
|
|
607
674
|
_returning;
|
|
608
675
|
_comment;
|
|
609
676
|
_with = [];
|
|
610
|
-
constructor(
|
|
611
|
-
this._table =
|
|
677
|
+
constructor(table, executor) {
|
|
678
|
+
this._table = table;
|
|
612
679
|
this._executor = executor;
|
|
613
680
|
}
|
|
614
681
|
then(onfulfilled, onrejected) {
|
|
@@ -691,14 +758,7 @@ class InsertBuilder {
|
|
|
691
758
|
if (colType === "json" || colType === "jsonb") {
|
|
692
759
|
params.push(val);
|
|
693
760
|
} else if (Array.isArray(val)) {
|
|
694
|
-
|
|
695
|
-
if (item === null || item === undefined)
|
|
696
|
-
return "NULL";
|
|
697
|
-
if (typeof item === "string")
|
|
698
|
-
return '"' + item.replace(/"/g, "\\\"") + '"';
|
|
699
|
-
return typeof item === "object" ? '"' + JSON.stringify(item).replace(/"/g, "\\\"") + '"' : String(item);
|
|
700
|
-
}).join(",") + "}";
|
|
701
|
-
params.push(pgArray);
|
|
761
|
+
params.push(toPgArray(val));
|
|
702
762
|
} else {
|
|
703
763
|
params.push(JSON.stringify(val));
|
|
704
764
|
}
|
|
@@ -749,14 +809,7 @@ class InsertBuilder {
|
|
|
749
809
|
if (colType === "json" || colType === "jsonb") {
|
|
750
810
|
params.push(value);
|
|
751
811
|
} else if (Array.isArray(value)) {
|
|
752
|
-
|
|
753
|
-
if (item === null || item === undefined)
|
|
754
|
-
return "NULL";
|
|
755
|
-
if (typeof item === "string")
|
|
756
|
-
return '"' + item.replace(/"/g, "\\\"") + '"';
|
|
757
|
-
return typeof item === "object" ? '"' + JSON.stringify(item).replace(/"/g, "\\\"") + '"' : String(item);
|
|
758
|
-
}).join(",") + "}";
|
|
759
|
-
params.push(pgArray);
|
|
812
|
+
params.push(toPgArray(value));
|
|
760
813
|
} else {
|
|
761
814
|
params.push(JSON.stringify(value));
|
|
762
815
|
}
|
|
@@ -789,22 +842,29 @@ class SelectBuilder {
|
|
|
789
842
|
_select;
|
|
790
843
|
_selection;
|
|
791
844
|
_joins = [];
|
|
845
|
+
_isNestedOutput = false;
|
|
792
846
|
_with = [];
|
|
793
847
|
_setOperations = [];
|
|
794
848
|
_comment;
|
|
795
|
-
constructor(
|
|
796
|
-
this._table =
|
|
849
|
+
constructor(table, executor, selection) {
|
|
850
|
+
this._table = table;
|
|
797
851
|
this._executor = executor;
|
|
798
852
|
this._selection = selection;
|
|
799
853
|
}
|
|
800
854
|
then(onfulfilled, onrejected) {
|
|
801
|
-
return this._executor.execute(this).then(
|
|
855
|
+
return this._executor.execute(this).then((rows) => {
|
|
856
|
+
if (this._isNestedOutput) {
|
|
857
|
+
rows = rows.map((r) => typeof r._nested_data === "string" ? JSON.parse(r._nested_data) : r._nested_data);
|
|
858
|
+
}
|
|
859
|
+
return onfulfilled ? onfulfilled(rows) : rows;
|
|
860
|
+
}, onrejected);
|
|
802
861
|
}
|
|
803
862
|
async single() {
|
|
804
863
|
if (this._limit === undefined) {
|
|
805
864
|
this.limit(1);
|
|
806
865
|
}
|
|
807
|
-
|
|
866
|
+
const rows = await this.then();
|
|
867
|
+
return rows[0] ?? null;
|
|
808
868
|
}
|
|
809
869
|
select(...columns) {
|
|
810
870
|
this._select = columns;
|
|
@@ -866,40 +926,82 @@ class SelectBuilder {
|
|
|
866
926
|
this._offset = n;
|
|
867
927
|
return this;
|
|
868
928
|
}
|
|
929
|
+
as(aliasName) {
|
|
930
|
+
const columns = {};
|
|
931
|
+
let fields = [];
|
|
932
|
+
if (this._selection) {
|
|
933
|
+
fields = Object.keys(this._selection);
|
|
934
|
+
} else if (this._select && this._select.length > 0) {
|
|
935
|
+
fields = this._select;
|
|
936
|
+
} else if (!(("alias" in this._table) && ("query" in this._table))) {
|
|
937
|
+
fields = Object.keys(getTableConfig(this._table).columns);
|
|
938
|
+
}
|
|
939
|
+
for (const f of fields) {
|
|
940
|
+
const key = typeof f === "string" ? f : f.name || f.alias;
|
|
941
|
+
const dataType = typeof f !== "string" && f.dataType ? f.dataType : "any";
|
|
942
|
+
if (key)
|
|
943
|
+
columns[key] = { name: key, tableName: aliasName, dataType };
|
|
944
|
+
}
|
|
945
|
+
const sqObj = { ...columns };
|
|
946
|
+
const TableConfigSymbol2 = Symbol.for("BungresTableConfig");
|
|
947
|
+
sqObj[TableConfigSymbol2] = {
|
|
948
|
+
name: aliasName,
|
|
949
|
+
qualifiedName: `"${aliasName}"`,
|
|
950
|
+
columns,
|
|
951
|
+
isSubquery: true,
|
|
952
|
+
builder: this
|
|
953
|
+
};
|
|
954
|
+
return sqObj;
|
|
955
|
+
}
|
|
869
956
|
join(rawClause) {
|
|
870
|
-
this._joins.push(rawClause);
|
|
957
|
+
this._joins.push({ chunk: rawSql(rawClause) });
|
|
871
958
|
return this;
|
|
872
959
|
}
|
|
873
|
-
|
|
874
|
-
|
|
960
|
+
_buildJoin(type, table, condition) {
|
|
961
|
+
const TableConfigSymbol2 = Symbol.for("BungresTableConfig");
|
|
962
|
+
const cfg = table[TableConfigSymbol2];
|
|
963
|
+
if (cfg && cfg.isSubquery) {
|
|
964
|
+
const sqChunk = cfg.builder.toSQL();
|
|
965
|
+
return {
|
|
966
|
+
table,
|
|
967
|
+
chunk: sql`${rawSql(type)} JOIN (${sqChunk}) AS "${rawSql(cfg.name)}" ON ${condition}`
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
return {
|
|
971
|
+
table,
|
|
972
|
+
chunk: sql`${rawSql(type)} JOIN ${rawSql(cfg.qualifiedName)} ON ${condition}`
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
innerJoin(table, condition) {
|
|
976
|
+
this._joins.push(this._buildJoin("INNER", table, condition));
|
|
875
977
|
return this;
|
|
876
978
|
}
|
|
877
|
-
leftJoin(
|
|
878
|
-
this._joins.push(
|
|
979
|
+
leftJoin(table, condition) {
|
|
980
|
+
this._joins.push(this._buildJoin("LEFT", table, condition));
|
|
879
981
|
return this;
|
|
880
982
|
}
|
|
881
|
-
rightJoin(
|
|
882
|
-
this._joins.push(
|
|
983
|
+
rightJoin(table, condition) {
|
|
984
|
+
this._joins.push(this._buildJoin("RIGHT", table, condition));
|
|
883
985
|
return this;
|
|
884
986
|
}
|
|
885
|
-
fullJoin(
|
|
886
|
-
this._joins.push(
|
|
987
|
+
fullJoin(table, condition) {
|
|
988
|
+
this._joins.push(this._buildJoin("FULL", table, condition));
|
|
887
989
|
return this;
|
|
888
990
|
}
|
|
889
991
|
_buildSelection(selection, params) {
|
|
890
992
|
const parts = [];
|
|
891
|
-
for (const [
|
|
993
|
+
for (const [alias2, col2] of Object.entries(selection)) {
|
|
892
994
|
if (typeof col2 === "object" && col2 !== null) {
|
|
893
995
|
if ("sql" in col2 && "params" in col2) {
|
|
894
996
|
const chunk = col2;
|
|
895
997
|
const offset = params.length;
|
|
896
998
|
params.push(...chunk.params);
|
|
897
|
-
parts.push(`'${
|
|
999
|
+
parts.push(`'${alias2}', ${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)}`);
|
|
898
1000
|
} else if ("name" in col2 && "dataType" in col2) {
|
|
899
1001
|
const c = col2;
|
|
900
|
-
parts.push(`'${
|
|
1002
|
+
parts.push(`'${alias2}', ${c.tableName ? c.tableName + "." : ""}"${c.name}"`);
|
|
901
1003
|
} else {
|
|
902
|
-
parts.push(`'${
|
|
1004
|
+
parts.push(`'${alias2}', json_build_object(${this._buildSelection(col2, params)})`);
|
|
903
1005
|
}
|
|
904
1006
|
}
|
|
905
1007
|
}
|
|
@@ -908,35 +1010,59 @@ class SelectBuilder {
|
|
|
908
1010
|
toSQL() {
|
|
909
1011
|
let cols = "";
|
|
910
1012
|
const params = [];
|
|
1013
|
+
const isCte = "alias" in this._table && "query" in this._table;
|
|
1014
|
+
const qName = isCte ? `"${this._table.alias}"` : getTableConfig(this._table).qualifiedName;
|
|
911
1015
|
if (this._selection) {
|
|
912
|
-
cols = Object.entries(this._selection).map(([
|
|
1016
|
+
cols = Object.entries(this._selection).map(([alias2, col2]) => {
|
|
913
1017
|
if (typeof col2 === "object" && col2 !== null && "sql" in col2 && "params" in col2) {
|
|
914
1018
|
const chunk = col2;
|
|
915
1019
|
const offset = params.length;
|
|
916
1020
|
params.push(...chunk.params);
|
|
917
|
-
return `${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)} AS "${
|
|
1021
|
+
return `${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)} AS "${alias2}"`;
|
|
918
1022
|
} else if (typeof col2 === "object" && col2 !== null && "name" in col2 && "dataType" in col2) {
|
|
919
1023
|
const c = col2;
|
|
920
|
-
return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${
|
|
1024
|
+
return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${alias2}"`;
|
|
921
1025
|
} else {
|
|
922
|
-
return `json_build_object(${this._buildSelection(col2, params)}) AS "${
|
|
1026
|
+
return `json_build_object(${this._buildSelection(col2, params)}) AS "${alias2}"`;
|
|
923
1027
|
}
|
|
924
1028
|
}).join(", ");
|
|
925
1029
|
} else if (this._select && this._select.length > 0) {
|
|
926
|
-
const qName = getTableConfig(this._table).qualifiedName;
|
|
927
1030
|
cols = this._select.map((c) => {
|
|
928
1031
|
if (typeof c === "string") {
|
|
929
|
-
|
|
1032
|
+
const colName2 = isCte ? c : getTableConfig(this._table).columns[c]?.name ?? c;
|
|
1033
|
+
return `${qName}."${colName2}" AS "${c}"`;
|
|
930
1034
|
}
|
|
931
1035
|
return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${c.alias || c.name}"`;
|
|
932
1036
|
}).join(", ");
|
|
933
1037
|
} else {
|
|
934
|
-
|
|
935
|
-
const colsKeys = Object.keys(getTableConfig(this._table).columns);
|
|
936
|
-
if (colsKeys.length === 0) {
|
|
1038
|
+
if (isCte) {
|
|
937
1039
|
cols = "*";
|
|
938
1040
|
} else {
|
|
939
|
-
|
|
1041
|
+
const hasJoinedTables = this._joins.some((j) => j.table);
|
|
1042
|
+
if (hasJoinedTables) {
|
|
1043
|
+
this._isNestedOutput = true;
|
|
1044
|
+
const rootCfg = getTableConfig(this._table);
|
|
1045
|
+
const tablesToSelect = [{ alias: rootCfg.name, config: rootCfg }];
|
|
1046
|
+
for (const join2 of this._joins) {
|
|
1047
|
+
if (join2.table) {
|
|
1048
|
+
const cfg = getTableConfig(join2.table);
|
|
1049
|
+
tablesToSelect.push({ alias: cfg.name, config: cfg });
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
cols = `json_build_object(${tablesToSelect.map((t) => {
|
|
1053
|
+
const innerFields = Object.keys(t.config.columns).map((c) => {
|
|
1054
|
+
return `'${c}', "${t.config.name}"."${t.config.columns[c].name}"`;
|
|
1055
|
+
}).join(", ");
|
|
1056
|
+
return `'${t.alias}', json_build_object(${innerFields})`;
|
|
1057
|
+
}).join(", ")}) AS _nested_data`;
|
|
1058
|
+
} else {
|
|
1059
|
+
const colsKeys = Object.keys(getTableConfig(this._table).columns);
|
|
1060
|
+
if (colsKeys.length === 0) {
|
|
1061
|
+
cols = "*";
|
|
1062
|
+
} else {
|
|
1063
|
+
cols = colsKeys.map((c) => `${qName}."${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ");
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
940
1066
|
}
|
|
941
1067
|
}
|
|
942
1068
|
let prefix = "";
|
|
@@ -950,9 +1076,9 @@ class SelectBuilder {
|
|
|
950
1076
|
}
|
|
951
1077
|
prefix = `WITH ${cteStrs.join(", ")} `;
|
|
952
1078
|
}
|
|
953
|
-
let query = `SELECT ${cols} FROM ${
|
|
1079
|
+
let query = `SELECT ${cols} FROM ${qName}`;
|
|
954
1080
|
if (this._joins.length > 0) {
|
|
955
|
-
const joinChunks = this._joins.map((j) =>
|
|
1081
|
+
const joinChunks = this._joins.map((j) => j.chunk);
|
|
956
1082
|
const combinedJoins = sqlJoin(joinChunks, " ");
|
|
957
1083
|
const offset = params.length;
|
|
958
1084
|
query += " " + combinedJoins.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
@@ -965,11 +1091,11 @@ class SelectBuilder {
|
|
|
965
1091
|
params.push(...combined.params);
|
|
966
1092
|
}
|
|
967
1093
|
if (this._groupBy.length > 0) {
|
|
968
|
-
const
|
|
1094
|
+
const qName2 = getTableConfig(this._table).qualifiedName;
|
|
969
1095
|
query += " GROUP BY " + this._groupBy.map((c) => {
|
|
970
1096
|
if (typeof c === "string") {
|
|
971
|
-
const dbCol = getTableConfig(this._table).columns[c]?.name ?? c;
|
|
972
|
-
return `${
|
|
1097
|
+
const dbCol = isCte ? c : getTableConfig(this._table).columns[c]?.name ?? c;
|
|
1098
|
+
return `${qName2}."${dbCol}"`;
|
|
973
1099
|
} else if ("sql" in c && "params" in c) {
|
|
974
1100
|
const offset = params.length;
|
|
975
1101
|
params.push(...c.params);
|
|
@@ -986,11 +1112,11 @@ class SelectBuilder {
|
|
|
986
1112
|
params.push(...combined.params);
|
|
987
1113
|
}
|
|
988
1114
|
if (this._orderBy.length > 0) {
|
|
989
|
-
const
|
|
1115
|
+
const qName2 = getTableConfig(this._table).qualifiedName;
|
|
990
1116
|
query += " ORDER BY " + this._orderBy.map((o) => {
|
|
991
1117
|
if (typeof o.column === "string") {
|
|
992
|
-
const dbCol = getTableConfig(this._table).columns[o.column]?.name ?? o.column;
|
|
993
|
-
return `${
|
|
1118
|
+
const dbCol = isCte ? o.column : getTableConfig(this._table).columns[o.column]?.name ?? o.column;
|
|
1119
|
+
return `${qName2}."${dbCol}" ${o.dir.toUpperCase()}`;
|
|
994
1120
|
} else if ("sql" in o.column && "params" in o.column) {
|
|
995
1121
|
const offset = params.length;
|
|
996
1122
|
params.push(...o.column.params);
|
|
@@ -1030,8 +1156,8 @@ class SelectBuilderIntermediate {
|
|
|
1030
1156
|
this._executor = _executor;
|
|
1031
1157
|
this._selection = _selection;
|
|
1032
1158
|
}
|
|
1033
|
-
from(
|
|
1034
|
-
return new SelectBuilder(
|
|
1159
|
+
from(table) {
|
|
1160
|
+
return new SelectBuilder(table, this._executor, this._selection);
|
|
1035
1161
|
}
|
|
1036
1162
|
}
|
|
1037
1163
|
|
|
@@ -1043,8 +1169,8 @@ class UpdateBuilder {
|
|
|
1043
1169
|
_returning;
|
|
1044
1170
|
_comment;
|
|
1045
1171
|
_with = [];
|
|
1046
|
-
constructor(
|
|
1047
|
-
this._table =
|
|
1172
|
+
constructor(table, executor) {
|
|
1173
|
+
this._table = table;
|
|
1048
1174
|
this._executor = executor;
|
|
1049
1175
|
}
|
|
1050
1176
|
then(onfulfilled, onrejected) {
|
|
@@ -1107,14 +1233,7 @@ class UpdateBuilder {
|
|
|
1107
1233
|
if (colType === "json" || colType === "jsonb") {
|
|
1108
1234
|
params.push(value);
|
|
1109
1235
|
} else if (Array.isArray(value)) {
|
|
1110
|
-
|
|
1111
|
-
if (item === null || item === undefined)
|
|
1112
|
-
return "NULL";
|
|
1113
|
-
if (typeof item === "string")
|
|
1114
|
-
return '"' + item.replace(/"/g, "\\\"") + '"';
|
|
1115
|
-
return typeof item === "object" ? '"' + JSON.stringify(item).replace(/"/g, "\\\"") + '"' : String(item);
|
|
1116
|
-
}).join(",") + "}";
|
|
1117
|
-
params.push(pgArray);
|
|
1236
|
+
params.push(toPgArray(value));
|
|
1118
1237
|
} else {
|
|
1119
1238
|
params.push(JSON.stringify(value));
|
|
1120
1239
|
}
|
|
@@ -1226,8 +1345,8 @@ class RelationalQueryBuilder {
|
|
|
1226
1345
|
let cached = schemaCache.get(tableName);
|
|
1227
1346
|
if (cached)
|
|
1228
1347
|
return cached;
|
|
1229
|
-
const
|
|
1230
|
-
const tConfig =
|
|
1348
|
+
const table = this._schema[tableName];
|
|
1349
|
+
const tConfig = table[TableConfigSymbol];
|
|
1231
1350
|
const ones = {};
|
|
1232
1351
|
const manys = {};
|
|
1233
1352
|
const manyToManys = {};
|
|
@@ -1240,6 +1359,8 @@ class RelationalQueryBuilder {
|
|
|
1240
1359
|
}
|
|
1241
1360
|
for (const [otherName, otherTable] of Object.entries(this._schema)) {
|
|
1242
1361
|
const otherConfig = otherTable[TableConfigSymbol];
|
|
1362
|
+
if (!otherConfig)
|
|
1363
|
+
continue;
|
|
1243
1364
|
for (const [colName2, col2] of Object.entries(otherConfig.columns)) {
|
|
1244
1365
|
if (col2.references && col2.references.table === tableName) {
|
|
1245
1366
|
const ref = col2.references;
|
|
@@ -1250,6 +1371,8 @@ class RelationalQueryBuilder {
|
|
|
1250
1371
|
}
|
|
1251
1372
|
for (const [junctionName, junctionTable] of Object.entries(this._schema)) {
|
|
1252
1373
|
const junctionConfig = junctionTable[TableConfigSymbol];
|
|
1374
|
+
if (!junctionConfig)
|
|
1375
|
+
continue;
|
|
1253
1376
|
const refs = Object.entries(junctionConfig.columns).filter(([_, c]) => c.references);
|
|
1254
1377
|
const toThis = refs.find(([_, c]) => c.references.table === tableName);
|
|
1255
1378
|
if (toThis) {
|
|
@@ -1272,7 +1395,7 @@ class RelationalQueryBuilder {
|
|
|
1272
1395
|
schemaCache.set(tableName, result);
|
|
1273
1396
|
return result;
|
|
1274
1397
|
}
|
|
1275
|
-
_buildSelectJson(tableName, args,
|
|
1398
|
+
_buildSelectJson(tableName, args, alias2, params, parentAlias, joinCondition, extraJoin) {
|
|
1276
1399
|
const tableConfig = this._schema[tableName][TableConfigSymbol];
|
|
1277
1400
|
const relations = this._getRuntimeRelations(tableName);
|
|
1278
1401
|
const withArgs = args.with || {};
|
|
@@ -1290,26 +1413,26 @@ class RelationalQueryBuilder {
|
|
|
1290
1413
|
continue;
|
|
1291
1414
|
}
|
|
1292
1415
|
}
|
|
1293
|
-
jsonFields.push(`'${colKey}', "${
|
|
1416
|
+
jsonFields.push(`'${colKey}', "${alias2}"."${colConfig.name}"`);
|
|
1294
1417
|
}
|
|
1295
1418
|
for (const [relKey, relArgs] of Object.entries(withArgs)) {
|
|
1296
1419
|
const isTrue = relArgs === true;
|
|
1297
1420
|
const rArgs = isTrue ? {} : relArgs;
|
|
1298
1421
|
if (relations.ones[relKey]) {
|
|
1299
1422
|
const rel = relations.ones[relKey];
|
|
1300
|
-
const subAlias = `${
|
|
1423
|
+
const subAlias = `${alias2}_${relKey}`;
|
|
1301
1424
|
const targetConfig = this._schema[rel.targetTable][TableConfigSymbol];
|
|
1302
1425
|
const targetPk = getPkColumn(targetConfig);
|
|
1303
|
-
const joinCond = `"${subAlias}"."${targetPk}" = "${
|
|
1304
|
-
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params,
|
|
1426
|
+
const joinCond = `"${subAlias}"."${targetPk}" = "${alias2}"."${rel.sourceColumn}"`;
|
|
1427
|
+
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias2, joinCond);
|
|
1305
1428
|
const subSql = `SELECT ${subQuery.sql} ${subQuery.from}`;
|
|
1306
1429
|
jsonFields.push(`'${relKey}', (${subSql})`);
|
|
1307
1430
|
} else if (relations.manys[relKey]) {
|
|
1308
1431
|
const rel = relations.manys[relKey];
|
|
1309
|
-
const subAlias = `${
|
|
1432
|
+
const subAlias = `${alias2}_${relKey}`;
|
|
1310
1433
|
const thisPk = getPkColumn(tableConfig);
|
|
1311
|
-
const joinCond = `"${subAlias}"."${rel.targetColumn}" = "${
|
|
1312
|
-
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params,
|
|
1434
|
+
const joinCond = `"${subAlias}"."${rel.targetColumn}" = "${alias2}"."${thisPk}"`;
|
|
1435
|
+
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias2, joinCond);
|
|
1313
1436
|
const aggAlias = `${subAlias}_agg`;
|
|
1314
1437
|
const aggSql = `
|
|
1315
1438
|
SELECT COALESCE(json_agg(_sub.obj), '[]'::json)
|
|
@@ -1321,16 +1444,16 @@ class RelationalQueryBuilder {
|
|
|
1321
1444
|
jsonFields.push(`'${relKey}', (${aggSql})`);
|
|
1322
1445
|
} else if (relations.manyToManys[relKey]) {
|
|
1323
1446
|
const rel = relations.manyToManys[relKey];
|
|
1324
|
-
const subAlias = `${
|
|
1325
|
-
const junctionAlias = `${
|
|
1447
|
+
const subAlias = `${alias2}_${relKey}`;
|
|
1448
|
+
const junctionAlias = `${alias2}_j_${relKey}`;
|
|
1326
1449
|
const targetTableConfig = this._schema[rel.targetTable][TableConfigSymbol];
|
|
1327
1450
|
const junctionTableConfig = this._schema[rel.junctionTable][TableConfigSymbol];
|
|
1328
1451
|
const fromExtra = `
|
|
1329
1452
|
INNER JOIN ${junctionTableConfig.qualifiedName} AS "${junctionAlias}"
|
|
1330
1453
|
ON "${junctionAlias}"."${rel.joinTargetColumn}" = "${subAlias}"."${getPkColumn(targetTableConfig)}"
|
|
1331
1454
|
`;
|
|
1332
|
-
const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${
|
|
1333
|
-
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params,
|
|
1455
|
+
const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${alias2}"."${getPkColumn(tableConfig)}"`;
|
|
1456
|
+
const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias2, whereExtra, fromExtra);
|
|
1334
1457
|
const aggSql = `
|
|
1335
1458
|
SELECT COALESCE(json_agg(_sub.obj), '[]'::json)
|
|
1336
1459
|
FROM (
|
|
@@ -1342,7 +1465,7 @@ class RelationalQueryBuilder {
|
|
|
1342
1465
|
}
|
|
1343
1466
|
}
|
|
1344
1467
|
let selectSql = `json_build_object(${jsonFields.join(", ")})`;
|
|
1345
|
-
let fromSql = `FROM ${tableConfig.qualifiedName} AS "${
|
|
1468
|
+
let fromSql = `FROM ${tableConfig.qualifiedName} AS "${alias2}"`;
|
|
1346
1469
|
if (extraJoin) {
|
|
1347
1470
|
fromSql += ` ${extraJoin}`;
|
|
1348
1471
|
}
|
|
@@ -1353,7 +1476,7 @@ class RelationalQueryBuilder {
|
|
|
1353
1476
|
const offset = params.length;
|
|
1354
1477
|
let whereChunk = args.where;
|
|
1355
1478
|
if (args.where && !args.where.sql) {
|
|
1356
|
-
whereChunk = parseWhereObject(tableConfig, args.where);
|
|
1479
|
+
whereChunk = parseWhereObject(tableConfig, args.where, alias2);
|
|
1357
1480
|
}
|
|
1358
1481
|
if (whereChunk && whereChunk.sql) {
|
|
1359
1482
|
fromSql += (joinCondition ? " AND " : " WHERE ") + whereChunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
@@ -1368,7 +1491,7 @@ class RelationalQueryBuilder {
|
|
|
1368
1491
|
fromSql += ` ORDER BY ` + args.orderBy.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
|
|
1369
1492
|
params.push(...args.orderBy.params);
|
|
1370
1493
|
} else {
|
|
1371
|
-
const chunks = parseOrderByObject(tableConfig, args.orderBy);
|
|
1494
|
+
const chunks = parseOrderByObject(tableConfig, args.orderBy, alias2);
|
|
1372
1495
|
if (chunks.length > 0) {
|
|
1373
1496
|
fromSql += ` ORDER BY ` + chunks.map((c) => {
|
|
1374
1497
|
const offset = params.length;
|
|
@@ -1390,7 +1513,7 @@ class RelationalQueryBuilder {
|
|
|
1390
1513
|
}
|
|
1391
1514
|
buildSQL(args) {
|
|
1392
1515
|
const params = [];
|
|
1393
|
-
const rootAlias =
|
|
1516
|
+
const rootAlias = this._tableName;
|
|
1394
1517
|
const subQuery = this._buildSelectJson(this._tableName, args, rootAlias, params);
|
|
1395
1518
|
const sql2 = `SELECT ${subQuery.sql} AS _data ${subQuery.from}`;
|
|
1396
1519
|
return { sql: sql2, params };
|
|
@@ -1466,14 +1589,14 @@ class BungresDB {
|
|
|
1466
1589
|
}
|
|
1467
1590
|
return new SelectBuilderIntermediate(this);
|
|
1468
1591
|
}
|
|
1469
|
-
insert(
|
|
1470
|
-
return new InsertBuilder(
|
|
1592
|
+
insert(table) {
|
|
1593
|
+
return new InsertBuilder(table, this);
|
|
1471
1594
|
}
|
|
1472
|
-
update(
|
|
1473
|
-
return new UpdateBuilder(
|
|
1595
|
+
update(table) {
|
|
1596
|
+
return new UpdateBuilder(table, this);
|
|
1474
1597
|
}
|
|
1475
|
-
delete(
|
|
1476
|
-
return new DeleteBuilder(
|
|
1598
|
+
delete(table) {
|
|
1599
|
+
return new DeleteBuilder(table, this);
|
|
1477
1600
|
}
|
|
1478
1601
|
async execute(builder) {
|
|
1479
1602
|
await this.ready();
|
|
@@ -1517,14 +1640,14 @@ class BungresTransaction {
|
|
|
1517
1640
|
}
|
|
1518
1641
|
return new SelectBuilderIntermediate(this);
|
|
1519
1642
|
}
|
|
1520
|
-
insert(
|
|
1521
|
-
return new InsertBuilder(
|
|
1643
|
+
insert(table) {
|
|
1644
|
+
return new InsertBuilder(table, this);
|
|
1522
1645
|
}
|
|
1523
|
-
update(
|
|
1524
|
-
return new UpdateBuilder(
|
|
1646
|
+
update(table) {
|
|
1647
|
+
return new UpdateBuilder(table, this);
|
|
1525
1648
|
}
|
|
1526
|
-
delete(
|
|
1527
|
-
return new DeleteBuilder(
|
|
1649
|
+
delete(table) {
|
|
1650
|
+
return new DeleteBuilder(table, this);
|
|
1528
1651
|
}
|
|
1529
1652
|
async execute(builder) {
|
|
1530
1653
|
const chunk = "toSQL" in builder ? builder.toSQL() : builder;
|
|
@@ -1683,15 +1806,30 @@ function formatDefaultValue(value, dataType) {
|
|
|
1683
1806
|
return value ? "TRUE" : "FALSE";
|
|
1684
1807
|
if (typeof value === "number")
|
|
1685
1808
|
return String(value);
|
|
1809
|
+
if (value instanceof Date)
|
|
1810
|
+
return `'${value.toISOString()}'`;
|
|
1811
|
+
if (Array.isArray(value)) {
|
|
1812
|
+
if (dataType === "json" || dataType === "jsonb") {
|
|
1813
|
+
return `'${JSON.stringify(value).replace(/'/g, "''")}'`;
|
|
1814
|
+
}
|
|
1815
|
+
const pgArray = "{" + value.map((item) => {
|
|
1816
|
+
if (item === null || item === undefined)
|
|
1817
|
+
return "NULL";
|
|
1818
|
+
if (typeof item === "string")
|
|
1819
|
+
return '"' + item.replace(/"/g, "\\\"") + '"';
|
|
1820
|
+
return typeof item === "object" ? '"' + JSON.stringify(item).replace(/"/g, "\\\"").replace(/'/g, "''") + '"' : String(item);
|
|
1821
|
+
}).join(",") + "}";
|
|
1822
|
+
return `'${pgArray.replace(/'/g, "''")}'`;
|
|
1823
|
+
}
|
|
1686
1824
|
return `'${JSON.stringify(value).replace(/'/g, "''")}'`;
|
|
1687
1825
|
}
|
|
1688
|
-
function buildIndex(
|
|
1689
|
-
const tableName =
|
|
1826
|
+
function buildIndex(table, idx) {
|
|
1827
|
+
const tableName = table.schema ? `"${table.schema}"."${table.name}"` : `"${table.name}"`;
|
|
1690
1828
|
const unique2 = idx.unique ? "UNIQUE " : "";
|
|
1691
1829
|
const using = idx.using ? ` USING ${idx.using.toUpperCase()}` : "";
|
|
1692
1830
|
const cols = idx.columns.map((c) => `"${c}"`).join(", ");
|
|
1693
1831
|
const where = idx.where ? ` WHERE ${idx.where}` : "";
|
|
1694
|
-
const idxName = idx.name ?? `idx_${
|
|
1832
|
+
const idxName = idx.name ?? `idx_${table.name}_${idx.columns.join("_")}`;
|
|
1695
1833
|
return `CREATE ${unique2}INDEX IF NOT EXISTS "${idxName}" ON ${tableName}${using} (${cols})${where};`;
|
|
1696
1834
|
}
|
|
1697
1835
|
function generateAddColumn(tableName, schema, key, col2) {
|
|
@@ -1726,7 +1864,14 @@ function inlineParams(chunk) {
|
|
|
1726
1864
|
}
|
|
1727
1865
|
function generateCreateView(view) {
|
|
1728
1866
|
const kind = view.materialized ? "MATERIALIZED VIEW" : "VIEW";
|
|
1729
|
-
|
|
1867
|
+
let inlineSql = "";
|
|
1868
|
+
if (view.sql) {
|
|
1869
|
+
inlineSql = view.sql;
|
|
1870
|
+
} else if (view.query && typeof view.query.toSQL === "function") {
|
|
1871
|
+
inlineSql = inlineParams(view.query.toSQL());
|
|
1872
|
+
} else {
|
|
1873
|
+
inlineSql = "SELECT * FROM (VALUES ('LEGACY_SNAPSHOT_MISSING_SQL')) AS t(c)";
|
|
1874
|
+
}
|
|
1730
1875
|
return `CREATE ${kind} "${view.name}" AS ${inlineSql};`;
|
|
1731
1876
|
}
|
|
1732
1877
|
function generateDropView(view, ifExists = true) {
|
|
@@ -1961,8 +2106,8 @@ function topoSortConfigs(tables) {
|
|
|
1961
2106
|
visit(dep);
|
|
1962
2107
|
result.push(config);
|
|
1963
2108
|
}
|
|
1964
|
-
for (const
|
|
1965
|
-
visit(
|
|
2109
|
+
for (const table of tables)
|
|
2110
|
+
visit(table.name);
|
|
1966
2111
|
return result;
|
|
1967
2112
|
}
|
|
1968
2113
|
function diffColumn(prev, next) {
|
|
@@ -3120,6 +3265,30 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
|
|
|
3120
3265
|
});
|
|
3121
3266
|
}
|
|
3122
3267
|
}
|
|
3268
|
+
class n extends V {
|
|
3269
|
+
get userInputWithCursor() {
|
|
3270
|
+
if (this.state === "submit")
|
|
3271
|
+
return this.userInput;
|
|
3272
|
+
const t2 = this.userInput;
|
|
3273
|
+
if (this.cursor >= t2.length)
|
|
3274
|
+
return `${this.userInput}\u2588`;
|
|
3275
|
+
const r2 = t2.slice(0, this.cursor), s = t2.slice(this.cursor, this.cursor + 1), e = t2.slice(this.cursor + 1);
|
|
3276
|
+
return `${r2}${styleText("inverse", s)}${e}`;
|
|
3277
|
+
}
|
|
3278
|
+
get cursor() {
|
|
3279
|
+
return this._cursor;
|
|
3280
|
+
}
|
|
3281
|
+
constructor(t2) {
|
|
3282
|
+
super({
|
|
3283
|
+
...t2,
|
|
3284
|
+
initialUserInput: t2.initialUserInput ?? t2.initialValue
|
|
3285
|
+
}), this.on("userInput", (r2) => {
|
|
3286
|
+
this._setValue(r2);
|
|
3287
|
+
}), this.on("finalize", () => {
|
|
3288
|
+
this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
|
|
3289
|
+
});
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3123
3292
|
|
|
3124
3293
|
// ../../node_modules/.bun/@clack+prompts@1.7.0/node_modules/@clack/prompts/dist/index.mjs
|
|
3125
3294
|
import { styleText as styleText2, stripVTControlCharacters } from "util";
|
|
@@ -3380,24 +3549,62 @@ var SELECT_INSTRUCTIONS = [
|
|
|
3380
3549
|
`${styleText2("dim", "Enter:")} confirm`
|
|
3381
3550
|
];
|
|
3382
3551
|
var i = `${styleText2("gray", S_BAR)} `;
|
|
3552
|
+
var text = (e) => new n({
|
|
3553
|
+
validate: e.validate,
|
|
3554
|
+
placeholder: e.placeholder,
|
|
3555
|
+
defaultValue: e.defaultValue,
|
|
3556
|
+
initialValue: e.initialValue,
|
|
3557
|
+
output: e.output,
|
|
3558
|
+
signal: e.signal,
|
|
3559
|
+
input: e.input,
|
|
3560
|
+
render() {
|
|
3561
|
+
const i2 = e?.withGuide ?? settings.withGuide, s = `${`${i2 ? `${styleText2("gray", S_BAR)}
|
|
3562
|
+
` : ""}${symbol(this.state)} `}${e.message}
|
|
3563
|
+
`, c2 = e.placeholder && e.placeholder.length > 0 ? styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c2, l2 = this.value ?? "";
|
|
3564
|
+
switch (this.state) {
|
|
3565
|
+
case "error": {
|
|
3566
|
+
const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
|
|
3567
|
+
return `${s.trim()}
|
|
3568
|
+
${r2}${o2}
|
|
3569
|
+
${d}${n2}
|
|
3570
|
+
`;
|
|
3571
|
+
}
|
|
3572
|
+
case "submit": {
|
|
3573
|
+
const n2 = l2 ? ` ${styleText2("dim", l2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
|
|
3574
|
+
return `${s}${r2}${n2}`;
|
|
3575
|
+
}
|
|
3576
|
+
case "cancel": {
|
|
3577
|
+
const n2 = l2 ? ` ${styleText2(["strikethrough", "dim"], l2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
|
|
3578
|
+
return `${s}${r2}${n2}${l2.trim() ? `
|
|
3579
|
+
${r2}` : ""}`;
|
|
3580
|
+
}
|
|
3581
|
+
default: {
|
|
3582
|
+
const n2 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "";
|
|
3583
|
+
return `${s}${n2}${o2}
|
|
3584
|
+
${r2}
|
|
3585
|
+
`;
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
}).prompt();
|
|
3383
3590
|
|
|
3384
3591
|
// src/commands/push.ts
|
|
3385
3592
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
3386
3593
|
async function runPush(config, opts = {}) {
|
|
3387
3594
|
intro(import_picocolors.default.bgCyan(import_picocolors.default.black(" @bungres/kit push ")));
|
|
3388
|
-
|
|
3389
|
-
|
|
3595
|
+
let activeSpinner = spinner();
|
|
3596
|
+
activeSpinner.start("Loading schemas...");
|
|
3390
3597
|
const schemas = await loadSchemas(config.schema);
|
|
3391
3598
|
if (schemas.length === 0) {
|
|
3392
|
-
|
|
3599
|
+
activeSpinner.stop("No schemas found.");
|
|
3393
3600
|
log.warn(import_picocolors.default.yellow("No table definitions found. Check your schema glob pattern."));
|
|
3394
3601
|
outro("Failed.");
|
|
3395
3602
|
return;
|
|
3396
3603
|
}
|
|
3397
|
-
|
|
3604
|
+
activeSpinner.stop(`Loaded ${schemas.length} schemas.`);
|
|
3398
3605
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
3399
|
-
|
|
3400
|
-
|
|
3606
|
+
activeSpinner = spinner();
|
|
3607
|
+
activeSpinner.start("Computing diff from database...");
|
|
3401
3608
|
try {
|
|
3402
3609
|
await sql2.unsafe(`CREATE SCHEMA IF NOT EXISTS "${config.migrationsSchema}";`);
|
|
3403
3610
|
const qualifiedPush = `"${config.migrationsSchema}"."__bungres_push"`;
|
|
@@ -3422,23 +3629,27 @@ async function runPush(config, opts = {}) {
|
|
|
3422
3629
|
}
|
|
3423
3630
|
}
|
|
3424
3631
|
const currentSnapshot = { tables: {}, enums: {}, views: {} };
|
|
3425
|
-
for (const
|
|
3426
|
-
if (
|
|
3427
|
-
currentSnapshot.tables[
|
|
3428
|
-
} else if (
|
|
3429
|
-
currentSnapshot.enums[
|
|
3430
|
-
} else if (
|
|
3431
|
-
currentSnapshot.views[
|
|
3632
|
+
for (const s of schemas) {
|
|
3633
|
+
if (s.type === "table") {
|
|
3634
|
+
currentSnapshot.tables[s.config.name] = s.config;
|
|
3635
|
+
} else if (s.type === "enum") {
|
|
3636
|
+
currentSnapshot.enums[s.enumName] = { enumName: s.enumName, enumValues: s.enumValues };
|
|
3637
|
+
} else if (s.type === "view") {
|
|
3638
|
+
currentSnapshot.views[s.config.name] = {
|
|
3639
|
+
name: s.config.name,
|
|
3640
|
+
materialized: s.config.materialized,
|
|
3641
|
+
sql: typeof s.config.query?.toSQL === "function" ? inlineParams(s.config.query.toSQL()) : s.config.sql
|
|
3642
|
+
};
|
|
3432
3643
|
}
|
|
3433
3644
|
}
|
|
3434
3645
|
const diff = diffSchemas(prevSnapshot, currentSnapshot);
|
|
3435
3646
|
if (diff.statements.length === 0) {
|
|
3436
|
-
|
|
3647
|
+
activeSpinner.stop("Up to date.");
|
|
3437
3648
|
log.success(import_picocolors.default.green("No schema changes detected. Database is up to date."));
|
|
3438
3649
|
outro("Done.");
|
|
3439
3650
|
return;
|
|
3440
3651
|
}
|
|
3441
|
-
|
|
3652
|
+
activeSpinner.stop(`Computed ${diff.statements.length} statements.`);
|
|
3442
3653
|
log.message(import_picocolors.default.bold("Changes to apply:"));
|
|
3443
3654
|
for (const change of diff.summary) {
|
|
3444
3655
|
if (change.startsWith("CREATE") || change.startsWith("ALTER TABLE") && change.includes("ADD")) {
|
|
@@ -3465,8 +3676,8 @@ async function runPush(config, opts = {}) {
|
|
|
3465
3676
|
return;
|
|
3466
3677
|
}
|
|
3467
3678
|
}
|
|
3468
|
-
|
|
3469
|
-
|
|
3679
|
+
activeSpinner = spinner();
|
|
3680
|
+
activeSpinner.start("Pushing changes...");
|
|
3470
3681
|
for (const stmt of diff.statements) {
|
|
3471
3682
|
if (config.verbose) {
|
|
3472
3683
|
log.info(import_picocolors.default.gray(`-- ${stmt}`));
|
|
@@ -3474,9 +3685,10 @@ async function runPush(config, opts = {}) {
|
|
|
3474
3685
|
await sql2.unsafe(stmt);
|
|
3475
3686
|
}
|
|
3476
3687
|
await sql2.unsafe(`INSERT INTO ${qualifiedPush} (snapshot) VALUES ($1);`, [JSON.stringify(currentSnapshot)]);
|
|
3477
|
-
|
|
3688
|
+
activeSpinner.stop(import_picocolors.default.green("Changes applied successfully."));
|
|
3478
3689
|
outro(import_picocolors.default.cyan("\u2728 Push complete."));
|
|
3479
3690
|
} catch (err) {
|
|
3691
|
+
activeSpinner.stop("Failed.");
|
|
3480
3692
|
log.error(import_picocolors.default.red(`Push failed: ${err.message}`));
|
|
3481
3693
|
outro("Failed.");
|
|
3482
3694
|
} finally {
|
|
@@ -3485,7 +3697,7 @@ async function runPush(config, opts = {}) {
|
|
|
3485
3697
|
}
|
|
3486
3698
|
// src/commands/generate.ts
|
|
3487
3699
|
import { join as join3, resolve as resolve3 } from "path";
|
|
3488
|
-
import { readdirSync } from "fs";
|
|
3700
|
+
import { readdirSync, existsSync, statSync } from "fs";
|
|
3489
3701
|
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
3490
3702
|
async function runGenerate(config, name) {
|
|
3491
3703
|
intro(import_picocolors2.default.bgCyan(import_picocolors2.default.black(" @bungres/kit generate ")));
|
|
@@ -3500,6 +3712,12 @@ async function runGenerate(config, name) {
|
|
|
3500
3712
|
}
|
|
3501
3713
|
s.stop(`Loaded ${schemas.length} schemas.`);
|
|
3502
3714
|
const migrationsDir = resolve3(config.out);
|
|
3715
|
+
if (existsSync(migrationsDir) && !statSync(migrationsDir).isDirectory()) {
|
|
3716
|
+
s.stop("Failed.");
|
|
3717
|
+
log.error(import_picocolors2.default.red(`Migration path exists but is not a directory: ${migrationsDir}`));
|
|
3718
|
+
outro("Failed.");
|
|
3719
|
+
return;
|
|
3720
|
+
}
|
|
3503
3721
|
const metaDir = join3(migrationsDir, "meta");
|
|
3504
3722
|
await Bun.$`mkdir -p ${migrationsDir}`.quiet();
|
|
3505
3723
|
await Bun.$`mkdir -p ${metaDir}`.quiet();
|
|
@@ -3510,7 +3728,11 @@ async function runGenerate(config, name) {
|
|
|
3510
3728
|
} else if (s2.type === "enum") {
|
|
3511
3729
|
currentSnapshot.enums[s2.enumName] = { enumName: s2.enumName, enumValues: s2.enumValues };
|
|
3512
3730
|
} else if (s2.type === "view") {
|
|
3513
|
-
currentSnapshot.views[s2.config.name] =
|
|
3731
|
+
currentSnapshot.views[s2.config.name] = {
|
|
3732
|
+
name: s2.config.name,
|
|
3733
|
+
materialized: s2.config.materialized,
|
|
3734
|
+
sql: typeof s2.config.query?.toSQL === "function" ? inlineParams(s2.config.query.toSQL()) : s2.config.sql
|
|
3735
|
+
};
|
|
3514
3736
|
}
|
|
3515
3737
|
}
|
|
3516
3738
|
let prevSnapshot = { tables: {}, enums: {}, views: {} };
|
|
@@ -3670,14 +3892,30 @@ function topoSort(schemas) {
|
|
|
3670
3892
|
}
|
|
3671
3893
|
// src/commands/migrate.ts
|
|
3672
3894
|
import { join as join4, resolve as resolve4 } from "path";
|
|
3895
|
+
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
3673
3896
|
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
3674
3897
|
async function runMigrate(config) {
|
|
3675
3898
|
intro(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" @bungres/kit migrate ")));
|
|
3676
3899
|
const migrationsDir = resolve4(config.out);
|
|
3900
|
+
let s = spinner();
|
|
3901
|
+
s.start("Checking pending migrations...");
|
|
3902
|
+
if (!existsSync2(migrationsDir)) {
|
|
3903
|
+
s.stop("No files found.");
|
|
3904
|
+
log.warn(import_picocolors3.default.yellow(`Migration directory does not exist: ${migrationsDir}`));
|
|
3905
|
+
log.info(`Run ${import_picocolors3.default.green("bungres generate")} first.`);
|
|
3906
|
+
outro("Done.");
|
|
3907
|
+
return;
|
|
3908
|
+
}
|
|
3909
|
+
if (!statSync2(migrationsDir).isDirectory()) {
|
|
3910
|
+
s.stop("Failed.");
|
|
3911
|
+
log.error(import_picocolors3.default.red(`Migration path exists but is not a directory: ${migrationsDir}`));
|
|
3912
|
+
outro("Failed.");
|
|
3913
|
+
return;
|
|
3914
|
+
}
|
|
3677
3915
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
3678
|
-
const
|
|
3916
|
+
const table = config.migrationsTable;
|
|
3679
3917
|
const schema = config.migrationsSchema;
|
|
3680
|
-
const qualifiedTable = `"${schema}"."${
|
|
3918
|
+
const qualifiedTable = `"${schema}"."${table}"`;
|
|
3681
3919
|
const createSchema = `CREATE SCHEMA IF NOT EXISTS "${schema}";`;
|
|
3682
3920
|
const createMigrationsTable = `
|
|
3683
3921
|
CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
|
|
@@ -3685,8 +3923,6 @@ CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
|
|
|
3685
3923
|
name TEXT NOT NULL UNIQUE,
|
|
3686
3924
|
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
3687
3925
|
);`.trim();
|
|
3688
|
-
const s = spinner();
|
|
3689
|
-
s.start("Checking pending migrations...");
|
|
3690
3926
|
try {
|
|
3691
3927
|
await sql2.unsafe(createSchema);
|
|
3692
3928
|
await sql2.unsafe(createMigrationsTable);
|
|
@@ -3714,9 +3950,24 @@ CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
|
|
|
3714
3950
|
}
|
|
3715
3951
|
s.stop(`Found ${pending.length} pending migration(s).`);
|
|
3716
3952
|
for (const file of pending) {
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
const
|
|
3953
|
+
s = spinner();
|
|
3954
|
+
s.start(`Applying ${file}...`);
|
|
3955
|
+
const filePath = join4(migrationsDir, file);
|
|
3956
|
+
if (!existsSync2(filePath)) {
|
|
3957
|
+
s.stop("Failed.");
|
|
3958
|
+
log.error(import_picocolors3.default.red(`Migration file not found: ${filePath}`));
|
|
3959
|
+
outro("Failed.");
|
|
3960
|
+
return;
|
|
3961
|
+
}
|
|
3962
|
+
let content = "";
|
|
3963
|
+
try {
|
|
3964
|
+
content = await Bun.file(filePath).text();
|
|
3965
|
+
} catch (err) {
|
|
3966
|
+
s.stop("Failed.");
|
|
3967
|
+
log.error(import_picocolors3.default.red(`Failed to read migration file ${file}: ${err.message}`));
|
|
3968
|
+
outro("Failed.");
|
|
3969
|
+
return;
|
|
3970
|
+
}
|
|
3720
3971
|
let upContent = content;
|
|
3721
3972
|
const upMatch = content.match(/-- ==== UP ====([\s\S]*?)(?:-- ==== DOWN ====|$)/i);
|
|
3722
3973
|
if (upMatch) {
|
|
@@ -3734,10 +3985,11 @@ ${upContent}
|
|
|
3734
3985
|
}
|
|
3735
3986
|
await txSql.unsafe(`INSERT INTO ${qualifiedTable} (name) VALUES ($1)`, [file]);
|
|
3736
3987
|
});
|
|
3737
|
-
|
|
3988
|
+
s.stop(import_picocolors3.default.green(`\u2713 Applied ${file}`));
|
|
3738
3989
|
}
|
|
3739
3990
|
outro(import_picocolors3.default.cyan("\u2728 All migrations applied successfully."));
|
|
3740
3991
|
} catch (err) {
|
|
3992
|
+
s.stop("Failed.");
|
|
3741
3993
|
log.error(import_picocolors3.default.red(`Migration failed: ${err.message}`));
|
|
3742
3994
|
outro("Failed.");
|
|
3743
3995
|
} finally {
|
|
@@ -3851,10 +4103,10 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
3851
4103
|
`} from "@bungres/orm";`,
|
|
3852
4104
|
``
|
|
3853
4105
|
];
|
|
3854
|
-
for (const [,
|
|
3855
|
-
const varName = toCamelCase(
|
|
3856
|
-
lines.push(`export const ${varName} = pgTable("${
|
|
3857
|
-
for (const col2 of
|
|
4106
|
+
for (const [, table] of tableMap) {
|
|
4107
|
+
const varName = toCamelCase(table.tableName);
|
|
4108
|
+
lines.push(`export const ${varName} = pgTable("${table.tableName}", {`);
|
|
4109
|
+
for (const col2 of table.columns) {
|
|
3858
4110
|
const colExpr = buildColumnExpression(col2);
|
|
3859
4111
|
lines.push(` ${toCamelCase(col2.name)}: ${colExpr},`);
|
|
3860
4112
|
}
|
|
@@ -3862,9 +4114,9 @@ function generateSchemaTS(tableMap, dbSchema) {
|
|
|
3862
4114
|
if (dbSchema !== "public") {
|
|
3863
4115
|
options.push(`schema: "${dbSchema}"`);
|
|
3864
4116
|
}
|
|
3865
|
-
if (
|
|
4117
|
+
if (table.indexes.length > 0) {
|
|
3866
4118
|
const idxLines = [];
|
|
3867
|
-
for (const idx of
|
|
4119
|
+
for (const idx of table.indexes) {
|
|
3868
4120
|
const m2 = idx.indexdef.match(/CREATE (UNIQUE )?INDEX (.+) ON (.+) USING (\w+) \((.+)\)(?: WHERE (.+))?/i);
|
|
3869
4121
|
if (m2) {
|
|
3870
4122
|
const isUnique = !!m2[1];
|
|
@@ -4001,22 +4253,36 @@ function toCamelCase(str) {
|
|
|
4001
4253
|
return str.replace(/_([a-z])/g, (_2, c2) => c2.toUpperCase());
|
|
4002
4254
|
}
|
|
4003
4255
|
// src/commands/status.ts
|
|
4004
|
-
import { resolve as resolve6 } from "path";
|
|
4005
4256
|
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
4257
|
+
import { existsSync as existsSync3, statSync as statSync3 } from "fs";
|
|
4258
|
+
import { resolve as resolve6 } from "path";
|
|
4006
4259
|
async function runStatus(config) {
|
|
4007
4260
|
intro(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" @bungres/kit status ")));
|
|
4008
4261
|
const migrationsDir = resolve6(config.out);
|
|
4009
|
-
const sql2 = new Bun.SQL(config.dbUrl);
|
|
4010
|
-
const table2 = config.migrationsTable;
|
|
4011
|
-
const schema = config.migrationsSchema;
|
|
4012
|
-
const qualifiedTable = `"${schema}"."${table2}"`;
|
|
4013
4262
|
const s = spinner();
|
|
4014
4263
|
s.start("Checking migration status...");
|
|
4264
|
+
if (!existsSync3(migrationsDir)) {
|
|
4265
|
+
s.stop("No migration directory found.");
|
|
4266
|
+
log.warn(import_picocolors4.default.yellow(`Migration directory does not exist: ${migrationsDir}`));
|
|
4267
|
+
log.info(`Run ${import_picocolors4.default.green("bungres generate")} first.`);
|
|
4268
|
+
outro("Done.");
|
|
4269
|
+
return;
|
|
4270
|
+
}
|
|
4271
|
+
if (!statSync3(migrationsDir).isDirectory()) {
|
|
4272
|
+
s.stop("Failed.");
|
|
4273
|
+
log.error(import_picocolors4.default.red(`Migration path exists but is not a directory: ${migrationsDir}`));
|
|
4274
|
+
outro("Failed.");
|
|
4275
|
+
return;
|
|
4276
|
+
}
|
|
4277
|
+
const sql2 = new Bun.SQL(config.dbUrl);
|
|
4278
|
+
const table = config.migrationsTable;
|
|
4279
|
+
const schema = config.migrationsSchema;
|
|
4280
|
+
const qualifiedTable = `"${schema}"."${table}"`;
|
|
4015
4281
|
try {
|
|
4016
4282
|
const tableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
4017
4283
|
SELECT 1 FROM information_schema.tables
|
|
4018
4284
|
WHERE table_schema = $1 AND table_name = $2
|
|
4019
|
-
) AS exists`, [schema,
|
|
4285
|
+
) AS exists`, [schema, table]);
|
|
4020
4286
|
const trackingExists = tableCheck[0]?.exists ?? false;
|
|
4021
4287
|
const glob = new Bun.Glob("*.sql");
|
|
4022
4288
|
const files = [];
|
|
@@ -4051,6 +4317,7 @@ async function runStatus(config) {
|
|
|
4051
4317
|
log.info(`${import_picocolors4.default.green(appliedSet.size.toString())} applied, ${import_picocolors4.default.yellow(pendingCount.toString())} pending.`);
|
|
4052
4318
|
outro("Done.");
|
|
4053
4319
|
} catch (err) {
|
|
4320
|
+
s.stop("Failed.");
|
|
4054
4321
|
log.error(import_picocolors4.default.red(`Status check failed: ${err.message}`));
|
|
4055
4322
|
outro("Failed.");
|
|
4056
4323
|
} finally {
|
|
@@ -4061,26 +4328,14 @@ async function runStatus(config) {
|
|
|
4061
4328
|
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
4062
4329
|
async function runDrop(config, opts = {}) {
|
|
4063
4330
|
intro(import_picocolors5.default.bgCyan(import_picocolors5.default.black(" @bungres/kit drop ")));
|
|
4064
|
-
const s = spinner();
|
|
4065
|
-
s.start("Loading schemas...");
|
|
4066
|
-
const schemas = await loadSchemas(config.schema);
|
|
4067
|
-
const tableSchemas = schemas.filter((s2) => s2.type === "table");
|
|
4068
|
-
const enumSchemas = schemas.filter((s2) => s2.type === "enum");
|
|
4069
|
-
const viewSchemas = schemas.filter((s2) => s2.type === "view");
|
|
4070
|
-
if (tableSchemas.length === 0 && enumSchemas.length === 0 && viewSchemas.length === 0) {
|
|
4071
|
-
s.stop("No schemas found.");
|
|
4072
|
-
log.warn(import_picocolors5.default.yellow("No definitions found in schema files."));
|
|
4073
|
-
outro("Failed.");
|
|
4074
|
-
return;
|
|
4075
|
-
}
|
|
4076
|
-
s.stop(`Loaded ${schemas.length} schemas.`);
|
|
4077
4331
|
const ms = spinner();
|
|
4078
|
-
ms.start("
|
|
4332
|
+
ms.start("Scanning database for objects to drop...");
|
|
4079
4333
|
const sql2 = new Bun.SQL(config.dbUrl);
|
|
4080
4334
|
try {
|
|
4081
|
-
const userSchema = config.dbSchema;
|
|
4082
|
-
const
|
|
4083
|
-
const
|
|
4335
|
+
const userSchema = config.dbSchema || "public";
|
|
4336
|
+
const existingViews = await sql2.unsafe(`SELECT table_name FROM information_schema.views WHERE table_schema = $1`, [userSchema]);
|
|
4337
|
+
const existingTables = await sql2.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = $1 AND table_type = 'BASE TABLE'`, [userSchema]);
|
|
4338
|
+
const existingTypes = await sql2.unsafe(`SELECT t.typname FROM pg_type t JOIN pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = $1 AND t.typtype = 'e'`, [userSchema]);
|
|
4084
4339
|
const migTableCheck = await sql2.unsafe(`SELECT EXISTS (
|
|
4085
4340
|
SELECT 1 FROM information_schema.tables
|
|
4086
4341
|
WHERE table_schema = $1 AND table_name = $2
|
|
@@ -4091,35 +4346,20 @@ async function runDrop(config, opts = {}) {
|
|
|
4091
4346
|
WHERE table_schema = $1 AND table_name = $2
|
|
4092
4347
|
) AS exists`, [config.migrationsSchema, "__bungres_push"]);
|
|
4093
4348
|
const pushTableExists = pushTableCheck[0]?.exists ?? false;
|
|
4094
|
-
const
|
|
4095
|
-
if (
|
|
4349
|
+
const totalObjects = existingViews.length + existingTables.length + existingTypes.length + (migrationTableExists ? 1 : 0) + (pushTableExists ? 1 : 0);
|
|
4350
|
+
if (totalObjects === 0) {
|
|
4096
4351
|
ms.stop("Nothing to do.");
|
|
4097
|
-
log.success(import_picocolors5.default.green("No items to drop (
|
|
4352
|
+
log.success(import_picocolors5.default.green("No items to drop (schema is empty)."));
|
|
4098
4353
|
outro("Done.");
|
|
4099
4354
|
return;
|
|
4100
4355
|
}
|
|
4101
|
-
ms.stop("Database
|
|
4102
|
-
const namesToPrint = tablesToDrop.map((sch) => (sch.config.schema ? sch.config.schema + "." : "") + sch.config.name + " (table)");
|
|
4103
|
-
for (const v of viewSchemas) {
|
|
4104
|
-
namesToPrint.push(`${v.config.name} (view)`);
|
|
4105
|
-
}
|
|
4106
|
-
for (const e of enumSchemas) {
|
|
4107
|
-
namesToPrint.push(`${e.enumName} (enum)`);
|
|
4108
|
-
}
|
|
4109
|
-
if (migrationTableExists) {
|
|
4110
|
-
namesToPrint.push(`${config.migrationsSchema}.${config.migrationsTable} (table)`);
|
|
4111
|
-
}
|
|
4112
|
-
if (pushTableExists) {
|
|
4113
|
-
namesToPrint.push(`${config.migrationsSchema}.__bungres_push (table)`);
|
|
4114
|
-
}
|
|
4356
|
+
ms.stop("Database scan complete.");
|
|
4115
4357
|
if (!opts.force) {
|
|
4116
4358
|
log.warn(import_picocolors5.default.bgRed(import_picocolors5.default.white(" \u26A0\uFE0F WARNING ")));
|
|
4117
|
-
log.message(import_picocolors5.default.bold(import_picocolors5.default.red("This will drop
|
|
4118
|
-
|
|
4119
|
-
log.info(import_picocolors5.default.yellow(` - ${name}`));
|
|
4120
|
-
}
|
|
4359
|
+
log.message(import_picocolors5.default.bold(import_picocolors5.default.red("This will GLOBALLY drop all tables, views, and types in the database schema!")));
|
|
4360
|
+
log.info(import_picocolors5.default.yellow(`Found ${existingViews.length} views, ${existingTables.length} tables, ${existingTypes.length} enums.`));
|
|
4121
4361
|
const confirm2 = await confirm({
|
|
4122
|
-
message: "Are you sure you want to
|
|
4362
|
+
message: "Are you absolutely sure you want to drop ALL data?",
|
|
4123
4363
|
initialValue: false
|
|
4124
4364
|
});
|
|
4125
4365
|
if (isCancel(confirm2) || !confirm2) {
|
|
@@ -4128,35 +4368,36 @@ async function runDrop(config, opts = {}) {
|
|
|
4128
4368
|
}
|
|
4129
4369
|
}
|
|
4130
4370
|
const exSpinner = spinner();
|
|
4131
|
-
exSpinner.start("Dropping
|
|
4132
|
-
for (const
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
log.step(import_picocolors5.default.gray(`Dropped ${entry.enumName}`));
|
|
4371
|
+
exSpinner.start("Dropping objects...");
|
|
4372
|
+
for (const v of existingViews) {
|
|
4373
|
+
await sql2.unsafe(`DROP VIEW IF EXISTS "${userSchema}"."${v.table_name}" CASCADE;`);
|
|
4374
|
+
if (opts.force !== true)
|
|
4375
|
+
log.step(import_picocolors5.default.gray(`Dropped view ${v.table_name}`));
|
|
4376
|
+
}
|
|
4377
|
+
for (const t2 of existingTables) {
|
|
4378
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS "${userSchema}"."${t2.table_name}" CASCADE;`);
|
|
4379
|
+
if (opts.force !== true)
|
|
4380
|
+
log.step(import_picocolors5.default.gray(`Dropped table ${t2.table_name}`));
|
|
4381
|
+
}
|
|
4382
|
+
for (const type of existingTypes) {
|
|
4383
|
+
await sql2.unsafe(`DROP TYPE IF EXISTS "${userSchema}"."${type.typname}" CASCADE;`);
|
|
4384
|
+
if (opts.force !== true)
|
|
4385
|
+
log.step(import_picocolors5.default.gray(`Dropped enum ${type.typname}`));
|
|
4147
4386
|
}
|
|
4148
4387
|
if (migrationTableExists) {
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4388
|
+
await sql2.unsafe(`DROP TABLE IF EXISTS "${config.migrationsSchema}"."${config.migrationsTable}" CASCADE`);
|
|
4389
|
+
if (opts.force !== true)
|
|
4390
|
+
log.step(import_picocolors5.default.gray(`Dropped ${config.migrationsSchema}.${config.migrationsTable}`));
|
|
4152
4391
|
}
|
|
4153
4392
|
if (pushTableExists) {
|
|
4154
4393
|
await sql2.unsafe(`DROP TABLE IF EXISTS "${config.migrationsSchema}"."__bungres_push" CASCADE`);
|
|
4155
|
-
|
|
4394
|
+
if (opts.force !== true)
|
|
4395
|
+
log.step(import_picocolors5.default.gray(`Dropped ${config.migrationsSchema}.__bungres_push`));
|
|
4156
4396
|
}
|
|
4157
4397
|
exSpinner.stop("Items dropped.");
|
|
4158
4398
|
outro(import_picocolors5.default.cyan("\u2728 Drop complete."));
|
|
4159
4399
|
} catch (err) {
|
|
4400
|
+
ms.stop("Scan failed.");
|
|
4160
4401
|
log.error(import_picocolors5.default.red(`Drop failed: ${err.message}`));
|
|
4161
4402
|
outro("Failed.");
|
|
4162
4403
|
} finally {
|