@bungres/kit 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js 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
- for (const file of CONFIG_FILES) {
174
- const configPath = join(cwd, file);
175
- if (await Bun.file(configPath).exists()) {
176
- const mod = await import(resolve(configPath));
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
- break;
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 ?? "";
@@ -268,10 +279,10 @@ function createTableFactory(casing) {
268
279
  return Object.assign(tableObj, columnConfigs);
269
280
  };
270
281
  }
271
- var table = createTableFactory("snake");
272
- var snakeCase = { table: createTableFactory("snake") };
273
- var camelCase = { table: createTableFactory("camel") };
274
- var noCasing = { table: createTableFactory("none") };
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(alias) {
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}[]` });
@@ -428,18 +439,26 @@ var ilike = (column, pattern) => sql`${rawSql(colName(column))} ILIKE ${pattern}
428
439
  var isNull = (column) => rawSql(`${colName(column)} IS NULL`);
429
440
  var isNotNull = (column) => rawSql(`${colName(column)} IS NOT NULL`);
430
441
  var inArray = (column, values) => {
431
- if (values.length === 0)
442
+ if (typeof values === "object" && values !== null && "toSQL" in values) {
443
+ return sql`${rawSql(colName(column))} IN (${values.toSQL()})`;
444
+ }
445
+ const arr = values;
446
+ if (arr.length === 0)
432
447
  return rawSql("FALSE");
433
- const params = values;
434
- const placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
435
- return { sql: `${colName(column)} = ANY(ARRAY[${placeholders}])`, params };
448
+ const params = arr;
449
+ const placeholders = arr.map((_, i) => `$${i + 1}`).join(", ");
450
+ return { sql: `${colName(column)} IN (${placeholders})`, params };
436
451
  };
437
452
  var notInArray = (column, values) => {
438
- if (values.length === 0)
453
+ if (typeof values === "object" && values !== null && "toSQL" in values) {
454
+ return sql`${rawSql(colName(column))} NOT IN (${values.toSQL()})`;
455
+ }
456
+ const arr = values;
457
+ if (arr.length === 0)
439
458
  return rawSql("TRUE");
440
- const params = values;
441
- const placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
442
- return { sql: `${colName(column)} != ALL(ARRAY[${placeholders}])`, params };
459
+ const params = arr;
460
+ const placeholders = arr.map((_, i) => `$${i + 1}`).join(", ");
461
+ return { sql: `${colName(column)} NOT IN (${placeholders})`, params };
443
462
  };
444
463
  var between = (column, min, max) => sql`${rawSql(colName(column))} BETWEEN ${min} AND ${max}`;
445
464
  var and = (...conditions) => sqlJoin(conditions, " AND ");
@@ -538,8 +557,8 @@ class DeleteBuilder {
538
557
  _returning;
539
558
  _comment;
540
559
  _with = [];
541
- constructor(table2, executor) {
542
- this._table = table2;
560
+ constructor(table, executor) {
561
+ this._table = table;
543
562
  this._executor = executor;
544
563
  }
545
564
  then(onfulfilled, onrejected) {
@@ -607,8 +626,8 @@ class InsertBuilder {
607
626
  _returning;
608
627
  _comment;
609
628
  _with = [];
610
- constructor(table2, executor) {
611
- this._table = table2;
629
+ constructor(table, executor) {
630
+ this._table = table;
612
631
  this._executor = executor;
613
632
  }
614
633
  then(onfulfilled, onrejected) {
@@ -789,22 +808,29 @@ class SelectBuilder {
789
808
  _select;
790
809
  _selection;
791
810
  _joins = [];
811
+ _isNestedOutput = false;
792
812
  _with = [];
793
813
  _setOperations = [];
794
814
  _comment;
795
- constructor(table2, executor, selection) {
796
- this._table = table2;
815
+ constructor(table, executor, selection) {
816
+ this._table = table;
797
817
  this._executor = executor;
798
818
  this._selection = selection;
799
819
  }
800
820
  then(onfulfilled, onrejected) {
801
- return this._executor.execute(this).then(onfulfilled, onrejected);
821
+ return this._executor.execute(this).then((rows) => {
822
+ if (this._isNestedOutput) {
823
+ rows = rows.map((r) => typeof r._nested_data === "string" ? JSON.parse(r._nested_data) : r._nested_data);
824
+ }
825
+ return onfulfilled ? onfulfilled(rows) : rows;
826
+ }, onrejected);
802
827
  }
803
828
  async single() {
804
829
  if (this._limit === undefined) {
805
830
  this.limit(1);
806
831
  }
807
- return this._executor.executeSingle(this);
832
+ const rows = await this.then();
833
+ return rows[0] ?? null;
808
834
  }
809
835
  select(...columns) {
810
836
  this._select = columns;
@@ -866,40 +892,82 @@ class SelectBuilder {
866
892
  this._offset = n;
867
893
  return this;
868
894
  }
895
+ as(aliasName) {
896
+ const columns = {};
897
+ let fields = [];
898
+ if (this._selection) {
899
+ fields = Object.keys(this._selection);
900
+ } else if (this._select && this._select.length > 0) {
901
+ fields = this._select;
902
+ } else if (!(("alias" in this._table) && ("query" in this._table))) {
903
+ fields = Object.keys(getTableConfig(this._table).columns);
904
+ }
905
+ for (const f of fields) {
906
+ const key = typeof f === "string" ? f : f.name || f.alias;
907
+ const dataType = typeof f !== "string" && f.dataType ? f.dataType : "any";
908
+ if (key)
909
+ columns[key] = { name: key, tableName: aliasName, dataType };
910
+ }
911
+ const sqObj = { ...columns };
912
+ const TableConfigSymbol2 = Symbol.for("BungresTableConfig");
913
+ sqObj[TableConfigSymbol2] = {
914
+ name: aliasName,
915
+ qualifiedName: `"${aliasName}"`,
916
+ columns,
917
+ isSubquery: true,
918
+ builder: this
919
+ };
920
+ return sqObj;
921
+ }
869
922
  join(rawClause) {
870
- this._joins.push(rawClause);
923
+ this._joins.push({ chunk: rawSql(rawClause) });
871
924
  return this;
872
925
  }
873
- innerJoin(table2, condition) {
874
- this._joins.push(sql`INNER JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
926
+ _buildJoin(type, table, condition) {
927
+ const TableConfigSymbol2 = Symbol.for("BungresTableConfig");
928
+ const cfg = table[TableConfigSymbol2];
929
+ if (cfg && cfg.isSubquery) {
930
+ const sqChunk = cfg.builder.toSQL();
931
+ return {
932
+ table,
933
+ chunk: sql`${rawSql(type)} JOIN (${sqChunk}) AS "${rawSql(cfg.name)}" ON ${condition}`
934
+ };
935
+ }
936
+ return {
937
+ table,
938
+ chunk: sql`${rawSql(type)} JOIN ${rawSql(cfg.qualifiedName)} ON ${condition}`
939
+ };
940
+ }
941
+ innerJoin(table, condition) {
942
+ this._joins.push(this._buildJoin("INNER", table, condition));
875
943
  return this;
876
944
  }
877
- leftJoin(table2, condition) {
878
- this._joins.push(sql`LEFT JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
945
+ leftJoin(table, condition) {
946
+ this._joins.push(this._buildJoin("LEFT", table, condition));
879
947
  return this;
880
948
  }
881
- rightJoin(table2, condition) {
882
- this._joins.push(sql`RIGHT JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
949
+ rightJoin(table, condition) {
950
+ this._joins.push(this._buildJoin("RIGHT", table, condition));
883
951
  return this;
884
952
  }
885
- fullJoin(table2, condition) {
886
- this._joins.push(sql`FULL JOIN ${rawSql(getTableConfig(table2).qualifiedName)} ON ${condition}`);
953
+ fullJoin(table, condition) {
954
+ this._joins.push(this._buildJoin("FULL", table, condition));
887
955
  return this;
888
956
  }
889
957
  _buildSelection(selection, params) {
890
958
  const parts = [];
891
- for (const [alias, col2] of Object.entries(selection)) {
959
+ for (const [alias2, col2] of Object.entries(selection)) {
892
960
  if (typeof col2 === "object" && col2 !== null) {
893
961
  if ("sql" in col2 && "params" in col2) {
894
962
  const chunk = col2;
895
963
  const offset = params.length;
896
964
  params.push(...chunk.params);
897
- parts.push(`'${alias}', ${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)}`);
965
+ parts.push(`'${alias2}', ${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)}`);
898
966
  } else if ("name" in col2 && "dataType" in col2) {
899
967
  const c = col2;
900
- parts.push(`'${alias}', ${c.tableName ? c.tableName + "." : ""}"${c.name}"`);
968
+ parts.push(`'${alias2}', ${c.tableName ? c.tableName + "." : ""}"${c.name}"`);
901
969
  } else {
902
- parts.push(`'${alias}', json_build_object(${this._buildSelection(col2, params)})`);
970
+ parts.push(`'${alias2}', json_build_object(${this._buildSelection(col2, params)})`);
903
971
  }
904
972
  }
905
973
  }
@@ -908,35 +976,59 @@ class SelectBuilder {
908
976
  toSQL() {
909
977
  let cols = "";
910
978
  const params = [];
979
+ const isCte = "alias" in this._table && "query" in this._table;
980
+ const qName = isCte ? `"${this._table.alias}"` : getTableConfig(this._table).qualifiedName;
911
981
  if (this._selection) {
912
- cols = Object.entries(this._selection).map(([alias, col2]) => {
982
+ cols = Object.entries(this._selection).map(([alias2, col2]) => {
913
983
  if (typeof col2 === "object" && col2 !== null && "sql" in col2 && "params" in col2) {
914
984
  const chunk = col2;
915
985
  const offset = params.length;
916
986
  params.push(...chunk.params);
917
- return `${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)} AS "${alias}"`;
987
+ return `${chunk.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`)} AS "${alias2}"`;
918
988
  } else if (typeof col2 === "object" && col2 !== null && "name" in col2 && "dataType" in col2) {
919
989
  const c = col2;
920
- return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${alias}"`;
990
+ return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${alias2}"`;
921
991
  } else {
922
- return `json_build_object(${this._buildSelection(col2, params)}) AS "${alias}"`;
992
+ return `json_build_object(${this._buildSelection(col2, params)}) AS "${alias2}"`;
923
993
  }
924
994
  }).join(", ");
925
995
  } else if (this._select && this._select.length > 0) {
926
- const qName = getTableConfig(this._table).qualifiedName;
927
996
  cols = this._select.map((c) => {
928
997
  if (typeof c === "string") {
929
- return `${qName}."${getTableConfig(this._table).columns[c]?.name ?? c}" AS "${c}"`;
998
+ const colName2 = isCte ? c : getTableConfig(this._table).columns[c]?.name ?? c;
999
+ return `${qName}."${colName2}" AS "${c}"`;
930
1000
  }
931
1001
  return `${c.tableName ? c.tableName + "." : ""}"${c.name}" AS "${c.alias || c.name}"`;
932
1002
  }).join(", ");
933
1003
  } else {
934
- const qName = getTableConfig(this._table).qualifiedName;
935
- const colsKeys = Object.keys(getTableConfig(this._table).columns);
936
- if (colsKeys.length === 0) {
1004
+ if (isCte) {
937
1005
  cols = "*";
938
1006
  } else {
939
- cols = colsKeys.map((c) => `${qName}."${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ");
1007
+ const hasJoinedTables = this._joins.some((j) => j.table);
1008
+ if (hasJoinedTables) {
1009
+ this._isNestedOutput = true;
1010
+ const rootCfg = getTableConfig(this._table);
1011
+ const tablesToSelect = [{ alias: rootCfg.name, config: rootCfg }];
1012
+ for (const join2 of this._joins) {
1013
+ if (join2.table) {
1014
+ const cfg = getTableConfig(join2.table);
1015
+ tablesToSelect.push({ alias: cfg.name, config: cfg });
1016
+ }
1017
+ }
1018
+ cols = `json_build_object(${tablesToSelect.map((t) => {
1019
+ const innerFields = Object.keys(t.config.columns).map((c) => {
1020
+ return `'${c}', "${t.config.name}"."${t.config.columns[c].name}"`;
1021
+ }).join(", ");
1022
+ return `'${t.alias}', json_build_object(${innerFields})`;
1023
+ }).join(", ")}) AS _nested_data`;
1024
+ } else {
1025
+ const colsKeys = Object.keys(getTableConfig(this._table).columns);
1026
+ if (colsKeys.length === 0) {
1027
+ cols = "*";
1028
+ } else {
1029
+ cols = colsKeys.map((c) => `${qName}."${getTableConfig(this._table).columns[c].name}" AS "${c}"`).join(", ");
1030
+ }
1031
+ }
940
1032
  }
941
1033
  }
942
1034
  let prefix = "";
@@ -950,9 +1042,9 @@ class SelectBuilder {
950
1042
  }
951
1043
  prefix = `WITH ${cteStrs.join(", ")} `;
952
1044
  }
953
- let query = `SELECT ${cols} FROM ${getTableConfig(this._table).qualifiedName}`;
1045
+ let query = `SELECT ${cols} FROM ${qName}`;
954
1046
  if (this._joins.length > 0) {
955
- const joinChunks = this._joins.map((j) => typeof j === "string" ? rawSql(j) : j);
1047
+ const joinChunks = this._joins.map((j) => j.chunk);
956
1048
  const combinedJoins = sqlJoin(joinChunks, " ");
957
1049
  const offset = params.length;
958
1050
  query += " " + combinedJoins.sql.replace(/\$(\d+)/g, (_, n) => `$${parseInt(n) + offset}`);
@@ -965,11 +1057,11 @@ class SelectBuilder {
965
1057
  params.push(...combined.params);
966
1058
  }
967
1059
  if (this._groupBy.length > 0) {
968
- const qName = getTableConfig(this._table).qualifiedName;
1060
+ const qName2 = getTableConfig(this._table).qualifiedName;
969
1061
  query += " GROUP BY " + this._groupBy.map((c) => {
970
1062
  if (typeof c === "string") {
971
- const dbCol = getTableConfig(this._table).columns[c]?.name ?? c;
972
- return `${qName}."${dbCol}"`;
1063
+ const dbCol = isCte ? c : getTableConfig(this._table).columns[c]?.name ?? c;
1064
+ return `${qName2}."${dbCol}"`;
973
1065
  } else if ("sql" in c && "params" in c) {
974
1066
  const offset = params.length;
975
1067
  params.push(...c.params);
@@ -986,11 +1078,11 @@ class SelectBuilder {
986
1078
  params.push(...combined.params);
987
1079
  }
988
1080
  if (this._orderBy.length > 0) {
989
- const qName = getTableConfig(this._table).qualifiedName;
1081
+ const qName2 = getTableConfig(this._table).qualifiedName;
990
1082
  query += " ORDER BY " + this._orderBy.map((o) => {
991
1083
  if (typeof o.column === "string") {
992
- const dbCol = getTableConfig(this._table).columns[o.column]?.name ?? o.column;
993
- return `${qName}."${dbCol}" ${o.dir.toUpperCase()}`;
1084
+ const dbCol = isCte ? o.column : getTableConfig(this._table).columns[o.column]?.name ?? o.column;
1085
+ return `${qName2}."${dbCol}" ${o.dir.toUpperCase()}`;
994
1086
  } else if ("sql" in o.column && "params" in o.column) {
995
1087
  const offset = params.length;
996
1088
  params.push(...o.column.params);
@@ -1030,8 +1122,8 @@ class SelectBuilderIntermediate {
1030
1122
  this._executor = _executor;
1031
1123
  this._selection = _selection;
1032
1124
  }
1033
- from(table2) {
1034
- return new SelectBuilder(table2, this._executor, this._selection);
1125
+ from(table) {
1126
+ return new SelectBuilder(table, this._executor, this._selection);
1035
1127
  }
1036
1128
  }
1037
1129
 
@@ -1043,8 +1135,8 @@ class UpdateBuilder {
1043
1135
  _returning;
1044
1136
  _comment;
1045
1137
  _with = [];
1046
- constructor(table2, executor) {
1047
- this._table = table2;
1138
+ constructor(table, executor) {
1139
+ this._table = table;
1048
1140
  this._executor = executor;
1049
1141
  }
1050
1142
  then(onfulfilled, onrejected) {
@@ -1226,8 +1318,8 @@ class RelationalQueryBuilder {
1226
1318
  let cached = schemaCache.get(tableName);
1227
1319
  if (cached)
1228
1320
  return cached;
1229
- const table2 = this._schema[tableName];
1230
- const tConfig = table2[TableConfigSymbol];
1321
+ const table = this._schema[tableName];
1322
+ const tConfig = table[TableConfigSymbol];
1231
1323
  const ones = {};
1232
1324
  const manys = {};
1233
1325
  const manyToManys = {};
@@ -1240,6 +1332,8 @@ class RelationalQueryBuilder {
1240
1332
  }
1241
1333
  for (const [otherName, otherTable] of Object.entries(this._schema)) {
1242
1334
  const otherConfig = otherTable[TableConfigSymbol];
1335
+ if (!otherConfig)
1336
+ continue;
1243
1337
  for (const [colName2, col2] of Object.entries(otherConfig.columns)) {
1244
1338
  if (col2.references && col2.references.table === tableName) {
1245
1339
  const ref = col2.references;
@@ -1250,6 +1344,8 @@ class RelationalQueryBuilder {
1250
1344
  }
1251
1345
  for (const [junctionName, junctionTable] of Object.entries(this._schema)) {
1252
1346
  const junctionConfig = junctionTable[TableConfigSymbol];
1347
+ if (!junctionConfig)
1348
+ continue;
1253
1349
  const refs = Object.entries(junctionConfig.columns).filter(([_, c]) => c.references);
1254
1350
  const toThis = refs.find(([_, c]) => c.references.table === tableName);
1255
1351
  if (toThis) {
@@ -1272,7 +1368,7 @@ class RelationalQueryBuilder {
1272
1368
  schemaCache.set(tableName, result);
1273
1369
  return result;
1274
1370
  }
1275
- _buildSelectJson(tableName, args, alias, params, parentAlias, joinCondition, extraJoin) {
1371
+ _buildSelectJson(tableName, args, alias2, params, parentAlias, joinCondition, extraJoin) {
1276
1372
  const tableConfig = this._schema[tableName][TableConfigSymbol];
1277
1373
  const relations = this._getRuntimeRelations(tableName);
1278
1374
  const withArgs = args.with || {};
@@ -1290,26 +1386,26 @@ class RelationalQueryBuilder {
1290
1386
  continue;
1291
1387
  }
1292
1388
  }
1293
- jsonFields.push(`'${colKey}', "${alias}"."${colConfig.name}"`);
1389
+ jsonFields.push(`'${colKey}', "${alias2}"."${colConfig.name}"`);
1294
1390
  }
1295
1391
  for (const [relKey, relArgs] of Object.entries(withArgs)) {
1296
1392
  const isTrue = relArgs === true;
1297
1393
  const rArgs = isTrue ? {} : relArgs;
1298
1394
  if (relations.ones[relKey]) {
1299
1395
  const rel = relations.ones[relKey];
1300
- const subAlias = `${alias}_${relKey}`;
1396
+ const subAlias = `${alias2}_${relKey}`;
1301
1397
  const targetConfig = this._schema[rel.targetTable][TableConfigSymbol];
1302
1398
  const targetPk = getPkColumn(targetConfig);
1303
- const joinCond = `"${subAlias}"."${targetPk}" = "${alias}"."${rel.sourceColumn}"`;
1304
- const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, joinCond);
1399
+ const joinCond = `"${subAlias}"."${targetPk}" = "${alias2}"."${rel.sourceColumn}"`;
1400
+ const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias2, joinCond);
1305
1401
  const subSql = `SELECT ${subQuery.sql} ${subQuery.from}`;
1306
1402
  jsonFields.push(`'${relKey}', (${subSql})`);
1307
1403
  } else if (relations.manys[relKey]) {
1308
1404
  const rel = relations.manys[relKey];
1309
- const subAlias = `${alias}_${relKey}`;
1405
+ const subAlias = `${alias2}_${relKey}`;
1310
1406
  const thisPk = getPkColumn(tableConfig);
1311
- const joinCond = `"${subAlias}"."${rel.targetColumn}" = "${alias}"."${thisPk}"`;
1312
- const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, joinCond);
1407
+ const joinCond = `"${subAlias}"."${rel.targetColumn}" = "${alias2}"."${thisPk}"`;
1408
+ const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias2, joinCond);
1313
1409
  const aggAlias = `${subAlias}_agg`;
1314
1410
  const aggSql = `
1315
1411
  SELECT COALESCE(json_agg(_sub.obj), '[]'::json)
@@ -1321,16 +1417,16 @@ class RelationalQueryBuilder {
1321
1417
  jsonFields.push(`'${relKey}', (${aggSql})`);
1322
1418
  } else if (relations.manyToManys[relKey]) {
1323
1419
  const rel = relations.manyToManys[relKey];
1324
- const subAlias = `${alias}_${relKey}`;
1325
- const junctionAlias = `${alias}_j_${relKey}`;
1420
+ const subAlias = `${alias2}_${relKey}`;
1421
+ const junctionAlias = `${alias2}_j_${relKey}`;
1326
1422
  const targetTableConfig = this._schema[rel.targetTable][TableConfigSymbol];
1327
1423
  const junctionTableConfig = this._schema[rel.junctionTable][TableConfigSymbol];
1328
1424
  const fromExtra = `
1329
1425
  INNER JOIN ${junctionTableConfig.qualifiedName} AS "${junctionAlias}"
1330
1426
  ON "${junctionAlias}"."${rel.joinTargetColumn}" = "${subAlias}"."${getPkColumn(targetTableConfig)}"
1331
1427
  `;
1332
- const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${alias}"."${getPkColumn(tableConfig)}"`;
1333
- const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias, whereExtra, fromExtra);
1428
+ const whereExtra = `"${junctionAlias}"."${rel.joinSourceColumn}" = "${alias2}"."${getPkColumn(tableConfig)}"`;
1429
+ const subQuery = this._buildSelectJson(rel.targetTable, rArgs, subAlias, params, alias2, whereExtra, fromExtra);
1334
1430
  const aggSql = `
1335
1431
  SELECT COALESCE(json_agg(_sub.obj), '[]'::json)
1336
1432
  FROM (
@@ -1342,7 +1438,7 @@ class RelationalQueryBuilder {
1342
1438
  }
1343
1439
  }
1344
1440
  let selectSql = `json_build_object(${jsonFields.join(", ")})`;
1345
- let fromSql = `FROM ${tableConfig.qualifiedName} AS "${alias}"`;
1441
+ let fromSql = `FROM ${tableConfig.qualifiedName} AS "${alias2}"`;
1346
1442
  if (extraJoin) {
1347
1443
  fromSql += ` ${extraJoin}`;
1348
1444
  }
@@ -1390,7 +1486,7 @@ class RelationalQueryBuilder {
1390
1486
  }
1391
1487
  buildSQL(args) {
1392
1488
  const params = [];
1393
- const rootAlias = "root";
1489
+ const rootAlias = this._tableName;
1394
1490
  const subQuery = this._buildSelectJson(this._tableName, args, rootAlias, params);
1395
1491
  const sql2 = `SELECT ${subQuery.sql} AS _data ${subQuery.from}`;
1396
1492
  return { sql: sql2, params };
@@ -1466,14 +1562,14 @@ class BungresDB {
1466
1562
  }
1467
1563
  return new SelectBuilderIntermediate(this);
1468
1564
  }
1469
- insert(table2) {
1470
- return new InsertBuilder(table2, this);
1565
+ insert(table) {
1566
+ return new InsertBuilder(table, this);
1471
1567
  }
1472
- update(table2) {
1473
- return new UpdateBuilder(table2, this);
1568
+ update(table) {
1569
+ return new UpdateBuilder(table, this);
1474
1570
  }
1475
- delete(table2) {
1476
- return new DeleteBuilder(table2, this);
1571
+ delete(table) {
1572
+ return new DeleteBuilder(table, this);
1477
1573
  }
1478
1574
  async execute(builder) {
1479
1575
  await this.ready();
@@ -1517,14 +1613,14 @@ class BungresTransaction {
1517
1613
  }
1518
1614
  return new SelectBuilderIntermediate(this);
1519
1615
  }
1520
- insert(table2) {
1521
- return new InsertBuilder(table2, this);
1616
+ insert(table) {
1617
+ return new InsertBuilder(table, this);
1522
1618
  }
1523
- update(table2) {
1524
- return new UpdateBuilder(table2, this);
1619
+ update(table) {
1620
+ return new UpdateBuilder(table, this);
1525
1621
  }
1526
- delete(table2) {
1527
- return new DeleteBuilder(table2, this);
1622
+ delete(table) {
1623
+ return new DeleteBuilder(table, this);
1528
1624
  }
1529
1625
  async execute(builder) {
1530
1626
  const chunk = "toSQL" in builder ? builder.toSQL() : builder;
@@ -1685,13 +1781,13 @@ function formatDefaultValue(value, dataType) {
1685
1781
  return String(value);
1686
1782
  return `'${JSON.stringify(value).replace(/'/g, "''")}'`;
1687
1783
  }
1688
- function buildIndex(table2, idx) {
1689
- const tableName = table2.schema ? `"${table2.schema}"."${table2.name}"` : `"${table2.name}"`;
1784
+ function buildIndex(table, idx) {
1785
+ const tableName = table.schema ? `"${table.schema}"."${table.name}"` : `"${table.name}"`;
1690
1786
  const unique2 = idx.unique ? "UNIQUE " : "";
1691
1787
  const using = idx.using ? ` USING ${idx.using.toUpperCase()}` : "";
1692
1788
  const cols = idx.columns.map((c) => `"${c}"`).join(", ");
1693
1789
  const where = idx.where ? ` WHERE ${idx.where}` : "";
1694
- const idxName = idx.name ?? `idx_${table2.name}_${idx.columns.join("_")}`;
1790
+ const idxName = idx.name ?? `idx_${table.name}_${idx.columns.join("_")}`;
1695
1791
  return `CREATE ${unique2}INDEX IF NOT EXISTS "${idxName}" ON ${tableName}${using} (${cols})${where};`;
1696
1792
  }
1697
1793
  function generateAddColumn(tableName, schema, key, col2) {
@@ -1726,7 +1822,14 @@ function inlineParams(chunk) {
1726
1822
  }
1727
1823
  function generateCreateView(view) {
1728
1824
  const kind = view.materialized ? "MATERIALIZED VIEW" : "VIEW";
1729
- const inlineSql = inlineParams(view.query.toSQL());
1825
+ let inlineSql = "";
1826
+ if (view.sql) {
1827
+ inlineSql = view.sql;
1828
+ } else if (view.query && typeof view.query.toSQL === "function") {
1829
+ inlineSql = inlineParams(view.query.toSQL());
1830
+ } else {
1831
+ inlineSql = "SELECT * FROM (VALUES ('LEGACY_SNAPSHOT_MISSING_SQL')) AS t(c)";
1832
+ }
1730
1833
  return `CREATE ${kind} "${view.name}" AS ${inlineSql};`;
1731
1834
  }
1732
1835
  function generateDropView(view, ifExists = true) {
@@ -1961,8 +2064,8 @@ function topoSortConfigs(tables) {
1961
2064
  visit(dep);
1962
2065
  result.push(config);
1963
2066
  }
1964
- for (const table2 of tables)
1965
- visit(table2.name);
2067
+ for (const table of tables)
2068
+ visit(table.name);
1966
2069
  return result;
1967
2070
  }
1968
2071
  function diffColumn(prev, next) {
@@ -3120,6 +3223,30 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
3120
3223
  });
3121
3224
  }
3122
3225
  }
3226
+ class n extends V {
3227
+ get userInputWithCursor() {
3228
+ if (this.state === "submit")
3229
+ return this.userInput;
3230
+ const t2 = this.userInput;
3231
+ if (this.cursor >= t2.length)
3232
+ return `${this.userInput}\u2588`;
3233
+ const r2 = t2.slice(0, this.cursor), s = t2.slice(this.cursor, this.cursor + 1), e = t2.slice(this.cursor + 1);
3234
+ return `${r2}${styleText("inverse", s)}${e}`;
3235
+ }
3236
+ get cursor() {
3237
+ return this._cursor;
3238
+ }
3239
+ constructor(t2) {
3240
+ super({
3241
+ ...t2,
3242
+ initialUserInput: t2.initialUserInput ?? t2.initialValue
3243
+ }), this.on("userInput", (r2) => {
3244
+ this._setValue(r2);
3245
+ }), this.on("finalize", () => {
3246
+ this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
3247
+ });
3248
+ }
3249
+ }
3123
3250
 
3124
3251
  // ../../node_modules/.bun/@clack+prompts@1.7.0/node_modules/@clack/prompts/dist/index.mjs
3125
3252
  import { styleText as styleText2, stripVTControlCharacters } from "util";
@@ -3380,24 +3507,62 @@ var SELECT_INSTRUCTIONS = [
3380
3507
  `${styleText2("dim", "Enter:")} confirm`
3381
3508
  ];
3382
3509
  var i = `${styleText2("gray", S_BAR)} `;
3510
+ var text = (e) => new n({
3511
+ validate: e.validate,
3512
+ placeholder: e.placeholder,
3513
+ defaultValue: e.defaultValue,
3514
+ initialValue: e.initialValue,
3515
+ output: e.output,
3516
+ signal: e.signal,
3517
+ input: e.input,
3518
+ render() {
3519
+ const i2 = e?.withGuide ?? settings.withGuide, s = `${`${i2 ? `${styleText2("gray", S_BAR)}
3520
+ ` : ""}${symbol(this.state)} `}${e.message}
3521
+ `, 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 ?? "";
3522
+ switch (this.state) {
3523
+ case "error": {
3524
+ const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
3525
+ return `${s.trim()}
3526
+ ${r2}${o2}
3527
+ ${d}${n2}
3528
+ `;
3529
+ }
3530
+ case "submit": {
3531
+ const n2 = l2 ? ` ${styleText2("dim", l2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
3532
+ return `${s}${r2}${n2}`;
3533
+ }
3534
+ case "cancel": {
3535
+ const n2 = l2 ? ` ${styleText2(["strikethrough", "dim"], l2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
3536
+ return `${s}${r2}${n2}${l2.trim() ? `
3537
+ ${r2}` : ""}`;
3538
+ }
3539
+ default: {
3540
+ const n2 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "";
3541
+ return `${s}${n2}${o2}
3542
+ ${r2}
3543
+ `;
3544
+ }
3545
+ }
3546
+ }
3547
+ }).prompt();
3383
3548
 
3384
3549
  // src/commands/push.ts
3385
3550
  var import_picocolors = __toESM(require_picocolors(), 1);
3386
3551
  async function runPush(config, opts = {}) {
3387
3552
  intro(import_picocolors.default.bgCyan(import_picocolors.default.black(" @bungres/kit push ")));
3388
- const s = spinner();
3389
- s.start("Loading schemas...");
3553
+ let activeSpinner = spinner();
3554
+ activeSpinner.start("Loading schemas...");
3390
3555
  const schemas = await loadSchemas(config.schema);
3391
3556
  if (schemas.length === 0) {
3392
- s.stop("No schemas found.");
3557
+ activeSpinner.stop("No schemas found.");
3393
3558
  log.warn(import_picocolors.default.yellow("No table definitions found. Check your schema glob pattern."));
3394
3559
  outro("Failed.");
3395
3560
  return;
3396
3561
  }
3397
- s.stop(`Loaded ${schemas.length} schemas.`);
3562
+ activeSpinner.stop(`Loaded ${schemas.length} schemas.`);
3398
3563
  const sql2 = new Bun.SQL(config.dbUrl);
3399
- const ms = spinner();
3400
- ms.start("Computing diff from database...");
3564
+ activeSpinner = spinner();
3565
+ activeSpinner.start("Computing diff from database...");
3401
3566
  try {
3402
3567
  await sql2.unsafe(`CREATE SCHEMA IF NOT EXISTS "${config.migrationsSchema}";`);
3403
3568
  const qualifiedPush = `"${config.migrationsSchema}"."__bungres_push"`;
@@ -3422,23 +3587,27 @@ async function runPush(config, opts = {}) {
3422
3587
  }
3423
3588
  }
3424
3589
  const currentSnapshot = { tables: {}, enums: {}, views: {} };
3425
- for (const s2 of schemas) {
3426
- if (s2.type === "table") {
3427
- currentSnapshot.tables[s2.config.name] = s2.config;
3428
- } else if (s2.type === "enum") {
3429
- currentSnapshot.enums[s2.enumName] = { enumName: s2.enumName, enumValues: s2.enumValues };
3430
- } else if (s2.type === "view") {
3431
- currentSnapshot.views[s2.config.name] = s2.config;
3590
+ for (const s of schemas) {
3591
+ if (s.type === "table") {
3592
+ currentSnapshot.tables[s.config.name] = s.config;
3593
+ } else if (s.type === "enum") {
3594
+ currentSnapshot.enums[s.enumName] = { enumName: s.enumName, enumValues: s.enumValues };
3595
+ } else if (s.type === "view") {
3596
+ currentSnapshot.views[s.config.name] = {
3597
+ name: s.config.name,
3598
+ materialized: s.config.materialized,
3599
+ sql: typeof s.config.query?.toSQL === "function" ? inlineParams(s.config.query.toSQL()) : s.config.sql
3600
+ };
3432
3601
  }
3433
3602
  }
3434
3603
  const diff = diffSchemas(prevSnapshot, currentSnapshot);
3435
3604
  if (diff.statements.length === 0) {
3436
- ms.stop("Up to date.");
3605
+ activeSpinner.stop("Up to date.");
3437
3606
  log.success(import_picocolors.default.green("No schema changes detected. Database is up to date."));
3438
3607
  outro("Done.");
3439
3608
  return;
3440
3609
  }
3441
- ms.stop(`Computed ${diff.statements.length} statements.`);
3610
+ activeSpinner.stop(`Computed ${diff.statements.length} statements.`);
3442
3611
  log.message(import_picocolors.default.bold("Changes to apply:"));
3443
3612
  for (const change of diff.summary) {
3444
3613
  if (change.startsWith("CREATE") || change.startsWith("ALTER TABLE") && change.includes("ADD")) {
@@ -3465,8 +3634,8 @@ async function runPush(config, opts = {}) {
3465
3634
  return;
3466
3635
  }
3467
3636
  }
3468
- const exSpinner = spinner();
3469
- exSpinner.start("Pushing changes...");
3637
+ activeSpinner = spinner();
3638
+ activeSpinner.start("Pushing changes...");
3470
3639
  for (const stmt of diff.statements) {
3471
3640
  if (config.verbose) {
3472
3641
  log.info(import_picocolors.default.gray(`-- ${stmt}`));
@@ -3474,9 +3643,10 @@ async function runPush(config, opts = {}) {
3474
3643
  await sql2.unsafe(stmt);
3475
3644
  }
3476
3645
  await sql2.unsafe(`INSERT INTO ${qualifiedPush} (snapshot) VALUES ($1);`, [JSON.stringify(currentSnapshot)]);
3477
- exSpinner.stop(import_picocolors.default.green("Changes applied successfully."));
3646
+ activeSpinner.stop(import_picocolors.default.green("Changes applied successfully."));
3478
3647
  outro(import_picocolors.default.cyan("\u2728 Push complete."));
3479
3648
  } catch (err) {
3649
+ activeSpinner.stop("Failed.");
3480
3650
  log.error(import_picocolors.default.red(`Push failed: ${err.message}`));
3481
3651
  outro("Failed.");
3482
3652
  } finally {
@@ -3510,7 +3680,11 @@ async function runGenerate(config, name) {
3510
3680
  } else if (s2.type === "enum") {
3511
3681
  currentSnapshot.enums[s2.enumName] = { enumName: s2.enumName, enumValues: s2.enumValues };
3512
3682
  } else if (s2.type === "view") {
3513
- currentSnapshot.views[s2.config.name] = s2.config;
3683
+ currentSnapshot.views[s2.config.name] = {
3684
+ name: s2.config.name,
3685
+ materialized: s2.config.materialized,
3686
+ sql: typeof s2.config.query?.toSQL === "function" ? inlineParams(s2.config.query.toSQL()) : s2.config.sql
3687
+ };
3514
3688
  }
3515
3689
  }
3516
3690
  let prevSnapshot = { tables: {}, enums: {}, views: {} };
@@ -3675,9 +3849,9 @@ async function runMigrate(config) {
3675
3849
  intro(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" @bungres/kit migrate ")));
3676
3850
  const migrationsDir = resolve4(config.out);
3677
3851
  const sql2 = new Bun.SQL(config.dbUrl);
3678
- const table2 = config.migrationsTable;
3852
+ const table = config.migrationsTable;
3679
3853
  const schema = config.migrationsSchema;
3680
- const qualifiedTable = `"${schema}"."${table2}"`;
3854
+ const qualifiedTable = `"${schema}"."${table}"`;
3681
3855
  const createSchema = `CREATE SCHEMA IF NOT EXISTS "${schema}";`;
3682
3856
  const createMigrationsTable = `
3683
3857
  CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
@@ -3685,7 +3859,7 @@ CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
3685
3859
  name TEXT NOT NULL UNIQUE,
3686
3860
  applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
3687
3861
  );`.trim();
3688
- const s = spinner();
3862
+ let s = spinner();
3689
3863
  s.start("Checking pending migrations...");
3690
3864
  try {
3691
3865
  await sql2.unsafe(createSchema);
@@ -3714,8 +3888,8 @@ CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
3714
3888
  }
3715
3889
  s.stop(`Found ${pending.length} pending migration(s).`);
3716
3890
  for (const file of pending) {
3717
- const ms = spinner();
3718
- ms.start(`Applying ${file}...`);
3891
+ s = spinner();
3892
+ s.start(`Applying ${file}...`);
3719
3893
  const content = await Bun.file(join4(migrationsDir, file)).text();
3720
3894
  let upContent = content;
3721
3895
  const upMatch = content.match(/-- ==== UP ====([\s\S]*?)(?:-- ==== DOWN ====|$)/i);
@@ -3734,10 +3908,11 @@ ${upContent}
3734
3908
  }
3735
3909
  await txSql.unsafe(`INSERT INTO ${qualifiedTable} (name) VALUES ($1)`, [file]);
3736
3910
  });
3737
- ms.stop(import_picocolors3.default.green(`\u2713 Applied ${file}`));
3911
+ s.stop(import_picocolors3.default.green(`\u2713 Applied ${file}`));
3738
3912
  }
3739
3913
  outro(import_picocolors3.default.cyan("\u2728 All migrations applied successfully."));
3740
3914
  } catch (err) {
3915
+ s.stop("Failed.");
3741
3916
  log.error(import_picocolors3.default.red(`Migration failed: ${err.message}`));
3742
3917
  outro("Failed.");
3743
3918
  } finally {
@@ -3851,10 +4026,10 @@ function generateSchemaTS(tableMap, dbSchema) {
3851
4026
  `} from "@bungres/orm";`,
3852
4027
  ``
3853
4028
  ];
3854
- for (const [, table2] of tableMap) {
3855
- const varName = toCamelCase(table2.tableName);
3856
- lines.push(`export const ${varName} = pgTable("${table2.tableName}", {`);
3857
- for (const col2 of table2.columns) {
4029
+ for (const [, table] of tableMap) {
4030
+ const varName = toCamelCase(table.tableName);
4031
+ lines.push(`export const ${varName} = pgTable("${table.tableName}", {`);
4032
+ for (const col2 of table.columns) {
3858
4033
  const colExpr = buildColumnExpression(col2);
3859
4034
  lines.push(` ${toCamelCase(col2.name)}: ${colExpr},`);
3860
4035
  }
@@ -3862,9 +4037,9 @@ function generateSchemaTS(tableMap, dbSchema) {
3862
4037
  if (dbSchema !== "public") {
3863
4038
  options.push(`schema: "${dbSchema}"`);
3864
4039
  }
3865
- if (table2.indexes.length > 0) {
4040
+ if (table.indexes.length > 0) {
3866
4041
  const idxLines = [];
3867
- for (const idx of table2.indexes) {
4042
+ for (const idx of table.indexes) {
3868
4043
  const m2 = idx.indexdef.match(/CREATE (UNIQUE )?INDEX (.+) ON (.+) USING (\w+) \((.+)\)(?: WHERE (.+))?/i);
3869
4044
  if (m2) {
3870
4045
  const isUnique = !!m2[1];
@@ -4007,16 +4182,16 @@ async function runStatus(config) {
4007
4182
  intro(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" @bungres/kit status ")));
4008
4183
  const migrationsDir = resolve6(config.out);
4009
4184
  const sql2 = new Bun.SQL(config.dbUrl);
4010
- const table2 = config.migrationsTable;
4185
+ const table = config.migrationsTable;
4011
4186
  const schema = config.migrationsSchema;
4012
- const qualifiedTable = `"${schema}"."${table2}"`;
4187
+ const qualifiedTable = `"${schema}"."${table}"`;
4013
4188
  const s = spinner();
4014
4189
  s.start("Checking migration status...");
4015
4190
  try {
4016
4191
  const tableCheck = await sql2.unsafe(`SELECT EXISTS (
4017
4192
  SELECT 1 FROM information_schema.tables
4018
4193
  WHERE table_schema = $1 AND table_name = $2
4019
- ) AS exists`, [schema, table2]);
4194
+ ) AS exists`, [schema, table]);
4020
4195
  const trackingExists = tableCheck[0]?.exists ?? false;
4021
4196
  const glob = new Bun.Glob("*.sql");
4022
4197
  const files = [];
@@ -4051,6 +4226,7 @@ async function runStatus(config) {
4051
4226
  log.info(`${import_picocolors4.default.green(appliedSet.size.toString())} applied, ${import_picocolors4.default.yellow(pendingCount.toString())} pending.`);
4052
4227
  outro("Done.");
4053
4228
  } catch (err) {
4229
+ s.stop("Failed.");
4054
4230
  log.error(import_picocolors4.default.red(`Status check failed: ${err.message}`));
4055
4231
  outro("Failed.");
4056
4232
  } finally {
@@ -4061,26 +4237,14 @@ async function runStatus(config) {
4061
4237
  var import_picocolors5 = __toESM(require_picocolors(), 1);
4062
4238
  async function runDrop(config, opts = {}) {
4063
4239
  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
4240
  const ms = spinner();
4078
- ms.start("Checking database tables...");
4241
+ ms.start("Scanning database for objects to drop...");
4079
4242
  const sql2 = new Bun.SQL(config.dbUrl);
4080
4243
  try {
4081
- const userSchema = config.dbSchema;
4082
- const existingUserTablesResult = await sql2.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = $1`, [userSchema]);
4083
- const existingTableNames = new Set(existingUserTablesResult.map((r2) => r2.table_name));
4244
+ const userSchema = config.dbSchema || "public";
4245
+ const existingViews = await sql2.unsafe(`SELECT table_name FROM information_schema.views WHERE table_schema = $1`, [userSchema]);
4246
+ const existingTables = await sql2.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = $1 AND table_type = 'BASE TABLE'`, [userSchema]);
4247
+ 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
4248
  const migTableCheck = await sql2.unsafe(`SELECT EXISTS (
4085
4249
  SELECT 1 FROM information_schema.tables
4086
4250
  WHERE table_schema = $1 AND table_name = $2
@@ -4091,35 +4255,20 @@ async function runDrop(config, opts = {}) {
4091
4255
  WHERE table_schema = $1 AND table_name = $2
4092
4256
  ) AS exists`, [config.migrationsSchema, "__bungres_push"]);
4093
4257
  const pushTableExists = pushTableCheck[0]?.exists ?? false;
4094
- const tablesToDrop = tableSchemas.filter((sch) => existingTableNames.has(sch.config.name));
4095
- if (tablesToDrop.length === 0 && enumSchemas.length === 0 && viewSchemas.length === 0 && !migrationTableExists && !pushTableExists) {
4258
+ const totalObjects = existingViews.length + existingTables.length + existingTypes.length + (migrationTableExists ? 1 : 0) + (pushTableExists ? 1 : 0);
4259
+ if (totalObjects === 0) {
4096
4260
  ms.stop("Nothing to do.");
4097
- log.success(import_picocolors5.default.green("No items to drop (they either don't exist or were already dropped)."));
4261
+ log.success(import_picocolors5.default.green("No items to drop (schema is empty)."));
4098
4262
  outro("Done.");
4099
4263
  return;
4100
4264
  }
4101
- ms.stop("Database check complete.");
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
- }
4265
+ ms.stop("Database scan complete.");
4115
4266
  if (!opts.force) {
4116
4267
  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 the following items and ALL their data:")));
4118
- for (const name of namesToPrint) {
4119
- log.info(import_picocolors5.default.yellow(` - ${name}`));
4120
- }
4268
+ log.message(import_picocolors5.default.bold(import_picocolors5.default.red("This will GLOBALLY drop all tables, views, and types in the database schema!")));
4269
+ log.info(import_picocolors5.default.yellow(`Found ${existingViews.length} views, ${existingTables.length} tables, ${existingTypes.length} enums.`));
4121
4270
  const confirm2 = await confirm({
4122
- message: "Are you sure you want to proceed?",
4271
+ message: "Are you absolutely sure you want to drop ALL data?",
4123
4272
  initialValue: false
4124
4273
  });
4125
4274
  if (isCancel(confirm2) || !confirm2) {
@@ -4128,35 +4277,36 @@ async function runDrop(config, opts = {}) {
4128
4277
  }
4129
4278
  }
4130
4279
  const exSpinner = spinner();
4131
- exSpinner.start("Dropping tables...");
4132
- for (const entry of viewSchemas) {
4133
- const isMat = entry.config.materialized ? "MATERIALIZED VIEW" : "VIEW";
4134
- const ddl = `DROP ${isMat} IF EXISTS "${entry.config.name}" CASCADE;`;
4135
- await sql2.unsafe(ddl);
4136
- log.step(import_picocolors5.default.gray(`Dropped ${entry.config.name}`));
4137
- }
4138
- for (const entry of tablesToDrop) {
4139
- const ddl = `DROP TABLE IF EXISTS "${entry.config.name}" CASCADE;`;
4140
- await sql2.unsafe(ddl);
4141
- log.step(import_picocolors5.default.gray(`Dropped ${entry.config.name}`));
4142
- }
4143
- for (const entry of enumSchemas) {
4144
- const ddl = `DROP TYPE IF EXISTS "${entry.enumName}" CASCADE;`;
4145
- await sql2.unsafe(ddl);
4146
- log.step(import_picocolors5.default.gray(`Dropped ${entry.enumName}`));
4280
+ exSpinner.start("Dropping objects...");
4281
+ for (const v of existingViews) {
4282
+ await sql2.unsafe(`DROP VIEW IF EXISTS "${userSchema}"."${v.table_name}" CASCADE;`);
4283
+ if (opts.force !== true)
4284
+ log.step(import_picocolors5.default.gray(`Dropped view ${v.table_name}`));
4285
+ }
4286
+ for (const t2 of existingTables) {
4287
+ await sql2.unsafe(`DROP TABLE IF EXISTS "${userSchema}"."${t2.table_name}" CASCADE;`);
4288
+ if (opts.force !== true)
4289
+ log.step(import_picocolors5.default.gray(`Dropped table ${t2.table_name}`));
4290
+ }
4291
+ for (const type of existingTypes) {
4292
+ await sql2.unsafe(`DROP TYPE IF EXISTS "${userSchema}"."${type.typname}" CASCADE;`);
4293
+ if (opts.force !== true)
4294
+ log.step(import_picocolors5.default.gray(`Dropped enum ${type.typname}`));
4147
4295
  }
4148
4296
  if (migrationTableExists) {
4149
- const qualifiedMigTable = `"${config.migrationsSchema}"."${config.migrationsTable}"`;
4150
- await sql2.unsafe(`DROP TABLE IF EXISTS ${qualifiedMigTable} CASCADE`);
4151
- log.step(import_picocolors5.default.gray(`Dropped ${config.migrationsSchema}.${config.migrationsTable}`));
4297
+ await sql2.unsafe(`DROP TABLE IF EXISTS "${config.migrationsSchema}"."${config.migrationsTable}" CASCADE`);
4298
+ if (opts.force !== true)
4299
+ log.step(import_picocolors5.default.gray(`Dropped ${config.migrationsSchema}.${config.migrationsTable}`));
4152
4300
  }
4153
4301
  if (pushTableExists) {
4154
4302
  await sql2.unsafe(`DROP TABLE IF EXISTS "${config.migrationsSchema}"."__bungres_push" CASCADE`);
4155
- log.step(import_picocolors5.default.gray(`Dropped ${config.migrationsSchema}.__bungres_push`));
4303
+ if (opts.force !== true)
4304
+ log.step(import_picocolors5.default.gray(`Dropped ${config.migrationsSchema}.__bungres_push`));
4156
4305
  }
4157
4306
  exSpinner.stop("Items dropped.");
4158
4307
  outro(import_picocolors5.default.cyan("\u2728 Drop complete."));
4159
4308
  } catch (err) {
4309
+ ms.stop("Scan failed.");
4160
4310
  log.error(import_picocolors5.default.red(`Drop failed: ${err.message}`));
4161
4311
  outro("Failed.");
4162
4312
  } finally {