bun-query-builder 0.1.26 → 0.1.28

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/src/index.js CHANGED
@@ -11762,6 +11762,7 @@ var init_config = __esm(() => {
11762
11762
  // src/db.ts
11763
11763
  var {SQL } = globalThis.Bun;
11764
11764
  import { Database } from "bun:sqlite";
11765
+ import process19 from "process";
11765
11766
 
11766
11767
  class SQLiteWrapper {
11767
11768
  db;
@@ -11975,6 +11976,16 @@ function createSQLiteSQL(filename) {
11975
11976
  return sqlFunction;
11976
11977
  }
11977
11978
  function createConnectionString(dialect, dbConfig) {
11979
+ if ((dialect === "postgres" || dialect === "mysql") && process19.env.DB_CONNECTION === dialect) {
11980
+ const e = process19.env;
11981
+ const envDb = (e.DB_DATABASE || dbConfig.database || "").replace(/^['"]|['"]$/g, "");
11982
+ const envUser = e.DB_USERNAME || dbConfig.username;
11983
+ const envPass = e.DB_PASSWORD ?? dbConfig.password ?? "";
11984
+ const envHost = e.DB_HOST || dbConfig.host || "localhost";
11985
+ const envPort = e.DB_PORT || dbConfig.port;
11986
+ const scheme = dialect === "postgres" ? "postgres" : "mysql";
11987
+ return `${scheme}://${envUser}:${envPass}@${envHost}${envPort ? `:${envPort}` : ""}/${envDb}`;
11988
+ }
11978
11989
  if (dbConfig.url) {
11979
11990
  return dbConfig.url;
11980
11991
  }
@@ -12392,13 +12403,29 @@ class QueryCache {
12392
12403
  this.cache.delete(key);
12393
12404
  return null;
12394
12405
  }
12406
+ this.cache.delete(key);
12407
+ this.cache.set(key, entry);
12395
12408
  return entry.data;
12396
12409
  }
12397
12410
  set(key, data, ttlMs) {
12411
+ if (this.cache.has(key))
12412
+ this.cache.delete(key);
12398
12413
  if (this.cache.size >= this.maxSize) {
12399
- const firstKey = this.cache.keys().next().value;
12400
- if (firstKey)
12401
- this.cache.delete(firstKey);
12414
+ const now = Date.now();
12415
+ let evicted = false;
12416
+ for (const [k, v] of this.cache) {
12417
+ if (now > v.expiresAt) {
12418
+ this.cache.delete(k);
12419
+ evicted = true;
12420
+ if (this.cache.size < this.maxSize)
12421
+ break;
12422
+ }
12423
+ }
12424
+ if (!evicted) {
12425
+ const lruKey = this.cache.keys().next().value;
12426
+ if (lruKey !== undefined)
12427
+ this.cache.delete(lruKey);
12428
+ }
12402
12429
  }
12403
12430
  this.cache.set(key, {
12404
12431
  data,
@@ -12469,6 +12496,9 @@ function reorderSelectClauses(sql) {
12469
12496
  continue;
12470
12497
  if (i === 0 || !/\s/.test(sql[i - 1]))
12471
12498
  continue;
12499
+ const lead = sql.charCodeAt(i) & ~32;
12500
+ if (lead !== 71 && lead !== 79 && lead !== 72 && lead !== 76 && lead !== 87)
12501
+ continue;
12472
12502
  const rest = sql.slice(i);
12473
12503
  for (const { key, tokens } of KEYWORDS) {
12474
12504
  const m = rest.match(tokens);
@@ -13245,28 +13275,6 @@ function createQueryBuilder(state) {
13245
13275
  if (!rels) {
13246
13276
  return fromTable;
13247
13277
  }
13248
- const _buildConditionalJoin = (baseJoinCondition, targetTable2) => {
13249
- let joinCondition = baseJoinCondition;
13250
- if (config5.softDeletes?.enabled && config5.softDeletes?.defaultFilter) {
13251
- const softDeleteColumn = config5.softDeletes.column || "deleted_at";
13252
- joinCondition = `${joinCondition} AND ${targetTable2}.${softDeleteColumn} IS NULL`;
13253
- }
13254
- if (!condition)
13255
- return joinCondition;
13256
- const conditionBuilder = {
13257
- where: (col, op, val) => {
13258
- const valStr = typeof val === "string" ? `'${val}'` : String(val);
13259
- return `${targetTable2}.${col} ${op} ${valStr}`;
13260
- }
13261
- };
13262
- try {
13263
- const additionalCondition = condition(conditionBuilder);
13264
- if (additionalCondition && typeof additionalCondition === "string") {
13265
- return `${joinCondition} AND ${additionalCondition}`;
13266
- }
13267
- } catch {}
13268
- return joinCondition;
13269
- };
13270
13278
  const addSoftDeleteCheck = (table2) => {
13271
13279
  if (config5.softDeletes?.enabled && config5.softDeletes?.defaultFilter) {
13272
13280
  const softDeleteColumn = config5.softDeletes.column || "deleted_at";
@@ -13745,6 +13753,8 @@ function createQueryBuilder(state) {
13745
13753
  where(expr, op, value) {
13746
13754
  const getWhereKeyword = () => SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
13747
13755
  if (typeof expr === "string" && op !== undefined) {
13756
+ validateIdentifier(String(expr), "where(column)");
13757
+ assertSafeWhereOperator(op, "where(operator)");
13748
13758
  const operator = String(op).toLowerCase();
13749
13759
  if (operator === "in" || operator === "not in") {
13750
13760
  const values = Array.isArray(value) ? value : [value];
@@ -13766,7 +13776,8 @@ function createQueryBuilder(state) {
13766
13776
  if (Array.isArray(expr)) {
13767
13777
  const [col, op2, val] = expr;
13768
13778
  const colName = String(col);
13769
- const operator = String(op2);
13779
+ validateIdentifier(colName, "where(column)");
13780
+ const operator = assertSafeWhereOperator(op2, "where(operator)");
13770
13781
  if (operator === "in" || operator === "not in") {
13771
13782
  const values = Array.isArray(val) ? val : [val];
13772
13783
  const placeholders = getPlaceholders(values.length, whereParams.length + 1);
@@ -13788,6 +13799,7 @@ function createQueryBuilder(state) {
13788
13799
  const keys = Object.keys(whereObject);
13789
13800
  const conditions = [];
13790
13801
  for (const key of keys) {
13802
+ validateIdentifier(key, "where(column)");
13791
13803
  const value2 = whereObject[key];
13792
13804
  if (Array.isArray(value2)) {
13793
13805
  const placeholders = getPlaceholders(value2.length, whereParams.length + 1);
@@ -13816,18 +13828,21 @@ function createQueryBuilder(state) {
13816
13828
  return this;
13817
13829
  },
13818
13830
  whereNull(column) {
13831
+ validateIdentifier(String(column), "whereNull(column)");
13819
13832
  const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
13820
13833
  text = `${text} ${keyword} ${String(column)} IS NULL`;
13821
13834
  built = null;
13822
13835
  return this;
13823
13836
  },
13824
13837
  whereNotNull(column) {
13838
+ validateIdentifier(String(column), "whereNotNull(column)");
13825
13839
  const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
13826
13840
  text = `${text} ${keyword} ${String(column)} IS NOT NULL`;
13827
13841
  built = null;
13828
13842
  return this;
13829
13843
  },
13830
13844
  whereBetween(column, start, end) {
13845
+ validateIdentifier(String(column), "whereBetween(column)");
13831
13846
  const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
13832
13847
  const i = whereParams.length + 1;
13833
13848
  text = `${text} ${keyword} ${String(column)} BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`;
@@ -13842,6 +13857,7 @@ function createQueryBuilder(state) {
13842
13857
  return this;
13843
13858
  },
13844
13859
  whereJsonContains(column, json) {
13860
+ validateIdentifier(String(column), "whereJsonContains(column)");
13845
13861
  const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
13846
13862
  const dialect = config5.dialect;
13847
13863
  const idx = whereParams.length + 1;
@@ -14011,6 +14027,7 @@ function createQueryBuilder(state) {
14011
14027
  return this;
14012
14028
  },
14013
14029
  whereNotBetween(column, start, end) {
14030
+ validateIdentifier(String(column), "whereNotBetween(column)");
14014
14031
  const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
14015
14032
  const i = whereParams.length + 1;
14016
14033
  text += ` ${keyword} ${column} NOT BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`;
@@ -14053,6 +14070,7 @@ function createQueryBuilder(state) {
14053
14070
  return this;
14054
14071
  },
14055
14072
  whereIn(column, values) {
14073
+ validateIdentifier(String(column), "whereIn(column)");
14056
14074
  const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
14057
14075
  if (Array.isArray(values)) {
14058
14076
  const placeholders = getPlaceholders(values.length, whereParams.length + 1);
@@ -14065,6 +14083,7 @@ function createQueryBuilder(state) {
14065
14083
  return this;
14066
14084
  },
14067
14085
  orWhereIn(column, values) {
14086
+ validateIdentifier(String(column), "orWhereIn(column)");
14068
14087
  if (Array.isArray(values)) {
14069
14088
  const placeholders = getPlaceholders(values.length, whereParams.length + 1);
14070
14089
  text += ` OR ${column} IN (${placeholders})`;
@@ -14076,6 +14095,7 @@ function createQueryBuilder(state) {
14076
14095
  return this;
14077
14096
  },
14078
14097
  whereNotIn(column, values) {
14098
+ validateIdentifier(String(column), "whereNotIn(column)");
14079
14099
  const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
14080
14100
  if (Array.isArray(values)) {
14081
14101
  const placeholders = getPlaceholders(values.length, whereParams.length + 1);
@@ -14088,6 +14108,7 @@ function createQueryBuilder(state) {
14088
14108
  return this;
14089
14109
  },
14090
14110
  orWhereNotIn(column, values) {
14111
+ validateIdentifier(String(column), "orWhereNotIn(column)");
14091
14112
  if (Array.isArray(values)) {
14092
14113
  const placeholders = getPlaceholders(values.length, whereParams.length + 1);
14093
14114
  text += ` OR ${column} NOT IN (${placeholders})`;
@@ -14113,6 +14134,8 @@ function createQueryBuilder(state) {
14113
14134
  },
14114
14135
  andWhere(expr, op, value) {
14115
14136
  if (typeof expr === "string" && op !== undefined) {
14137
+ validateIdentifier(String(expr), "andWhere(column)");
14138
+ assertSafeWhereOperator(op, "andWhere(operator)");
14116
14139
  const paramIndex = whereParams.length + 1;
14117
14140
  whereConditions.push(`${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`);
14118
14141
  whereParams.push(value);
@@ -14123,7 +14146,8 @@ function createQueryBuilder(state) {
14123
14146
  if (Array.isArray(expr)) {
14124
14147
  const [col, op2, val] = expr;
14125
14148
  const colName = String(col);
14126
- const operator = String(op2);
14149
+ validateIdentifier(colName, "andWhere(column)");
14150
+ const operator = assertSafeWhereOperator(op2, "andWhere(operator)");
14127
14151
  if (operator === "in" || operator === "not in") {
14128
14152
  const values = Array.isArray(val) ? val : [val];
14129
14153
  const placeholders = getPlaceholders(values.length, whereParams.length + 1);
@@ -14173,6 +14197,8 @@ function createQueryBuilder(state) {
14173
14197
  },
14174
14198
  orWhere(expr, op, value) {
14175
14199
  if (typeof expr === "string" && op !== undefined) {
14200
+ validateIdentifier(String(expr), "orWhere(column)");
14201
+ assertSafeWhereOperator(op, "orWhere(operator)");
14176
14202
  const paramIndex = whereParams.length + 1;
14177
14203
  whereConditions.push(`OR ${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`);
14178
14204
  whereParams.push(value);
@@ -14183,7 +14209,8 @@ function createQueryBuilder(state) {
14183
14209
  if (Array.isArray(expr)) {
14184
14210
  const [col, op2, val] = expr;
14185
14211
  const colName = String(col);
14186
- const operator = String(op2);
14212
+ validateIdentifier(colName, "orWhere(column)");
14213
+ const operator = assertSafeWhereOperator(op2, "orWhere(operator)");
14187
14214
  if (operator === "in" || operator === "not in") {
14188
14215
  const values = Array.isArray(val) ? val : [val];
14189
14216
  const placeholders = getPlaceholders(values.length, whereParams.length + 1);
@@ -14281,6 +14308,10 @@ function createQueryBuilder(state) {
14281
14308
  return this;
14282
14309
  },
14283
14310
  join(table2, onLeft, operator, onRight) {
14311
+ validateIdentifier(table2, "join(table)");
14312
+ validateQualifiedIdentifier(onLeft, "join(onLeft)");
14313
+ validateQualifiedIdentifier(onRight, "join(onRight)");
14314
+ assertSafeWhereOperator(operator, "join(operator)");
14284
14315
  insertJoin(`JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
14285
14316
  joinedTables.add(table2);
14286
14317
  return this;
@@ -14295,31 +14326,49 @@ function createQueryBuilder(state) {
14295
14326
  return this;
14296
14327
  },
14297
14328
  innerJoin(table2, onLeft, operator, onRight) {
14329
+ validateIdentifier(table2, "innerJoin(table)");
14330
+ validateQualifiedIdentifier(onLeft, "innerJoin(onLeft)");
14331
+ validateQualifiedIdentifier(onRight, "innerJoin(onRight)");
14332
+ assertSafeWhereOperator(operator, "innerJoin(operator)");
14298
14333
  insertJoin(`INNER JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
14299
14334
  joinedTables.add(table2);
14300
14335
  return this;
14301
14336
  },
14302
14337
  leftJoin(table2, onLeft, operator, onRight) {
14338
+ validateIdentifier(table2, "leftJoin(table)");
14339
+ validateQualifiedIdentifier(onLeft, "leftJoin(onLeft)");
14340
+ validateQualifiedIdentifier(onRight, "leftJoin(onRight)");
14341
+ assertSafeWhereOperator(operator, "leftJoin(operator)");
14303
14342
  insertJoin(`LEFT JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
14304
14343
  joinedTables.add(table2);
14305
14344
  return this;
14306
14345
  },
14307
14346
  leftJoinSub(sub, alias, onLeft, operator, onRight) {
14347
+ validateIdentifier(alias, "leftJoinSub(alias)");
14348
+ validateQualifiedIdentifier(onLeft, "leftJoinSub(onLeft)");
14349
+ validateQualifiedIdentifier(onRight, "leftJoinSub(onRight)");
14350
+ assertSafeWhereOperator(operator, "leftJoinSub(operator)");
14308
14351
  insertJoin(`LEFT JOIN (${String(sub.toSQL())}) AS ${alias} ON ${onLeft} ${operator} ${onRight}`);
14309
14352
  joinedTables.add(alias);
14310
14353
  return this;
14311
14354
  },
14312
14355
  rightJoin(table2, onLeft, operator, onRight) {
14356
+ validateIdentifier(table2, "rightJoin(table)");
14357
+ validateQualifiedIdentifier(onLeft, "rightJoin(onLeft)");
14358
+ validateQualifiedIdentifier(onRight, "rightJoin(onRight)");
14359
+ assertSafeWhereOperator(operator, "rightJoin(operator)");
14313
14360
  insertJoin(`RIGHT JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
14314
14361
  joinedTables.add(table2);
14315
14362
  return this;
14316
14363
  },
14317
14364
  crossJoin(table2) {
14365
+ validateIdentifier(table2, "crossJoin(table)");
14318
14366
  insertJoin(`CROSS JOIN ${table2}`);
14319
14367
  joinedTables.add(table2);
14320
14368
  return this;
14321
14369
  },
14322
14370
  crossJoinSub(sub, alias) {
14371
+ validateIdentifier(alias, "crossJoinSub(alias)");
14323
14372
  insertJoin(`CROSS JOIN (${String(sub.toSQL())}) AS ${alias}`);
14324
14373
  joinedTables.add(alias);
14325
14374
  return this;
@@ -14679,17 +14728,15 @@ function createQueryBuilder(state) {
14679
14728
  addWhereText("WHERE", `${String(col)} IS ${onlyTrashed ? "NOT " : ""}NULL`);
14680
14729
  }
14681
14730
  }
14731
+ const cacheKey = useCache ? `${String(finalQuery)}\x00${JSON.stringify(whereParams)}` : "";
14682
14732
  if (useCache) {
14683
- const cacheKey = String(finalQuery);
14684
14733
  const cached = queryCache.get(cacheKey);
14685
14734
  if (cached)
14686
14735
  return cached;
14687
14736
  }
14688
14737
  const result = await runWithHooks(finalQuery, "select", { signal: abortSignal, timeoutMs });
14689
- if (useCache) {
14690
- const cacheKey = String(finalQuery);
14738
+ if (useCache)
14691
14739
  queryCache.set(cacheKey, result, cacheTtl);
14692
- }
14693
14740
  return hydratePivotRows(result);
14694
14741
  },
14695
14742
  async executeTakeFirst() {
@@ -16251,7 +16298,7 @@ var init_cache = __esm(() => {
16251
16298
  });
16252
16299
 
16253
16300
  // src/actions/console.ts
16254
- import process19 from "process";
16301
+ import process21 from "process";
16255
16302
  import { createInterface } from "readline";
16256
16303
  async function startConsole() {
16257
16304
  console.log("-- Query Builder Interactive Console");
@@ -16260,8 +16307,8 @@ async function startConsole() {
16260
16307
  console.log();
16261
16308
  const qb = createQueryBuilder();
16262
16309
  const rl = createInterface({
16263
- input: process19.stdin,
16264
- output: process19.stdout,
16310
+ input: process21.stdin,
16311
+ output: process21.stdout,
16265
16312
  prompt: "qb> "
16266
16313
  });
16267
16314
  let multilineBuffer = "";
@@ -16312,7 +16359,7 @@ Tips:
16312
16359
  if (cmd === ".exit" || cmd === ".quit") {
16313
16360
  console.log("Goodbye!");
16314
16361
  rl.close();
16315
- process19.exit(0);
16362
+ process21.exit(0);
16316
16363
  } else if (cmd === ".help") {
16317
16364
  console.log(helpText);
16318
16365
  } else if (cmd === ".clear") {
@@ -16383,7 +16430,7 @@ Tips:
16383
16430
  rl.on("close", () => {
16384
16431
  console.log(`
16385
16432
  Goodbye!`);
16386
- process19.exit(0);
16433
+ process21.exit(0);
16387
16434
  });
16388
16435
  rl.prompt();
16389
16436
  }
@@ -16761,9 +16808,9 @@ var init_db_info = __esm(() => {
16761
16808
  });
16762
16809
 
16763
16810
  // src/actions/db-optimize.ts
16764
- import process21 from "process";
16811
+ import process22 from "process";
16765
16812
  async function dbOptimize(options = {}) {
16766
- const dialect = options.dialect || process21.env.DB_DIALECT || "postgres";
16813
+ const dialect = options.dialect || process22.env.DB_DIALECT || "postgres";
16767
16814
  const aggressive = options.aggressive || false;
16768
16815
  if (options.verbose) {
16769
16816
  console.log(`Optimizing ${dialect} database${aggressive ? " (aggressive mode)" : ""}...`);
@@ -16803,7 +16850,7 @@ async function dbOptimize(options = {}) {
16803
16850
  await bunSql`ANALYZE TABLE ${bunSql(table)}`;
16804
16851
  }
16805
16852
  } else {
16806
- const dbName = process21.env.DB_NAME || "test";
16853
+ const dbName = process22.env.DB_NAME || "test";
16807
16854
  const tables = await bunSql`
16808
16855
  SELECT table_name
16809
16856
  FROM information_schema.tables
@@ -16855,9 +16902,9 @@ var init_db_optimize = __esm(() => {
16855
16902
  });
16856
16903
 
16857
16904
  // src/actions/db-wipe.ts
16858
- import process22 from "process";
16905
+ import process23 from "process";
16859
16906
  async function dbWipe(options = {}) {
16860
- const dialect = options.dialect || process22.env.DB_DIALECT || "postgres";
16907
+ const dialect = options.dialect || process23.env.DB_DIALECT || "postgres";
16861
16908
  if (options.verbose) {
16862
16909
  console.log(`Wiping all tables from ${dialect} database...`);
16863
16910
  }
@@ -16871,7 +16918,7 @@ async function dbWipe(options = {}) {
16871
16918
  `;
16872
16919
  tables = result.map((row) => row.tablename);
16873
16920
  } else if (dialect === "mysql") {
16874
- const dbName = process22.env.DB_NAME || "test";
16921
+ const dbName = process23.env.DB_NAME || "test";
16875
16922
  const result = await bunSql`
16876
16923
  SELECT table_name
16877
16924
  FROM information_schema.tables
@@ -17287,7 +17334,7 @@ var init_introspect_db = __esm(() => {
17287
17334
  // src/actions/make-model.ts
17288
17335
  import { existsSync as existsSync14, mkdirSync as mkdirSync5, writeFileSync as writeFileSync10 } from "fs";
17289
17336
  import { dirname as dirname5, join as join7 } from "path";
17290
- import process23 from "process";
17337
+ import process24 from "process";
17291
17338
  function findWorkspaceRoot(startPath) {
17292
17339
  let currentPath = startPath;
17293
17340
  while (currentPath !== dirname5(currentPath)) {
@@ -17296,10 +17343,10 @@ function findWorkspaceRoot(startPath) {
17296
17343
  }
17297
17344
  currentPath = dirname5(currentPath);
17298
17345
  }
17299
- return process23.cwd();
17346
+ return process24.cwd();
17300
17347
  }
17301
17348
  async function makeModel(name, options = {}) {
17302
- const workspaceRoot = findWorkspaceRoot(process23.cwd());
17349
+ const workspaceRoot = findWorkspaceRoot(process24.cwd());
17303
17350
  const modelsDir = options.dir || join7(workspaceRoot, "app/Models");
17304
17351
  if (!existsSync14(modelsDir)) {
17305
17352
  mkdirSync5(modelsDir, { recursive: true });
@@ -17856,7 +17903,7 @@ __export(exports_migrate, {
17856
17903
  import { existsSync as existsSync16, mkdirSync as mkdirSync7, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
17857
17904
  import { tmpdir } from "os";
17858
17905
  import { join as join9 } from "path";
17859
- import process24 from "process";
17906
+ import process25 from "process";
17860
17907
  function info(message) {
17861
17908
  if (config5.verbose)
17862
17909
  console.log(message);
@@ -17903,7 +17950,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
17903
17950
  info(`-- Model snapshot saved to ${snapshotPath}`);
17904
17951
  }
17905
17952
  function getWorkspaceRoot() {
17906
- return process24.cwd();
17953
+ return process25.cwd();
17907
17954
  }
17908
17955
  function ensureSqlDirectory(workspaceRoot) {
17909
17956
  const sqlDir = getSqlDirectory(workspaceRoot);
@@ -17915,7 +17962,7 @@ function ensureSqlDirectory(workspaceRoot) {
17915
17962
  }
17916
17963
  async function generateMigration(dir, opts = {}) {
17917
17964
  if (!dir) {
17918
- dir = join9(process24.cwd(), "app/Models");
17965
+ dir = join9(process25.cwd(), "app/Models");
17919
17966
  }
17920
17967
  const dialect = opts.dialect || config5.dialect || "postgres";
17921
17968
  const workspaceRoot = getWorkspaceRoot();
@@ -17970,7 +18017,7 @@ async function generateMigration(dir, opts = {}) {
17970
18017
  }
17971
18018
  async function executeMigration(dir) {
17972
18019
  if (!dir) {
17973
- dir = join9(process24.cwd(), "app/Models");
18020
+ dir = join9(process25.cwd(), "app/Models");
17974
18021
  }
17975
18022
  const workspaceRoot = getWorkspaceRoot();
17976
18023
  const sqlDir = ensureSqlDirectory(workspaceRoot);
@@ -18035,7 +18082,7 @@ async function executeMigration(dir) {
18035
18082
  }
18036
18083
  async function resetDatabase(dir, opts = {}) {
18037
18084
  if (!dir) {
18038
- dir = join9(process24.cwd(), "app/Models");
18085
+ dir = join9(process25.cwd(), "app/Models");
18039
18086
  }
18040
18087
  const dialect = opts.dialect || "postgres";
18041
18088
  const driver = getDialectDriver(dialect);
@@ -18128,7 +18175,7 @@ async function resetDatabase(dir, opts = {}) {
18128
18175
  }
18129
18176
  async function deleteMigrationFiles(dir, workspaceRoot, opts = {}) {
18130
18177
  if (!dir) {
18131
- dir = join9(process24.cwd(), "app/Models");
18178
+ dir = join9(process25.cwd(), "app/Models");
18132
18179
  }
18133
18180
  if (!workspaceRoot) {
18134
18181
  workspaceRoot = getWorkspaceRoot();
@@ -18228,7 +18275,7 @@ var init_migrate_generate = __esm(() => {
18228
18275
  // src/actions/migrate-rollback.ts
18229
18276
  import { existsSync as existsSync17, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
18230
18277
  import { dirname as dirname7, join as join10 } from "path";
18231
- import process25 from "process";
18278
+ import process26 from "process";
18232
18279
  function splitSqlStatements2(sql) {
18233
18280
  const out = [];
18234
18281
  let buf = "";
@@ -18279,11 +18326,11 @@ function findWorkspaceRoot2(startPath) {
18279
18326
  }
18280
18327
  currentPath = dirname7(currentPath);
18281
18328
  }
18282
- return process25.cwd();
18329
+ return process26.cwd();
18283
18330
  }
18284
18331
  function getSqlDirectory2(workspaceRoot) {
18285
18332
  if (!workspaceRoot) {
18286
- workspaceRoot = findWorkspaceRoot2(process25.cwd());
18333
+ workspaceRoot = findWorkspaceRoot2(process26.cwd());
18287
18334
  }
18288
18335
  return join10(workspaceRoot, "database", "migrations");
18289
18336
  }
@@ -18366,7 +18413,7 @@ var init_migrate_rollback = __esm(() => {
18366
18413
  // src/actions/migrate-status.ts
18367
18414
  import { existsSync as existsSync18, readdirSync as readdirSync8 } from "fs";
18368
18415
  import { dirname as dirname8, join as join11 } from "path";
18369
- import process26 from "process";
18416
+ import process27 from "process";
18370
18417
  function findWorkspaceRoot3(startPath) {
18371
18418
  let currentPath = startPath;
18372
18419
  while (currentPath !== dirname8(currentPath)) {
@@ -18375,11 +18422,11 @@ function findWorkspaceRoot3(startPath) {
18375
18422
  }
18376
18423
  currentPath = dirname8(currentPath);
18377
18424
  }
18378
- return process26.cwd();
18425
+ return process27.cwd();
18379
18426
  }
18380
18427
  function getSqlDirectory3(workspaceRoot) {
18381
18428
  if (!workspaceRoot) {
18382
- workspaceRoot = findWorkspaceRoot3(process26.cwd());
18429
+ workspaceRoot = findWorkspaceRoot3(process27.cwd());
18383
18430
  }
18384
18431
  return join11(workspaceRoot, "database", "migrations");
18385
18432
  }
@@ -18473,9 +18520,9 @@ var init_migrate_status = __esm(() => {
18473
18520
  // src/actions/model-show.ts
18474
18521
  import { readdirSync as readdirSync9 } from "fs";
18475
18522
  import { extname as extname2, join as join12 } from "path";
18476
- import process27 from "process";
18523
+ import process28 from "process";
18477
18524
  async function modelShow(modelName, options = {}) {
18478
- const dir = options.dir || join12(process27.cwd(), "app/Models");
18525
+ const dir = options.dir || join12(process28.cwd(), "app/Models");
18479
18526
  try {
18480
18527
  const files = readdirSync9(dir);
18481
18528
  const modelFile = files.find((f) => {
@@ -18689,9 +18736,9 @@ var init_query_explain_all = __esm(() => {
18689
18736
  // src/actions/relation-diagram.ts
18690
18737
  import { writeFileSync as writeFileSync12 } from "fs";
18691
18738
  import { join as join14 } from "path";
18692
- import process28 from "process";
18739
+ import process29 from "process";
18693
18740
  async function relationDiagram(options = {}) {
18694
- const dir = options.dir || join14(process28.cwd(), "app/Models");
18741
+ const dir = options.dir || join14(process29.cwd(), "app/Models");
18695
18742
  const format = options.format || "mermaid";
18696
18743
  try {
18697
18744
  const models = await loadModels({ modelsDir: dir });
@@ -18813,7 +18860,7 @@ var init_relation_diagram = __esm(() => {
18813
18860
  // src/actions/seed.ts
18814
18861
  import { existsSync as existsSync19, mkdirSync as mkdirSync8, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
18815
18862
  import { dirname as dirname9, join as join15 } from "path";
18816
- import process29 from "process";
18863
+ import process30 from "process";
18817
18864
  function findWorkspaceRoot4(startPath) {
18818
18865
  let currentPath = startPath;
18819
18866
  while (currentPath !== dirname9(currentPath)) {
@@ -18822,7 +18869,7 @@ function findWorkspaceRoot4(startPath) {
18822
18869
  }
18823
18870
  currentPath = dirname9(currentPath);
18824
18871
  }
18825
- return process29.cwd();
18872
+ return process30.cwd();
18826
18873
  }
18827
18874
  async function loadSeeders(seedersDir) {
18828
18875
  if (!existsSync19(seedersDir)) {
@@ -18854,7 +18901,7 @@ async function loadSeeders(seedersDir) {
18854
18901
  return seeders;
18855
18902
  }
18856
18903
  async function runSeeders(config6 = {}) {
18857
- const workspaceRoot = findWorkspaceRoot4(process29.cwd());
18904
+ const workspaceRoot = findWorkspaceRoot4(process30.cwd());
18858
18905
  const seedersDir = config6.seedersDir || join15(workspaceRoot, "database/seeders");
18859
18906
  const verbose = config6.verbose ?? true;
18860
18907
  if (verbose) {
@@ -18889,7 +18936,7 @@ async function runSeeders(config6 = {}) {
18889
18936
  }
18890
18937
  }
18891
18938
  async function runSeeder(className, options = {}) {
18892
- const workspaceRoot = findWorkspaceRoot4(process29.cwd());
18939
+ const workspaceRoot = findWorkspaceRoot4(process30.cwd());
18893
18940
  const seedersDir = join15(workspaceRoot, "database/seeders");
18894
18941
  const verbose = options.verbose ?? true;
18895
18942
  if (verbose) {
@@ -18913,7 +18960,7 @@ async function runSeeder(className, options = {}) {
18913
18960
  }
18914
18961
  }
18915
18962
  async function makeSeeder(name) {
18916
- const workspaceRoot = findWorkspaceRoot4(process29.cwd());
18963
+ const workspaceRoot = findWorkspaceRoot4(process30.cwd());
18917
18964
  const seedersDir = join15(workspaceRoot, "database/seeders");
18918
18965
  if (!existsSync19(seedersDir)) {
18919
18966
  mkdirSync8(seedersDir, { recursive: true });
@@ -18977,7 +19024,7 @@ export default class ${className} extends Seeder {
18977
19024
  console.log(`-- \u2713 Created seeder: ${filePath}`);
18978
19025
  }
18979
19026
  async function freshDatabase(options = {}) {
18980
- const workspaceRoot = findWorkspaceRoot4(process29.cwd());
19027
+ const workspaceRoot = findWorkspaceRoot4(process30.cwd());
18981
19028
  const modelsDir = options.modelsDir || join15(workspaceRoot, "app/Models");
18982
19029
  const seedersDir = options.seedersDir || join15(workspaceRoot, "database/seeders");
18983
19030
  const verbose = options.verbose ?? true;
@@ -19039,7 +19086,7 @@ var init_unsafe = __esm(() => {
19039
19086
  // src/actions/validate.ts
19040
19087
  import { existsSync as existsSync20 } from "fs";
19041
19088
  import { dirname as dirname10, join as join16 } from "path";
19042
- import process30 from "process";
19089
+ import process31 from "process";
19043
19090
  function findWorkspaceRoot5(startPath) {
19044
19091
  let currentPath = startPath;
19045
19092
  while (currentPath !== dirname10(currentPath)) {
@@ -19048,11 +19095,11 @@ function findWorkspaceRoot5(startPath) {
19048
19095
  }
19049
19096
  currentPath = dirname10(currentPath);
19050
19097
  }
19051
- return process30.cwd();
19098
+ return process31.cwd();
19052
19099
  }
19053
19100
  async function validateSchema(dir) {
19054
19101
  if (!dir) {
19055
- dir = join16(findWorkspaceRoot5(process30.cwd()), "app/Models");
19102
+ dir = join16(findWorkspaceRoot5(process31.cwd()), "app/Models");
19056
19103
  }
19057
19104
  const dialect = config5.dialect || "postgres";
19058
19105
  console.log("-- Validating Schema");
@@ -23754,6 +23801,13 @@ function assertValidIdentifier(name, context) {
23754
23801
  if (!SAFE_SQL_IDENTIFIER.test(name))
23755
23802
  throw new TypeError(`[bun-query-builder] ${context}: identifier '${name}' contains characters outside [A-Za-z0-9_] \u2014 refusing to interpolate into SQL`);
23756
23803
  }
23804
+ function assertValidOrderByColumn(name, context) {
23805
+ if (typeof name !== "string" || name.length === 0)
23806
+ throw new TypeError(`[bun-query-builder] ${context}: identifier must be a non-empty string, got ${typeof name}`);
23807
+ const parts = name.split(".");
23808
+ if (parts.length > 2 || parts.some((p2) => p2.length === 0 || p2.length > 64 || !SAFE_SQL_IDENTIFIER.test(p2)))
23809
+ throw new TypeError(`[bun-query-builder] ${context}: invalid ORDER BY column '${name}' \u2014 expected 'column' or 'table.column' of [A-Za-z0-9_] \u2014 refusing to interpolate into SQL`);
23810
+ }
23757
23811
  function getModelFromRegistry(name) {
23758
23812
  if (!_getModel) {
23759
23813
  try {
@@ -24042,12 +24096,16 @@ class ModelInstance {
24042
24096
  for (const [key, value] of Object.entries(data)) {
24043
24097
  const attr = attrs[key];
24044
24098
  if (attr?.fillable && !attr?.guarded) {
24099
+ if (this._original === null)
24100
+ this._original = { ...this._attributes };
24045
24101
  this._attributes[key] = value;
24046
24102
  }
24047
24103
  }
24048
24104
  return this;
24049
24105
  }
24050
24106
  forceFill(data) {
24107
+ if (this._original === null)
24108
+ this._original = { ...this._attributes };
24051
24109
  Object.assign(this._attributes, data);
24052
24110
  return this;
24053
24111
  }
@@ -24443,7 +24501,7 @@ class BelongsToManyRelationBuilder {
24443
24501
  return this;
24444
24502
  }
24445
24503
  orderBy(column, direction = "asc") {
24446
- assertValidIdentifier(column, "orderBy(column)");
24504
+ assertValidOrderByColumn(column, "orderBy(column)");
24447
24505
  if (direction !== "asc" && direction !== "desc")
24448
24506
  throw new TypeError(`[bun-query-builder] orderBy(direction): expected 'asc' or 'desc', got '${direction}'`);
24449
24507
  this._orderBy.push(`${column} ${direction.toUpperCase()}`);
@@ -24784,7 +24842,7 @@ class ModelQueryBuilder {
24784
24842
  return this;
24785
24843
  }
24786
24844
  orderBy(column, direction = "asc") {
24787
- assertValidIdentifier(column, "orderBy(column)");
24845
+ assertValidOrderByColumn(column, "orderBy(column)");
24788
24846
  if (direction !== "asc" && direction !== "desc")
24789
24847
  throw new TypeError(`[bun-query-builder] orderBy(direction): expected 'asc' or 'desc', got '${direction}'`);
24790
24848
  this._orderBy.push({ column, direction });
@@ -24885,6 +24943,8 @@ class ModelQueryBuilder {
24885
24943
  let rel = relationCache.get(cacheKey);
24886
24944
  if (rel === undefined) {
24887
24945
  rel = resolveRelation(this._definition, relationName);
24946
+ if (relationCache.size >= RELATION_CACHE_MAX)
24947
+ relationCache.clear();
24888
24948
  relationCache.set(cacheKey, rel);
24889
24949
  }
24890
24950
  if (!rel)
@@ -24921,8 +24981,13 @@ class ModelQueryBuilder {
24921
24981
  }
24922
24982
  }
24923
24983
  if (rel.type === "belongsTo") {
24924
- const fkValues = instances.map((i2) => i2._attributes[rel.foreignKey]).filter((v2) => v2 != null);
24925
- const uniqueFkValues = [...new Set(fkValues)];
24984
+ const fkSet = new Set;
24985
+ for (const i2 of instances) {
24986
+ const v2 = i2._attributes[rel.foreignKey];
24987
+ if (v2 != null)
24988
+ fkSet.add(v2);
24989
+ }
24990
+ const uniqueFkValues = [...fkSet];
24926
24991
  if (uniqueFkValues.length === 0)
24927
24992
  continue;
24928
24993
  const placeholders = uniqueFkValues.map(() => "?").join(", ");
@@ -24952,7 +25017,13 @@ class ModelQueryBuilder {
24952
25017
  instance.setRelation(relationName, []);
24953
25018
  continue;
24954
25019
  }
24955
- const relatedIds = [...new Set(pivotRows.map((p2) => p2[rel.pivotFkRelated]))].filter((v2) => v2 != null);
25020
+ const relatedIdSet = new Set;
25021
+ for (const p2 of pivotRows) {
25022
+ const v2 = p2[rel.pivotFkRelated];
25023
+ if (v2 != null)
25024
+ relatedIdSet.add(v2);
25025
+ }
25026
+ const relatedIds = [...relatedIdSet];
24956
25027
  const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
24957
25028
  const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
24958
25029
  const relatedPk = relDef?.primaryKey || "id";
@@ -25402,7 +25473,7 @@ async function seedModel(definition, count, faker) {
25402
25473
  await exec.run(`INSERT INTO ${definition.table} (${columns.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`, Object.values(data));
25403
25474
  }
25404
25475
  }
25405
- var SAFE_SQL_IDENTIFIER, _getModel = null, globalDb = null, _executor = null, _executorForDb = null, _executorDialect = null, _executorDatabase = null, SOFT_DELETE_COLUMN = "deleted_at", BTM_RELATED_ALIAS = "__btm_rel__", snakeCaseCache, tableNameCache, relationCache;
25476
+ var SAFE_SQL_IDENTIFIER, _getModel = null, globalDb = null, _executor = null, _executorForDb = null, _executorDialect = null, _executorDatabase = null, SOFT_DELETE_COLUMN = "deleted_at", BTM_RELATED_ALIAS = "__btm_rel__", snakeCaseCache, tableNameCache, relationCache, RELATION_CACHE_MAX = 1000;
25406
25477
  var init_orm = __esm(() => {
25407
25478
  init_config();
25408
25479
  init_db();
@@ -26858,9 +26929,9 @@ function buildDatabaseSchema(models) {
26858
26929
  // src/loader.ts
26859
26930
  import { readdirSync as readdirSync12, statSync as statSync5 } from "fs";
26860
26931
  import { basename, extname as extname4 } from "path";
26861
- import process31 from "process";
26932
+ import process33 from "process";
26862
26933
  async function loadModels(options) {
26863
- const cwd = options.cwd ?? process31.cwd();
26934
+ const cwd = options.cwd ?? process33.cwd();
26864
26935
  const dir = options.modelsDir.startsWith("/") ? options.modelsDir : `${cwd}/${options.modelsDir}`;
26865
26936
  const result = {};
26866
26937
  const entries = readdirSync12(dir);
@@ -26990,7 +27061,7 @@ var init_meta = () => {};
26990
27061
  // src/migrations.ts
26991
27062
  import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync14 } from "fs";
26992
27063
  import { dirname as dirname11, join as join17 } from "path";
26993
- import process33 from "process";
27064
+ import process35 from "process";
26994
27065
  function info2(message) {
26995
27066
  if (config5.verbose)
26996
27067
  console.log(message);
@@ -27006,10 +27077,10 @@ function findWorkspaceRoot6(startPath) {
27006
27077
  }
27007
27078
  currentPath = dirname11(currentPath);
27008
27079
  }
27009
- return process33.cwd();
27080
+ return process35.cwd();
27010
27081
  }
27011
27082
  function ensureSqlDirectory2() {
27012
- const workspaceRoot = findWorkspaceRoot6(process33.cwd());
27083
+ const workspaceRoot = findWorkspaceRoot6(process35.cwd());
27013
27084
  const sqlDir = join17(workspaceRoot, "database", "migrations");
27014
27085
  if (!existsSync21(sqlDir)) {
27015
27086
  mkdirSync9(sqlDir, { recursive: true });