bun-query-builder 0.1.24 → 0.1.26
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/actions/index.d.ts +1 -0
- package/dist/actions/introspect-db.d.ts +32 -0
- package/dist/actions/migrate-rollback.d.ts +14 -0
- package/dist/bin/cli.js +1084 -391
- package/dist/client.d.ts +3 -3
- package/dist/config.d.ts +1 -15
- package/dist/db.d.ts +54 -0
- package/dist/orm.d.ts +100 -35
- package/dist/relation-utils.d.ts +27 -0
- package/dist/src/index.js +1075 -385
- package/dist/types.d.ts +21 -0
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -11694,7 +11694,7 @@ function setConfig(userConfig) {
|
|
|
11694
11694
|
Object.assign(_config, config5);
|
|
11695
11695
|
}
|
|
11696
11696
|
}
|
|
11697
|
-
var defaultConfig4, config5, _config = null, _lastConfiguredDialect = null, _warnedDialectConflicts;
|
|
11697
|
+
var defaultConfig4, CONFIG_SINGLETON_KEY, config5, _config = null, _lastConfiguredDialect = null, _warnedDialectConflicts;
|
|
11698
11698
|
var init_config = __esm(() => {
|
|
11699
11699
|
init_dist();
|
|
11700
11700
|
defaultConfig4 = {
|
|
@@ -11754,14 +11754,14 @@ var init_config = __esm(() => {
|
|
|
11754
11754
|
defaultFilter: true
|
|
11755
11755
|
}
|
|
11756
11756
|
};
|
|
11757
|
-
|
|
11757
|
+
CONFIG_SINGLETON_KEY = Symbol.for("bun-query-builder.config");
|
|
11758
|
+
config5 = globalThis[CONFIG_SINGLETON_KEY] ??= { ...defaultConfig4 };
|
|
11758
11759
|
_warnedDialectConflicts = new Set;
|
|
11759
11760
|
});
|
|
11760
11761
|
|
|
11761
11762
|
// src/db.ts
|
|
11762
11763
|
var {SQL } = globalThis.Bun;
|
|
11763
11764
|
import { Database } from "bun:sqlite";
|
|
11764
|
-
import process19 from "process";
|
|
11765
11765
|
|
|
11766
11766
|
class SQLiteWrapper {
|
|
11767
11767
|
db;
|
|
@@ -11993,6 +11993,21 @@ function createConnectionString(dialect, dbConfig) {
|
|
|
11993
11993
|
throw new Error(`Unsupported dialect: ${dialect}`);
|
|
11994
11994
|
}
|
|
11995
11995
|
}
|
|
11996
|
+
function resolvePoolOptions(pool) {
|
|
11997
|
+
if (!pool)
|
|
11998
|
+
return {};
|
|
11999
|
+
const out = {};
|
|
12000
|
+
const toSeconds = (ms) => Math.max(0, Math.round(ms / 1000));
|
|
12001
|
+
if (typeof pool.max === "number" && Number.isFinite(pool.max))
|
|
12002
|
+
out.max = pool.max;
|
|
12003
|
+
if (typeof pool.idleTimeoutMs === "number" && Number.isFinite(pool.idleTimeoutMs))
|
|
12004
|
+
out.idleTimeout = toSeconds(pool.idleTimeoutMs);
|
|
12005
|
+
if (typeof pool.acquireTimeoutMs === "number" && Number.isFinite(pool.acquireTimeoutMs))
|
|
12006
|
+
out.connectionTimeout = toSeconds(pool.acquireTimeoutMs);
|
|
12007
|
+
if (typeof pool.maxLifetimeMs === "number" && Number.isFinite(pool.maxLifetimeMs))
|
|
12008
|
+
out.maxLifetime = toSeconds(pool.maxLifetimeMs);
|
|
12009
|
+
return out;
|
|
12010
|
+
}
|
|
11996
12011
|
function getBunSql() {
|
|
11997
12012
|
const dialect = config5.dialect;
|
|
11998
12013
|
const connectionString = createConnectionString(dialect, config5.database);
|
|
@@ -12000,43 +12015,42 @@ function getBunSql() {
|
|
|
12000
12015
|
if (dialect === "sqlite") {
|
|
12001
12016
|
return createSQLiteSQL(connectionString);
|
|
12002
12017
|
}
|
|
12003
|
-
const
|
|
12004
|
-
|
|
12005
|
-
sql.catch((error) => {
|
|
12006
|
-
if (config5.verbose && !error.message.includes("database") && !error.message.includes("does not exist")) {
|
|
12007
|
-
console.warn(`[query-builder] Database connection error: ${error.message}`);
|
|
12008
|
-
}
|
|
12009
|
-
});
|
|
12010
|
-
}
|
|
12018
|
+
const poolOptions = resolvePoolOptions(config5.database.pool);
|
|
12019
|
+
const sql = Object.keys(poolOptions).length > 0 ? new SQL(connectionString, poolOptions) : new SQL(connectionString);
|
|
12011
12020
|
return sql;
|
|
12012
12021
|
} catch (error) {
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
}
|
|
12016
|
-
try {
|
|
12022
|
+
console.error(`[query-builder] Failed to create database connection for dialect '${dialect}': ${error.message}`);
|
|
12023
|
+
if (dialect === "sqlite") {
|
|
12017
12024
|
return createSQLiteSQL(":memory:");
|
|
12018
|
-
} catch {
|
|
12019
|
-
return {
|
|
12020
|
-
query: () => Promise.resolve([]),
|
|
12021
|
-
execute: () => Promise.resolve([]),
|
|
12022
|
-
close: () => Promise.resolve()
|
|
12023
|
-
};
|
|
12024
12025
|
}
|
|
12026
|
+
throw error;
|
|
12025
12027
|
}
|
|
12026
12028
|
}
|
|
12029
|
+
function connectionSignature() {
|
|
12030
|
+
const d = config5.database;
|
|
12031
|
+
return JSON.stringify({
|
|
12032
|
+
dialect: config5.dialect,
|
|
12033
|
+
database: d.database,
|
|
12034
|
+
username: d.username,
|
|
12035
|
+
password: d.password,
|
|
12036
|
+
host: d.host,
|
|
12037
|
+
port: d.port,
|
|
12038
|
+
url: d.url,
|
|
12039
|
+
pool: resolvePoolOptions(d.pool)
|
|
12040
|
+
});
|
|
12041
|
+
}
|
|
12027
12042
|
function getOrCreateBunSql(forceNew = false) {
|
|
12028
|
-
const
|
|
12043
|
+
const signature = connectionSignature();
|
|
12044
|
+
const configChanged = _bunSqlInstance !== null && _currentSignature !== signature;
|
|
12029
12045
|
if (forceNew || configChanged || !_bunSqlInstance) {
|
|
12030
12046
|
_bunSqlInstance = getBunSql();
|
|
12031
|
-
|
|
12032
|
-
_currentDatabase = config5.database.database;
|
|
12047
|
+
_currentSignature = signature;
|
|
12033
12048
|
}
|
|
12034
12049
|
return _bunSqlInstance;
|
|
12035
12050
|
}
|
|
12036
12051
|
function resetConnection() {
|
|
12037
12052
|
_bunSqlInstance = null;
|
|
12038
|
-
|
|
12039
|
-
_currentDatabase = null;
|
|
12053
|
+
_currentSignature = null;
|
|
12040
12054
|
}
|
|
12041
12055
|
async function withFreshConnection(fn) {
|
|
12042
12056
|
try {
|
|
@@ -12051,7 +12065,7 @@ async function withFreshConnection(fn) {
|
|
|
12051
12065
|
}
|
|
12052
12066
|
}
|
|
12053
12067
|
function createLazyBunSql() {
|
|
12054
|
-
return new Proxy({}, {
|
|
12068
|
+
return new Proxy(function lazyBunSql() {}, {
|
|
12055
12069
|
get(_target, prop) {
|
|
12056
12070
|
const sql = getOrCreateBunSql();
|
|
12057
12071
|
const value = sql[prop];
|
|
@@ -12066,20 +12080,10 @@ function createLazyBunSql() {
|
|
|
12066
12080
|
}
|
|
12067
12081
|
});
|
|
12068
12082
|
}
|
|
12069
|
-
var _bunSqlInstance = null,
|
|
12083
|
+
var _bunSqlInstance = null, _currentSignature = null, bunSql;
|
|
12070
12084
|
var init_db = __esm(() => {
|
|
12071
12085
|
init_config();
|
|
12072
12086
|
bunSql = createLazyBunSql();
|
|
12073
|
-
if (typeof process19 !== "undefined" && process19.on) {
|
|
12074
|
-
const existingHandler = process19.listeners("unhandledRejection").find((h) => h.name === "sqlConnectionErrorHandler");
|
|
12075
|
-
if (!existingHandler) {
|
|
12076
|
-
let sqlConnectionErrorHandler = function(reason) {
|
|
12077
|
-
if (reason && (reason.message?.includes("database") || reason.message?.includes("does not exist") || reason.code === "ERR_POSTGRES_SERVER_ERROR" || reason.code === "3D000")) {}
|
|
12078
|
-
};
|
|
12079
|
-
Object.defineProperty(sqlConnectionErrorHandler, "name", { value: "sqlConnectionErrorHandler" });
|
|
12080
|
-
process19.on("unhandledRejection", sqlConnectionErrorHandler);
|
|
12081
|
-
}
|
|
12082
|
-
}
|
|
12083
12087
|
});
|
|
12084
12088
|
|
|
12085
12089
|
// src/actions/benchmark.ts
|
|
@@ -12329,6 +12333,47 @@ function* iterateAllPivots(meta, options = {}) {
|
|
|
12329
12333
|
function isRawExpression(expr) {
|
|
12330
12334
|
return typeof expr === "object" && expr !== null && "raw" in expr && typeof expr.raw === "string";
|
|
12331
12335
|
}
|
|
12336
|
+
function quoteInsertIdent(id) {
|
|
12337
|
+
return config5.dialect === "mysql" ? `\`${id.replace(/`/g, "``")}\`` : `"${id.replace(/"/g, '""')}"`;
|
|
12338
|
+
}
|
|
12339
|
+
function buildInsertClause(rows, startIndex = 1) {
|
|
12340
|
+
const cols = Object.keys(rows[0] ?? {});
|
|
12341
|
+
const params = [];
|
|
12342
|
+
let idx = startIndex;
|
|
12343
|
+
const tuples = rows.map((row) => {
|
|
12344
|
+
const phs = cols.map((c) => {
|
|
12345
|
+
params.push(row[c]);
|
|
12346
|
+
return getPlaceholder(idx++);
|
|
12347
|
+
});
|
|
12348
|
+
return `(${phs.join(", ")})`;
|
|
12349
|
+
});
|
|
12350
|
+
return {
|
|
12351
|
+
colsSql: cols.map(quoteInsertIdent).join(", "),
|
|
12352
|
+
valuesSql: tuples.join(", "),
|
|
12353
|
+
params,
|
|
12354
|
+
nextIndex: idx
|
|
12355
|
+
};
|
|
12356
|
+
}
|
|
12357
|
+
function hasSlowQueryHook(h) {
|
|
12358
|
+
return Boolean(h && (h.onSlowQuery || h.slowQueryThresholdMs != null && h.slowQueryThresholdMs >= 0));
|
|
12359
|
+
}
|
|
12360
|
+
function renderSelectColumn(col) {
|
|
12361
|
+
if (typeof col === "string")
|
|
12362
|
+
return col;
|
|
12363
|
+
if (isRawExpression(col))
|
|
12364
|
+
return col.raw;
|
|
12365
|
+
if (col && typeof col === "object") {
|
|
12366
|
+
const anyCol = col;
|
|
12367
|
+
if (typeof anyCol.raw === "function")
|
|
12368
|
+
return String(anyCol.raw());
|
|
12369
|
+
if (typeof anyCol.sql === "string")
|
|
12370
|
+
return anyCol.sql;
|
|
12371
|
+
const str = String(col);
|
|
12372
|
+
if (str !== "[object Object]")
|
|
12373
|
+
return str;
|
|
12374
|
+
}
|
|
12375
|
+
throw new TypeError(`[query-builder] select(): unsupported column ${String(col)} \u2014 pass a column name, a string[], or a SQL fragment (e.g. sql\`count(*) as c\`)`);
|
|
12376
|
+
}
|
|
12332
12377
|
function validateIdentifier(name, context) {
|
|
12333
12378
|
if (!SQL_PATTERNS.IDENTIFIER.test(name)) {
|
|
12334
12379
|
const contextMsg = context ? ` in ${context}` : "";
|
|
@@ -12543,20 +12588,35 @@ function createQueryBuilder(state) {
|
|
|
12543
12588
|
config5.debug.captureText = prev;
|
|
12544
12589
|
return s;
|
|
12545
12590
|
}
|
|
12591
|
+
function computeParams(q) {
|
|
12592
|
+
if (!q || typeof q !== "object")
|
|
12593
|
+
return;
|
|
12594
|
+
if (Array.isArray(q.values))
|
|
12595
|
+
return q.values;
|
|
12596
|
+
if (Array.isArray(q.parameters))
|
|
12597
|
+
return q.parameters;
|
|
12598
|
+
if (Array.isArray(q.params))
|
|
12599
|
+
return q.params;
|
|
12600
|
+
return;
|
|
12601
|
+
}
|
|
12546
12602
|
function runWithHooks(q, kind, opts) {
|
|
12547
12603
|
const hooks = config5.hooks;
|
|
12548
|
-
const
|
|
12604
|
+
const slowMs = hooks?.slowQueryThresholdMs;
|
|
12605
|
+
const slowEnabled = slowMs != null && slowMs >= 0;
|
|
12606
|
+
const hasSlowQuery = Boolean(hooks?.onSlowQuery || slowEnabled);
|
|
12607
|
+
const hasHooks = hooks && (hooks.onQueryStart || hooks.onQueryEnd || hooks.onQueryError || hooks.startSpan || hasSlowQuery);
|
|
12549
12608
|
const hasTimeoutOrSignal = opts?.timeoutMs && opts.timeoutMs > 0 || opts?.signal;
|
|
12550
12609
|
if (!hasHooks && !hasTimeoutOrSignal) {
|
|
12551
12610
|
return q.execute();
|
|
12552
12611
|
}
|
|
12553
12612
|
const text = computeSqlText(q);
|
|
12613
|
+
const params = computeParams(q);
|
|
12554
12614
|
const startAt = Date.now();
|
|
12555
12615
|
let span;
|
|
12556
12616
|
try {
|
|
12557
|
-
hooks?.onQueryStart?.({ sql: text, kind });
|
|
12617
|
+
hooks?.onQueryStart?.({ sql: text, params, kind });
|
|
12558
12618
|
if (hooks?.startSpan)
|
|
12559
|
-
span = hooks.startSpan({ sql: text, kind });
|
|
12619
|
+
span = hooks.startSpan({ sql: text, params, kind });
|
|
12560
12620
|
} catch {}
|
|
12561
12621
|
let finished = false;
|
|
12562
12622
|
const finish = (err, rowCount) => {
|
|
@@ -12566,9 +12626,15 @@ function createQueryBuilder(state) {
|
|
|
12566
12626
|
const durationMs = Date.now() - startAt;
|
|
12567
12627
|
try {
|
|
12568
12628
|
if (err) {
|
|
12569
|
-
hooks?.onQueryError?.({ sql: text, error: err, durationMs, kind });
|
|
12629
|
+
hooks?.onQueryError?.({ sql: text, params, error: err, durationMs, kind });
|
|
12570
12630
|
} else {
|
|
12571
|
-
hooks?.onQueryEnd?.({ sql: text, durationMs, rowCount, kind });
|
|
12631
|
+
hooks?.onQueryEnd?.({ sql: text, params, durationMs, rowCount, kind });
|
|
12632
|
+
if (slowEnabled && durationMs >= slowMs) {
|
|
12633
|
+
if (hooks?.onSlowQuery)
|
|
12634
|
+
hooks.onSlowQuery({ sql: text, params, durationMs, kind });
|
|
12635
|
+
else
|
|
12636
|
+
console.warn(`[query-builder] slow query (${durationMs}ms >= ${slowMs}ms): ${text}`);
|
|
12637
|
+
}
|
|
12572
12638
|
}
|
|
12573
12639
|
} catch {}
|
|
12574
12640
|
try {
|
|
@@ -12648,6 +12714,36 @@ function createQueryBuilder(state) {
|
|
|
12648
12714
|
const p = hasWhere ? prefix : "WHERE";
|
|
12649
12715
|
text = `${text} ${p} ${clause}`;
|
|
12650
12716
|
};
|
|
12717
|
+
const appendSetOp = (op, other) => {
|
|
12718
|
+
const st = other.__rawState?.();
|
|
12719
|
+
if (st) {
|
|
12720
|
+
const offset = whereParams.length;
|
|
12721
|
+
const otherSql = config5.dialect === "postgres" ? st.sql.replace(/\$(\d+)/g, (_m, n) => `$${Number(n) + offset}`) : st.sql;
|
|
12722
|
+
text += ` ${op} ${otherSql}`;
|
|
12723
|
+
whereParams.push(...st.params);
|
|
12724
|
+
} else {
|
|
12725
|
+
text += ` ${op} ${String(other.toSQL())}`;
|
|
12726
|
+
}
|
|
12727
|
+
built = null;
|
|
12728
|
+
};
|
|
12729
|
+
const insertJoin = (joinClause) => {
|
|
12730
|
+
const re = /\(|\)|\b(?:WHERE|GROUP BY|HAVING|ORDER BY|LIMIT|OFFSET|UNION)\b/gi;
|
|
12731
|
+
let depth = 0;
|
|
12732
|
+
let cut = -1;
|
|
12733
|
+
let mm;
|
|
12734
|
+
while (mm = re.exec(text)) {
|
|
12735
|
+
if (mm[0] === "(") {
|
|
12736
|
+
depth++;
|
|
12737
|
+
} else if (mm[0] === ")") {
|
|
12738
|
+
depth = Math.max(0, depth - 1);
|
|
12739
|
+
} else if (depth === 0) {
|
|
12740
|
+
cut = mm.index;
|
|
12741
|
+
break;
|
|
12742
|
+
}
|
|
12743
|
+
}
|
|
12744
|
+
text = cut >= 0 ? `${text.slice(0, cut)}${joinClause} ${text.slice(cut)}` : `${text} ${joinClause}`;
|
|
12745
|
+
built = null;
|
|
12746
|
+
};
|
|
12651
12747
|
const joinedTables = new Set;
|
|
12652
12748
|
let timeoutMs;
|
|
12653
12749
|
let abortSignal;
|
|
@@ -12732,6 +12828,18 @@ function createQueryBuilder(state) {
|
|
|
12732
12828
|
}
|
|
12733
12829
|
}
|
|
12734
12830
|
};
|
|
12831
|
+
const buildOverClause = (partitionBy, orderBy) => {
|
|
12832
|
+
const cols = Array.isArray(partitionBy) ? partitionBy : partitionBy ? [partitionBy] : [];
|
|
12833
|
+
const parts = [];
|
|
12834
|
+
if (cols.length)
|
|
12835
|
+
parts.push(`PARTITION BY ${cols.join(", ")}`);
|
|
12836
|
+
if (orderBy && orderBy.length)
|
|
12837
|
+
parts.push(`ORDER BY ${orderBy.map(([c, d]) => `${c} ${d === "desc" ? "DESC" : "ASC"}`).join(", ")}`);
|
|
12838
|
+
return parts.length ? `OVER (${parts.join(" ")})` : "OVER ()";
|
|
12839
|
+
};
|
|
12840
|
+
const addWindowFunction = (fnExpr, alias, partitionBy, orderBy) => {
|
|
12841
|
+
addToSelectClause(`${fnExpr} ${buildOverClause(partitionBy, orderBy)} AS ${alias}`);
|
|
12842
|
+
};
|
|
12735
12843
|
function assertSafeWhereOperator(op, context) {
|
|
12736
12844
|
if (typeof op !== "string")
|
|
12737
12845
|
throw new TypeError(`[query-builder] ${context}: operator must be a string, got ${typeof op}`);
|
|
@@ -12871,6 +12979,46 @@ function createQueryBuilder(state) {
|
|
|
12871
12979
|
validateIdentifier(fkA, "withCount (foreign key)");
|
|
12872
12980
|
return `(SELECT COUNT(*) FROM ${pivot} WHERE ${pivot}.${fkA} = ${parentTable}.${pk})`;
|
|
12873
12981
|
};
|
|
12982
|
+
const applyRelationAggregate = (fn, relation, column) => {
|
|
12983
|
+
if (!meta)
|
|
12984
|
+
return;
|
|
12985
|
+
validateIdentifier(column, `with${fn[0]}${fn.slice(1).toLowerCase()} (column)`);
|
|
12986
|
+
const parentTable = String(table);
|
|
12987
|
+
const rels = meta.relations?.[parentTable];
|
|
12988
|
+
if (!rels)
|
|
12989
|
+
return;
|
|
12990
|
+
const found = Object.entries(rels).find(([_t, relMap2]) => relMap2 && typeof relMap2 === "object" && (relation in relMap2));
|
|
12991
|
+
if (!found)
|
|
12992
|
+
return;
|
|
12993
|
+
const [type, relMap] = found;
|
|
12994
|
+
const entry = relMap[relation];
|
|
12995
|
+
const targetModel = typeof entry === "string" ? entry : entry?.model || entry?.target || entry;
|
|
12996
|
+
const targetTable = meta.modelToTable[targetModel] || targetModel;
|
|
12997
|
+
const pk = meta.primaryKeys[parentTable] ?? "id";
|
|
12998
|
+
validateIdentifier(targetTable, `with${fn} (target table)`);
|
|
12999
|
+
const aggExpr = `${fn}(${targetTable}.${column})`;
|
|
13000
|
+
let sub;
|
|
13001
|
+
if (type === "hasMany" || type === "hasOne") {
|
|
13002
|
+
const fk = `${parentTable.endsWith("s") ? parentTable.slice(0, -1) : parentTable}_id`;
|
|
13003
|
+
validateIdentifier(fk, `with${fn} (foreign key)`);
|
|
13004
|
+
sub = `(SELECT ${aggExpr} FROM ${targetTable} WHERE ${targetTable}.${fk} = ${parentTable}.${pk})`;
|
|
13005
|
+
} else if (type === "belongsToMany") {
|
|
13006
|
+
const resolved = meta ? resolvePivot(meta, parentTable, relation, { singularize, models: meta.models }) : null;
|
|
13007
|
+
const a = singularize(parentTable);
|
|
13008
|
+
const b = singularize(targetTable);
|
|
13009
|
+
const pivot = resolved?.pivotTable ?? [a, b].sort().join("_");
|
|
13010
|
+
const fkA = resolved?.fkParent ?? `${a}_id`;
|
|
13011
|
+
const fkB = resolved?.fkRelated ?? `${b}_id`;
|
|
13012
|
+
const targetPk = meta.primaryKeys[targetTable] ?? "id";
|
|
13013
|
+
validateIdentifier(pivot, `with${fn} (pivot table)`);
|
|
13014
|
+
validateIdentifier(fkA, `with${fn} (foreign key)`);
|
|
13015
|
+
validateIdentifier(fkB, `with${fn} (related key)`);
|
|
13016
|
+
sub = `(SELECT ${aggExpr} FROM ${pivot} JOIN ${targetTable} ON ${targetTable}.${targetPk} = ${pivot}.${fkB} WHERE ${pivot}.${fkA} = ${parentTable}.${pk})`;
|
|
13017
|
+
} else {
|
|
13018
|
+
return;
|
|
13019
|
+
}
|
|
13020
|
+
addToSelectClause(`${sub} AS ${relation}_${fn.toLowerCase()}_${column}`);
|
|
13021
|
+
};
|
|
12874
13022
|
const applyPivotColumnsToQuery = () => {
|
|
12875
13023
|
if (pivotColumns.size === 0)
|
|
12876
13024
|
return;
|
|
@@ -12965,6 +13113,52 @@ function createQueryBuilder(state) {
|
|
|
12965
13113
|
built = null;
|
|
12966
13114
|
return this;
|
|
12967
13115
|
},
|
|
13116
|
+
over(expression, alias, opts = {}) {
|
|
13117
|
+
addWindowFunction(expression, alias, opts.partitionBy, opts.orderBy);
|
|
13118
|
+
return this;
|
|
13119
|
+
},
|
|
13120
|
+
lag(column, opts = {}) {
|
|
13121
|
+
const args = [column, String(opts.offset ?? 1)];
|
|
13122
|
+
if (opts.defaultValue !== undefined)
|
|
13123
|
+
args.push(String(opts.defaultValue));
|
|
13124
|
+
addWindowFunction(`LAG(${args.join(", ")})`, opts.alias ?? `${column}_lag`, opts.partitionBy, opts.orderBy);
|
|
13125
|
+
return this;
|
|
13126
|
+
},
|
|
13127
|
+
lead(column, opts = {}) {
|
|
13128
|
+
const args = [column, String(opts.offset ?? 1)];
|
|
13129
|
+
if (opts.defaultValue !== undefined)
|
|
13130
|
+
args.push(String(opts.defaultValue));
|
|
13131
|
+
addWindowFunction(`LEAD(${args.join(", ")})`, opts.alias ?? `${column}_lead`, opts.partitionBy, opts.orderBy);
|
|
13132
|
+
return this;
|
|
13133
|
+
},
|
|
13134
|
+
sumOver(column, opts = {}) {
|
|
13135
|
+
addWindowFunction(`SUM(${column})`, opts.alias ?? `${column}_sum`, opts.partitionBy, opts.orderBy);
|
|
13136
|
+
return this;
|
|
13137
|
+
},
|
|
13138
|
+
avgOver(column, opts = {}) {
|
|
13139
|
+
addWindowFunction(`AVG(${column})`, opts.alias ?? `${column}_avg`, opts.partitionBy, opts.orderBy);
|
|
13140
|
+
return this;
|
|
13141
|
+
},
|
|
13142
|
+
countOver(column = "*", opts = {}) {
|
|
13143
|
+
addWindowFunction(`COUNT(${column})`, opts.alias ?? "count_over", opts.partitionBy, opts.orderBy);
|
|
13144
|
+
return this;
|
|
13145
|
+
},
|
|
13146
|
+
minOver(column, opts = {}) {
|
|
13147
|
+
addWindowFunction(`MIN(${column})`, opts.alias ?? `${column}_min`, opts.partitionBy, opts.orderBy);
|
|
13148
|
+
return this;
|
|
13149
|
+
},
|
|
13150
|
+
maxOver(column, opts = {}) {
|
|
13151
|
+
addWindowFunction(`MAX(${column})`, opts.alias ?? `${column}_max`, opts.partitionBy, opts.orderBy);
|
|
13152
|
+
return this;
|
|
13153
|
+
},
|
|
13154
|
+
firstValue(column, opts = {}) {
|
|
13155
|
+
addWindowFunction(`FIRST_VALUE(${column})`, opts.alias ?? `${column}_first`, opts.partitionBy, opts.orderBy);
|
|
13156
|
+
return this;
|
|
13157
|
+
},
|
|
13158
|
+
lastValue(column, opts = {}) {
|
|
13159
|
+
addWindowFunction(`LAST_VALUE(${column})`, opts.alias ?? `${column}_last`, opts.partitionBy, opts.orderBy);
|
|
13160
|
+
return this;
|
|
13161
|
+
},
|
|
12968
13162
|
selectAll() {
|
|
12969
13163
|
return this;
|
|
12970
13164
|
},
|
|
@@ -12974,22 +13168,24 @@ function createQueryBuilder(state) {
|
|
|
12974
13168
|
const cols = Array.isArray(columns2) ? columns2 : [columns2];
|
|
12975
13169
|
if (cols.length === 0)
|
|
12976
13170
|
return this;
|
|
13171
|
+
const rendered = cols.map(renderSelectColumn);
|
|
12977
13172
|
const fromIndex = text.indexOf(" FROM ");
|
|
12978
13173
|
if (fromIndex !== -1) {
|
|
12979
|
-
text = `SELECT ${
|
|
13174
|
+
text = `SELECT ${rendered.join(", ")}${text.substring(fromIndex)}`;
|
|
12980
13175
|
} else {
|
|
12981
|
-
text = `SELECT ${
|
|
13176
|
+
text = `SELECT ${rendered.join(", ")} FROM ${table}`;
|
|
12982
13177
|
}
|
|
12983
13178
|
return this;
|
|
12984
13179
|
},
|
|
12985
13180
|
addSelect(...columns2) {
|
|
12986
13181
|
if (!columns2.length)
|
|
12987
13182
|
return this;
|
|
13183
|
+
const rendered = columns2.map(renderSelectColumn);
|
|
12988
13184
|
const fromIdx = text.indexOf(" FROM ");
|
|
12989
13185
|
if (fromIdx !== -1) {
|
|
12990
|
-
text = `${text.substring(0, fromIdx)}, ${
|
|
13186
|
+
text = `${text.substring(0, fromIdx)}, ${rendered.join(", ")}${text.substring(fromIdx)}`;
|
|
12991
13187
|
} else {
|
|
12992
|
-
text += `, ${
|
|
13188
|
+
text += `, ${rendered.join(", ")}`;
|
|
12993
13189
|
}
|
|
12994
13190
|
built = null;
|
|
12995
13191
|
return this;
|
|
@@ -13406,6 +13602,22 @@ function createQueryBuilder(state) {
|
|
|
13406
13602
|
}
|
|
13407
13603
|
return this;
|
|
13408
13604
|
},
|
|
13605
|
+
withSum(relation, column) {
|
|
13606
|
+
applyRelationAggregate("SUM", relation, column);
|
|
13607
|
+
return this;
|
|
13608
|
+
},
|
|
13609
|
+
withAvg(relation, column) {
|
|
13610
|
+
applyRelationAggregate("AVG", relation, column);
|
|
13611
|
+
return this;
|
|
13612
|
+
},
|
|
13613
|
+
withMax(relation, column) {
|
|
13614
|
+
applyRelationAggregate("MAX", relation, column);
|
|
13615
|
+
return this;
|
|
13616
|
+
},
|
|
13617
|
+
withMin(relation, column) {
|
|
13618
|
+
applyRelationAggregate("MIN", relation, column);
|
|
13619
|
+
return this;
|
|
13620
|
+
},
|
|
13409
13621
|
applyPivotColumns() {
|
|
13410
13622
|
applyPivotColumnsToQuery();
|
|
13411
13623
|
return this;
|
|
@@ -13617,8 +13829,9 @@ function createQueryBuilder(state) {
|
|
|
13617
13829
|
},
|
|
13618
13830
|
whereBetween(column, start, end) {
|
|
13619
13831
|
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
13832
|
+
const i = whereParams.length + 1;
|
|
13833
|
+
text = `${text} ${keyword} ${String(column)} BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`;
|
|
13620
13834
|
whereParams.push(start, end);
|
|
13621
|
-
text = `${text} ${keyword} ${String(column)} BETWEEN ? AND ?`;
|
|
13622
13835
|
built = null;
|
|
13623
13836
|
return this;
|
|
13624
13837
|
},
|
|
@@ -13630,9 +13843,30 @@ function createQueryBuilder(state) {
|
|
|
13630
13843
|
},
|
|
13631
13844
|
whereJsonContains(column, json) {
|
|
13632
13845
|
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
13846
|
+
const dialect = config5.dialect;
|
|
13633
13847
|
const idx = whereParams.length + 1;
|
|
13634
|
-
|
|
13635
|
-
|
|
13848
|
+
if (dialect === "postgres") {
|
|
13849
|
+
if (config5.sql?.jsonContainsMode === "function")
|
|
13850
|
+
text += ` ${keyword} jsonb_contains(${column}, ${getPlaceholder(idx)})`;
|
|
13851
|
+
else
|
|
13852
|
+
text += ` ${keyword} ${column} @> ${getPlaceholder(idx)}`;
|
|
13853
|
+
whereParams.push(JSON.stringify(json));
|
|
13854
|
+
} else if (dialect === "mysql") {
|
|
13855
|
+
text += ` ${keyword} JSON_CONTAINS(${column}, ${getPlaceholder(idx)})`;
|
|
13856
|
+
whereParams.push(JSON.stringify(json));
|
|
13857
|
+
} else {
|
|
13858
|
+
if (Array.isArray(json)) {
|
|
13859
|
+
const conds = json.map((_, i) => `EXISTS (SELECT 1 FROM json_each(${column}) WHERE json_each.value = ${getPlaceholder(idx + i)})`);
|
|
13860
|
+
text += ` ${keyword} (${conds.join(" AND ")})`;
|
|
13861
|
+
for (const v of json)
|
|
13862
|
+
whereParams.push(v);
|
|
13863
|
+
} else if (json !== null && typeof json === "object") {
|
|
13864
|
+
throw new Error("[query-builder] whereJsonContains: object containment is not supported on SQLite \u2014 pass a scalar or array, or use whereJsonPath.");
|
|
13865
|
+
} else {
|
|
13866
|
+
text += ` ${keyword} EXISTS (SELECT 1 FROM json_each(${column}) WHERE json_each.value = ${getPlaceholder(idx)})`;
|
|
13867
|
+
whereParams.push(json);
|
|
13868
|
+
}
|
|
13869
|
+
}
|
|
13636
13870
|
built = null;
|
|
13637
13871
|
return this;
|
|
13638
13872
|
},
|
|
@@ -13659,69 +13893,85 @@ function createQueryBuilder(state) {
|
|
|
13659
13893
|
whereLike(column, pattern, caseSensitive = false) {
|
|
13660
13894
|
const expr = caseSensitive ? sql`${sql(String(column))} LIKE ${pattern}` : sql`LOWER(${sql(String(column))}) LIKE LOWER(${pattern})`;
|
|
13661
13895
|
built = sql`${ensureBuilt()} WHERE ${expr}`;
|
|
13662
|
-
|
|
13896
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13897
|
+
addWhereText("WHERE", `${caseSensitive ? String(column) : `LOWER(${String(column)})`} LIKE ${caseSensitive ? ph : `LOWER(${ph})`}`);
|
|
13898
|
+
whereParams.push(pattern);
|
|
13663
13899
|
return this;
|
|
13664
13900
|
},
|
|
13665
13901
|
whereILike(column, pattern) {
|
|
13902
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13666
13903
|
if (config5.dialect === "postgres") {
|
|
13667
13904
|
built = sql`${ensureBuilt()} WHERE ${sql(String(column))} ILIKE ${pattern}`;
|
|
13668
|
-
addWhereText("WHERE", `${String(column)} ILIKE
|
|
13905
|
+
addWhereText("WHERE", `${String(column)} ILIKE ${ph}`);
|
|
13669
13906
|
} else {
|
|
13670
13907
|
const expr = sql`LOWER(${sql(String(column))}) LIKE LOWER(${pattern})`;
|
|
13671
13908
|
built = sql`${ensureBuilt()} WHERE ${expr}`;
|
|
13672
|
-
addWhereText("WHERE", `LOWER(${String(column)}) LIKE LOWER(
|
|
13909
|
+
addWhereText("WHERE", `LOWER(${String(column)}) LIKE LOWER(${ph})`);
|
|
13673
13910
|
}
|
|
13911
|
+
whereParams.push(pattern);
|
|
13674
13912
|
return this;
|
|
13675
13913
|
},
|
|
13676
13914
|
orWhereLike(column, pattern, caseSensitive = false) {
|
|
13677
13915
|
const expr = caseSensitive ? sql`${sql(String(column))} LIKE ${pattern}` : sql`LOWER(${sql(String(column))}) LIKE LOWER(${pattern})`;
|
|
13678
13916
|
built = sql`${ensureBuilt()} OR ${expr}`;
|
|
13679
|
-
|
|
13917
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13918
|
+
addWhereText("OR", `${caseSensitive ? String(column) : `LOWER(${String(column)})`} LIKE ${caseSensitive ? ph : `LOWER(${ph})`}`);
|
|
13919
|
+
whereParams.push(pattern);
|
|
13680
13920
|
return this;
|
|
13681
13921
|
},
|
|
13682
13922
|
orWhereILike(column, pattern) {
|
|
13923
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13683
13924
|
if (config5.dialect === "postgres") {
|
|
13684
13925
|
built = sql`${ensureBuilt()} OR ${sql(String(column))} ILIKE ${pattern}`;
|
|
13685
|
-
addWhereText("OR", `${String(column)} ILIKE
|
|
13926
|
+
addWhereText("OR", `${String(column)} ILIKE ${ph}`);
|
|
13686
13927
|
} else {
|
|
13687
13928
|
const expr = sql`LOWER(${sql(String(column))}) LIKE LOWER(${pattern})`;
|
|
13688
13929
|
built = sql`${ensureBuilt()} OR ${expr}`;
|
|
13689
|
-
addWhereText("OR", `LOWER(${String(column)}) LIKE LOWER(
|
|
13930
|
+
addWhereText("OR", `LOWER(${String(column)}) LIKE LOWER(${ph})`);
|
|
13690
13931
|
}
|
|
13932
|
+
whereParams.push(pattern);
|
|
13691
13933
|
return this;
|
|
13692
13934
|
},
|
|
13693
13935
|
whereNotLike(column, pattern, caseSensitive = false) {
|
|
13694
13936
|
const expr = caseSensitive ? sql`${sql(String(column))} NOT LIKE ${pattern}` : sql`LOWER(${sql(String(column))}) NOT LIKE LOWER(${pattern})`;
|
|
13695
13937
|
built = sql`${ensureBuilt()} WHERE ${expr}`;
|
|
13696
|
-
|
|
13938
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13939
|
+
addWhereText("WHERE", `${caseSensitive ? String(column) : `LOWER(${String(column)})`} NOT LIKE ${caseSensitive ? ph : `LOWER(${ph})`}`);
|
|
13940
|
+
whereParams.push(pattern);
|
|
13697
13941
|
return this;
|
|
13698
13942
|
},
|
|
13699
13943
|
whereNotILike(column, pattern) {
|
|
13944
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13700
13945
|
if (config5.dialect === "postgres") {
|
|
13701
13946
|
built = sql`${ensureBuilt()} WHERE ${sql(String(column))} NOT ILIKE ${pattern}`;
|
|
13702
|
-
addWhereText("WHERE", `${String(column)} NOT ILIKE
|
|
13947
|
+
addWhereText("WHERE", `${String(column)} NOT ILIKE ${ph}`);
|
|
13703
13948
|
} else {
|
|
13704
13949
|
const expr = sql`LOWER(${sql(String(column))}) NOT LIKE LOWER(${pattern})`;
|
|
13705
13950
|
built = sql`${ensureBuilt()} WHERE ${expr}`;
|
|
13706
|
-
addWhereText("WHERE", `LOWER(${String(column)}) NOT LIKE LOWER(
|
|
13951
|
+
addWhereText("WHERE", `LOWER(${String(column)}) NOT LIKE LOWER(${ph})`);
|
|
13707
13952
|
}
|
|
13953
|
+
whereParams.push(pattern);
|
|
13708
13954
|
return this;
|
|
13709
13955
|
},
|
|
13710
13956
|
orWhereNotLike(column, pattern, caseSensitive = false) {
|
|
13711
13957
|
const expr = caseSensitive ? sql`${sql(String(column))} NOT LIKE ${pattern}` : sql`LOWER(${sql(String(column))}) NOT LIKE LOWER(${pattern})`;
|
|
13712
13958
|
built = sql`${ensureBuilt()} OR ${expr}`;
|
|
13713
|
-
|
|
13959
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13960
|
+
addWhereText("OR", `${caseSensitive ? String(column) : `LOWER(${String(column)})`} NOT LIKE ${caseSensitive ? ph : `LOWER(${ph})`}`);
|
|
13961
|
+
whereParams.push(pattern);
|
|
13714
13962
|
return this;
|
|
13715
13963
|
},
|
|
13716
13964
|
orWhereNotILike(column, pattern) {
|
|
13965
|
+
const ph = getPlaceholder(whereParams.length + 1);
|
|
13717
13966
|
if (config5.dialect === "postgres") {
|
|
13718
13967
|
built = sql`${ensureBuilt()} OR ${sql(String(column))} NOT ILIKE ${pattern}`;
|
|
13719
|
-
addWhereText("OR", `${String(column)} NOT ILIKE
|
|
13968
|
+
addWhereText("OR", `${String(column)} NOT ILIKE ${ph}`);
|
|
13720
13969
|
} else {
|
|
13721
13970
|
const expr = sql`LOWER(${sql(String(column))}) NOT LIKE LOWER(${pattern})`;
|
|
13722
13971
|
built = sql`${ensureBuilt()} OR ${expr}`;
|
|
13723
|
-
addWhereText("OR", `LOWER(${String(column)}) NOT LIKE LOWER(
|
|
13972
|
+
addWhereText("OR", `LOWER(${String(column)}) NOT LIKE LOWER(${ph})`);
|
|
13724
13973
|
}
|
|
13974
|
+
whereParams.push(pattern);
|
|
13725
13975
|
return this;
|
|
13726
13976
|
},
|
|
13727
13977
|
whereAny(cols, op, value) {
|
|
@@ -13762,7 +14012,8 @@ function createQueryBuilder(state) {
|
|
|
13762
14012
|
},
|
|
13763
14013
|
whereNotBetween(column, start, end) {
|
|
13764
14014
|
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
13765
|
-
|
|
14015
|
+
const i = whereParams.length + 1;
|
|
14016
|
+
text += ` ${keyword} ${column} NOT BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`;
|
|
13766
14017
|
whereParams.push(start, end);
|
|
13767
14018
|
built = null;
|
|
13768
14019
|
return this;
|
|
@@ -14030,7 +14281,7 @@ function createQueryBuilder(state) {
|
|
|
14030
14281
|
return this;
|
|
14031
14282
|
},
|
|
14032
14283
|
join(table2, onLeft, operator, onRight) {
|
|
14033
|
-
|
|
14284
|
+
insertJoin(`JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
|
|
14034
14285
|
joinedTables.add(table2);
|
|
14035
14286
|
return this;
|
|
14036
14287
|
},
|
|
@@ -14039,44 +14290,37 @@ function createQueryBuilder(state) {
|
|
|
14039
14290
|
validateQualifiedIdentifier(onLeft, "joinSub(onLeft)");
|
|
14040
14291
|
validateQualifiedIdentifier(onRight, "joinSub(onRight)");
|
|
14041
14292
|
assertSafeWhereOperator(operator, "joinSub(operator)");
|
|
14042
|
-
|
|
14043
|
-
built = null;
|
|
14293
|
+
insertJoin(`JOIN (${String(sub.toSQL())}) AS ${alias} ON ${onLeft} ${operator} ${onRight}`);
|
|
14044
14294
|
joinedTables.add(alias);
|
|
14045
14295
|
return this;
|
|
14046
14296
|
},
|
|
14047
14297
|
innerJoin(table2, onLeft, operator, onRight) {
|
|
14048
|
-
|
|
14049
|
-
built = null;
|
|
14298
|
+
insertJoin(`INNER JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
|
|
14050
14299
|
joinedTables.add(table2);
|
|
14051
14300
|
return this;
|
|
14052
14301
|
},
|
|
14053
14302
|
leftJoin(table2, onLeft, operator, onRight) {
|
|
14054
|
-
|
|
14055
|
-
built = null;
|
|
14303
|
+
insertJoin(`LEFT JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
|
|
14056
14304
|
joinedTables.add(table2);
|
|
14057
14305
|
return this;
|
|
14058
14306
|
},
|
|
14059
14307
|
leftJoinSub(sub, alias, onLeft, operator, onRight) {
|
|
14060
|
-
|
|
14061
|
-
built = null;
|
|
14308
|
+
insertJoin(`LEFT JOIN (${String(sub.toSQL())}) AS ${alias} ON ${onLeft} ${operator} ${onRight}`);
|
|
14062
14309
|
joinedTables.add(alias);
|
|
14063
14310
|
return this;
|
|
14064
14311
|
},
|
|
14065
14312
|
rightJoin(table2, onLeft, operator, onRight) {
|
|
14066
|
-
|
|
14067
|
-
built = null;
|
|
14313
|
+
insertJoin(`RIGHT JOIN ${table2} ON ${onLeft} ${operator} ${onRight}`);
|
|
14068
14314
|
joinedTables.add(table2);
|
|
14069
14315
|
return this;
|
|
14070
14316
|
},
|
|
14071
14317
|
crossJoin(table2) {
|
|
14072
|
-
|
|
14073
|
-
built = null;
|
|
14318
|
+
insertJoin(`CROSS JOIN ${table2}`);
|
|
14074
14319
|
joinedTables.add(table2);
|
|
14075
14320
|
return this;
|
|
14076
14321
|
},
|
|
14077
14322
|
crossJoinSub(sub, alias) {
|
|
14078
|
-
|
|
14079
|
-
built = null;
|
|
14323
|
+
insertJoin(`CROSS JOIN (${String(sub.toSQL())}) AS ${alias}`);
|
|
14080
14324
|
joinedTables.add(alias);
|
|
14081
14325
|
return this;
|
|
14082
14326
|
},
|
|
@@ -14129,9 +14373,10 @@ function createQueryBuilder(state) {
|
|
|
14129
14373
|
return this;
|
|
14130
14374
|
},
|
|
14131
14375
|
having(expr) {
|
|
14376
|
+
const kw = /\bHAVING\b/i.test(text) ? "AND" : "HAVING";
|
|
14132
14377
|
if (Array.isArray(expr)) {
|
|
14133
14378
|
const paramIdx = whereParams.length + 1;
|
|
14134
|
-
text = `${text}
|
|
14379
|
+
text = `${text} ${kw} ${expr[0]} ${expr[1]} ${getPlaceholder(paramIdx)}`;
|
|
14135
14380
|
whereParams.push(expr[2]);
|
|
14136
14381
|
built = null;
|
|
14137
14382
|
} else if (expr && typeof expr === "object" && !("raw" in expr)) {
|
|
@@ -14145,18 +14390,19 @@ function createQueryBuilder(state) {
|
|
|
14145
14390
|
conditions[i] = `${key} = ${getPlaceholder(baseIdx + i + 1)}`;
|
|
14146
14391
|
whereParams.push(expr[key]);
|
|
14147
14392
|
}
|
|
14148
|
-
text = `${text}
|
|
14393
|
+
text = `${text} ${kw} ${conditions.join(" AND ")}`;
|
|
14149
14394
|
built = null;
|
|
14150
14395
|
}
|
|
14151
14396
|
} else if (expr && typeof expr.raw !== "undefined") {
|
|
14152
|
-
text += `
|
|
14397
|
+
text += ` ${kw} ${expr.raw}`;
|
|
14153
14398
|
built = null;
|
|
14154
14399
|
}
|
|
14155
14400
|
return this;
|
|
14156
14401
|
},
|
|
14157
14402
|
havingRaw(fragment) {
|
|
14158
14403
|
assertSqlFragment(fragment, "havingRaw(fragment)");
|
|
14159
|
-
text
|
|
14404
|
+
const kw = /\bHAVING\b/i.test(text) ? "AND" : "HAVING";
|
|
14405
|
+
text += ` ${kw} ${String(fragment)}`;
|
|
14160
14406
|
built = null;
|
|
14161
14407
|
return this;
|
|
14162
14408
|
},
|
|
@@ -14167,13 +14413,27 @@ function createQueryBuilder(state) {
|
|
|
14167
14413
|
return this;
|
|
14168
14414
|
},
|
|
14169
14415
|
union(other) {
|
|
14170
|
-
|
|
14171
|
-
built = null;
|
|
14416
|
+
appendSetOp("UNION", other);
|
|
14172
14417
|
return this;
|
|
14173
14418
|
},
|
|
14174
14419
|
unionAll(other) {
|
|
14175
|
-
|
|
14176
|
-
|
|
14420
|
+
appendSetOp("UNION ALL", other);
|
|
14421
|
+
return this;
|
|
14422
|
+
},
|
|
14423
|
+
intersect(other) {
|
|
14424
|
+
appendSetOp("INTERSECT", other);
|
|
14425
|
+
return this;
|
|
14426
|
+
},
|
|
14427
|
+
intersectAll(other) {
|
|
14428
|
+
appendSetOp("INTERSECT ALL", other);
|
|
14429
|
+
return this;
|
|
14430
|
+
},
|
|
14431
|
+
except(other) {
|
|
14432
|
+
appendSetOp("EXCEPT", other);
|
|
14433
|
+
return this;
|
|
14434
|
+
},
|
|
14435
|
+
exceptAll(other) {
|
|
14436
|
+
appendSetOp("EXCEPT ALL", other);
|
|
14177
14437
|
return this;
|
|
14178
14438
|
},
|
|
14179
14439
|
forPage(page, perPage) {
|
|
@@ -14217,11 +14477,22 @@ function createQueryBuilder(state) {
|
|
|
14217
14477
|
const e = await this.exists();
|
|
14218
14478
|
return !e;
|
|
14219
14479
|
},
|
|
14220
|
-
async paginate(perPage, page = 1) {
|
|
14480
|
+
async paginate(perPage, page = 1, opts = {}) {
|
|
14221
14481
|
if (!Number.isFinite(perPage) || perPage <= 0 || !Number.isInteger(perPage))
|
|
14222
14482
|
throw new TypeError(`[query-builder] paginate(perPage): expected positive integer, got ${perPage}`);
|
|
14223
14483
|
if (!Number.isFinite(page) || page < 1 || !Number.isInteger(page))
|
|
14224
14484
|
throw new TypeError(`[query-builder] paginate(page): expected integer >= 1, got ${page}`);
|
|
14485
|
+
if (opts.tx) {
|
|
14486
|
+
const baseSql = reorderSelectClauses(text);
|
|
14487
|
+
const baseParams = [...whereParams];
|
|
14488
|
+
const cRows2 = await opts.tx.unsafe(`SELECT COUNT(*) as c FROM (${baseSql}) as sub`, baseParams);
|
|
14489
|
+
const total2 = Number(cRows2?.[0]?.c ?? 0);
|
|
14490
|
+
const lastPage2 = Math.max(1, Math.ceil(total2 / perPage));
|
|
14491
|
+
const p2 = Math.max(1, Math.min(page, lastPage2));
|
|
14492
|
+
const offset2 = (p2 - 1) * perPage;
|
|
14493
|
+
const data2 = await opts.tx.unsafe(`${baseSql} LIMIT ${perPage} OFFSET ${offset2}`, baseParams);
|
|
14494
|
+
return { data: data2, meta: { perPage, page: p2, total: total2, lastPage: lastPage2 } };
|
|
14495
|
+
}
|
|
14225
14496
|
const countQ = sql`SELECT COUNT(*) as c FROM (${ensureBuilt()}) as sub`;
|
|
14226
14497
|
const cRows = await runWithHooks(countQ, "select", { signal: abortSignal, timeoutMs });
|
|
14227
14498
|
const [cRow] = cRows;
|
|
@@ -14378,7 +14649,7 @@ function createQueryBuilder(state) {
|
|
|
14378
14649
|
},
|
|
14379
14650
|
async get() {
|
|
14380
14651
|
const hooks = config5.hooks;
|
|
14381
|
-
const hasQueryHooks = hooks && (hooks.onQueryStart || hooks.onQueryEnd || hooks.onQueryError || hooks.startSpan);
|
|
14652
|
+
const hasQueryHooks = hooks && (hooks.onQueryStart || hooks.onQueryEnd || hooks.onQueryError || hooks.startSpan || hasSlowQueryHook(hooks));
|
|
14382
14653
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !hasQueryHooks) {
|
|
14383
14654
|
const prepareFn = _sql._prepareStatement;
|
|
14384
14655
|
if (prepareFn) {
|
|
@@ -14433,7 +14704,7 @@ function createQueryBuilder(state) {
|
|
|
14433
14704
|
},
|
|
14434
14705
|
async first() {
|
|
14435
14706
|
const fHooks = config5.hooks;
|
|
14436
|
-
const fHasQueryHooks = fHooks && (fHooks.onQueryStart || fHooks.onQueryEnd || fHooks.onQueryError || fHooks.startSpan);
|
|
14707
|
+
const fHasQueryHooks = fHooks && (fHooks.onQueryStart || fHooks.onQueryEnd || fHooks.onQueryError || fHooks.startSpan || hasSlowQueryHook(fHooks));
|
|
14437
14708
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !fHasQueryHooks) {
|
|
14438
14709
|
const prepareFn = _sql._prepareStatement;
|
|
14439
14710
|
if (prepareFn) {
|
|
@@ -14515,7 +14786,7 @@ function createQueryBuilder(state) {
|
|
|
14515
14786
|
countText = `SELECT COUNT(*) as c FROM ${table}`;
|
|
14516
14787
|
}
|
|
14517
14788
|
const cHooks = config5.hooks;
|
|
14518
|
-
const cHasHooks = cHooks && (cHooks.onQueryStart || cHooks.onQueryEnd || cHooks.onQueryError || cHooks.startSpan);
|
|
14789
|
+
const cHasHooks = cHooks && (cHooks.onQueryStart || cHooks.onQueryEnd || cHooks.onQueryError || cHooks.startSpan || hasSlowQueryHook(cHooks));
|
|
14519
14790
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !cHasHooks) {
|
|
14520
14791
|
const prepareFn = _sql._prepareStatement;
|
|
14521
14792
|
if (prepareFn) {
|
|
@@ -14533,7 +14804,7 @@ function createQueryBuilder(state) {
|
|
|
14533
14804
|
const fromIdx = text.indexOf(" FROM ");
|
|
14534
14805
|
const avgText = fromIdx !== -1 ? `SELECT AVG(${column}) as a${text.substring(fromIdx)}` : `SELECT AVG(${column}) as a FROM ${table}`;
|
|
14535
14806
|
const aHooks = config5.hooks;
|
|
14536
|
-
const aHasHooks = aHooks && (aHooks.onQueryStart || aHooks.onQueryEnd || aHooks.onQueryError || aHooks.startSpan);
|
|
14807
|
+
const aHasHooks = aHooks && (aHooks.onQueryStart || aHooks.onQueryEnd || aHooks.onQueryError || aHooks.startSpan || hasSlowQueryHook(aHooks));
|
|
14537
14808
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !aHasHooks) {
|
|
14538
14809
|
const prepareFn = _sql._prepareStatement;
|
|
14539
14810
|
if (prepareFn) {
|
|
@@ -14603,6 +14874,9 @@ function createQueryBuilder(state) {
|
|
|
14603
14874
|
toParams() {
|
|
14604
14875
|
return ensureBuilt().values?.() ?? [];
|
|
14605
14876
|
},
|
|
14877
|
+
__rawState() {
|
|
14878
|
+
return { sql: reorderSelectClauses(text), params: [...whereParams] };
|
|
14879
|
+
},
|
|
14606
14880
|
raw() {
|
|
14607
14881
|
return ensureBuilt().raw();
|
|
14608
14882
|
},
|
|
@@ -14961,15 +15235,15 @@ function createQueryBuilder(state) {
|
|
|
14961
15235
|
params.length = totalParams;
|
|
14962
15236
|
if (rowCount === 1) {
|
|
14963
15237
|
if (!isPostgres) {
|
|
14964
|
-
let cols = keys[0];
|
|
15238
|
+
let cols = quoteId(keys[0]);
|
|
14965
15239
|
let placeholders = "?";
|
|
14966
15240
|
params[0] = firstRow[keys[0]];
|
|
14967
15241
|
for (let c = 1;c < colCount; c++) {
|
|
14968
|
-
cols += `,${keys[c]}`;
|
|
15242
|
+
cols += `,${quoteId(keys[c])}`;
|
|
14969
15243
|
placeholders += ",?";
|
|
14970
15244
|
params[c] = firstRow[keys[c]];
|
|
14971
15245
|
}
|
|
14972
|
-
sqlText = `INSERT INTO ${table}(${cols})VALUES(${placeholders})`;
|
|
15246
|
+
sqlText = `INSERT INTO ${quoteId(table)}(${cols})VALUES(${placeholders})`;
|
|
14973
15247
|
} else {
|
|
14974
15248
|
const columnList = keys.map((k) => quoteId(k)).join(",");
|
|
14975
15249
|
sqlText = `INSERT INTO ${quoteId(table)}(${columnList})VALUES(`;
|
|
@@ -15027,7 +15301,7 @@ function createQueryBuilder(state) {
|
|
|
15027
15301
|
},
|
|
15028
15302
|
execute() {
|
|
15029
15303
|
const hooks = config5.hooks;
|
|
15030
|
-
const hasHooks = hooks && (hooks.onQueryStart || hooks.onQueryEnd || hooks.onQueryError || hooks.startSpan || hooks.beforeCreate || hooks.afterCreate);
|
|
15304
|
+
const hasHooks = hooks && (hooks.onQueryStart || hooks.onQueryEnd || hooks.onQueryError || hooks.startSpan || hooks.beforeCreate || hooks.afterCreate || hasSlowQueryHook(hooks));
|
|
15031
15305
|
if (!hasHooks) {
|
|
15032
15306
|
const prepareFn = _sql._prepareStatement;
|
|
15033
15307
|
if (prepareFn) {
|
|
@@ -15501,55 +15775,72 @@ function createQueryBuilder(state) {
|
|
|
15501
15775
|
};
|
|
15502
15776
|
},
|
|
15503
15777
|
async insertOrIgnore(table, values) {
|
|
15504
|
-
|
|
15505
|
-
|
|
15506
|
-
return
|
|
15507
|
-
}
|
|
15508
|
-
const
|
|
15509
|
-
|
|
15778
|
+
const rows = Array.isArray(values) ? values : [values];
|
|
15779
|
+
if (!rows.length)
|
|
15780
|
+
return;
|
|
15781
|
+
const { colsSql, valuesSql, params } = buildInsertClause(rows);
|
|
15782
|
+
const tbl = quoteInsertIdent(String(table));
|
|
15783
|
+
const sqlText = config5.dialect === "mysql" ? `INSERT IGNORE INTO ${tbl} (${colsSql}) VALUES ${valuesSql}` : `INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql} ON CONFLICT DO NOTHING`;
|
|
15784
|
+
return bunSql.unsafe(sqlText, params).execute();
|
|
15510
15785
|
},
|
|
15511
15786
|
async insertGetId(table, values, idColumn = "id") {
|
|
15787
|
+
const { colsSql, valuesSql, params } = buildInsertClause([values]);
|
|
15788
|
+
const tbl = quoteInsertIdent(String(table));
|
|
15512
15789
|
if (config5.dialect === "mysql") {
|
|
15513
|
-
|
|
15514
|
-
const
|
|
15515
|
-
|
|
15516
|
-
|
|
15517
|
-
|
|
15518
|
-
const
|
|
15519
|
-
|
|
15520
|
-
|
|
15521
|
-
const
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
}
|
|
15790
|
+
await bunSql.unsafe(`INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`, params).execute();
|
|
15791
|
+
const [row2] = await bunSql.unsafe(`SELECT LAST_INSERT_ID() as id`).execute();
|
|
15792
|
+
return row2?.id;
|
|
15793
|
+
}
|
|
15794
|
+
if (config5.dialect === "sqlite") {
|
|
15795
|
+
const res = await bunSql.unsafe(`INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`, params).execute();
|
|
15796
|
+
if (res?.lastInsertRowid != null)
|
|
15797
|
+
return res.lastInsertRowid;
|
|
15798
|
+
const [row2] = await bunSql.unsafe(`SELECT last_insert_rowid() as id`).execute();
|
|
15799
|
+
return row2?.id;
|
|
15800
|
+
}
|
|
15801
|
+
const [row] = await bunSql.unsafe(`INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql} RETURNING ${quoteInsertIdent(String(idColumn))} as id`, params).execute();
|
|
15802
|
+
return row?.id;
|
|
15525
15803
|
},
|
|
15526
15804
|
async updateOrInsert(table, match, values) {
|
|
15527
|
-
const
|
|
15528
|
-
const
|
|
15529
|
-
|
|
15805
|
+
const tbl = quoteInsertIdent(String(table));
|
|
15806
|
+
const matchKeys = Object.keys(match);
|
|
15807
|
+
let idx = 1;
|
|
15808
|
+
const whereSql = matchKeys.map((k) => `${quoteInsertIdent(k)} = ${getPlaceholder(idx++)}`).join(" AND ");
|
|
15809
|
+
const whereParams = matchKeys.map((k) => match[k]);
|
|
15810
|
+
const existsRows = await bunSql.unsafe(`SELECT 1 FROM ${tbl} WHERE ${whereSql} LIMIT 1`, whereParams).execute();
|
|
15530
15811
|
if (existsRows.length) {
|
|
15531
|
-
const
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
const
|
|
15536
|
-
await
|
|
15812
|
+
const setKeys = Object.keys(values);
|
|
15813
|
+
let i = 1;
|
|
15814
|
+
const setSql = setKeys.map((k) => `${quoteInsertIdent(k)} = ${getPlaceholder(i++)}`).join(", ");
|
|
15815
|
+
const whereSql2 = matchKeys.map((k) => `${quoteInsertIdent(k)} = ${getPlaceholder(i++)}`).join(" AND ");
|
|
15816
|
+
const params2 = [...setKeys.map((k) => values[k]), ...matchKeys.map((k) => match[k])];
|
|
15817
|
+
await bunSql.unsafe(`UPDATE ${tbl} SET ${setSql} WHERE ${whereSql2}`, params2).execute();
|
|
15537
15818
|
return true;
|
|
15538
15819
|
}
|
|
15820
|
+
const { colsSql, valuesSql, params } = buildInsertClause([{ ...match, ...values }]);
|
|
15821
|
+
await bunSql.unsafe(`INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`, params).execute();
|
|
15822
|
+
return true;
|
|
15539
15823
|
},
|
|
15540
15824
|
async upsert(table, rows, conflictColumns, mergeColumns) {
|
|
15541
15825
|
const targetCols = conflictColumns.map((c) => String(c));
|
|
15542
15826
|
const setCols = (mergeColumns ?? []).map((c) => String(c));
|
|
15827
|
+
const list = rows;
|
|
15828
|
+
if (!list.length)
|
|
15829
|
+
return;
|
|
15830
|
+
const { colsSql, valuesSql, params } = buildInsertClause(list);
|
|
15831
|
+
const tbl = quoteInsertIdent(String(table));
|
|
15832
|
+
const insert = `INSERT INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`;
|
|
15543
15833
|
if (config5.dialect === "mysql") {
|
|
15544
|
-
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
|
|
15548
|
-
|
|
15549
|
-
const
|
|
15550
|
-
|
|
15551
|
-
|
|
15552
|
-
|
|
15834
|
+
if (setCols.length === 0)
|
|
15835
|
+
return bunSql.unsafe(`INSERT IGNORE INTO ${tbl} (${colsSql}) VALUES ${valuesSql}`, params).execute();
|
|
15836
|
+
const updateList2 = setCols.map((c) => `${quoteInsertIdent(c)} = VALUES(${quoteInsertIdent(c)})`).join(", ");
|
|
15837
|
+
return bunSql.unsafe(`${insert} ON DUPLICATE KEY UPDATE ${updateList2}`, params).execute();
|
|
15838
|
+
}
|
|
15839
|
+
const targets = targetCols.map(quoteInsertIdent).join(", ");
|
|
15840
|
+
if (setCols.length === 0)
|
|
15841
|
+
return bunSql.unsafe(`${insert} ON CONFLICT (${targets}) DO NOTHING`, params).execute();
|
|
15842
|
+
const updateList = setCols.map((c) => `${quoteInsertIdent(c)} = EXCLUDED.${quoteInsertIdent(c)}`).join(", ");
|
|
15843
|
+
return bunSql.unsafe(`${insert} ON CONFLICT (${targets}) DO UPDATE SET ${updateList}`, params).execute();
|
|
15553
15844
|
},
|
|
15554
15845
|
async save(table, values) {
|
|
15555
15846
|
const pk = meta?.primaryKeys[String(table)] ?? "id";
|
|
@@ -15652,7 +15943,8 @@ function createQueryBuilder(state) {
|
|
|
15652
15943
|
const colCount = keys.length;
|
|
15653
15944
|
const rowCount = rows.length;
|
|
15654
15945
|
const params = Array.from({ length: rowCount * colCount });
|
|
15655
|
-
|
|
15946
|
+
const quoteId = config5.dialect === "mysql" ? (id) => `\`${String(id).replace(/`/g, "``")}\`` : (id) => `"${String(id).replace(/"/g, '""')}"`;
|
|
15947
|
+
let sql = `INSERT INTO ${quoteId(String(table))}(${keys.map(quoteId).join(",")})VALUES`;
|
|
15656
15948
|
let pidx = 0;
|
|
15657
15949
|
for (let r = 0;r < rowCount; r++) {
|
|
15658
15950
|
if (r > 0)
|
|
@@ -15959,7 +16251,7 @@ var init_cache = __esm(() => {
|
|
|
15959
16251
|
});
|
|
15960
16252
|
|
|
15961
16253
|
// src/actions/console.ts
|
|
15962
|
-
import
|
|
16254
|
+
import process19 from "process";
|
|
15963
16255
|
import { createInterface } from "readline";
|
|
15964
16256
|
async function startConsole() {
|
|
15965
16257
|
console.log("-- Query Builder Interactive Console");
|
|
@@ -15968,8 +16260,8 @@ async function startConsole() {
|
|
|
15968
16260
|
console.log();
|
|
15969
16261
|
const qb = createQueryBuilder();
|
|
15970
16262
|
const rl = createInterface({
|
|
15971
|
-
input:
|
|
15972
|
-
output:
|
|
16263
|
+
input: process19.stdin,
|
|
16264
|
+
output: process19.stdout,
|
|
15973
16265
|
prompt: "qb> "
|
|
15974
16266
|
});
|
|
15975
16267
|
let multilineBuffer = "";
|
|
@@ -16020,7 +16312,7 @@ Tips:
|
|
|
16020
16312
|
if (cmd === ".exit" || cmd === ".quit") {
|
|
16021
16313
|
console.log("Goodbye!");
|
|
16022
16314
|
rl.close();
|
|
16023
|
-
|
|
16315
|
+
process19.exit(0);
|
|
16024
16316
|
} else if (cmd === ".help") {
|
|
16025
16317
|
console.log(helpText);
|
|
16026
16318
|
} else if (cmd === ".clear") {
|
|
@@ -16091,7 +16383,7 @@ Tips:
|
|
|
16091
16383
|
rl.on("close", () => {
|
|
16092
16384
|
console.log(`
|
|
16093
16385
|
Goodbye!`);
|
|
16094
|
-
|
|
16386
|
+
process19.exit(0);
|
|
16095
16387
|
});
|
|
16096
16388
|
rl.prompt();
|
|
16097
16389
|
}
|
|
@@ -16469,9 +16761,9 @@ var init_db_info = __esm(() => {
|
|
|
16469
16761
|
});
|
|
16470
16762
|
|
|
16471
16763
|
// src/actions/db-optimize.ts
|
|
16472
|
-
import
|
|
16764
|
+
import process21 from "process";
|
|
16473
16765
|
async function dbOptimize(options = {}) {
|
|
16474
|
-
const dialect = options.dialect ||
|
|
16766
|
+
const dialect = options.dialect || process21.env.DB_DIALECT || "postgres";
|
|
16475
16767
|
const aggressive = options.aggressive || false;
|
|
16476
16768
|
if (options.verbose) {
|
|
16477
16769
|
console.log(`Optimizing ${dialect} database${aggressive ? " (aggressive mode)" : ""}...`);
|
|
@@ -16511,7 +16803,7 @@ async function dbOptimize(options = {}) {
|
|
|
16511
16803
|
await bunSql`ANALYZE TABLE ${bunSql(table)}`;
|
|
16512
16804
|
}
|
|
16513
16805
|
} else {
|
|
16514
|
-
const dbName =
|
|
16806
|
+
const dbName = process21.env.DB_NAME || "test";
|
|
16515
16807
|
const tables = await bunSql`
|
|
16516
16808
|
SELECT table_name
|
|
16517
16809
|
FROM information_schema.tables
|
|
@@ -16563,9 +16855,9 @@ var init_db_optimize = __esm(() => {
|
|
|
16563
16855
|
});
|
|
16564
16856
|
|
|
16565
16857
|
// src/actions/db-wipe.ts
|
|
16566
|
-
import
|
|
16858
|
+
import process22 from "process";
|
|
16567
16859
|
async function dbWipe(options = {}) {
|
|
16568
|
-
const dialect = options.dialect ||
|
|
16860
|
+
const dialect = options.dialect || process22.env.DB_DIALECT || "postgres";
|
|
16569
16861
|
if (options.verbose) {
|
|
16570
16862
|
console.log(`Wiping all tables from ${dialect} database...`);
|
|
16571
16863
|
}
|
|
@@ -16579,7 +16871,7 @@ async function dbWipe(options = {}) {
|
|
|
16579
16871
|
`;
|
|
16580
16872
|
tables = result.map((row) => row.tablename);
|
|
16581
16873
|
} else if (dialect === "mysql") {
|
|
16582
|
-
const dbName =
|
|
16874
|
+
const dbName = process22.env.DB_NAME || "test";
|
|
16583
16875
|
const result = await bunSql`
|
|
16584
16876
|
SELECT table_name
|
|
16585
16877
|
FROM information_schema.tables
|
|
@@ -16872,10 +17164,130 @@ var init_introspect = __esm(() => {
|
|
|
16872
17164
|
init_src2();
|
|
16873
17165
|
});
|
|
16874
17166
|
|
|
17167
|
+
// src/actions/introspect-db.ts
|
|
17168
|
+
function sqlTypeToAttr(sqlType) {
|
|
17169
|
+
const t = sqlType.toLowerCase();
|
|
17170
|
+
if (/^bool|boolean|tinyint\(1\)/.test(t))
|
|
17171
|
+
return "boolean";
|
|
17172
|
+
if (/int|serial|numeric|decimal|double|real|float|money/.test(t))
|
|
17173
|
+
return "number";
|
|
17174
|
+
if (/timestamp|datetime|date|time/.test(t))
|
|
17175
|
+
return "datetime";
|
|
17176
|
+
if (/json/.test(t))
|
|
17177
|
+
return "json";
|
|
17178
|
+
return "string";
|
|
17179
|
+
}
|
|
17180
|
+
function singularize(name) {
|
|
17181
|
+
if (/ies$/i.test(name))
|
|
17182
|
+
return name.replace(/ies$/i, "y");
|
|
17183
|
+
if (/ses$/i.test(name))
|
|
17184
|
+
return name.replace(/es$/i, "");
|
|
17185
|
+
if (/s$/i.test(name) && !/ss$/i.test(name))
|
|
17186
|
+
return name.replace(/s$/i, "");
|
|
17187
|
+
return name;
|
|
17188
|
+
}
|
|
17189
|
+
function pascalCase(name) {
|
|
17190
|
+
return name.replace(/[-_\s]+/g, " ").split(" ").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
17191
|
+
}
|
|
17192
|
+
function modelNameForTable(table) {
|
|
17193
|
+
return pascalCase(singularize(table));
|
|
17194
|
+
}
|
|
17195
|
+
async function listTables(qb, dialect) {
|
|
17196
|
+
if (dialect === "postgres") {
|
|
17197
|
+
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`);
|
|
17198
|
+
return rows2.map((r) => r.table_name);
|
|
17199
|
+
}
|
|
17200
|
+
if (dialect === "mysql") {
|
|
17201
|
+
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`);
|
|
17202
|
+
return rows2.map((r) => r.table_name ?? r.TABLE_NAME);
|
|
17203
|
+
}
|
|
17204
|
+
const rows = await qb.unsafe(`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
|
17205
|
+
return rows.map((r) => r.name);
|
|
17206
|
+
}
|
|
17207
|
+
async function readColumns(qb, dialect, table) {
|
|
17208
|
+
if (dialect === "sqlite") {
|
|
17209
|
+
const rows2 = await qb.unsafe(`PRAGMA table_info(${table})`);
|
|
17210
|
+
return rows2.map((r) => ({
|
|
17211
|
+
name: r.name,
|
|
17212
|
+
sqlType: String(r.type || ""),
|
|
17213
|
+
nullable: Number(r.notnull) === 0,
|
|
17214
|
+
isPrimaryKey: Number(r.pk) > 0
|
|
17215
|
+
}));
|
|
17216
|
+
}
|
|
17217
|
+
if (dialect === "postgres") {
|
|
17218
|
+
const rows2 = await qb.unsafe(`SELECT c.column_name, c.data_type, c.is_nullable,
|
|
17219
|
+
(SELECT COUNT(*) FROM information_schema.table_constraints tc
|
|
17220
|
+
JOIN information_schema.key_column_usage k ON k.constraint_name = tc.constraint_name
|
|
17221
|
+
WHERE tc.constraint_type = 'PRIMARY KEY' AND tc.table_name = c.table_name AND k.column_name = c.column_name) AS is_pk
|
|
17222
|
+
FROM information_schema.columns c
|
|
17223
|
+
WHERE c.table_name = $1 AND c.table_schema = 'public'
|
|
17224
|
+
ORDER BY c.ordinal_position`, [table]);
|
|
17225
|
+
return rows2.map((r) => ({
|
|
17226
|
+
name: r.column_name,
|
|
17227
|
+
sqlType: String(r.data_type || ""),
|
|
17228
|
+
nullable: String(r.is_nullable).toUpperCase() === "YES",
|
|
17229
|
+
isPrimaryKey: Number(r.is_pk) > 0
|
|
17230
|
+
}));
|
|
17231
|
+
}
|
|
17232
|
+
const rows = await qb.unsafe(`SELECT column_name, data_type, is_nullable, column_key
|
|
17233
|
+
FROM information_schema.columns
|
|
17234
|
+
WHERE table_name = ? AND table_schema = DATABASE()
|
|
17235
|
+
ORDER BY ordinal_position`, [table]);
|
|
17236
|
+
return rows.map((r) => ({
|
|
17237
|
+
name: r.column_name ?? r.COLUMN_NAME,
|
|
17238
|
+
sqlType: String(r.data_type ?? r.DATA_TYPE ?? ""),
|
|
17239
|
+
nullable: String(r.is_nullable ?? r.IS_NULLABLE).toUpperCase() === "YES",
|
|
17240
|
+
isPrimaryKey: String(r.column_key ?? r.COLUMN_KEY).toUpperCase() === "PRI"
|
|
17241
|
+
}));
|
|
17242
|
+
}
|
|
17243
|
+
function generateModelSource(table, columns) {
|
|
17244
|
+
const modelName = modelNameForTable(table);
|
|
17245
|
+
const pk = columns.find((c) => c.isPrimaryKey)?.name ?? "id";
|
|
17246
|
+
const attrLines = columns.map((c) => {
|
|
17247
|
+
const parts = [`type: '${sqlTypeToAttr(c.sqlType)}'`];
|
|
17248
|
+
if (!c.nullable && !c.isPrimaryKey)
|
|
17249
|
+
parts.push("required: true");
|
|
17250
|
+
return ` ${c.name}: { ${parts.join(", ")} },`;
|
|
17251
|
+
}).join(`
|
|
17252
|
+
`);
|
|
17253
|
+
return `export const ${modelName} = defineModel({
|
|
17254
|
+
name: '${modelName}',
|
|
17255
|
+
table: '${table}',
|
|
17256
|
+
primaryKey: '${pk}',
|
|
17257
|
+
attributes: {
|
|
17258
|
+
${attrLines}
|
|
17259
|
+
},
|
|
17260
|
+
})
|
|
17261
|
+
`;
|
|
17262
|
+
}
|
|
17263
|
+
async function introspectDatabase(opts = {}) {
|
|
17264
|
+
const dialect = config5.dialect || "postgres";
|
|
17265
|
+
const qb = createQueryBuilder();
|
|
17266
|
+
const tables = opts.tables?.length ? opts.tables : await listTables(qb, dialect);
|
|
17267
|
+
const out = [];
|
|
17268
|
+
for (const table of tables) {
|
|
17269
|
+
const columns = await readColumns(qb, dialect, table);
|
|
17270
|
+
if (!columns.length)
|
|
17271
|
+
continue;
|
|
17272
|
+
out.push({
|
|
17273
|
+
table,
|
|
17274
|
+
modelName: modelNameForTable(table),
|
|
17275
|
+
primaryKey: columns.find((c) => c.isPrimaryKey)?.name ?? "id",
|
|
17276
|
+
columns,
|
|
17277
|
+
source: generateModelSource(table, columns)
|
|
17278
|
+
});
|
|
17279
|
+
}
|
|
17280
|
+
return out;
|
|
17281
|
+
}
|
|
17282
|
+
var init_introspect_db = __esm(() => {
|
|
17283
|
+
init_config();
|
|
17284
|
+
init_src2();
|
|
17285
|
+
});
|
|
17286
|
+
|
|
16875
17287
|
// src/actions/make-model.ts
|
|
16876
17288
|
import { existsSync as existsSync14, mkdirSync as mkdirSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
16877
17289
|
import { dirname as dirname5, join as join7 } from "path";
|
|
16878
|
-
import
|
|
17290
|
+
import process23 from "process";
|
|
16879
17291
|
function findWorkspaceRoot(startPath) {
|
|
16880
17292
|
let currentPath = startPath;
|
|
16881
17293
|
while (currentPath !== dirname5(currentPath)) {
|
|
@@ -16884,10 +17296,10 @@ function findWorkspaceRoot(startPath) {
|
|
|
16884
17296
|
}
|
|
16885
17297
|
currentPath = dirname5(currentPath);
|
|
16886
17298
|
}
|
|
16887
|
-
return
|
|
17299
|
+
return process23.cwd();
|
|
16888
17300
|
}
|
|
16889
17301
|
async function makeModel(name, options = {}) {
|
|
16890
|
-
const workspaceRoot = findWorkspaceRoot(
|
|
17302
|
+
const workspaceRoot = findWorkspaceRoot(process23.cwd());
|
|
16891
17303
|
const modelsDir = options.dir || join7(workspaceRoot, "app/Models");
|
|
16892
17304
|
if (!existsSync14(modelsDir)) {
|
|
16893
17305
|
mkdirSync5(modelsDir, { recursive: true });
|
|
@@ -17444,7 +17856,7 @@ __export(exports_migrate, {
|
|
|
17444
17856
|
import { existsSync as existsSync16, mkdirSync as mkdirSync7, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
|
|
17445
17857
|
import { tmpdir } from "os";
|
|
17446
17858
|
import { join as join9 } from "path";
|
|
17447
|
-
import
|
|
17859
|
+
import process24 from "process";
|
|
17448
17860
|
function info(message) {
|
|
17449
17861
|
if (config5.verbose)
|
|
17450
17862
|
console.log(message);
|
|
@@ -17491,7 +17903,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
|
|
|
17491
17903
|
info(`-- Model snapshot saved to ${snapshotPath}`);
|
|
17492
17904
|
}
|
|
17493
17905
|
function getWorkspaceRoot() {
|
|
17494
|
-
return
|
|
17906
|
+
return process24.cwd();
|
|
17495
17907
|
}
|
|
17496
17908
|
function ensureSqlDirectory(workspaceRoot) {
|
|
17497
17909
|
const sqlDir = getSqlDirectory(workspaceRoot);
|
|
@@ -17503,7 +17915,7 @@ function ensureSqlDirectory(workspaceRoot) {
|
|
|
17503
17915
|
}
|
|
17504
17916
|
async function generateMigration(dir, opts = {}) {
|
|
17505
17917
|
if (!dir) {
|
|
17506
|
-
dir = join9(
|
|
17918
|
+
dir = join9(process24.cwd(), "app/Models");
|
|
17507
17919
|
}
|
|
17508
17920
|
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
17509
17921
|
const workspaceRoot = getWorkspaceRoot();
|
|
@@ -17558,7 +17970,7 @@ async function generateMigration(dir, opts = {}) {
|
|
|
17558
17970
|
}
|
|
17559
17971
|
async function executeMigration(dir) {
|
|
17560
17972
|
if (!dir) {
|
|
17561
|
-
dir = join9(
|
|
17973
|
+
dir = join9(process24.cwd(), "app/Models");
|
|
17562
17974
|
}
|
|
17563
17975
|
const workspaceRoot = getWorkspaceRoot();
|
|
17564
17976
|
const sqlDir = ensureSqlDirectory(workspaceRoot);
|
|
@@ -17623,7 +18035,7 @@ async function executeMigration(dir) {
|
|
|
17623
18035
|
}
|
|
17624
18036
|
async function resetDatabase(dir, opts = {}) {
|
|
17625
18037
|
if (!dir) {
|
|
17626
|
-
dir = join9(
|
|
18038
|
+
dir = join9(process24.cwd(), "app/Models");
|
|
17627
18039
|
}
|
|
17628
18040
|
const dialect = opts.dialect || "postgres";
|
|
17629
18041
|
const driver = getDialectDriver(dialect);
|
|
@@ -17716,7 +18128,7 @@ async function resetDatabase(dir, opts = {}) {
|
|
|
17716
18128
|
}
|
|
17717
18129
|
async function deleteMigrationFiles(dir, workspaceRoot, opts = {}) {
|
|
17718
18130
|
if (!dir) {
|
|
17719
|
-
dir = join9(
|
|
18131
|
+
dir = join9(process24.cwd(), "app/Models");
|
|
17720
18132
|
}
|
|
17721
18133
|
if (!workspaceRoot) {
|
|
17722
18134
|
workspaceRoot = getWorkspaceRoot();
|
|
@@ -17814,9 +18226,51 @@ var init_migrate_generate = __esm(() => {
|
|
|
17814
18226
|
});
|
|
17815
18227
|
|
|
17816
18228
|
// src/actions/migrate-rollback.ts
|
|
17817
|
-
import { existsSync as existsSync17, unlinkSync as unlinkSync2 } from "fs";
|
|
18229
|
+
import { existsSync as existsSync17, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
17818
18230
|
import { dirname as dirname7, join as join10 } from "path";
|
|
17819
|
-
import
|
|
18231
|
+
import process25 from "process";
|
|
18232
|
+
function splitSqlStatements2(sql) {
|
|
18233
|
+
const out = [];
|
|
18234
|
+
let buf = "";
|
|
18235
|
+
let inString = false;
|
|
18236
|
+
const lines = sql.split(`
|
|
18237
|
+
`).filter((l) => !/^\s*--/.test(l));
|
|
18238
|
+
const text = lines.join(`
|
|
18239
|
+
`);
|
|
18240
|
+
for (let i = 0;i < text.length; i++) {
|
|
18241
|
+
const ch = text[i];
|
|
18242
|
+
if (ch === "'")
|
|
18243
|
+
inString = !inString;
|
|
18244
|
+
if (ch === ";" && !inString) {
|
|
18245
|
+
if (buf.trim())
|
|
18246
|
+
out.push(buf.trim());
|
|
18247
|
+
buf = "";
|
|
18248
|
+
} else {
|
|
18249
|
+
buf += ch;
|
|
18250
|
+
}
|
|
18251
|
+
}
|
|
18252
|
+
if (buf.trim())
|
|
18253
|
+
out.push(buf.trim());
|
|
18254
|
+
return out;
|
|
18255
|
+
}
|
|
18256
|
+
function deriveDownStatements(forwardSql, dialect = config5.dialect) {
|
|
18257
|
+
const q = (id) => dialect === "mysql" ? `\`${id}\`` : `"${id}"`;
|
|
18258
|
+
const down = [];
|
|
18259
|
+
const skipped = [];
|
|
18260
|
+
for (const stmt of splitSqlStatements2(forwardSql)) {
|
|
18261
|
+
let m;
|
|
18262
|
+
if (m = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
|
|
18263
|
+
down.push(`DROP TABLE IF EXISTS ${q(m[1])}`);
|
|
18264
|
+
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+(?:COLUMN\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
|
|
18265
|
+
down.push(`ALTER TABLE ${q(m[1])} DROP COLUMN ${q(m[2])}`);
|
|
18266
|
+
} else if (m = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?(?:\s+ON\s+["`']?(\w+)["`']?)?/i.exec(stmt)) {
|
|
18267
|
+
down.push(dialect === "mysql" && m[2] ? `DROP INDEX ${q(m[1])} ON ${q(m[2])}` : `DROP INDEX IF EXISTS ${q(m[1])}`);
|
|
18268
|
+
} else {
|
|
18269
|
+
skipped.push(stmt);
|
|
18270
|
+
}
|
|
18271
|
+
}
|
|
18272
|
+
return { down: down.reverse(), skipped };
|
|
18273
|
+
}
|
|
17820
18274
|
function findWorkspaceRoot2(startPath) {
|
|
17821
18275
|
let currentPath = startPath;
|
|
17822
18276
|
while (currentPath !== dirname7(currentPath)) {
|
|
@@ -17825,16 +18279,17 @@ function findWorkspaceRoot2(startPath) {
|
|
|
17825
18279
|
}
|
|
17826
18280
|
currentPath = dirname7(currentPath);
|
|
17827
18281
|
}
|
|
17828
|
-
return
|
|
18282
|
+
return process25.cwd();
|
|
17829
18283
|
}
|
|
17830
18284
|
function getSqlDirectory2(workspaceRoot) {
|
|
17831
18285
|
if (!workspaceRoot) {
|
|
17832
|
-
workspaceRoot = findWorkspaceRoot2(
|
|
18286
|
+
workspaceRoot = findWorkspaceRoot2(process25.cwd());
|
|
17833
18287
|
}
|
|
17834
18288
|
return join10(workspaceRoot, "database", "migrations");
|
|
17835
18289
|
}
|
|
17836
18290
|
async function migrateRollback(options = {}) {
|
|
17837
18291
|
const steps = options.steps || 1;
|
|
18292
|
+
const reverseSchema = options.reverseSchema !== false;
|
|
17838
18293
|
console.log("-- Rolling back migrations");
|
|
17839
18294
|
console.log(`-- Steps: ${steps}`);
|
|
17840
18295
|
console.log();
|
|
@@ -17864,13 +18319,25 @@ async function migrateRollback(options = {}) {
|
|
|
17864
18319
|
console.log(` - ${migration.migration}`);
|
|
17865
18320
|
}
|
|
17866
18321
|
console.log();
|
|
18322
|
+
const sqlDir = getSqlDirectory2();
|
|
18323
|
+
let reversedAny = false;
|
|
17867
18324
|
for (const migration of migrationsToRollback) {
|
|
17868
18325
|
try {
|
|
18326
|
+
const filePath = join10(sqlDir, migration.migration);
|
|
18327
|
+
if (reverseSchema && existsSync17(filePath)) {
|
|
18328
|
+
const forwardSql = readFileSync4(filePath, "utf8");
|
|
18329
|
+
const { down, skipped } = deriveDownStatements(forwardSql);
|
|
18330
|
+
for (const stmt of down) {
|
|
18331
|
+
await qb.unsafe(stmt);
|
|
18332
|
+
console.log(`-- \u21A9 ${stmt}`);
|
|
18333
|
+
reversedAny = true;
|
|
18334
|
+
}
|
|
18335
|
+
if (skipped.length > 0)
|
|
18336
|
+
console.log(`-- \u26A0\uFE0F ${skipped.length} statement(s) in ${migration.migration} could not be auto-reversed (data/complex DDL) \u2014 reverse manually.`);
|
|
18337
|
+
}
|
|
17869
18338
|
const deleteSql = `DELETE FROM migrations WHERE migration = $1`;
|
|
17870
18339
|
await qb.unsafe(deleteSql, [migration.migration]);
|
|
17871
18340
|
console.log(`-- \u2713 Removed migration record: ${migration.migration}`);
|
|
17872
|
-
const sqlDir = getSqlDirectory2();
|
|
17873
|
-
const filePath = join10(sqlDir, migration.migration);
|
|
17874
18341
|
if (existsSync17(filePath)) {
|
|
17875
18342
|
unlinkSync2(filePath);
|
|
17876
18343
|
console.log(`-- \uD83D\uDDD1\uFE0F Deleted migration file: ${migration.migration}`);
|
|
@@ -17881,24 +18348,25 @@ async function migrateRollback(options = {}) {
|
|
|
17881
18348
|
}
|
|
17882
18349
|
}
|
|
17883
18350
|
console.log();
|
|
17884
|
-
|
|
17885
|
-
|
|
17886
|
-
|
|
17887
|
-
|
|
17888
|
-
|
|
18351
|
+
if (reverseSchema) {
|
|
18352
|
+
console.log(reversedAny ? "-- \u2713 Reverse DDL executed for the rolled-back migration(s)." : "-- \u26A0\uFE0F No reversible DDL found; only migration records were removed.");
|
|
18353
|
+
} else {
|
|
18354
|
+
console.log("-- \u26A0\uFE0F reverseSchema disabled: only migration records were removed.");
|
|
18355
|
+
}
|
|
17889
18356
|
} catch (err) {
|
|
17890
18357
|
console.error("-- Rollback failed:", err);
|
|
17891
18358
|
throw err;
|
|
17892
18359
|
}
|
|
17893
18360
|
}
|
|
17894
18361
|
var init_migrate_rollback = __esm(() => {
|
|
18362
|
+
init_config();
|
|
17895
18363
|
init_src2();
|
|
17896
18364
|
});
|
|
17897
18365
|
|
|
17898
18366
|
// src/actions/migrate-status.ts
|
|
17899
18367
|
import { existsSync as existsSync18, readdirSync as readdirSync8 } from "fs";
|
|
17900
18368
|
import { dirname as dirname8, join as join11 } from "path";
|
|
17901
|
-
import
|
|
18369
|
+
import process26 from "process";
|
|
17902
18370
|
function findWorkspaceRoot3(startPath) {
|
|
17903
18371
|
let currentPath = startPath;
|
|
17904
18372
|
while (currentPath !== dirname8(currentPath)) {
|
|
@@ -17907,11 +18375,11 @@ function findWorkspaceRoot3(startPath) {
|
|
|
17907
18375
|
}
|
|
17908
18376
|
currentPath = dirname8(currentPath);
|
|
17909
18377
|
}
|
|
17910
|
-
return
|
|
18378
|
+
return process26.cwd();
|
|
17911
18379
|
}
|
|
17912
18380
|
function getSqlDirectory3(workspaceRoot) {
|
|
17913
18381
|
if (!workspaceRoot) {
|
|
17914
|
-
workspaceRoot = findWorkspaceRoot3(
|
|
18382
|
+
workspaceRoot = findWorkspaceRoot3(process26.cwd());
|
|
17915
18383
|
}
|
|
17916
18384
|
return join11(workspaceRoot, "database", "migrations");
|
|
17917
18385
|
}
|
|
@@ -18005,9 +18473,9 @@ var init_migrate_status = __esm(() => {
|
|
|
18005
18473
|
// src/actions/model-show.ts
|
|
18006
18474
|
import { readdirSync as readdirSync9 } from "fs";
|
|
18007
18475
|
import { extname as extname2, join as join12 } from "path";
|
|
18008
|
-
import
|
|
18476
|
+
import process27 from "process";
|
|
18009
18477
|
async function modelShow(modelName, options = {}) {
|
|
18010
|
-
const dir = options.dir || join12(
|
|
18478
|
+
const dir = options.dir || join12(process27.cwd(), "app/Models");
|
|
18011
18479
|
try {
|
|
18012
18480
|
const files = readdirSync9(dir);
|
|
18013
18481
|
const modelFile = files.find((f) => {
|
|
@@ -18126,7 +18594,7 @@ var init_ping = __esm(() => {
|
|
|
18126
18594
|
});
|
|
18127
18595
|
|
|
18128
18596
|
// src/actions/query-explain-all.ts
|
|
18129
|
-
import { readdirSync as readdirSync10, readFileSync as
|
|
18597
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
18130
18598
|
import { extname as extname3, join as join13 } from "path";
|
|
18131
18599
|
async function queryExplainAll(path, options = {}) {
|
|
18132
18600
|
const results = [];
|
|
@@ -18152,7 +18620,7 @@ async function queryExplainAll(path, options = {}) {
|
|
|
18152
18620
|
}
|
|
18153
18621
|
for (const file2 of files) {
|
|
18154
18622
|
try {
|
|
18155
|
-
const query =
|
|
18623
|
+
const query = readFileSync5(file2, "utf8").trim();
|
|
18156
18624
|
if (!query) {
|
|
18157
18625
|
if (options.verbose) {
|
|
18158
18626
|
console.log(`\u2298 ${file2}: empty file`);
|
|
@@ -18189,7 +18657,7 @@ async function queryExplainAll(path, options = {}) {
|
|
|
18189
18657
|
} catch (error) {
|
|
18190
18658
|
results.push({
|
|
18191
18659
|
file: file2,
|
|
18192
|
-
query:
|
|
18660
|
+
query: readFileSync5(file2, "utf8").trim(),
|
|
18193
18661
|
plan: [],
|
|
18194
18662
|
error: error.message
|
|
18195
18663
|
});
|
|
@@ -18221,9 +18689,9 @@ var init_query_explain_all = __esm(() => {
|
|
|
18221
18689
|
// src/actions/relation-diagram.ts
|
|
18222
18690
|
import { writeFileSync as writeFileSync12 } from "fs";
|
|
18223
18691
|
import { join as join14 } from "path";
|
|
18224
|
-
import
|
|
18692
|
+
import process28 from "process";
|
|
18225
18693
|
async function relationDiagram(options = {}) {
|
|
18226
|
-
const dir = options.dir || join14(
|
|
18694
|
+
const dir = options.dir || join14(process28.cwd(), "app/Models");
|
|
18227
18695
|
const format = options.format || "mermaid";
|
|
18228
18696
|
try {
|
|
18229
18697
|
const models = await loadModels({ modelsDir: dir });
|
|
@@ -18345,7 +18813,7 @@ var init_relation_diagram = __esm(() => {
|
|
|
18345
18813
|
// src/actions/seed.ts
|
|
18346
18814
|
import { existsSync as existsSync19, mkdirSync as mkdirSync8, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
|
|
18347
18815
|
import { dirname as dirname9, join as join15 } from "path";
|
|
18348
|
-
import
|
|
18816
|
+
import process29 from "process";
|
|
18349
18817
|
function findWorkspaceRoot4(startPath) {
|
|
18350
18818
|
let currentPath = startPath;
|
|
18351
18819
|
while (currentPath !== dirname9(currentPath)) {
|
|
@@ -18354,7 +18822,7 @@ function findWorkspaceRoot4(startPath) {
|
|
|
18354
18822
|
}
|
|
18355
18823
|
currentPath = dirname9(currentPath);
|
|
18356
18824
|
}
|
|
18357
|
-
return
|
|
18825
|
+
return process29.cwd();
|
|
18358
18826
|
}
|
|
18359
18827
|
async function loadSeeders(seedersDir) {
|
|
18360
18828
|
if (!existsSync19(seedersDir)) {
|
|
@@ -18386,7 +18854,7 @@ async function loadSeeders(seedersDir) {
|
|
|
18386
18854
|
return seeders;
|
|
18387
18855
|
}
|
|
18388
18856
|
async function runSeeders(config6 = {}) {
|
|
18389
|
-
const workspaceRoot = findWorkspaceRoot4(
|
|
18857
|
+
const workspaceRoot = findWorkspaceRoot4(process29.cwd());
|
|
18390
18858
|
const seedersDir = config6.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
18391
18859
|
const verbose = config6.verbose ?? true;
|
|
18392
18860
|
if (verbose) {
|
|
@@ -18421,7 +18889,7 @@ async function runSeeders(config6 = {}) {
|
|
|
18421
18889
|
}
|
|
18422
18890
|
}
|
|
18423
18891
|
async function runSeeder(className, options = {}) {
|
|
18424
|
-
const workspaceRoot = findWorkspaceRoot4(
|
|
18892
|
+
const workspaceRoot = findWorkspaceRoot4(process29.cwd());
|
|
18425
18893
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
18426
18894
|
const verbose = options.verbose ?? true;
|
|
18427
18895
|
if (verbose) {
|
|
@@ -18445,7 +18913,7 @@ async function runSeeder(className, options = {}) {
|
|
|
18445
18913
|
}
|
|
18446
18914
|
}
|
|
18447
18915
|
async function makeSeeder(name) {
|
|
18448
|
-
const workspaceRoot = findWorkspaceRoot4(
|
|
18916
|
+
const workspaceRoot = findWorkspaceRoot4(process29.cwd());
|
|
18449
18917
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
18450
18918
|
if (!existsSync19(seedersDir)) {
|
|
18451
18919
|
mkdirSync8(seedersDir, { recursive: true });
|
|
@@ -18509,7 +18977,7 @@ export default class ${className} extends Seeder {
|
|
|
18509
18977
|
console.log(`-- \u2713 Created seeder: ${filePath}`);
|
|
18510
18978
|
}
|
|
18511
18979
|
async function freshDatabase(options = {}) {
|
|
18512
|
-
const workspaceRoot = findWorkspaceRoot4(
|
|
18980
|
+
const workspaceRoot = findWorkspaceRoot4(process29.cwd());
|
|
18513
18981
|
const modelsDir = options.modelsDir || join15(workspaceRoot, "app/Models");
|
|
18514
18982
|
const seedersDir = options.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
18515
18983
|
const verbose = options.verbose ?? true;
|
|
@@ -18571,7 +19039,7 @@ var init_unsafe = __esm(() => {
|
|
|
18571
19039
|
// src/actions/validate.ts
|
|
18572
19040
|
import { existsSync as existsSync20 } from "fs";
|
|
18573
19041
|
import { dirname as dirname10, join as join16 } from "path";
|
|
18574
|
-
import
|
|
19042
|
+
import process30 from "process";
|
|
18575
19043
|
function findWorkspaceRoot5(startPath) {
|
|
18576
19044
|
let currentPath = startPath;
|
|
18577
19045
|
while (currentPath !== dirname10(currentPath)) {
|
|
@@ -18580,11 +19048,11 @@ function findWorkspaceRoot5(startPath) {
|
|
|
18580
19048
|
}
|
|
18581
19049
|
currentPath = dirname10(currentPath);
|
|
18582
19050
|
}
|
|
18583
|
-
return
|
|
19051
|
+
return process30.cwd();
|
|
18584
19052
|
}
|
|
18585
19053
|
async function validateSchema(dir) {
|
|
18586
19054
|
if (!dir) {
|
|
18587
|
-
dir = join16(findWorkspaceRoot5(
|
|
19055
|
+
dir = join16(findWorkspaceRoot5(process30.cwd()), "app/Models");
|
|
18588
19056
|
}
|
|
18589
19057
|
const dialect = config5.dialect || "postgres";
|
|
18590
19058
|
console.log("-- Validating Schema");
|
|
@@ -18803,6 +19271,7 @@ var init_actions = __esm(() => {
|
|
|
18803
19271
|
init_file();
|
|
18804
19272
|
init_inspect();
|
|
18805
19273
|
init_introspect();
|
|
19274
|
+
init_introspect_db();
|
|
18806
19275
|
init_make_model();
|
|
18807
19276
|
init_migrate();
|
|
18808
19277
|
init_migrate_generate();
|
|
@@ -23273,6 +23742,10 @@ var init_src = __esm(() => {
|
|
|
23273
23742
|
|
|
23274
23743
|
// src/orm.ts
|
|
23275
23744
|
import { Database as Database2 } from "bun:sqlite";
|
|
23745
|
+
function formatNow() {
|
|
23746
|
+
const iso = new Date().toISOString();
|
|
23747
|
+
return config5.dialect === "mysql" ? iso.slice(0, 19).replace("T", " ") : iso;
|
|
23748
|
+
}
|
|
23276
23749
|
function assertValidIdentifier(name, context) {
|
|
23277
23750
|
if (typeof name !== "string" || name.length === 0)
|
|
23278
23751
|
throw new TypeError(`[bun-query-builder] ${context}: identifier must be a non-empty string, got ${typeof name}`);
|
|
@@ -23293,19 +23766,138 @@ function getModelFromRegistry(name) {
|
|
|
23293
23766
|
}
|
|
23294
23767
|
return _getModel(name);
|
|
23295
23768
|
}
|
|
23769
|
+
function toPostgresPlaceholders(sql2) {
|
|
23770
|
+
let i2 = 0;
|
|
23771
|
+
return sql2.replace(/\?/g, () => `$${++i2}`);
|
|
23772
|
+
}
|
|
23773
|
+
function extractChanges(res) {
|
|
23774
|
+
if (res == null)
|
|
23775
|
+
return 0;
|
|
23776
|
+
if (typeof res.affectedRows === "number")
|
|
23777
|
+
return res.affectedRows;
|
|
23778
|
+
if (typeof res.count === "number")
|
|
23779
|
+
return res.count;
|
|
23780
|
+
if (Array.isArray(res))
|
|
23781
|
+
return res.length;
|
|
23782
|
+
return 0;
|
|
23783
|
+
}
|
|
23784
|
+
function extractInsertId(res) {
|
|
23785
|
+
if (res == null || typeof res !== "object")
|
|
23786
|
+
return null;
|
|
23787
|
+
if ("insertId" in res && res.insertId != null)
|
|
23788
|
+
return res.insertId;
|
|
23789
|
+
if ("lastInsertRowid" in res && res.lastInsertRowid != null)
|
|
23790
|
+
return res.lastInsertRowid;
|
|
23791
|
+
return null;
|
|
23792
|
+
}
|
|
23793
|
+
|
|
23794
|
+
class SqliteExecutor {
|
|
23795
|
+
sqliteDb;
|
|
23796
|
+
dialect = "sqlite";
|
|
23797
|
+
constructor(sqliteDb) {
|
|
23798
|
+
this.sqliteDb = sqliteDb;
|
|
23799
|
+
}
|
|
23800
|
+
all(sql2, params) {
|
|
23801
|
+
return Promise.resolve(this.sqliteDb.query(sql2).all(...params));
|
|
23802
|
+
}
|
|
23803
|
+
get(sql2, params) {
|
|
23804
|
+
return Promise.resolve(this.sqliteDb.query(sql2).get(...params) ?? undefined);
|
|
23805
|
+
}
|
|
23806
|
+
run(sql2, params) {
|
|
23807
|
+
const r2 = this.sqliteDb.run(sql2, params);
|
|
23808
|
+
return Promise.resolve({ changes: r2.changes, lastInsertId: r2.lastInsertRowid });
|
|
23809
|
+
}
|
|
23810
|
+
insert(sql2, params) {
|
|
23811
|
+
return this.run(sql2, params);
|
|
23812
|
+
}
|
|
23813
|
+
}
|
|
23814
|
+
|
|
23815
|
+
class DriverExecutor {
|
|
23816
|
+
dialect;
|
|
23817
|
+
constructor(dialect) {
|
|
23818
|
+
this.dialect = dialect;
|
|
23819
|
+
}
|
|
23820
|
+
conn() {
|
|
23821
|
+
return getOrCreateBunSql();
|
|
23822
|
+
}
|
|
23823
|
+
text(sql2) {
|
|
23824
|
+
return this.dialect === "postgres" ? toPostgresPlaceholders(sql2) : sql2;
|
|
23825
|
+
}
|
|
23826
|
+
async all(sql2, params) {
|
|
23827
|
+
const rows = await this.conn().unsafe(this.text(sql2), params);
|
|
23828
|
+
return Array.isArray(rows) ? rows : [];
|
|
23829
|
+
}
|
|
23830
|
+
async get(sql2, params) {
|
|
23831
|
+
const rows = await this.conn().unsafe(this.text(sql2), params);
|
|
23832
|
+
if (Array.isArray(rows))
|
|
23833
|
+
return rows[0] ?? undefined;
|
|
23834
|
+
return rows ?? undefined;
|
|
23835
|
+
}
|
|
23836
|
+
async run(sql2, params) {
|
|
23837
|
+
const res = await this.conn().unsafe(this.text(sql2), params);
|
|
23838
|
+
return { changes: extractChanges(res), lastInsertId: extractInsertId(res) };
|
|
23839
|
+
}
|
|
23840
|
+
async insert(sql2, params, primaryKey) {
|
|
23841
|
+
if (this.dialect === "postgres") {
|
|
23842
|
+
const rows = await this.conn().unsafe(`${toPostgresPlaceholders(sql2)} RETURNING ${primaryKey}`, params);
|
|
23843
|
+
const row = Array.isArray(rows) ? rows[0] : rows;
|
|
23844
|
+
return { changes: 1, lastInsertId: row ? row[primaryKey] ?? null : null };
|
|
23845
|
+
}
|
|
23846
|
+
const res = await this.conn().unsafe(sql2, params);
|
|
23847
|
+
let id = extractInsertId(res);
|
|
23848
|
+
if (id == null) {
|
|
23849
|
+
const rows = await this.conn().unsafe("SELECT LAST_INSERT_ID() as id", []);
|
|
23850
|
+
const row = Array.isArray(rows) ? rows[0] : rows;
|
|
23851
|
+
id = row?.id ?? null;
|
|
23852
|
+
}
|
|
23853
|
+
return { changes: extractChanges(res) || 1, lastInsertId: id };
|
|
23854
|
+
}
|
|
23855
|
+
}
|
|
23296
23856
|
function configureOrm(options) {
|
|
23297
23857
|
if (options.database instanceof Database2) {
|
|
23298
23858
|
globalDb = options.database;
|
|
23299
23859
|
} else {
|
|
23300
23860
|
globalDb = new Database2(options.database || ":memory:", { create: true });
|
|
23301
23861
|
}
|
|
23302
|
-
|
|
23862
|
+
_executor = null;
|
|
23863
|
+
_executorForDb = null;
|
|
23303
23864
|
}
|
|
23304
|
-
function
|
|
23305
|
-
if (
|
|
23306
|
-
|
|
23865
|
+
function getExecutor() {
|
|
23866
|
+
if (globalDb) {
|
|
23867
|
+
if (!_executor || _executorForDb !== globalDb) {
|
|
23868
|
+
_executor = new SqliteExecutor(globalDb);
|
|
23869
|
+
_executorForDb = globalDb;
|
|
23870
|
+
_executorDialect = "sqlite";
|
|
23871
|
+
_executorDatabase = null;
|
|
23872
|
+
}
|
|
23873
|
+
return _executor;
|
|
23307
23874
|
}
|
|
23308
|
-
|
|
23875
|
+
const dialect = config5.dialect;
|
|
23876
|
+
const database = config5.database?.database ?? null;
|
|
23877
|
+
if (_executor && _executorForDb === null && _executorDialect === dialect && _executorDatabase === database)
|
|
23878
|
+
return _executor;
|
|
23879
|
+
_executorForDb = null;
|
|
23880
|
+
_executorDialect = dialect;
|
|
23881
|
+
_executorDatabase = database;
|
|
23882
|
+
if (dialect === "sqlite")
|
|
23883
|
+
_executor = new SqliteExecutor(new Database2(database || ":memory:", { create: true }));
|
|
23884
|
+
else
|
|
23885
|
+
_executor = new DriverExecutor(dialect);
|
|
23886
|
+
return _executor;
|
|
23887
|
+
}
|
|
23888
|
+
function getDatabase() {
|
|
23889
|
+
const exec = getExecutor();
|
|
23890
|
+
if (exec.sqliteDb)
|
|
23891
|
+
return exec.sqliteDb;
|
|
23892
|
+
throw new Error(`[bun-query-builder] getDatabase() is only available for the sqlite dialect; ` + `the configured dialect is '${exec.dialect}'. Use the async model API instead.`);
|
|
23893
|
+
}
|
|
23894
|
+
function softDeletesEnabled(definition) {
|
|
23895
|
+
const t2 = definition.traits;
|
|
23896
|
+
return Boolean(t2?.useSoftDeletes || t2?.softDeletable);
|
|
23897
|
+
}
|
|
23898
|
+
function timestampsEnabled(definition) {
|
|
23899
|
+
const t2 = definition.traits;
|
|
23900
|
+
return Boolean(t2?.useTimestamps || t2?.timestampable);
|
|
23309
23901
|
}
|
|
23310
23902
|
function collectBelongsToManyKeys(definition) {
|
|
23311
23903
|
const keys = new Set;
|
|
@@ -23459,8 +24051,8 @@ class ModelInstance {
|
|
|
23459
24051
|
Object.assign(this._attributes, data);
|
|
23460
24052
|
return this;
|
|
23461
24053
|
}
|
|
23462
|
-
save() {
|
|
23463
|
-
const
|
|
24054
|
+
async save() {
|
|
24055
|
+
const exec = getExecutor();
|
|
23464
24056
|
const pk = this._definition.primaryKey || "id";
|
|
23465
24057
|
const hooks = this._definition.hooks;
|
|
23466
24058
|
const setters = this._definition.set || {};
|
|
@@ -23470,88 +24062,108 @@ class ModelInstance {
|
|
|
23470
24062
|
}
|
|
23471
24063
|
}
|
|
23472
24064
|
if (this._attributes[pk]) {
|
|
23473
|
-
hooks?.beforeUpdate?.(this, this.getChanges());
|
|
24065
|
+
await hooks?.beforeUpdate?.(this, this.getChanges());
|
|
23474
24066
|
const changes = this.getChanges();
|
|
23475
24067
|
const changeKeys = Object.keys(changes);
|
|
23476
24068
|
if (changeKeys.length > 0) {
|
|
23477
24069
|
const sets = changeKeys.map((k2) => `${k2} = ?`).join(", ");
|
|
23478
24070
|
const values = [...Object.values(changes), this._attributes[pk]];
|
|
23479
|
-
if (this._definition
|
|
23480
|
-
const now =
|
|
23481
|
-
|
|
24071
|
+
if (timestampsEnabled(this._definition)) {
|
|
24072
|
+
const now = formatNow();
|
|
24073
|
+
await exec.run(`UPDATE ${this._definition.table} SET ${sets}, updated_at = ? WHERE ${pk} = ?`, [...Object.values(changes), now, this._attributes[pk]]);
|
|
23482
24074
|
} else {
|
|
23483
|
-
|
|
24075
|
+
await exec.run(`UPDATE ${this._definition.table} SET ${sets} WHERE ${pk} = ?`, values);
|
|
23484
24076
|
}
|
|
23485
24077
|
}
|
|
23486
|
-
hooks?.afterUpdate?.(this);
|
|
24078
|
+
await hooks?.afterUpdate?.(this);
|
|
23487
24079
|
} else {
|
|
23488
24080
|
const attrs = this._definition.attributes;
|
|
23489
24081
|
const data = {};
|
|
23490
24082
|
for (const [key, attr] of Object.entries(attrs)) {
|
|
23491
|
-
if (attr.
|
|
24083
|
+
if (attr.guarded)
|
|
24084
|
+
continue;
|
|
24085
|
+
if (this._attributes[key] !== undefined) {
|
|
23492
24086
|
data[key] = this._attributes[key];
|
|
23493
24087
|
}
|
|
23494
24088
|
}
|
|
23495
|
-
if (this._definition
|
|
23496
|
-
const now =
|
|
24089
|
+
if (timestampsEnabled(this._definition)) {
|
|
24090
|
+
const now = formatNow();
|
|
23497
24091
|
data.created_at = now;
|
|
23498
24092
|
data.updated_at = now;
|
|
23499
24093
|
}
|
|
23500
24094
|
if (this._definition.traits?.useUuid && !data.uuid) {
|
|
23501
24095
|
data.uuid = crypto.randomUUID();
|
|
23502
24096
|
}
|
|
23503
|
-
hooks?.beforeCreate?.(data);
|
|
24097
|
+
await hooks?.beforeCreate?.(data);
|
|
23504
24098
|
const columns = Object.keys(data);
|
|
23505
24099
|
const placeholders = columns.map(() => "?").join(", ");
|
|
23506
|
-
const result =
|
|
24100
|
+
const result = await exec.insert(`INSERT INTO ${this._definition.table} (${columns.join(", ")}) VALUES (${placeholders})`, Object.values(data), pk);
|
|
23507
24101
|
for (const [key, value] of Object.entries(data)) {
|
|
23508
24102
|
this._attributes[key] = value;
|
|
23509
24103
|
}
|
|
23510
|
-
|
|
23511
|
-
|
|
24104
|
+
if (result.lastInsertId != null)
|
|
24105
|
+
this._attributes[pk] = result.lastInsertId;
|
|
24106
|
+
await hooks?.afterCreate?.(this);
|
|
23512
24107
|
}
|
|
23513
24108
|
this._original = { ...this._attributes };
|
|
23514
24109
|
this._hasSaved = true;
|
|
23515
24110
|
return this;
|
|
23516
24111
|
}
|
|
23517
|
-
update(data) {
|
|
24112
|
+
async update(data) {
|
|
23518
24113
|
this.fill(data);
|
|
23519
24114
|
return this.save();
|
|
23520
24115
|
}
|
|
23521
|
-
fresh() {
|
|
23522
|
-
const
|
|
24116
|
+
async fresh() {
|
|
24117
|
+
const exec = getExecutor();
|
|
23523
24118
|
const pk = this._definition.primaryKey || "id";
|
|
23524
24119
|
const id = this._attributes[pk];
|
|
23525
24120
|
if (id == null)
|
|
23526
24121
|
return null;
|
|
23527
|
-
const row =
|
|
24122
|
+
const row = await exec.get(`SELECT * FROM ${this._definition.table} WHERE ${pk} = ?`, [id]);
|
|
23528
24123
|
if (!row)
|
|
23529
24124
|
return null;
|
|
23530
24125
|
return new ModelInstance(this._definition, row);
|
|
23531
24126
|
}
|
|
23532
|
-
delete() {
|
|
23533
|
-
const
|
|
24127
|
+
async delete() {
|
|
24128
|
+
const exec = getExecutor();
|
|
23534
24129
|
const pk = this._definition.primaryKey || "id";
|
|
23535
24130
|
const pkValue = this._attributes[pk];
|
|
23536
24131
|
const hooks = this._definition.hooks;
|
|
23537
24132
|
if (!pkValue)
|
|
23538
24133
|
throw new Error("Cannot delete a model without a primary key");
|
|
23539
|
-
hooks?.beforeDelete?.(this);
|
|
23540
|
-
if (this._definition
|
|
23541
|
-
|
|
24134
|
+
await hooks?.beforeDelete?.(this);
|
|
24135
|
+
if (softDeletesEnabled(this._definition)) {
|
|
24136
|
+
const now = formatNow();
|
|
24137
|
+
await exec.run(`UPDATE ${this._definition.table} SET deleted_at = ? WHERE ${pk} = ?`, [now, pkValue]);
|
|
24138
|
+
this._attributes[SOFT_DELETE_COLUMN] = now;
|
|
23542
24139
|
} else {
|
|
23543
|
-
|
|
24140
|
+
await exec.run(`DELETE FROM ${this._definition.table} WHERE ${pk} = ?`, [pkValue]);
|
|
23544
24141
|
}
|
|
23545
|
-
hooks?.afterDelete?.(this);
|
|
24142
|
+
await hooks?.afterDelete?.(this);
|
|
23546
24143
|
return true;
|
|
23547
24144
|
}
|
|
23548
|
-
|
|
23549
|
-
|
|
24145
|
+
async restore() {
|
|
24146
|
+
if (!softDeletesEnabled(this._definition))
|
|
24147
|
+
throw new Error(`[orm] restore() requires soft deletes on '${this._definition.name}'`);
|
|
24148
|
+
const pk = this._definition.primaryKey || "id";
|
|
24149
|
+
const pkValue = this._attributes[pk];
|
|
24150
|
+
if (!pkValue)
|
|
24151
|
+
throw new Error("Cannot restore a model without a primary key");
|
|
24152
|
+
await getExecutor().run(`UPDATE ${this._definition.table} SET ${SOFT_DELETE_COLUMN} = ? WHERE ${pk} = ?`, [null, pkValue]);
|
|
24153
|
+
this._attributes[SOFT_DELETE_COLUMN] = null;
|
|
24154
|
+
this._original = null;
|
|
24155
|
+
return this;
|
|
24156
|
+
}
|
|
24157
|
+
trashed() {
|
|
24158
|
+
return this._attributes[SOFT_DELETE_COLUMN] != null;
|
|
24159
|
+
}
|
|
24160
|
+
async refresh() {
|
|
24161
|
+
const exec = getExecutor();
|
|
23550
24162
|
const pk = this._definition.primaryKey || "id";
|
|
23551
24163
|
const pkValue = this._attributes[pk];
|
|
23552
24164
|
if (!pkValue)
|
|
23553
24165
|
throw new Error("Cannot refresh a model without a primary key");
|
|
23554
|
-
const row =
|
|
24166
|
+
const row = await exec.get(`SELECT * FROM ${this._definition.table} WHERE ${pk} = ?`, [pkValue]);
|
|
23555
24167
|
if (!row)
|
|
23556
24168
|
return null;
|
|
23557
24169
|
this._attributes = row;
|
|
@@ -23849,9 +24461,23 @@ class BelongsToManyRelationBuilder {
|
|
|
23849
24461
|
this._offset = n2;
|
|
23850
24462
|
return this;
|
|
23851
24463
|
}
|
|
24464
|
+
relatedSelectColumns() {
|
|
24465
|
+
const cols = new Set([this.relatedPk, ...Object.keys(this._relatedDef.attributes ?? {})]);
|
|
24466
|
+
const t2 = this._relatedDef.traits;
|
|
24467
|
+
if (t2?.useTimestamps || t2?.timestampable) {
|
|
24468
|
+
cols.add("created_at");
|
|
24469
|
+
cols.add("updated_at");
|
|
24470
|
+
}
|
|
24471
|
+
if (t2?.useSoftDeletes || t2?.softDeletable)
|
|
24472
|
+
cols.add("deleted_at");
|
|
24473
|
+
if (t2?.useUuid)
|
|
24474
|
+
cols.add("uuid");
|
|
24475
|
+
return [...cols];
|
|
24476
|
+
}
|
|
23852
24477
|
buildSelect() {
|
|
23853
24478
|
const params = [];
|
|
23854
|
-
|
|
24479
|
+
const relatedSelect = this.relatedSelectColumns().map((c2) => `${this.relatedTable}.${c2} AS ${BTM_RELATED_ALIAS}${c2}`).join(", ");
|
|
24480
|
+
let sql2 = `SELECT ${relatedSelect}, ${this.pivotTable}.* FROM ${this.relatedTable}`;
|
|
23855
24481
|
sql2 += ` INNER JOIN ${this.pivotTable} ON ${this.pivotTable}.${this.fkRelated} = ${this.relatedTable}.${this.relatedPk}`;
|
|
23856
24482
|
sql2 += ` WHERE ${this.pivotTable}.${this.fkParent} = ?`;
|
|
23857
24483
|
params.push(this.parentId);
|
|
@@ -23872,58 +24498,51 @@ class BelongsToManyRelationBuilder {
|
|
|
23872
24498
|
return { sql: sql2, params };
|
|
23873
24499
|
}
|
|
23874
24500
|
hydrateRows(rows) {
|
|
23875
|
-
const relatedAttrs = new Set(Object.keys(this._relatedDef.attributes ?? {}));
|
|
23876
|
-
relatedAttrs.add(this.relatedPk);
|
|
23877
|
-
relatedAttrs.add("created_at");
|
|
23878
|
-
relatedAttrs.add("updated_at");
|
|
23879
|
-
relatedAttrs.add("deleted_at");
|
|
23880
24501
|
const fkParent = this.fkParent;
|
|
23881
24502
|
const fkRelated = this.fkRelated;
|
|
23882
24503
|
return rows.map((raw) => {
|
|
23883
24504
|
const relatedRow = {};
|
|
23884
24505
|
const pivotExtras = {};
|
|
23885
24506
|
for (const [k2, v2] of Object.entries(raw)) {
|
|
23886
|
-
if (k2
|
|
23887
|
-
|
|
23888
|
-
if (
|
|
23889
|
-
relatedRow[k2] = v2;
|
|
23890
|
-
else
|
|
24507
|
+
if (k2.startsWith(BTM_RELATED_ALIAS))
|
|
24508
|
+
relatedRow[k2.slice(BTM_RELATED_ALIAS.length)] = v2;
|
|
24509
|
+
else if (k2 !== fkParent && k2 !== fkRelated)
|
|
23891
24510
|
pivotExtras[k2] = v2;
|
|
23892
24511
|
}
|
|
23893
|
-
relatedRow[this.relatedPk] = raw[this.relatedPk];
|
|
23894
24512
|
const inst = new ModelInstance(this._relatedDef, relatedRow);
|
|
23895
24513
|
inst.pivot = pivotExtras;
|
|
23896
24514
|
return inst;
|
|
23897
24515
|
});
|
|
23898
24516
|
}
|
|
23899
|
-
get() {
|
|
23900
|
-
const
|
|
24517
|
+
async get() {
|
|
24518
|
+
const exec = getExecutor();
|
|
23901
24519
|
const { sql: sql2, params } = this.buildSelect();
|
|
23902
|
-
const rows =
|
|
24520
|
+
const rows = await exec.all(sql2, params);
|
|
23903
24521
|
return this.hydrateRows(rows);
|
|
23904
24522
|
}
|
|
23905
|
-
first() {
|
|
24523
|
+
async first() {
|
|
23906
24524
|
this._limit = 1;
|
|
23907
|
-
return this.get()[0];
|
|
24525
|
+
return (await this.get())[0];
|
|
23908
24526
|
}
|
|
23909
|
-
count() {
|
|
23910
|
-
const
|
|
24527
|
+
async count() {
|
|
24528
|
+
const exec = getExecutor();
|
|
23911
24529
|
let sql2 = `SELECT COUNT(*) as count FROM ${this.pivotTable} WHERE ${this.fkParent} = ?`;
|
|
23912
24530
|
const params = [this.parentId];
|
|
23913
24531
|
for (const w of this._pivotWheres) {
|
|
23914
24532
|
sql2 += ` AND ${w.sql}`;
|
|
23915
24533
|
params.push(...w.params);
|
|
23916
24534
|
}
|
|
23917
|
-
|
|
24535
|
+
const row = await exec.get(sql2, params);
|
|
24536
|
+
return Number(row?.count ?? 0);
|
|
23918
24537
|
}
|
|
23919
|
-
exists() {
|
|
23920
|
-
return this.count() > 0;
|
|
24538
|
+
async exists() {
|
|
24539
|
+
return await this.count() > 0;
|
|
23921
24540
|
}
|
|
23922
24541
|
now() {
|
|
23923
|
-
return
|
|
24542
|
+
return formatNow();
|
|
23924
24543
|
}
|
|
23925
|
-
attach(idOrIds, extras = {}) {
|
|
23926
|
-
const
|
|
24544
|
+
async attach(idOrIds, extras = {}) {
|
|
24545
|
+
const exec = getExecutor();
|
|
23927
24546
|
const ids = Array.isArray(idOrIds) ? idOrIds : [idOrIds];
|
|
23928
24547
|
if (ids.length === 0)
|
|
23929
24548
|
return 0;
|
|
@@ -23945,13 +24564,13 @@ class BelongsToManyRelationBuilder {
|
|
|
23945
24564
|
const placeholders = cols.map(() => "?").join(", ");
|
|
23946
24565
|
const sql2 = `INSERT INTO ${this.pivotTable} (${cols.join(", ")}) VALUES (${placeholders})`;
|
|
23947
24566
|
const params = cols.map((c2) => row[c2]);
|
|
23948
|
-
|
|
24567
|
+
await exec.run(sql2, params);
|
|
23949
24568
|
inserted++;
|
|
23950
24569
|
}
|
|
23951
24570
|
return inserted;
|
|
23952
24571
|
}
|
|
23953
|
-
detach(idOrIds) {
|
|
23954
|
-
const
|
|
24572
|
+
async detach(idOrIds) {
|
|
24573
|
+
const exec = getExecutor();
|
|
23955
24574
|
let sql2 = `DELETE FROM ${this.pivotTable} WHERE ${this.fkParent} = ?`;
|
|
23956
24575
|
const params = [this.parentId];
|
|
23957
24576
|
if (idOrIds !== undefined && idOrIds !== null) {
|
|
@@ -23962,10 +24581,10 @@ class BelongsToManyRelationBuilder {
|
|
|
23962
24581
|
sql2 += ` AND ${this.fkRelated} IN (${placeholders})`;
|
|
23963
24582
|
params.push(...ids);
|
|
23964
24583
|
}
|
|
23965
|
-
return
|
|
24584
|
+
return (await exec.run(sql2, params)).changes;
|
|
23966
24585
|
}
|
|
23967
|
-
updateExistingPivot(relatedId, extras) {
|
|
23968
|
-
const
|
|
24586
|
+
async updateExistingPivot(relatedId, extras) {
|
|
24587
|
+
const exec = getExecutor();
|
|
23969
24588
|
const updates = { ...extras };
|
|
23970
24589
|
if (this._resolved.pivotTimestamps && updates.updated_at === undefined) {
|
|
23971
24590
|
updates.updated_at = this.now();
|
|
@@ -23976,10 +24595,10 @@ class BelongsToManyRelationBuilder {
|
|
|
23976
24595
|
const setClause = cols.map((c2) => `${c2} = ?`).join(", ");
|
|
23977
24596
|
const sql2 = `UPDATE ${this.pivotTable} SET ${setClause} WHERE ${this.fkParent} = ? AND ${this.fkRelated} = ?`;
|
|
23978
24597
|
const params = [...cols.map((c2) => updates[c2]), this.parentId, relatedId];
|
|
23979
|
-
return
|
|
24598
|
+
return (await exec.run(sql2, params)).changes;
|
|
23980
24599
|
}
|
|
23981
|
-
sync(items) {
|
|
23982
|
-
const
|
|
24600
|
+
async sync(items) {
|
|
24601
|
+
const exec = getExecutor();
|
|
23983
24602
|
const desired = new Map;
|
|
23984
24603
|
for (const item of items) {
|
|
23985
24604
|
if (item != null && typeof item === "object" && "id" in item) {
|
|
@@ -23989,41 +24608,41 @@ class BelongsToManyRelationBuilder {
|
|
|
23989
24608
|
desired.set(item, {});
|
|
23990
24609
|
}
|
|
23991
24610
|
}
|
|
23992
|
-
const current =
|
|
24611
|
+
const current = await exec.all(`SELECT * FROM ${this.pivotTable} WHERE ${this.fkParent} = ?`, [this.parentId]);
|
|
23993
24612
|
const currentIds = new Set(current.map((r2) => r2[this.fkRelated]));
|
|
23994
24613
|
const attached = [];
|
|
23995
24614
|
const detached = [];
|
|
23996
24615
|
const updated = [];
|
|
23997
24616
|
const toDetach = [...currentIds].filter((id) => !desired.has(id));
|
|
23998
24617
|
if (toDetach.length > 0) {
|
|
23999
|
-
this.detach(toDetach);
|
|
24618
|
+
await this.detach(toDetach);
|
|
24000
24619
|
detached.push(...toDetach);
|
|
24001
24620
|
}
|
|
24002
24621
|
for (const [id, extras] of desired) {
|
|
24003
24622
|
if (!currentIds.has(id)) {
|
|
24004
|
-
this.attach(id, extras);
|
|
24623
|
+
await this.attach(id, extras);
|
|
24005
24624
|
attached.push(id);
|
|
24006
24625
|
} else if (Object.keys(extras).length > 0) {
|
|
24007
|
-
this.updateExistingPivot(id, extras);
|
|
24626
|
+
await this.updateExistingPivot(id, extras);
|
|
24008
24627
|
updated.push(id);
|
|
24009
24628
|
}
|
|
24010
24629
|
}
|
|
24011
24630
|
return { attached, detached, updated };
|
|
24012
24631
|
}
|
|
24013
|
-
toggle(idOrIds) {
|
|
24014
|
-
const
|
|
24632
|
+
async toggle(idOrIds) {
|
|
24633
|
+
const exec = getExecutor();
|
|
24015
24634
|
const ids = Array.isArray(idOrIds) ? idOrIds : [idOrIds];
|
|
24016
24635
|
if (ids.length === 0)
|
|
24017
24636
|
return { attached: [], detached: [] };
|
|
24018
24637
|
const placeholders = ids.map(() => "?").join(", ");
|
|
24019
|
-
const present =
|
|
24638
|
+
const present = await exec.all(`SELECT ${this.fkRelated} FROM ${this.pivotTable} WHERE ${this.fkParent} = ? AND ${this.fkRelated} IN (${placeholders})`, [this.parentId, ...ids]);
|
|
24020
24639
|
const presentIds = new Set(present.map((r2) => r2[this.fkRelated]));
|
|
24021
24640
|
const toAttach = ids.filter((id) => !presentIds.has(id));
|
|
24022
24641
|
const toDetach = ids.filter((id) => presentIds.has(id));
|
|
24023
24642
|
if (toAttach.length > 0)
|
|
24024
|
-
this.attach(toAttach);
|
|
24643
|
+
await this.attach(toAttach);
|
|
24025
24644
|
if (toDetach.length > 0)
|
|
24026
|
-
this.detach(toDetach);
|
|
24645
|
+
await this.detach(toDetach);
|
|
24027
24646
|
return { attached: toAttach, detached: toDetach };
|
|
24028
24647
|
}
|
|
24029
24648
|
}
|
|
@@ -24036,9 +24655,18 @@ class ModelQueryBuilder {
|
|
|
24036
24655
|
_offset;
|
|
24037
24656
|
_select = ["*"];
|
|
24038
24657
|
_withRelations = [];
|
|
24658
|
+
_trashed = "exclude";
|
|
24039
24659
|
constructor(definition) {
|
|
24040
24660
|
this._definition = definition;
|
|
24041
24661
|
}
|
|
24662
|
+
withTrashed() {
|
|
24663
|
+
this._trashed = "include";
|
|
24664
|
+
return this;
|
|
24665
|
+
}
|
|
24666
|
+
onlyTrashed() {
|
|
24667
|
+
this._trashed = "only";
|
|
24668
|
+
return this;
|
|
24669
|
+
}
|
|
24042
24670
|
where(column, operatorOrValue, value) {
|
|
24043
24671
|
if (value === undefined) {
|
|
24044
24672
|
this._wheres.push({ column, operator: "=", value: operatorOrValue, boolean: "and" });
|
|
@@ -24216,11 +24844,24 @@ class ModelQueryBuilder {
|
|
|
24216
24844
|
}
|
|
24217
24845
|
return clauses.join(" ");
|
|
24218
24846
|
}
|
|
24847
|
+
softDeleteClause() {
|
|
24848
|
+
if (this._trashed === "include" || !softDeletesEnabled(this._definition))
|
|
24849
|
+
return "";
|
|
24850
|
+
return this._trashed === "only" ? `${SOFT_DELETE_COLUMN} IS NOT NULL` : `${SOFT_DELETE_COLUMN} IS NULL`;
|
|
24851
|
+
}
|
|
24852
|
+
composeWhere(params) {
|
|
24853
|
+
const userClause = this._wheres.length > 0 ? this.buildWhereClauses(params) : "";
|
|
24854
|
+
const sd = this.softDeleteClause();
|
|
24855
|
+
if (userClause && sd)
|
|
24856
|
+
return `(${userClause}) AND ${sd}`;
|
|
24857
|
+
return userClause || sd;
|
|
24858
|
+
}
|
|
24219
24859
|
buildQuery() {
|
|
24220
24860
|
const params = [];
|
|
24221
24861
|
let sql2 = `SELECT ${this._select.join(", ")} FROM ${this._definition.table}`;
|
|
24222
|
-
|
|
24223
|
-
|
|
24862
|
+
const whereBody = this.composeWhere(params);
|
|
24863
|
+
if (whereBody) {
|
|
24864
|
+
sql2 += ` WHERE ${whereBody}`;
|
|
24224
24865
|
}
|
|
24225
24866
|
if (this._orderBy.length > 0) {
|
|
24226
24867
|
sql2 += ` ORDER BY ${this._orderBy.map((o2) => `${o2.column} ${o2.direction.toUpperCase()}`).join(", ")}`;
|
|
@@ -24234,10 +24875,10 @@ class ModelQueryBuilder {
|
|
|
24234
24875
|
toSql() {
|
|
24235
24876
|
return this.buildQuery();
|
|
24236
24877
|
}
|
|
24237
|
-
eagerLoadRelations(instances) {
|
|
24878
|
+
async eagerLoadRelations(instances) {
|
|
24238
24879
|
if (instances.length === 0 || this._withRelations.length === 0)
|
|
24239
24880
|
return;
|
|
24240
|
-
const
|
|
24881
|
+
const exec = getExecutor();
|
|
24241
24882
|
const pk = this._definition.primaryKey || "id";
|
|
24242
24883
|
for (const relationName of this._withRelations) {
|
|
24243
24884
|
const cacheKey = `${this._definition.name}:${relationName}`;
|
|
@@ -24253,7 +24894,7 @@ class ModelQueryBuilder {
|
|
|
24253
24894
|
if (parentIds.length === 0)
|
|
24254
24895
|
continue;
|
|
24255
24896
|
const placeholders = parentIds.map(() => "?").join(", ");
|
|
24256
|
-
const rows =
|
|
24897
|
+
const rows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.foreignKey} IN (${placeholders})`, parentIds);
|
|
24257
24898
|
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
24258
24899
|
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
24259
24900
|
if (rel.type === "hasMany") {
|
|
@@ -24285,7 +24926,7 @@ class ModelQueryBuilder {
|
|
|
24285
24926
|
if (uniqueFkValues.length === 0)
|
|
24286
24927
|
continue;
|
|
24287
24928
|
const placeholders = uniqueFkValues.map(() => "?").join(", ");
|
|
24288
|
-
const rows =
|
|
24929
|
+
const rows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.localKey} IN (${placeholders})`, uniqueFkValues);
|
|
24289
24930
|
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
24290
24931
|
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
24291
24932
|
const byPk = new Map;
|
|
@@ -24305,7 +24946,7 @@ class ModelQueryBuilder {
|
|
|
24305
24946
|
if (!rel.pivotTable || !rel.pivotFkParent || !rel.pivotFkRelated)
|
|
24306
24947
|
continue;
|
|
24307
24948
|
const pivotPlaceholders = parentIds.map(() => "?").join(", ");
|
|
24308
|
-
const pivotRows =
|
|
24949
|
+
const pivotRows = await exec.all(`SELECT * FROM ${rel.pivotTable} WHERE ${rel.pivotFkParent} IN (${pivotPlaceholders})`, parentIds);
|
|
24309
24950
|
if (pivotRows.length === 0) {
|
|
24310
24951
|
for (const instance of instances)
|
|
24311
24952
|
instance.setRelation(relationName, []);
|
|
@@ -24318,7 +24959,7 @@ class ModelQueryBuilder {
|
|
|
24318
24959
|
let relatedRows = [];
|
|
24319
24960
|
if (relatedIds.length > 0) {
|
|
24320
24961
|
const relPlaceholders = relatedIds.map(() => "?").join(", ");
|
|
24321
|
-
relatedRows =
|
|
24962
|
+
relatedRows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${relatedPk} IN (${relPlaceholders})`, relatedIds);
|
|
24322
24963
|
}
|
|
24323
24964
|
const relatedByPk = new Map;
|
|
24324
24965
|
for (const r2 of relatedRows)
|
|
@@ -24352,75 +24993,77 @@ class ModelQueryBuilder {
|
|
|
24352
24993
|
}
|
|
24353
24994
|
}
|
|
24354
24995
|
}
|
|
24355
|
-
get() {
|
|
24356
|
-
const
|
|
24996
|
+
async get() {
|
|
24997
|
+
const exec = getExecutor();
|
|
24357
24998
|
const { sql: sql2, params } = this.buildQuery();
|
|
24358
|
-
const rows =
|
|
24999
|
+
const rows = await exec.all(sql2, params);
|
|
24359
25000
|
const instances = rows.map((row) => new ModelInstance(this._definition, row));
|
|
24360
25001
|
if (this._withRelations.length > 0) {
|
|
24361
|
-
this.eagerLoadRelations(instances);
|
|
25002
|
+
await this.eagerLoadRelations(instances);
|
|
24362
25003
|
}
|
|
24363
25004
|
return instances;
|
|
24364
25005
|
}
|
|
24365
|
-
first() {
|
|
25006
|
+
async first() {
|
|
24366
25007
|
this._limit = 1;
|
|
24367
|
-
return this.get()[0];
|
|
25008
|
+
return (await this.get())[0];
|
|
24368
25009
|
}
|
|
24369
|
-
firstOrFail() {
|
|
24370
|
-
const result = this.first();
|
|
25010
|
+
async firstOrFail() {
|
|
25011
|
+
const result = await this.first();
|
|
24371
25012
|
if (!result)
|
|
24372
25013
|
throw new Error(`No ${this._definition.name} found`);
|
|
24373
25014
|
return result;
|
|
24374
25015
|
}
|
|
24375
|
-
last() {
|
|
25016
|
+
async last() {
|
|
24376
25017
|
const pk = this._definition.primaryKey || "id";
|
|
24377
25018
|
this._orderBy = [{ column: pk, direction: "desc" }];
|
|
24378
25019
|
this._limit = 1;
|
|
24379
|
-
return this.get()[0];
|
|
25020
|
+
return (await this.get())[0];
|
|
24380
25021
|
}
|
|
24381
|
-
count() {
|
|
24382
|
-
const
|
|
25022
|
+
async count() {
|
|
25023
|
+
const exec = getExecutor();
|
|
24383
25024
|
const params = [];
|
|
24384
25025
|
let sql2 = `SELECT COUNT(*) as count FROM ${this._definition.table}`;
|
|
24385
|
-
|
|
24386
|
-
|
|
25026
|
+
const whereBody = this.composeWhere(params);
|
|
25027
|
+
if (whereBody) {
|
|
25028
|
+
sql2 += ` WHERE ${whereBody}`;
|
|
24387
25029
|
}
|
|
24388
|
-
|
|
25030
|
+
const row = await exec.get(sql2, params);
|
|
25031
|
+
return Number(row?.count ?? 0);
|
|
24389
25032
|
}
|
|
24390
|
-
exists() {
|
|
24391
|
-
return this.count() > 0;
|
|
25033
|
+
async exists() {
|
|
25034
|
+
return await this.count() > 0;
|
|
24392
25035
|
}
|
|
24393
|
-
doesntExist() {
|
|
24394
|
-
return this.count() === 0;
|
|
25036
|
+
async doesntExist() {
|
|
25037
|
+
return await this.count() === 0;
|
|
24395
25038
|
}
|
|
24396
|
-
sole() {
|
|
25039
|
+
async sole() {
|
|
24397
25040
|
this._limit = 2;
|
|
24398
|
-
const results = this.get();
|
|
25041
|
+
const results = await this.get();
|
|
24399
25042
|
if (results.length === 0)
|
|
24400
25043
|
throw new Error(`No ${this._definition.name} found`);
|
|
24401
25044
|
if (results.length > 1)
|
|
24402
25045
|
throw new Error(`Expected one ${this._definition.name}, found multiple`);
|
|
24403
25046
|
return results[0];
|
|
24404
25047
|
}
|
|
24405
|
-
increment(column, amount = 1) {
|
|
25048
|
+
async increment(column, amount = 1) {
|
|
24406
25049
|
assertValidIdentifier(column, "increment(column)");
|
|
24407
|
-
const
|
|
25050
|
+
const exec = getExecutor();
|
|
24408
25051
|
const params = [amount];
|
|
24409
25052
|
let sql2 = `UPDATE ${this._definition.table} SET ${column} = ${column} + ?`;
|
|
24410
|
-
if (this._definition
|
|
25053
|
+
if (timestampsEnabled(this._definition)) {
|
|
24411
25054
|
sql2 += `, updated_at = ?`;
|
|
24412
|
-
params.push(
|
|
25055
|
+
params.push(formatNow());
|
|
24413
25056
|
}
|
|
24414
25057
|
if (this._wheres.length > 0) {
|
|
24415
25058
|
const clauses = this.buildWhereClauses(params);
|
|
24416
25059
|
sql2 += ` WHERE ${clauses}`;
|
|
24417
25060
|
}
|
|
24418
|
-
return
|
|
25061
|
+
return (await exec.run(sql2, params)).changes;
|
|
24419
25062
|
}
|
|
24420
25063
|
decrement(column, amount = 1) {
|
|
24421
25064
|
return this.increment(column, -amount);
|
|
24422
25065
|
}
|
|
24423
|
-
chunk(size, callback) {
|
|
25066
|
+
async chunk(size, callback) {
|
|
24424
25067
|
let page = 0;
|
|
24425
25068
|
while (true) {
|
|
24426
25069
|
const builder = new ModelQueryBuilder(this._definition);
|
|
@@ -24428,12 +25071,13 @@ class ModelQueryBuilder {
|
|
|
24428
25071
|
builder._orderBy = [...this._orderBy];
|
|
24429
25072
|
builder._select = [...this._select];
|
|
24430
25073
|
builder._withRelations = [...this._withRelations];
|
|
25074
|
+
builder._trashed = this._trashed;
|
|
24431
25075
|
builder._limit = size;
|
|
24432
25076
|
builder._offset = page * size;
|
|
24433
|
-
const results = builder.get();
|
|
25077
|
+
const results = await builder.get();
|
|
24434
25078
|
if (results.length === 0)
|
|
24435
25079
|
break;
|
|
24436
|
-
const result = callback(results);
|
|
25080
|
+
const result = await callback(results);
|
|
24437
25081
|
if (result === false)
|
|
24438
25082
|
break;
|
|
24439
25083
|
if (results.length < size)
|
|
@@ -24441,12 +25085,12 @@ class ModelQueryBuilder {
|
|
|
24441
25085
|
page++;
|
|
24442
25086
|
}
|
|
24443
25087
|
}
|
|
24444
|
-
paginate(page = 1, perPage = 15) {
|
|
24445
|
-
const total = this.count();
|
|
25088
|
+
async paginate(page = 1, perPage = 15) {
|
|
25089
|
+
const total = await this.count();
|
|
24446
25090
|
const lastPage = Math.ceil(total / perPage);
|
|
24447
25091
|
this._limit = perPage;
|
|
24448
25092
|
this._offset = (page - 1) * perPage;
|
|
24449
|
-
const data = this.get();
|
|
25093
|
+
const data = await this.get();
|
|
24450
25094
|
return {
|
|
24451
25095
|
data,
|
|
24452
25096
|
total,
|
|
@@ -24459,13 +25103,14 @@ class ModelQueryBuilder {
|
|
|
24459
25103
|
to: data.length > 0 ? (page - 1) * perPage + data.length : null
|
|
24460
25104
|
};
|
|
24461
25105
|
}
|
|
24462
|
-
pluck(column) {
|
|
25106
|
+
async pluck(column) {
|
|
24463
25107
|
assertValidIdentifier(column, "pluck(column)");
|
|
24464
|
-
const
|
|
25108
|
+
const exec = getExecutor();
|
|
24465
25109
|
const params = [];
|
|
24466
25110
|
let sql2 = `SELECT ${column} FROM ${this._definition.table}`;
|
|
24467
|
-
|
|
24468
|
-
|
|
25111
|
+
const whereBody = this.composeWhere(params);
|
|
25112
|
+
if (whereBody) {
|
|
25113
|
+
sql2 += ` WHERE ${whereBody}`;
|
|
24469
25114
|
}
|
|
24470
25115
|
if (this._orderBy.length > 0) {
|
|
24471
25116
|
sql2 += ` ORDER BY ${this._orderBy.map((o2) => `${o2.column} ${o2.direction.toUpperCase()}`).join(", ")}`;
|
|
@@ -24474,19 +25119,20 @@ class ModelQueryBuilder {
|
|
|
24474
25119
|
sql2 += ` LIMIT ${this._limit}`;
|
|
24475
25120
|
if (this._offset !== undefined)
|
|
24476
25121
|
sql2 += ` OFFSET ${this._offset}`;
|
|
24477
|
-
const rows =
|
|
25122
|
+
const rows = await exec.all(sql2, params);
|
|
24478
25123
|
return rows.map((r2) => r2[column]);
|
|
24479
25124
|
}
|
|
24480
|
-
aggregate(fn, column) {
|
|
25125
|
+
async aggregate(fn, column) {
|
|
24481
25126
|
assertValidIdentifier(column, `${fn}(column)`);
|
|
24482
|
-
const
|
|
25127
|
+
const exec = getExecutor();
|
|
24483
25128
|
const params = [];
|
|
24484
25129
|
let sql2 = `SELECT ${fn}(${column}) as v FROM ${this._definition.table}`;
|
|
24485
|
-
|
|
24486
|
-
|
|
25130
|
+
const whereBody = this.composeWhere(params);
|
|
25131
|
+
if (whereBody) {
|
|
25132
|
+
sql2 += ` WHERE ${whereBody}`;
|
|
24487
25133
|
}
|
|
24488
|
-
const row =
|
|
24489
|
-
return row?.v
|
|
25134
|
+
const row = await exec.get(sql2, params);
|
|
25135
|
+
return row?.v == null ? null : Number(row.v);
|
|
24490
25136
|
}
|
|
24491
25137
|
max(column) {
|
|
24492
25138
|
return this.aggregate("MAX", column);
|
|
@@ -24494,34 +25140,34 @@ class ModelQueryBuilder {
|
|
|
24494
25140
|
min(column) {
|
|
24495
25141
|
return this.aggregate("MIN", column);
|
|
24496
25142
|
}
|
|
24497
|
-
avg(column) {
|
|
24498
|
-
return this.aggregate("AVG", column) || 0;
|
|
25143
|
+
async avg(column) {
|
|
25144
|
+
return await this.aggregate("AVG", column) || 0;
|
|
24499
25145
|
}
|
|
24500
|
-
sum(column) {
|
|
24501
|
-
return this.aggregate("SUM", column) || 0;
|
|
25146
|
+
async sum(column) {
|
|
25147
|
+
return await this.aggregate("SUM", column) || 0;
|
|
24502
25148
|
}
|
|
24503
|
-
delete() {
|
|
24504
|
-
const
|
|
25149
|
+
async delete() {
|
|
25150
|
+
const exec = getExecutor();
|
|
24505
25151
|
const params = [];
|
|
24506
25152
|
let sql2 = `DELETE FROM ${this._definition.table}`;
|
|
24507
25153
|
if (this._wheres.length > 0) {
|
|
24508
25154
|
sql2 += ` WHERE ${this.buildWhereClauses(params)}`;
|
|
24509
25155
|
}
|
|
24510
|
-
return
|
|
25156
|
+
return (await exec.run(sql2, params)).changes;
|
|
24511
25157
|
}
|
|
24512
|
-
update(data) {
|
|
24513
|
-
const
|
|
25158
|
+
async update(data) {
|
|
25159
|
+
const exec = getExecutor();
|
|
24514
25160
|
const entries = Object.entries(data);
|
|
24515
25161
|
const sets = entries.map(([k2]) => `${k2} = ?`).join(", ");
|
|
24516
25162
|
const params = entries.map(([, v2]) => v2);
|
|
24517
|
-
if (this._definition
|
|
24518
|
-
params.push(
|
|
25163
|
+
if (timestampsEnabled(this._definition)) {
|
|
25164
|
+
params.push(formatNow());
|
|
24519
25165
|
}
|
|
24520
|
-
let sql2 = `UPDATE ${this._definition.table} SET ${sets}${this._definition
|
|
25166
|
+
let sql2 = `UPDATE ${this._definition.table} SET ${sets}${timestampsEnabled(this._definition) ? ", updated_at = ?" : ""}`;
|
|
24521
25167
|
if (this._wheres.length > 0) {
|
|
24522
25168
|
sql2 += ` WHERE ${this.buildWhereClauses(params)}`;
|
|
24523
25169
|
}
|
|
24524
|
-
return
|
|
25170
|
+
return (await exec.run(sql2, params)).changes;
|
|
24525
25171
|
}
|
|
24526
25172
|
}
|
|
24527
25173
|
function createModel(definition) {
|
|
@@ -24563,28 +25209,26 @@ function createModel(definition) {
|
|
|
24563
25209
|
limit: (count) => new ModelQueryBuilder(definition).limit(count),
|
|
24564
25210
|
take: (count) => new ModelQueryBuilder(definition).take(count),
|
|
24565
25211
|
skip: (count) => new ModelQueryBuilder(definition).skip(count),
|
|
24566
|
-
|
|
24567
|
-
|
|
25212
|
+
withTrashed: () => new ModelQueryBuilder(definition).withTrashed(),
|
|
25213
|
+
onlyTrashed: () => new ModelQueryBuilder(definition).onlyTrashed(),
|
|
25214
|
+
async find(id) {
|
|
25215
|
+
const exec = getExecutor();
|
|
24568
25216
|
const pk = definition.primaryKey || "id";
|
|
24569
|
-
const
|
|
24570
|
-
|
|
24571
|
-
if (!stmt) {
|
|
24572
|
-
stmt = db.prepare(sql2);
|
|
24573
|
-
preparedStatementCache.set(sql2, stmt);
|
|
24574
|
-
}
|
|
24575
|
-
const row = stmt.get(id);
|
|
25217
|
+
const sd = softDeletesEnabled(definition) ? ` AND ${SOFT_DELETE_COLUMN} IS NULL` : "";
|
|
25218
|
+
const row = await exec.get(`SELECT * FROM ${definition.table} WHERE ${pk} = ?${sd}`, [id]);
|
|
24576
25219
|
return row ? new ModelInstance(definition, row) : undefined;
|
|
24577
25220
|
},
|
|
24578
|
-
findOrFail(id) {
|
|
24579
|
-
const result = model.find(id);
|
|
25221
|
+
async findOrFail(id) {
|
|
25222
|
+
const result = await model.find(id);
|
|
24580
25223
|
if (!result)
|
|
24581
25224
|
throw new Error(`${definition.name} with id ${id} not found`);
|
|
24582
25225
|
return result;
|
|
24583
25226
|
},
|
|
24584
|
-
findMany(ids) {
|
|
24585
|
-
const
|
|
25227
|
+
async findMany(ids) {
|
|
25228
|
+
const exec = getExecutor();
|
|
24586
25229
|
const pk = definition.primaryKey || "id";
|
|
24587
|
-
const
|
|
25230
|
+
const sd = softDeletesEnabled(definition) ? ` AND ${SOFT_DELETE_COLUMN} IS NULL` : "";
|
|
25231
|
+
const rows = await exec.all(`SELECT * FROM ${definition.table} WHERE ${pk} IN (${ids.map(() => "?").join(", ")})${sd}`, ids);
|
|
24588
25232
|
return rows.map((row) => new ModelInstance(definition, row));
|
|
24589
25233
|
},
|
|
24590
25234
|
all: () => new ModelQueryBuilder(definition).get(),
|
|
@@ -24601,44 +25245,47 @@ function createModel(definition) {
|
|
|
24601
25245
|
whereNotBetween(column, range) {
|
|
24602
25246
|
return new ModelQueryBuilder(definition).whereNotBetween(column, range);
|
|
24603
25247
|
},
|
|
24604
|
-
create(data) {
|
|
25248
|
+
async create(data) {
|
|
24605
25249
|
const instance = new ModelInstance(definition, data);
|
|
24606
|
-
instance.save();
|
|
25250
|
+
await instance.save();
|
|
24607
25251
|
return instance;
|
|
24608
25252
|
},
|
|
24609
|
-
createMany(items) {
|
|
24610
|
-
|
|
25253
|
+
async createMany(items) {
|
|
25254
|
+
const out = [];
|
|
25255
|
+
for (const data of items)
|
|
25256
|
+
out.push(await this.create(data));
|
|
25257
|
+
return out;
|
|
24611
25258
|
},
|
|
24612
|
-
updateOrCreate(search, data) {
|
|
25259
|
+
async updateOrCreate(search, data) {
|
|
24613
25260
|
let query = new ModelQueryBuilder(definition);
|
|
24614
25261
|
for (const [key, value] of Object.entries(search)) {
|
|
24615
25262
|
query = query.where(key, value);
|
|
24616
25263
|
}
|
|
24617
|
-
const existing = query.first();
|
|
25264
|
+
const existing = await query.first();
|
|
24618
25265
|
if (existing) {
|
|
24619
|
-
existing.update(data);
|
|
25266
|
+
await existing.update(data);
|
|
24620
25267
|
return existing;
|
|
24621
25268
|
}
|
|
24622
25269
|
return this.create({ ...search, ...data });
|
|
24623
25270
|
},
|
|
24624
|
-
firstOrCreate(search, data) {
|
|
25271
|
+
async firstOrCreate(search, data) {
|
|
24625
25272
|
let query = new ModelQueryBuilder(definition);
|
|
24626
25273
|
for (const [key, value] of Object.entries(search)) {
|
|
24627
25274
|
query = query.where(key, value);
|
|
24628
25275
|
}
|
|
24629
|
-
const existing = query.first();
|
|
25276
|
+
const existing = await query.first();
|
|
24630
25277
|
return existing || this.create({ ...search, ...data });
|
|
24631
25278
|
},
|
|
24632
|
-
destroy(id) {
|
|
24633
|
-
const
|
|
25279
|
+
async destroy(id) {
|
|
25280
|
+
const exec = getExecutor();
|
|
24634
25281
|
const pk = definition.primaryKey || "id";
|
|
24635
|
-
return
|
|
25282
|
+
return (await exec.run(`DELETE FROM ${definition.table} WHERE ${pk} = ?`, [id])).changes > 0;
|
|
24636
25283
|
},
|
|
24637
25284
|
remove(id) {
|
|
24638
25285
|
return this.destroy(id);
|
|
24639
25286
|
},
|
|
24640
|
-
truncate() {
|
|
24641
|
-
|
|
25287
|
+
async truncate() {
|
|
25288
|
+
await getExecutor().run(`DELETE FROM ${definition.table}`, []);
|
|
24642
25289
|
},
|
|
24643
25290
|
getDefinition: () => definition,
|
|
24644
25291
|
getTable: () => definition.table,
|
|
@@ -24668,8 +25315,8 @@ function createModel(definition) {
|
|
|
24668
25315
|
}
|
|
24669
25316
|
});
|
|
24670
25317
|
}
|
|
24671
|
-
function createTableFromModel(definition) {
|
|
24672
|
-
const
|
|
25318
|
+
async function createTableFromModel(definition) {
|
|
25319
|
+
const exec = getExecutor();
|
|
24673
25320
|
const pk = definition.primaryKey || "id";
|
|
24674
25321
|
const columns = [];
|
|
24675
25322
|
columns.push(definition.autoIncrement !== false ? `${pk} INTEGER PRIMARY KEY AUTOINCREMENT` : `${pk} INTEGER PRIMARY KEY`);
|
|
@@ -24696,13 +25343,13 @@ function createTableFromModel(definition) {
|
|
|
24696
25343
|
}
|
|
24697
25344
|
columns.push(colDef);
|
|
24698
25345
|
}
|
|
24699
|
-
if (definition
|
|
25346
|
+
if (timestampsEnabled(definition)) {
|
|
24700
25347
|
columns.push("created_at TEXT", "updated_at TEXT");
|
|
24701
25348
|
}
|
|
24702
|
-
if (definition
|
|
25349
|
+
if (softDeletesEnabled(definition)) {
|
|
24703
25350
|
columns.push("deleted_at TEXT");
|
|
24704
25351
|
}
|
|
24705
|
-
|
|
25352
|
+
await exec.run(`CREATE TABLE IF NOT EXISTS ${definition.table} (${columns.join(", ")})`, []);
|
|
24706
25353
|
}
|
|
24707
25354
|
function createFakerCompatLayer(underlying) {
|
|
24708
25355
|
return new Proxy(underlying, {
|
|
@@ -24726,7 +25373,7 @@ function createFakerCompatLayer(underlying) {
|
|
|
24726
25373
|
});
|
|
24727
25374
|
}
|
|
24728
25375
|
async function seedModel(definition, count, faker) {
|
|
24729
|
-
const
|
|
25376
|
+
const exec = getExecutor();
|
|
24730
25377
|
const seeder = definition.traits?.useSeeder;
|
|
24731
25378
|
const seedCount = count ?? (typeof seeder === "object" && seeder ? seeder.count : 10);
|
|
24732
25379
|
if (!faker) {
|
|
@@ -24744,24 +25391,25 @@ async function seedModel(definition, count, faker) {
|
|
|
24744
25391
|
if (attr.factory)
|
|
24745
25392
|
data[name] = attr.factory(faker);
|
|
24746
25393
|
}
|
|
24747
|
-
if (definition
|
|
24748
|
-
const now =
|
|
25394
|
+
if (timestampsEnabled(definition)) {
|
|
25395
|
+
const now = formatNow();
|
|
24749
25396
|
data.created_at = now;
|
|
24750
25397
|
data.updated_at = now;
|
|
24751
25398
|
}
|
|
24752
25399
|
if (definition.traits?.useUuid)
|
|
24753
25400
|
data.uuid = crypto.randomUUID();
|
|
24754
25401
|
const columns = Object.keys(data);
|
|
24755
|
-
|
|
25402
|
+
await exec.run(`INSERT INTO ${definition.table} (${columns.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`, Object.values(data));
|
|
24756
25403
|
}
|
|
24757
25404
|
}
|
|
24758
|
-
var SAFE_SQL_IDENTIFIER, _getModel = null, globalDb = null, snakeCaseCache, tableNameCache, relationCache
|
|
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;
|
|
24759
25406
|
var init_orm = __esm(() => {
|
|
25407
|
+
init_config();
|
|
25408
|
+
init_db();
|
|
24760
25409
|
SAFE_SQL_IDENTIFIER = /^[A-Z_][A-Z0-9_]*$/i;
|
|
24761
25410
|
snakeCaseCache = new Map;
|
|
24762
25411
|
tableNameCache = new Map;
|
|
24763
25412
|
relationCache = new Map;
|
|
24764
|
-
preparedStatementCache = new Map;
|
|
24765
25413
|
});
|
|
24766
25414
|
|
|
24767
25415
|
// src/model.ts
|
|
@@ -26210,9 +26858,9 @@ function buildDatabaseSchema(models) {
|
|
|
26210
26858
|
// src/loader.ts
|
|
26211
26859
|
import { readdirSync as readdirSync12, statSync as statSync5 } from "fs";
|
|
26212
26860
|
import { basename, extname as extname4 } from "path";
|
|
26213
|
-
import
|
|
26861
|
+
import process31 from "process";
|
|
26214
26862
|
async function loadModels(options) {
|
|
26215
|
-
const cwd = options.cwd ??
|
|
26863
|
+
const cwd = options.cwd ?? process31.cwd();
|
|
26216
26864
|
const dir = options.modelsDir.startsWith("/") ? options.modelsDir : `${cwd}/${options.modelsDir}`;
|
|
26217
26865
|
const result = {};
|
|
26218
26866
|
const entries = readdirSync12(dir);
|
|
@@ -26239,6 +26887,23 @@ async function loadModels(options) {
|
|
|
26239
26887
|
}
|
|
26240
26888
|
var init_loader = () => {};
|
|
26241
26889
|
|
|
26890
|
+
// src/relation-utils.ts
|
|
26891
|
+
function normalizeRelationEntry(entry) {
|
|
26892
|
+
if (typeof entry === "string")
|
|
26893
|
+
return { model: entry };
|
|
26894
|
+
if (entry && typeof entry === "object" && typeof entry.model === "string") {
|
|
26895
|
+
const e2 = entry;
|
|
26896
|
+
return { model: e2.model, foreignKey: e2.foreignKey, onDelete: e2.onDelete };
|
|
26897
|
+
}
|
|
26898
|
+
return null;
|
|
26899
|
+
}
|
|
26900
|
+
function normalizeRelationList(rel) {
|
|
26901
|
+
if (!rel)
|
|
26902
|
+
return [];
|
|
26903
|
+
const entries = Array.isArray(rel) ? rel : typeof rel === "object" ? Object.values(rel) : [];
|
|
26904
|
+
return entries.map(normalizeRelationEntry).filter((x2) => x2 !== null);
|
|
26905
|
+
}
|
|
26906
|
+
|
|
26242
26907
|
// src/meta.ts
|
|
26243
26908
|
function buildSchemaMeta(models) {
|
|
26244
26909
|
const modelToTable = {};
|
|
@@ -26256,13 +26921,24 @@ function buildSchemaMeta(models) {
|
|
|
26256
26921
|
const toRecord = (v2) => {
|
|
26257
26922
|
if (!v2)
|
|
26258
26923
|
return {};
|
|
26924
|
+
const rec = {};
|
|
26259
26925
|
if (Array.isArray(v2)) {
|
|
26260
|
-
const
|
|
26261
|
-
|
|
26262
|
-
|
|
26926
|
+
for (const item of v2) {
|
|
26927
|
+
const n2 = normalizeRelationEntry(item);
|
|
26928
|
+
if (n2)
|
|
26929
|
+
rec[n2.model] = n2.model;
|
|
26930
|
+
}
|
|
26263
26931
|
return rec;
|
|
26264
26932
|
}
|
|
26265
|
-
|
|
26933
|
+
if (typeof v2 === "object") {
|
|
26934
|
+
for (const [key, val] of Object.entries(v2)) {
|
|
26935
|
+
const n2 = normalizeRelationEntry(val);
|
|
26936
|
+
if (n2)
|
|
26937
|
+
rec[key] = n2.model;
|
|
26938
|
+
}
|
|
26939
|
+
return rec;
|
|
26940
|
+
}
|
|
26941
|
+
return {};
|
|
26266
26942
|
};
|
|
26267
26943
|
const toBelongsToManyRecord = (v2) => {
|
|
26268
26944
|
if (!v2)
|
|
@@ -26309,11 +26985,12 @@ function buildSchemaMeta(models) {
|
|
|
26309
26985
|
}
|
|
26310
26986
|
return { modelToTable, tableToModel, primaryKeys, relations, scopes: scopesByTable, models };
|
|
26311
26987
|
}
|
|
26988
|
+
var init_meta = () => {};
|
|
26312
26989
|
|
|
26313
26990
|
// src/migrations.ts
|
|
26314
26991
|
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync14 } from "fs";
|
|
26315
26992
|
import { dirname as dirname11, join as join17 } from "path";
|
|
26316
|
-
import
|
|
26993
|
+
import process33 from "process";
|
|
26317
26994
|
function info2(message) {
|
|
26318
26995
|
if (config5.verbose)
|
|
26319
26996
|
console.log(message);
|
|
@@ -26329,10 +27006,10 @@ function findWorkspaceRoot6(startPath) {
|
|
|
26329
27006
|
}
|
|
26330
27007
|
currentPath = dirname11(currentPath);
|
|
26331
27008
|
}
|
|
26332
|
-
return
|
|
27009
|
+
return process33.cwd();
|
|
26333
27010
|
}
|
|
26334
27011
|
function ensureSqlDirectory2() {
|
|
26335
|
-
const workspaceRoot = findWorkspaceRoot6(
|
|
27012
|
+
const workspaceRoot = findWorkspaceRoot6(process33.cwd());
|
|
26336
27013
|
const sqlDir = join17(workspaceRoot, "database", "migrations");
|
|
26337
27014
|
if (!existsSync21(sqlDir)) {
|
|
26338
27015
|
mkdirSync9(sqlDir, { recursive: true });
|
|
@@ -26471,15 +27148,6 @@ function detectTypeFromValidationRule(rule) {
|
|
|
26471
27148
|
}
|
|
26472
27149
|
return;
|
|
26473
27150
|
}
|
|
26474
|
-
function normalizeBelongsTo(belongsTo) {
|
|
26475
|
-
if (!belongsTo)
|
|
26476
|
-
return [];
|
|
26477
|
-
if (Array.isArray(belongsTo))
|
|
26478
|
-
return belongsTo;
|
|
26479
|
-
if (typeof belongsTo === "object")
|
|
26480
|
-
return Object.values(belongsTo);
|
|
26481
|
-
return [];
|
|
26482
|
-
}
|
|
26483
27151
|
function buildMigrationPlan2(models, options) {
|
|
26484
27152
|
const meta = buildSchemaMeta(models);
|
|
26485
27153
|
const tables = [];
|
|
@@ -26568,12 +27236,12 @@ function buildMigrationPlan2(models, options) {
|
|
|
26568
27236
|
}
|
|
26569
27237
|
columns.push(col);
|
|
26570
27238
|
}
|
|
26571
|
-
const
|
|
26572
|
-
for (const
|
|
26573
|
-
const fkColumnName = `${snakeCase(
|
|
27239
|
+
const belongsToRelations = normalizeRelationList(model.belongsTo);
|
|
27240
|
+
for (const rel of belongsToRelations) {
|
|
27241
|
+
const fkColumnName = rel.foreignKey ?? `${snakeCase(rel.model)}_id`;
|
|
26574
27242
|
if (columns.some((c2) => c2.name === fkColumnName))
|
|
26575
27243
|
continue;
|
|
26576
|
-
const refTable = meta.modelToTable[
|
|
27244
|
+
const refTable = meta.modelToTable[rel.model];
|
|
26577
27245
|
if (!refTable)
|
|
26578
27246
|
continue;
|
|
26579
27247
|
const refPk = meta.primaryKeys[refTable] ?? "id";
|
|
@@ -26584,7 +27252,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
26584
27252
|
isUnique: false,
|
|
26585
27253
|
isNullable: true,
|
|
26586
27254
|
hasDefault: false,
|
|
26587
|
-
references: { table: refTable, column: refPk }
|
|
27255
|
+
references: { table: refTable, column: refPk, onDelete: rel.onDelete }
|
|
26588
27256
|
});
|
|
26589
27257
|
}
|
|
26590
27258
|
const traits = model.traits;
|
|
@@ -26901,6 +27569,13 @@ function columnsAreDifferent(col1, col2) {
|
|
|
26901
27569
|
}
|
|
26902
27570
|
return false;
|
|
26903
27571
|
}
|
|
27572
|
+
function referencesAreDifferent(r1, r2) {
|
|
27573
|
+
if (Boolean(r1) !== Boolean(r2))
|
|
27574
|
+
return true;
|
|
27575
|
+
if (!r1 || !r2)
|
|
27576
|
+
return false;
|
|
27577
|
+
return r1.table !== r2.table || r1.column !== r2.column || r1.onDelete !== r2.onDelete || r1.onUpdate !== r2.onUpdate;
|
|
27578
|
+
}
|
|
26904
27579
|
function mapIndexesByKey(indexes) {
|
|
26905
27580
|
const map = {};
|
|
26906
27581
|
for (const i2 of indexes) {
|
|
@@ -27044,6 +27719,13 @@ function generateDiffSql(previous, next) {
|
|
|
27044
27719
|
info2(`-- Detected column type change: ${curr.table}.${colName} (${prevCol.type} -> ${currCol.type})`);
|
|
27045
27720
|
hasChanges = true;
|
|
27046
27721
|
}
|
|
27722
|
+
if (referencesAreDifferent(prevCol.references, currCol.references) && currCol.references) {
|
|
27723
|
+
const addFkStatement = driver.addForeignKey(curr.table, currCol.name, currCol.references.table, currCol.references.column, currCol.references.onDelete, currCol.references.onUpdate);
|
|
27724
|
+
tableChanges.push(addFkStatement);
|
|
27725
|
+
chunks.push(addFkStatement);
|
|
27726
|
+
info2(`-- Detected foreign-key change: ${curr.table}.${colName} -> ${currCol.references.table}(${currCol.references.column})${currCol.references.onDelete ? ` ON DELETE ${currCol.references.onDelete}` : ""}`);
|
|
27727
|
+
hasChanges = true;
|
|
27728
|
+
}
|
|
27047
27729
|
}
|
|
27048
27730
|
}
|
|
27049
27731
|
for (const colName of Object.keys(currCols)) {
|
|
@@ -27097,6 +27779,7 @@ var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0
|
|
|
27097
27779
|
var init_migrations = __esm(() => {
|
|
27098
27780
|
init_config();
|
|
27099
27781
|
init_drivers();
|
|
27782
|
+
init_meta();
|
|
27100
27783
|
});
|
|
27101
27784
|
|
|
27102
27785
|
// src/schema.ts
|
|
@@ -27131,6 +27814,7 @@ var init_src2 = __esm(() => {
|
|
|
27131
27814
|
init_dynamodb_tooling_adapter();
|
|
27132
27815
|
init_dynamodb();
|
|
27133
27816
|
init_loader();
|
|
27817
|
+
init_meta();
|
|
27134
27818
|
init_migrations();
|
|
27135
27819
|
init_orm();
|
|
27136
27820
|
});
|
|
@@ -27140,7 +27824,7 @@ import { existsSync as existsSync23 } from "fs";
|
|
|
27140
27824
|
import fs from "fs/promises";
|
|
27141
27825
|
import os from "os";
|
|
27142
27826
|
import path from "path";
|
|
27143
|
-
import
|
|
27827
|
+
import process35 from "process";
|
|
27144
27828
|
import { EventEmitter } from "events";
|
|
27145
27829
|
import process52 from "process";
|
|
27146
27830
|
import process210 from "process";
|
|
@@ -27164,10 +27848,10 @@ class Telemetry {
|
|
|
27164
27848
|
this.configPath = path.join(configDir, "telemetry.json");
|
|
27165
27849
|
}
|
|
27166
27850
|
async isEnabled() {
|
|
27167
|
-
if (
|
|
27851
|
+
if (process35.env.DO_NOT_TRACK === "1" || process35.env.DO_NOT_TRACK === "true") {
|
|
27168
27852
|
return false;
|
|
27169
27853
|
}
|
|
27170
|
-
if (
|
|
27854
|
+
if (process35.env.NO_TELEMETRY === "1" || process35.env.NO_TELEMETRY === "true") {
|
|
27171
27855
|
return false;
|
|
27172
27856
|
}
|
|
27173
27857
|
const config6 = await this.loadConfig();
|
|
@@ -27196,7 +27880,7 @@ class Telemetry {
|
|
|
27196
27880
|
...data,
|
|
27197
27881
|
timestamp: Date.now(),
|
|
27198
27882
|
platform: os.platform(),
|
|
27199
|
-
nodeVersion:
|
|
27883
|
+
nodeVersion: process35.version
|
|
27200
27884
|
};
|
|
27201
27885
|
this.events.push(telemetryEvent);
|
|
27202
27886
|
if (this.events.length >= 10) {
|
|
@@ -27252,7 +27936,7 @@ class Telemetry {
|
|
|
27252
27936
|
const config6 = await this.loadConfig();
|
|
27253
27937
|
return {
|
|
27254
27938
|
enabled: config6.enabled,
|
|
27255
|
-
doNotTrack:
|
|
27939
|
+
doNotTrack: process35.env.DO_NOT_TRACK === "1" || process35.env.DO_NOT_TRACK === "true",
|
|
27256
27940
|
eventsQueued: this.events.length,
|
|
27257
27941
|
lastSent: config6.lastSent
|
|
27258
27942
|
};
|
|
@@ -29174,7 +29858,7 @@ function getPrefix() {
|
|
|
29174
29858
|
}
|
|
29175
29859
|
var prefix = getPrefix();
|
|
29176
29860
|
// package.json
|
|
29177
|
-
var version2 = "0.1.
|
|
29861
|
+
var version2 = "0.1.26";
|
|
29178
29862
|
|
|
29179
29863
|
// bin/cli.ts
|
|
29180
29864
|
init_actions();
|
|
@@ -29200,6 +29884,15 @@ var cli = new CLI("query-builder");
|
|
|
29200
29884
|
cli.command("introspect <dir>", "Load models and print inferred schema").option("--verbose", "Enable verbose logging").example("query-builder introspect ./app/Models --verbose").action(async (dir, _options) => {
|
|
29201
29885
|
await introspect(dir, _options);
|
|
29202
29886
|
});
|
|
29887
|
+
cli.command("introspect:db", "Reverse-introspect the live database into defineModel() source (#1047)").option("--table <table>", "Limit to a single table (repeatable)").example("query-builder introspect:db > app/Models/generated.ts").action(async (_options) => {
|
|
29888
|
+
const t2 = _options?.table;
|
|
29889
|
+
const tables = t2 ? Array.isArray(t2) ? t2 : [t2] : undefined;
|
|
29890
|
+
const models = await introspectDatabase({ tables });
|
|
29891
|
+
console.log(`import { defineModel } from 'bun-query-builder'
|
|
29892
|
+
|
|
29893
|
+
${models.map((m2) => m2.source).join(`
|
|
29894
|
+
`)}`);
|
|
29895
|
+
});
|
|
29203
29896
|
cli.command("sql <dir> <table>", "Build a sample query for a table").option("--limit <n>", "Limit rows", { default: 10 }).example("query-builder sql ./app/Models users --limit 5").action(async (dir, table, opts) => {
|
|
29204
29897
|
await sql(dir, table, opts);
|
|
29205
29898
|
});
|