bun-query-builder 0.1.41 → 0.1.45

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/bin/cli.js CHANGED
@@ -11640,6 +11640,9 @@ var init_dist = __esm(() => {
11640
11640
  });
11641
11641
 
11642
11642
  // src/config.ts
11643
+ function isMysqlLike(dialect = config5.dialect) {
11644
+ return dialect === "mysql" || dialect === "singlestore";
11645
+ }
11643
11646
  function getPlaceholder(index) {
11644
11647
  if (config5.dialect === "postgres") {
11645
11648
  return `$${index}`;
@@ -11760,16 +11763,46 @@ var init_config = __esm(() => {
11760
11763
  _warnedDialectConflicts = new Set;
11761
11764
  });
11762
11765
 
11766
+ // src/sqlite-pragmas.ts
11767
+ function resolveSqlitePragmas() {
11768
+ const custom = config5.sqlite?.pragmas;
11769
+ return Array.isArray(custom) ? custom : DEFAULT_SQLITE_PRAGMAS;
11770
+ }
11771
+ function applySqliteBootstrapPragmas(db) {
11772
+ for (const pragma of resolveSqlitePragmas()) {
11773
+ try {
11774
+ db.run(pragma);
11775
+ } catch {}
11776
+ }
11777
+ }
11778
+ var DEFAULT_SQLITE_PRAGMAS;
11779
+ var init_sqlite_pragmas = __esm(() => {
11780
+ init_config();
11781
+ DEFAULT_SQLITE_PRAGMAS = [
11782
+ "PRAGMA journal_mode = WAL",
11783
+ "PRAGMA foreign_keys = ON",
11784
+ "PRAGMA busy_timeout = 5000"
11785
+ ];
11786
+ });
11787
+
11763
11788
  // src/db.ts
11764
11789
  var {SQL } = globalThis.Bun;
11765
11790
  import { Database } from "bun:sqlite";
11791
+ import { mkdirSync as mkdirSync5 } from "fs";
11792
+ import { dirname as dirname5 } from "path";
11766
11793
  import process19 from "process";
11767
11794
 
11768
11795
  class SQLiteWrapper {
11769
11796
  db;
11770
11797
  constructor(filename) {
11798
+ if (filename !== ":memory:" && !filename.startsWith(":")) {
11799
+ const dir = dirname5(filename);
11800
+ if (dir && dir !== ".") {
11801
+ mkdirSync5(dir, { recursive: true });
11802
+ }
11803
+ }
11771
11804
  this.db = new Database(filename);
11772
- this.db.run("PRAGMA journal_mode = WAL");
11805
+ applySqliteBootstrapPragmas(this.db);
11773
11806
  }
11774
11807
  query(sql, params = []) {
11775
11808
  const stmt = this.db.prepare(sql);
@@ -11793,6 +11826,21 @@ function createRawMarker(value) {
11793
11826
  toString: () => value
11794
11827
  };
11795
11828
  }
11829
+ function stripLeadingComments(segment) {
11830
+ let s = segment.trimStart();
11831
+ for (;; ) {
11832
+ if (s.startsWith("--")) {
11833
+ const nl = s.indexOf(`
11834
+ `);
11835
+ s = nl === -1 ? "" : s.slice(nl + 1).trimStart();
11836
+ } else if (s.startsWith("/*")) {
11837
+ const end = s.indexOf("*/");
11838
+ s = end === -1 ? "" : s.slice(end + 2).trimStart();
11839
+ } else {
11840
+ return s;
11841
+ }
11842
+ }
11843
+ }
11796
11844
  function splitSqlStatements(sql) {
11797
11845
  const statements = [];
11798
11846
  let current = "";
@@ -11845,18 +11893,18 @@ function splitSqlStatements(sql) {
11845
11893
  continue;
11846
11894
  }
11847
11895
  if (char === ";" && !inSingleQuote && !inDoubleQuote) {
11848
- const trimmed2 = current.trim();
11849
- if (trimmed2 && !trimmed2.startsWith("--")) {
11850
- statements.push(trimmed2);
11896
+ const sql2 = stripLeadingComments(current.trim());
11897
+ if (sql2) {
11898
+ statements.push(sql2);
11851
11899
  }
11852
11900
  current = "";
11853
11901
  continue;
11854
11902
  }
11855
11903
  current += char;
11856
11904
  }
11857
- const trimmed = current.trim();
11858
- if (trimmed && !trimmed.startsWith("--")) {
11859
- statements.push(trimmed);
11905
+ const tail = stripLeadingComments(current.trim());
11906
+ if (tail) {
11907
+ statements.push(tail);
11860
11908
  }
11861
11909
  return statements;
11862
11910
  }
@@ -12014,7 +12062,7 @@ function createSQLiteSQL(filename) {
12014
12062
  return sqlFunction;
12015
12063
  }
12016
12064
  function createConnectionString(dialect, dbConfig) {
12017
- if ((dialect === "postgres" || dialect === "mysql") && process19.env.DB_CONNECTION === dialect) {
12065
+ if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") && process19.env.DB_CONNECTION === dialect) {
12018
12066
  const e = process19.env;
12019
12067
  const envDb = (e.DB_DATABASE || dbConfig.database || "").replace(/^['"]|['"]$/g, "");
12020
12068
  const envUser = e.DB_USERNAME || dbConfig.username;
@@ -12022,17 +12070,20 @@ function createConnectionString(dialect, dbConfig) {
12022
12070
  const envHost = e.DB_HOST || dbConfig.host || "localhost";
12023
12071
  const envPort = e.DB_PORT || dbConfig.port;
12024
12072
  const scheme = dialect === "postgres" ? "postgres" : "mysql";
12025
- return `${scheme}://${envUser}:${envPass}@${envHost}${envPort ? `:${envPort}` : ""}/${envDb}`;
12073
+ const ssl2 = e.DB_SSL === "true" || e.DB_SSL === "1" || dbConfig.ssl ? "?ssl=true" : "";
12074
+ return `${scheme}://${envUser}:${envPass}@${envHost}${envPort ? `:${envPort}` : ""}/${envDb}${ssl2}`;
12026
12075
  }
12027
12076
  if (dbConfig.url) {
12028
12077
  return dbConfig.url;
12029
12078
  }
12030
- const { database, username, password, host = "localhost", port } = dbConfig;
12079
+ const { database, username, password, host = "localhost", port, ssl } = dbConfig;
12080
+ const sslQ = ssl || process19.env.DB_SSL === "true" || process19.env.DB_SSL === "1" ? "?ssl=true" : "";
12031
12081
  switch (dialect) {
12032
12082
  case "postgres":
12033
- return `postgres://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}`;
12083
+ return `postgres://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}${sslQ}`;
12034
12084
  case "mysql":
12035
- return `mysql://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}`;
12085
+ case "singlestore":
12086
+ return `mysql://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}${sslQ}`;
12036
12087
  case "sqlite":
12037
12088
  if (database === ":memory:") {
12038
12089
  return ":memory:";
@@ -12132,6 +12183,7 @@ function createLazyBunSql() {
12132
12183
  var _bunSqlInstance = null, _currentSignature = null, bunSql;
12133
12184
  var init_db = __esm(() => {
12134
12185
  init_config();
12186
+ init_sqlite_pragmas();
12135
12187
  bunSql = createLazyBunSql();
12136
12188
  });
12137
12189
 
@@ -12391,7 +12443,7 @@ function raw(strings, ...values) {
12391
12443
  return { raw: out };
12392
12444
  }
12393
12445
  function quoteInsertIdent(id) {
12394
- return config5.dialect === "mysql" ? `\`${id.replace(/`/g, "``")}\`` : `"${id.replace(/"/g, '""')}"`;
12446
+ return isMysqlLike(config5.dialect) ? `\`${id.replace(/`/g, "``")}\`` : `"${id.replace(/"/g, '""')}"`;
12395
12447
  }
12396
12448
  function buildInsertClause(rows, startIndex = 1) {
12397
12449
  const cols = Object.keys(rows[0] ?? {});
@@ -13991,7 +14043,7 @@ function createQueryBuilder(state) {
13991
14043
  else
13992
14044
  text += ` ${keyword} ${column} @> ${getPlaceholder(idx)}`;
13993
14045
  whereParams.push(JSON.stringify(json));
13994
- } else if (dialect === "mysql") {
14046
+ } else if (isMysqlLike(dialect)) {
13995
14047
  text += ` ${keyword} JSON_CONTAINS(${column}, ${getPlaceholder(idx)})`;
13996
14048
  whereParams.push(JSON.stringify(json));
13997
14049
  } else {
@@ -14021,7 +14073,7 @@ function createQueryBuilder(state) {
14021
14073
  const idx = whereParams.length + 1;
14022
14074
  if (dialect === "postgres") {
14023
14075
  text += ` ${keyword} ${path} ${op} ${getPlaceholder(idx)}`;
14024
- } else if (dialect === "mysql") {
14076
+ } else if (isMysqlLike(dialect)) {
14025
14077
  text += ` ${keyword} JSON_EXTRACT(${path}) ${op} ${getPlaceholder(idx)}`;
14026
14078
  } else {
14027
14079
  text += ` ${keyword} json_extract(${path}) ${op} ${getPlaceholder(idx)}`;
@@ -15380,7 +15432,7 @@ function createQueryBuilder(state) {
15380
15432
  let sqlText = "";
15381
15433
  const params = [];
15382
15434
  const isPostgres = config5.dialect === "postgres";
15383
- const quoteId = isPostgres ? (id) => `"${String(id).replace(/"/g, '""')}"` : config5.dialect === "mysql" ? (id) => `\`${String(id).replace(/`/g, "``")}\`` : (id) => `"${String(id).replace(/"/g, '""')}"`;
15435
+ const quoteId = isPostgres ? (id) => `"${String(id).replace(/"/g, '""')}"` : isMysqlLike(config5.dialect) ? (id) => `\`${String(id).replace(/`/g, "``")}\`` : (id) => `"${String(id).replace(/"/g, '""')}"`;
15384
15436
  const getPlaceholder2 = isPostgres ? (index) => `$${index + 1}` : (_index) => "?";
15385
15437
  return {
15386
15438
  values(data) {
@@ -15542,7 +15594,7 @@ function createQueryBuilder(state) {
15542
15594
  const params = [];
15543
15595
  const quoteId = (identifier) => {
15544
15596
  const s = String(identifier);
15545
- if (config5.dialect === "mysql")
15597
+ if (isMysqlLike(config5.dialect))
15546
15598
  return `\`${s.replace(/`/g, "``")}\``;
15547
15599
  return `"${s.replace(/"/g, '""')}"`;
15548
15600
  };
@@ -15669,7 +15721,7 @@ function createQueryBuilder(state) {
15669
15721
  deleteFrom(table) {
15670
15722
  const quoteId = (identifier) => {
15671
15723
  const s = String(identifier);
15672
- if (config5.dialect === "mysql")
15724
+ if (isMysqlLike(config5.dialect))
15673
15725
  return `\`${s.replace(/`/g, "``")}\``;
15674
15726
  return `"${s.replace(/"/g, '""')}"`;
15675
15727
  };
@@ -15836,7 +15888,7 @@ function createQueryBuilder(state) {
15836
15888
  await runWithHooks(q, "raw");
15837
15889
  return;
15838
15890
  }
15839
- if (config5.dialect === "mysql") {
15891
+ if (isMysqlLike(config5.dialect)) {
15840
15892
  const lockName = `bqb:${String(key)}`;
15841
15893
  const q = bunSql`SELECT GET_LOCK(${lockName}, -1) AS ok`;
15842
15894
  await runWithHooks(q, "raw");
@@ -15855,7 +15907,7 @@ function createQueryBuilder(state) {
15855
15907
  const rows = await runWithHooks(q, "raw");
15856
15908
  return Boolean(rows?.[0]?.ok);
15857
15909
  }
15858
- if (config5.dialect === "mysql") {
15910
+ if (isMysqlLike(config5.dialect)) {
15859
15911
  const lockName = `bqb:${String(key)}`;
15860
15912
  const q = bunSql`SELECT GET_LOCK(${lockName}, 0) AS ok`;
15861
15913
  const rows = await runWithHooks(q, "raw");
@@ -15924,7 +15976,7 @@ function createQueryBuilder(state) {
15924
15976
  const upper = level === "read committed" ? "READ COMMITTED" : level === "repeatable read" ? "REPEATABLE READ" : "SERIALIZABLE";
15925
15977
  if (config5.dialect === "postgres") {
15926
15978
  await tx.unsafe(`SET TRANSACTION ISOLATION LEVEL ${upper}`);
15927
- } else if (config5.dialect === "mysql") {
15979
+ } else if (isMysqlLike(config5.dialect)) {
15928
15980
  await tx.unsafe(`SET TRANSACTION ISOLATION LEVEL ${upper}`);
15929
15981
  } else {
15930
15982
  if (level !== "serializable") {
@@ -15935,7 +15987,7 @@ function createQueryBuilder(state) {
15935
15987
  if (opts?.readOnly) {
15936
15988
  if (config5.dialect === "postgres") {
15937
15989
  await tx.unsafe("SET TRANSACTION READ ONLY");
15938
- } else if (config5.dialect === "mysql") {
15990
+ } else if (isMysqlLike(config5.dialect)) {
15939
15991
  await tx.unsafe("SET TRANSACTION READ ONLY");
15940
15992
  } else {
15941
15993
  throw new Error("[query-builder] transaction({ readOnly: true }) not supported on SQLite. Use a Postgres or MySQL deployment.");
@@ -16011,13 +16063,13 @@ function createQueryBuilder(state) {
16011
16063
  return;
16012
16064
  const { colsSql, valuesSql, params } = buildInsertClause(rows);
16013
16065
  const tbl = quoteInsertIdent(String(table));
16014
- const sqlText = config5.dialect === "mysql" ? `INSERT IGNORE INTO ${tbl} (${colsSql}) VALUES ${valuesSql}` : `INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql} ON CONFLICT DO NOTHING`;
16066
+ const sqlText = isMysqlLike(config5.dialect) ? `INSERT IGNORE INTO ${tbl} (${colsSql}) VALUES ${valuesSql}` : `INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql} ON CONFLICT DO NOTHING`;
16015
16067
  return bunSql.unsafe(sqlText, params).execute();
16016
16068
  },
16017
16069
  async insertGetId(table, values, idColumn = "id") {
16018
16070
  const { colsSql, valuesSql, params } = buildInsertClause([values]);
16019
16071
  const tbl = quoteInsertIdent(String(table));
16020
- if (config5.dialect === "mysql") {
16072
+ if (isMysqlLike(config5.dialect)) {
16021
16073
  await bunSql.unsafe(`INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`, params).execute();
16022
16074
  const [row2] = await bunSql.unsafe(`SELECT LAST_INSERT_ID() as id`).execute();
16023
16075
  return row2?.id;
@@ -16061,7 +16113,7 @@ function createQueryBuilder(state) {
16061
16113
  const { colsSql, valuesSql, params } = buildInsertClause(list);
16062
16114
  const tbl = quoteInsertIdent(String(table));
16063
16115
  const insert = `INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`;
16064
- if (config5.dialect === "mysql") {
16116
+ if (isMysqlLike(config5.dialect)) {
16065
16117
  if (setCols.length === 0)
16066
16118
  return bunSql.unsafe(`INSERT IGNORE INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`, params).execute();
16067
16119
  const updateList2 = setCols.map((c) => `${quoteInsertIdent(c)} = VALUES(${quoteInsertIdent(c)})`).join(", ");
@@ -16174,7 +16226,7 @@ function createQueryBuilder(state) {
16174
16226
  const colCount = keys.length;
16175
16227
  const rowCount = rows.length;
16176
16228
  const params = Array.from({ length: rowCount * colCount });
16177
- const quoteId = config5.dialect === "mysql" ? (id) => `\`${String(id).replace(/`/g, "``")}\`` : (id) => `"${String(id).replace(/"/g, '""')}"`;
16229
+ const quoteId = isMysqlLike(config5.dialect) ? (id) => `\`${String(id).replace(/`/g, "``")}\`` : (id) => `"${String(id).replace(/"/g, '""')}"`;
16178
16230
  let sql = `INSERT INTO ${quoteId(String(table))}(${keys.map(quoteId).join(",")})VALUES`;
16179
16231
  let pidx = 0;
16180
16232
  for (let r = 0;r < rowCount; r++) {
@@ -16802,7 +16854,7 @@ async function dumpDatabase(options = {}) {
16802
16854
  ORDER BY table_name
16803
16855
  `);
16804
16856
  tables = result.map((r) => r.table_name);
16805
- } else if (dialect === "mysql") {
16857
+ } else if (isMysqlLike(dialect)) {
16806
16858
  const result = await qb.unsafe(`
16807
16859
  SELECT table_name
16808
16860
  FROM information_schema.tables
@@ -16882,7 +16934,7 @@ async function dbInfo() {
16882
16934
  ORDER BY table_name
16883
16935
  `);
16884
16936
  tableNames = result.map((r) => r.table_name);
16885
- } else if (dialect === "mysql") {
16937
+ } else if (isMysqlLike(dialect)) {
16886
16938
  const result = await qb.unsafe(`
16887
16939
  SELECT table_name
16888
16940
  FROM information_schema.tables
@@ -16920,7 +16972,7 @@ async function dbInfo() {
16920
16972
  WHERE tablename = $1
16921
16973
  `, [tableName]);
16922
16974
  indexCount = Number(idxResult[0]?.count || 0);
16923
- } else if (dialect === "mysql") {
16975
+ } else if (isMysqlLike(dialect)) {
16924
16976
  const colResult = await qb.unsafe(`
16925
16977
  SELECT COUNT(*) as count
16926
16978
  FROM information_schema.columns
@@ -17026,7 +17078,7 @@ async function dbOptimize(options = {}) {
17026
17078
  }
17027
17079
  }
17028
17080
  console.log("\u2713 PostgreSQL optimization complete");
17029
- } else if (dialect === "mysql") {
17081
+ } else if (isMysqlLike(dialect)) {
17030
17082
  if (options.tables && options.tables.length > 0) {
17031
17083
  for (const table of options.tables) {
17032
17084
  if (options.verbose) {
@@ -17084,6 +17136,7 @@ async function dbOptimize(options = {}) {
17084
17136
  }
17085
17137
  }
17086
17138
  var init_db_optimize = __esm(() => {
17139
+ init_config();
17087
17140
  init_db();
17088
17141
  });
17089
17142
 
@@ -17103,7 +17156,7 @@ async function dbWipe(options = {}) {
17103
17156
  WHERE schemaname = 'public'
17104
17157
  `;
17105
17158
  tables = result.map((row) => row.tablename);
17106
- } else if (dialect === "mysql") {
17159
+ } else if (isMysqlLike(dialect)) {
17107
17160
  const dbName = process23.env.DB_NAME || "test";
17108
17161
  const result = await bunSql`
17109
17162
  SELECT table_name
@@ -17134,7 +17187,7 @@ async function dbWipe(options = {}) {
17134
17187
  }
17135
17188
  await bunSql`DROP TABLE IF EXISTS ${bunSql(table)} CASCADE`;
17136
17189
  }
17137
- } else if (dialect === "mysql") {
17190
+ } else if (isMysqlLike(dialect)) {
17138
17191
  await bunSql`SET FOREIGN_KEY_CHECKS = 0`;
17139
17192
  for (const table of tables) {
17140
17193
  if (options.verbose) {
@@ -17160,6 +17213,7 @@ async function dbWipe(options = {}) {
17160
17213
  }
17161
17214
  }
17162
17215
  var init_db_wipe = __esm(() => {
17216
+ init_config();
17163
17217
  init_db();
17164
17218
  });
17165
17219
 
@@ -17267,7 +17321,7 @@ async function inspectTable(tableName, options = {}) {
17267
17321
  unique: idx.is_unique
17268
17322
  });
17269
17323
  }
17270
- } else if (dialect === "mysql") {
17324
+ } else if (isMysqlLike(dialect)) {
17271
17325
  const colsResult = await qb.unsafe(`
17272
17326
  SELECT
17273
17327
  COLUMN_NAME as column_name,
@@ -17430,7 +17484,7 @@ async function listTables(qb, dialect) {
17430
17484
  const rows2 = await qb.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' ORDER BY table_name`);
17431
17485
  return rows2.map((r) => r.table_name);
17432
17486
  }
17433
- if (dialect === "mysql") {
17487
+ if (isMysqlLike(dialect)) {
17434
17488
  const rows2 = await qb.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE' ORDER BY table_name`);
17435
17489
  return rows2.map((r) => r.table_name ?? r.TABLE_NAME);
17436
17490
  }
@@ -17517,7 +17571,7 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
17517
17571
  return "enum";
17518
17572
  const t = String(rawType || "").toLowerCase().trim();
17519
17573
  const base = t.replace(/\(.*$/, "").replace(/\s+/g, " ").trim();
17520
- if (dialect === "mysql" && /^tinyint\(1\)/.test(t))
17574
+ if (isMysqlLike(dialect) && /^tinyint\(1\)/.test(t))
17521
17575
  return "boolean";
17522
17576
  if (/^bool/.test(base))
17523
17577
  return "boolean";
@@ -17793,16 +17847,16 @@ var init_introspect_db = __esm(() => {
17793
17847
  });
17794
17848
 
17795
17849
  // src/actions/make-model.ts
17796
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, writeFileSync as writeFileSync10 } from "fs";
17797
- import { dirname as dirname5, join as join7 } from "path";
17850
+ import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10 } from "fs";
17851
+ import { dirname as dirname7, join as join7 } from "path";
17798
17852
  import process24 from "process";
17799
17853
  function findWorkspaceRoot(startPath) {
17800
17854
  let currentPath = startPath;
17801
- while (currentPath !== dirname5(currentPath)) {
17855
+ while (currentPath !== dirname7(currentPath)) {
17802
17856
  if (existsSync14(join7(currentPath, "package.json"))) {
17803
17857
  return currentPath;
17804
17858
  }
17805
- currentPath = dirname5(currentPath);
17859
+ currentPath = dirname7(currentPath);
17806
17860
  }
17807
17861
  return process24.cwd();
17808
17862
  }
@@ -17810,7 +17864,7 @@ async function makeModel(name, options = {}) {
17810
17864
  const workspaceRoot = findWorkspaceRoot(process24.cwd());
17811
17865
  const modelsDir = options.dir || join7(workspaceRoot, "app/Models");
17812
17866
  if (!existsSync14(modelsDir)) {
17813
- mkdirSync5(modelsDir, { recursive: true });
17867
+ mkdirSync7(modelsDir, { recursive: true });
17814
17868
  console.log(`-- Created models directory: ${modelsDir}`);
17815
17869
  }
17816
17870
  const className = name.charAt(0).toUpperCase() + name.slice(1);
@@ -17858,7 +17912,7 @@ class MySQLDriver {
17858
17912
  getColumnType(column) {
17859
17913
  switch (column.type) {
17860
17914
  case "string":
17861
- return "varchar(255)";
17915
+ return `varchar(${column.maxLength ?? 255})`;
17862
17916
  case "text":
17863
17917
  return "text";
17864
17918
  case "boolean":
@@ -18035,7 +18089,7 @@ class PostgresDriver {
18035
18089
  getColumnType(column) {
18036
18090
  switch (column.type) {
18037
18091
  case "string":
18038
- return "varchar(255)";
18092
+ return `varchar(${column.maxLength ?? 255})`;
18039
18093
  case "text":
18040
18094
  return "text";
18041
18095
  case "boolean":
@@ -18058,7 +18112,7 @@ class PostgresDriver {
18058
18112
  return "jsonb";
18059
18113
  case "enum":
18060
18114
  if (column.enumValues && column.enumValues.length > 0) {
18061
- return `${column.name}_type`;
18115
+ return this.quoteIdentifier(column.enumTypeName ?? `${column.name}_type`);
18062
18116
  }
18063
18117
  return "text";
18064
18118
  default:
@@ -18194,13 +18248,64 @@ class PostgresDriver {
18194
18248
  }
18195
18249
  }
18196
18250
 
18251
+ // src/drivers/singlestore.ts
18252
+ var SingleStoreDriver;
18253
+ var init_singlestore = __esm(() => {
18254
+ SingleStoreDriver = class SingleStoreDriver extends MySQLDriver {
18255
+ createTable(table) {
18256
+ const columns = table.columns.map((c) => this.renderColumn(c)).join(`,
18257
+ `);
18258
+ const clauses = [];
18259
+ if (table.tableKind !== "reference") {
18260
+ const shardCols = table.shardKey?.length ? table.shardKey : table.columns.filter((c) => c.isPrimaryKey).map((c) => c.name);
18261
+ if (shardCols && shardCols.length > 0) {
18262
+ clauses.push(`SHARD KEY (${shardCols.map((c) => this.quoteIdentifier(c)).join(", ")})`);
18263
+ }
18264
+ }
18265
+ if (table.tableKind !== "rowstore" && table.tableKind !== "reference") {
18266
+ const sortCols = table.sortKey?.length ? table.sortKey : undefined;
18267
+ clauses.push(`SORT KEY (${(sortCols ?? []).map((c) => this.quoteIdentifier(c)).join(", ")})`);
18268
+ }
18269
+ const body = [columns, ...clauses].join(`,
18270
+ `);
18271
+ const suffix = this.tableKindSuffix(table.tableKind);
18272
+ return `CREATE${suffix} TABLE IF NOT EXISTS ${this.quoteIdentifier(table.table)} (
18273
+ ${body}
18274
+ );`;
18275
+ }
18276
+ tableKindSuffix(kind) {
18277
+ switch (kind) {
18278
+ case "rowstore":
18279
+ return " ROWSTORE";
18280
+ case "reference":
18281
+ return " REFERENCE";
18282
+ default:
18283
+ return "";
18284
+ }
18285
+ }
18286
+ addForeignKey() {
18287
+ return "";
18288
+ }
18289
+ createIndex(tableName, index) {
18290
+ if (index.where) {
18291
+ throw new Error(`[migrations] Partial indexes (CompositeIndex.where) are not supported on SingleStore. Index '${index.name}' on table '${tableName}' uses WHERE clause: ${index.where}`);
18292
+ }
18293
+ return super.createIndex(tableName, index);
18294
+ }
18295
+ };
18296
+ });
18297
+
18197
18298
  // src/drivers/sqlite.ts
18299
+ function isNumericPlanType(type) {
18300
+ return type === "integer" || type === "bigint" || type === "float" || type === "double" || type === "decimal";
18301
+ }
18302
+
18198
18303
  class SQLiteDriver {
18199
18304
  quoteIdentifier(id) {
18200
18305
  return `"${id.replace(/"/g, '""')}"`;
18201
18306
  }
18202
18307
  getColumnType(column) {
18203
- if (column.name.endsWith("_id")) {
18308
+ if (column.name.endsWith("_id") && isNumericPlanType(column.type)) {
18204
18309
  return "INTEGER";
18205
18310
  }
18206
18311
  switch (column.type) {
@@ -18396,13 +18501,18 @@ function getDialectDriver(dialect) {
18396
18501
  return new PostgresDriver;
18397
18502
  case "mysql":
18398
18503
  return new MySQLDriver;
18504
+ case "singlestore":
18505
+ return new SingleStoreDriver;
18399
18506
  case "sqlite":
18400
18507
  return new SQLiteDriver;
18401
18508
  default:
18402
18509
  throw new Error(`Unsupported dialect: ${dialect}`);
18403
18510
  }
18404
18511
  }
18405
- var init_drivers = () => {};
18512
+ var init_drivers = __esm(() => {
18513
+ init_singlestore();
18514
+ init_singlestore();
18515
+ });
18406
18516
 
18407
18517
  // src/actions/migrate.ts
18408
18518
  var exports_migrate = {};
@@ -18414,7 +18524,7 @@ __export(exports_migrate, {
18414
18524
  copyModelsToGenerated: () => copyModelsToGenerated,
18415
18525
  clearGeneratedDirectory: () => clearGeneratedDirectory
18416
18526
  });
18417
- import { existsSync as existsSync16, mkdirSync as mkdirSync7, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
18527
+ import { existsSync as existsSync16, mkdirSync as mkdirSync8, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
18418
18528
  import { tmpdir } from "os";
18419
18529
  import { join as join9 } from "path";
18420
18530
  import process25 from "process";
@@ -18451,7 +18561,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
18451
18561
  const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
18452
18562
  const snapshotDir = join9(workspaceRoot, ".qb");
18453
18563
  if (!existsSync16(snapshotDir)) {
18454
- mkdirSync7(snapshotDir, { recursive: true });
18564
+ mkdirSync8(snapshotDir, { recursive: true });
18455
18565
  info(`-- Created snapshot directory: ${snapshotDir}`);
18456
18566
  }
18457
18567
  const snapshot = {
@@ -18469,7 +18579,7 @@ function getWorkspaceRoot() {
18469
18579
  function ensureSqlDirectory(workspaceRoot) {
18470
18580
  const sqlDir = getSqlDirectory(workspaceRoot);
18471
18581
  if (!existsSync16(sqlDir)) {
18472
- mkdirSync7(sqlDir, { recursive: true });
18582
+ mkdirSync8(sqlDir, { recursive: true });
18473
18583
  info(`-- Created SQL directory: ${sqlDir}`);
18474
18584
  }
18475
18585
  return sqlDir;
@@ -18637,7 +18747,7 @@ async function resetDatabase(dir, opts = {}) {
18637
18747
  for (const table of plan.tables) {
18638
18748
  for (const column of table.columns) {
18639
18749
  if (column.type === "enum" && column.enumValues && column.enumValues.length > 0) {
18640
- const enumTypeName = `${column.name}_type`;
18750
+ const enumTypeName = `${table.table}_${column.name}_type`;
18641
18751
  enumTypes.add(enumTypeName);
18642
18752
  }
18643
18753
  }
@@ -18809,7 +18919,7 @@ var init_migrate_generate = __esm(() => {
18809
18919
 
18810
18920
  // src/actions/migrate-rollback.ts
18811
18921
  import { existsSync as existsSync17, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
18812
- import { dirname as dirname7, join as join10 } from "path";
18922
+ import { dirname as dirname8, join as join10 } from "path";
18813
18923
  import process26 from "process";
18814
18924
  function splitSqlStatements2(sql) {
18815
18925
  const out = [];
@@ -18836,7 +18946,7 @@ function splitSqlStatements2(sql) {
18836
18946
  return out;
18837
18947
  }
18838
18948
  function deriveDownStatements(forwardSql, dialect = config5.dialect) {
18839
- const q = (id) => dialect === "mysql" ? `\`${id}\`` : `"${id}"`;
18949
+ const q = (id) => isMysqlLike(dialect) ? `\`${id}\`` : `"${id}"`;
18840
18950
  const down = [];
18841
18951
  const skipped = [];
18842
18952
  for (const stmt of splitSqlStatements2(forwardSql)) {
@@ -18846,7 +18956,7 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
18846
18956
  } else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+(?:COLUMN\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
18847
18957
  down.push(`ALTER TABLE ${q(m[1])} DROP COLUMN ${q(m[2])}`);
18848
18958
  } else if (m = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?(?:\s+ON\s+["`']?(\w+)["`']?)?/i.exec(stmt)) {
18849
- down.push(dialect === "mysql" && m[2] ? `DROP INDEX ${q(m[1])} ON ${q(m[2])}` : `DROP INDEX IF EXISTS ${q(m[1])}`);
18959
+ down.push(isMysqlLike(dialect) && m[2] ? `DROP INDEX ${q(m[1])} ON ${q(m[2])}` : `DROP INDEX IF EXISTS ${q(m[1])}`);
18850
18960
  } else {
18851
18961
  skipped.push(stmt);
18852
18962
  }
@@ -18855,11 +18965,11 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
18855
18965
  }
18856
18966
  function findWorkspaceRoot2(startPath) {
18857
18967
  let currentPath = startPath;
18858
- while (currentPath !== dirname7(currentPath)) {
18968
+ while (currentPath !== dirname8(currentPath)) {
18859
18969
  if (existsSync17(join10(currentPath, "package.json"))) {
18860
18970
  return currentPath;
18861
18971
  }
18862
- currentPath = dirname7(currentPath);
18972
+ currentPath = dirname8(currentPath);
18863
18973
  }
18864
18974
  return process26.cwd();
18865
18975
  }
@@ -18947,15 +19057,15 @@ var init_migrate_rollback = __esm(() => {
18947
19057
 
18948
19058
  // src/actions/migrate-status.ts
18949
19059
  import { existsSync as existsSync18, readdirSync as readdirSync8 } from "fs";
18950
- import { dirname as dirname8, join as join11 } from "path";
19060
+ import { dirname as dirname9, join as join11 } from "path";
18951
19061
  import process27 from "process";
18952
19062
  function findWorkspaceRoot3(startPath) {
18953
19063
  let currentPath = startPath;
18954
- while (currentPath !== dirname8(currentPath)) {
19064
+ while (currentPath !== dirname9(currentPath)) {
18955
19065
  if (existsSync18(join11(currentPath, "package.json"))) {
18956
19066
  return currentPath;
18957
19067
  }
18958
- currentPath = dirname8(currentPath);
19068
+ currentPath = dirname9(currentPath);
18959
19069
  }
18960
19070
  return process27.cwd();
18961
19071
  }
@@ -19393,16 +19503,16 @@ var init_relation_diagram = __esm(() => {
19393
19503
  });
19394
19504
 
19395
19505
  // src/actions/seed.ts
19396
- import { existsSync as existsSync19, mkdirSync as mkdirSync8, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
19397
- import { dirname as dirname9, join as join15 } from "path";
19506
+ import { existsSync as existsSync19, mkdirSync as mkdirSync9, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
19507
+ import { dirname as dirname10, join as join15 } from "path";
19398
19508
  import process30 from "process";
19399
19509
  function findWorkspaceRoot4(startPath) {
19400
19510
  let currentPath = startPath;
19401
- while (currentPath !== dirname9(currentPath)) {
19511
+ while (currentPath !== dirname10(currentPath)) {
19402
19512
  if (existsSync19(join15(currentPath, "package.json"))) {
19403
19513
  return currentPath;
19404
19514
  }
19405
- currentPath = dirname9(currentPath);
19515
+ currentPath = dirname10(currentPath);
19406
19516
  }
19407
19517
  return process30.cwd();
19408
19518
  }
@@ -19498,7 +19608,7 @@ async function makeSeeder(name) {
19498
19608
  const workspaceRoot = findWorkspaceRoot4(process30.cwd());
19499
19609
  const seedersDir = join15(workspaceRoot, "database/seeders");
19500
19610
  if (!existsSync19(seedersDir)) {
19501
- mkdirSync8(seedersDir, { recursive: true });
19611
+ mkdirSync9(seedersDir, { recursive: true });
19502
19612
  console.log(`-- Created seeders directory: ${seedersDir}`);
19503
19613
  }
19504
19614
  const baseName = name.replace(/Seeder$/i, "");
@@ -19620,15 +19730,15 @@ var init_unsafe = __esm(() => {
19620
19730
 
19621
19731
  // src/actions/validate.ts
19622
19732
  import { existsSync as existsSync20 } from "fs";
19623
- import { dirname as dirname10, join as join16 } from "path";
19733
+ import { dirname as dirname11, join as join16 } from "path";
19624
19734
  import process31 from "process";
19625
19735
  function findWorkspaceRoot5(startPath) {
19626
19736
  let currentPath = startPath;
19627
- while (currentPath !== dirname10(currentPath)) {
19737
+ while (currentPath !== dirname11(currentPath)) {
19628
19738
  if (existsSync20(join16(currentPath, "package.json"))) {
19629
19739
  return currentPath;
19630
19740
  }
19631
- currentPath = dirname10(currentPath);
19741
+ currentPath = dirname11(currentPath);
19632
19742
  }
19633
19743
  return process31.cwd();
19634
19744
  }
@@ -19664,7 +19774,7 @@ async function validateSchema(dir) {
19664
19774
  AND table_name != 'migrations'
19665
19775
  `);
19666
19776
  actualTables = result.map((r) => r.table_name);
19667
- } else if (dialect === "mysql") {
19777
+ } else if (isMysqlLike(dialect)) {
19668
19778
  const result = await qb.unsafe(`
19669
19779
  SELECT table_name
19670
19780
  FROM information_schema.tables
@@ -19716,7 +19826,7 @@ async function validateSchema(dir) {
19716
19826
  name: r.column_name,
19717
19827
  type: r.data_type.toLowerCase()
19718
19828
  }));
19719
- } else if (dialect === "mysql") {
19829
+ } else if (isMysqlLike(dialect)) {
19720
19830
  const result = await qb.unsafe(`
19721
19831
  SELECT column_name, data_type
19722
19832
  FROM information_schema.columns
@@ -24326,7 +24436,7 @@ var init_src = __esm(() => {
24326
24436
  import { Database as Database2 } from "bun:sqlite";
24327
24437
  function formatNow() {
24328
24438
  const iso = new Date().toISOString();
24329
- return config5.dialect === "mysql" ? iso.slice(0, 19).replace("T", " ") : iso;
24439
+ return isMysqlLike(config5.dialect) ? iso.slice(0, 19).replace("T", " ") : iso;
24330
24440
  }
24331
24441
  function assertValidIdentifier(name, context) {
24332
24442
  if (typeof name !== "string" || name.length === 0)
@@ -24454,6 +24564,7 @@ function configureOrm(options) {
24454
24564
  globalDb = options.database;
24455
24565
  } else {
24456
24566
  globalDb = new Database2(options.database || ":memory:", { create: true });
24567
+ applySqliteBootstrapPragmas(globalDb);
24457
24568
  }
24458
24569
  _executor = null;
24459
24570
  _executorForDb = null;
@@ -24475,10 +24586,13 @@ function getExecutor() {
24475
24586
  _executorForDb = null;
24476
24587
  _executorDialect = dialect;
24477
24588
  _executorDatabase = database;
24478
- if (dialect === "sqlite")
24479
- _executor = new SqliteExecutor(new Database2(database || ":memory:", { create: true }));
24480
- else
24589
+ if (dialect === "sqlite") {
24590
+ const db = new Database2(database || ":memory:", { create: true });
24591
+ applySqliteBootstrapPragmas(db);
24592
+ _executor = new SqliteExecutor(db);
24593
+ } else {
24481
24594
  _executor = new DriverExecutor(dialect);
24595
+ }
24482
24596
  return _executor;
24483
24597
  }
24484
24598
  function getDatabase() {
@@ -25891,7 +26005,7 @@ class ModelQueryBuilder {
25891
26005
  return (await exec.run(sql2, params)).changes;
25892
26006
  }
25893
26007
  }
25894
- function createModel(definition) {
26008
+ function createModelInternal(definition) {
25895
26009
  const model = {
25896
26010
  query: () => new ModelQueryBuilder(definition),
25897
26011
  where(column, operatorOrValue, value) {
@@ -26036,6 +26150,9 @@ function createModel(definition) {
26036
26150
  }
26037
26151
  });
26038
26152
  }
26153
+ function createModel(definition) {
26154
+ return createModelInternal(definition);
26155
+ }
26039
26156
  async function createTableFromModel(definition) {
26040
26157
  const exec = getExecutor();
26041
26158
  const pk = definition.primaryKey || "id";
@@ -26127,6 +26244,7 @@ var SAFE_SQL_IDENTIFIER, _getModel = null, pgPlaceholderCache, PG_PLACEHOLDER_CA
26127
26244
  var init_orm = __esm(() => {
26128
26245
  init_config();
26129
26246
  init_db();
26247
+ init_sqlite_pragmas();
26130
26248
  SAFE_SQL_IDENTIFIER = /^[A-Z_][A-Z0-9_]*$/i;
26131
26249
  pgPlaceholderCache = new Map;
26132
26250
  btmKeysCache = new WeakMap;
@@ -27711,8 +27829,8 @@ function buildSchemaMeta(models) {
27711
27829
  var init_meta = () => {};
27712
27830
 
27713
27831
  // src/migrations.ts
27714
- import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync14 } from "fs";
27715
- import { dirname as dirname11, join as join17 } from "path";
27832
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync14 } from "fs";
27833
+ import { dirname as dirname12, join as join17 } from "path";
27716
27834
  import process35 from "process";
27717
27835
  function info2(message) {
27718
27836
  if (config5.verbose)
@@ -27723,11 +27841,11 @@ function snakeCase(str) {
27723
27841
  }
27724
27842
  function findWorkspaceRoot6(startPath) {
27725
27843
  let currentPath = startPath;
27726
- while (currentPath !== dirname11(currentPath)) {
27844
+ while (currentPath !== dirname12(currentPath)) {
27727
27845
  if (existsSync21(join17(currentPath, "package.json"))) {
27728
27846
  return currentPath;
27729
27847
  }
27730
- currentPath = dirname11(currentPath);
27848
+ currentPath = dirname12(currentPath);
27731
27849
  }
27732
27850
  return process35.cwd();
27733
27851
  }
@@ -27735,7 +27853,7 @@ function ensureSqlDirectory2() {
27735
27853
  const workspaceRoot = findWorkspaceRoot6(process35.cwd());
27736
27854
  const sqlDir = join17(workspaceRoot, "database", "migrations");
27737
27855
  if (!existsSync21(sqlDir)) {
27738
- mkdirSync9(sqlDir, { recursive: true });
27856
+ mkdirSync10(sqlDir, { recursive: true });
27739
27857
  info2(`-- Created SQL directory: ${sqlDir}`);
27740
27858
  }
27741
27859
  return sqlDir;
@@ -27926,6 +28044,7 @@ function buildMigrationPlan2(models, options) {
27926
28044
  if (!inferred) {
27927
28045
  inferred = isPk ? "bigint" : "string";
27928
28046
  }
28047
+ const maxLen = inferred === "string" ? extractMaxFromRules(attr.validation?.rule) : undefined;
27929
28048
  const col = {
27930
28049
  name: columnName,
27931
28050
  type: inferred,
@@ -27934,7 +28053,8 @@ function buildMigrationPlan2(models, options) {
27934
28053
  isNullable,
27935
28054
  hasDefault: typeof attr.default !== "undefined",
27936
28055
  defaultValue: normalizeDefaultValue(attr.default),
27937
- enumValues
28056
+ enumValues,
28057
+ maxLength: typeof maxLen === "number" && maxLen > 0 && maxLen <= 255 ? maxLen : undefined
27938
28058
  };
27939
28059
  if (columnName.endsWith("_id") && attr.foreignKey !== false) {
27940
28060
  if (typeof attr.foreignKey === "object" && attr.foreignKey !== null) {
@@ -28041,7 +28161,10 @@ function buildMigrationPlan2(models, options) {
28041
28161
  if (c2.isUnique && !c2.isPrimaryKey)
28042
28162
  indexes.push({ name: `${table}_${c2.name}_unique`, columns: [c2.name], type: "unique" });
28043
28163
  }
28044
- tables.push({ table, columns, indexes });
28164
+ const shardKey = Array.isArray(model.shardKey) ? model.shardKey.map(snakeCase) : undefined;
28165
+ const sortKey = Array.isArray(model.sortKey) ? model.sortKey.map(snakeCase) : undefined;
28166
+ const tableKind = model.tableKind;
28167
+ tables.push({ table, columns, indexes, shardKey, sortKey, tableKind });
28045
28168
  }
28046
28169
  const seenTables = new Set(tables.map((t2) => t2.table));
28047
28170
  function ensureTable(plan) {
@@ -28190,7 +28313,8 @@ function generateSql(plan, opts = {}) {
28190
28313
  const enumTypes = new Set;
28191
28314
  for (const c2 of t2.columns) {
28192
28315
  if (c2.type === "enum" && c2.enumValues && c2.enumValues.length > 0) {
28193
- const enumTypeName = `${c2.name}_type`;
28316
+ const enumTypeName = `${t2.table}_${c2.name}_type`;
28317
+ c2.enumTypeName = enumTypeName;
28194
28318
  if (!enumTypes.has(enumTypeName)) {
28195
28319
  const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
28196
28320
  if (createEnumStatement) {
@@ -28276,7 +28400,7 @@ function mapColumnsByName(columns) {
28276
28400
  }
28277
28401
  function canonicalStorageType(col, dialect) {
28278
28402
  if (dialect === "sqlite") {
28279
- if (col.name.endsWith("_id"))
28403
+ if (col.name.endsWith("_id") && isNumericPlanType(col.type))
28280
28404
  return "INTEGER";
28281
28405
  switch (col.type) {
28282
28406
  case "string":
@@ -28454,7 +28578,8 @@ function generateDiffOperations(previous, next, opts = {}) {
28454
28578
  const enumTypes2 = new Set;
28455
28579
  for (const c2 of t2.columns) {
28456
28580
  if (c2.type === "enum" && c2.enumValues && c2.enumValues.length > 0) {
28457
- const enumTypeName = `${c2.name}_type`;
28581
+ const enumTypeName = `${t2.table}_${c2.name}_type`;
28582
+ c2.enumTypeName = enumTypeName;
28458
28583
  if (!enumTypes2.has(enumTypeName)) {
28459
28584
  const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
28460
28585
  if (createEnumStatement) {
@@ -28512,7 +28637,8 @@ function generateDiffOperations(previous, next, opts = {}) {
28512
28637
  if (!prevCols[colName]) {
28513
28638
  const c2 = currCols[colName];
28514
28639
  if (c2.type === "enum" && c2.enumValues && c2.enumValues.length > 0) {
28515
- const enumTypeName = `${c2.name}_type`;
28640
+ const enumTypeName = `${curr.table}_${c2.name}_type`;
28641
+ c2.enumTypeName = enumTypeName;
28516
28642
  if (!enumTypes.has(enumTypeName)) {
28517
28643
  const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
28518
28644
  if (createEnumStatement) {
@@ -28733,6 +28859,7 @@ var init_src2 = __esm(() => {
28733
28859
  init_meta();
28734
28860
  init_migrations();
28735
28861
  init_orm();
28862
+ init_sqlite_pragmas();
28736
28863
  });
28737
28864
 
28738
28865
  // ../../node_modules/@stacksjs/clapp/dist/index.js
@@ -30774,7 +30901,7 @@ function getPrefix() {
30774
30901
  }
30775
30902
  var prefix = getPrefix();
30776
30903
  // package.json
30777
- var version2 = "0.1.41";
30904
+ var version2 = "0.1.45";
30778
30905
 
30779
30906
  // bin/cli.ts
30780
30907
  init_actions();