bun-query-builder 0.1.59 → 0.1.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +260 -188
- package/dist/db.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/inflect.d.ts +29 -0
- package/dist/src/index.js +265 -190
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
package/dist/bin/cli.js
CHANGED
|
@@ -12062,6 +12062,13 @@ function createSQLiteSQL(filename) {
|
|
|
12062
12062
|
sqlFunction._wrapper = wrapper;
|
|
12063
12063
|
return sqlFunction;
|
|
12064
12064
|
}
|
|
12065
|
+
function sqliteFileFromUrl(url) {
|
|
12066
|
+
const stripped = url.replace(/^(?:sqlite|sqlite3|file):/i, "");
|
|
12067
|
+
if (stripped === url)
|
|
12068
|
+
return url;
|
|
12069
|
+
const path = stripped.startsWith("///") ? stripped.slice(2) : stripped.startsWith("//") ? stripped.slice(2) : stripped;
|
|
12070
|
+
return path || ":memory:";
|
|
12071
|
+
}
|
|
12065
12072
|
function createConnectionString(dialect, dbConfig) {
|
|
12066
12073
|
if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") && process19.env.DB_CONNECTION === dialect) {
|
|
12067
12074
|
const e = process19.env;
|
|
@@ -12075,7 +12082,7 @@ function createConnectionString(dialect, dbConfig) {
|
|
|
12075
12082
|
return `${scheme}://${envUser}:${envPass}@${envHost}${envPort ? `:${envPort}` : ""}/${envDb}${ssl2}`;
|
|
12076
12083
|
}
|
|
12077
12084
|
if (dbConfig.url) {
|
|
12078
|
-
return dbConfig.url;
|
|
12085
|
+
return dialect === "sqlite" ? sqliteFileFromUrl(dbConfig.url) : dbConfig.url;
|
|
12079
12086
|
}
|
|
12080
12087
|
const { database, username, password, host = "localhost", port, ssl } = dbConfig;
|
|
12081
12088
|
const sslQ = ssl || process19.env.DB_SSL === "true" || process19.env.DB_SSL === "1" ? "?ssl=true" : "";
|
|
@@ -12351,9 +12358,37 @@ var init_benchmark = __esm(() => {
|
|
|
12351
12358
|
init_src2();
|
|
12352
12359
|
});
|
|
12353
12360
|
|
|
12361
|
+
// src/inflect.ts
|
|
12362
|
+
function stripTrailingS(name) {
|
|
12363
|
+
return name.endsWith("s") ? name.slice(0, -1) : name;
|
|
12364
|
+
}
|
|
12365
|
+
function inflectSingular(name) {
|
|
12366
|
+
if (name.endsWith("ies") && name.length > 3) {
|
|
12367
|
+
const stem = name.slice(0, -3);
|
|
12368
|
+
const prev = stem[stem.length - 1];
|
|
12369
|
+
if (prev && !"aeiou".includes(prev))
|
|
12370
|
+
return `${stem}y`;
|
|
12371
|
+
}
|
|
12372
|
+
if (name.endsWith("es") && name.length > 2) {
|
|
12373
|
+
const stem = name.slice(0, -2);
|
|
12374
|
+
if (stem.endsWith("s") || stem.endsWith("x") || stem.endsWith("ch") || stem.endsWith("sh"))
|
|
12375
|
+
return stem;
|
|
12376
|
+
}
|
|
12377
|
+
if (name.endsWith("s") && !name.endsWith("ss") && !name.endsWith("us") && !name.endsWith("is"))
|
|
12378
|
+
return name.slice(0, -1);
|
|
12379
|
+
return name;
|
|
12380
|
+
}
|
|
12381
|
+
function singularizerFor(strategy) {
|
|
12382
|
+
if (strategy === "none")
|
|
12383
|
+
return (name) => name;
|
|
12384
|
+
if (strategy === "inflect")
|
|
12385
|
+
return inflectSingular;
|
|
12386
|
+
return stripTrailingS;
|
|
12387
|
+
}
|
|
12388
|
+
|
|
12354
12389
|
// src/pivot.ts
|
|
12355
12390
|
function defaultSingularize(name) {
|
|
12356
|
-
return
|
|
12391
|
+
return singularizerFor(config5.relations?.singularizeStrategy)(name);
|
|
12357
12392
|
}
|
|
12358
12393
|
function resolvePivot(meta, parentTable, relationKey, options = {}) {
|
|
12359
12394
|
const singularize = options.singularize ?? defaultSingularize;
|
|
@@ -12430,6 +12465,9 @@ function* iterateAllPivots(meta, options = {}) {
|
|
|
12430
12465
|
}
|
|
12431
12466
|
}
|
|
12432
12467
|
}
|
|
12468
|
+
var init_pivot = __esm(() => {
|
|
12469
|
+
init_config();
|
|
12470
|
+
});
|
|
12433
12471
|
|
|
12434
12472
|
// src/client.ts
|
|
12435
12473
|
function isRawExpression(expr) {
|
|
@@ -12610,7 +12648,13 @@ class QueryCache {
|
|
|
12610
12648
|
this.cache.clear();
|
|
12611
12649
|
}
|
|
12612
12650
|
setMaxSize(size) {
|
|
12613
|
-
this.maxSize = size;
|
|
12651
|
+
this.maxSize = Math.max(0, Math.floor(size));
|
|
12652
|
+
while (this.cache.size > this.maxSize) {
|
|
12653
|
+
const lruKey = this.cache.keys().next().value;
|
|
12654
|
+
if (lruKey === undefined)
|
|
12655
|
+
break;
|
|
12656
|
+
this.cache.delete(lruKey);
|
|
12657
|
+
}
|
|
12614
12658
|
}
|
|
12615
12659
|
}
|
|
12616
12660
|
function isRetriableTxError(err) {
|
|
@@ -12715,8 +12759,7 @@ function computeBackoffMs(attempt, cfg) {
|
|
|
12715
12759
|
const max = Math.max(base, cfg?.maxMs ?? 2000);
|
|
12716
12760
|
let ms = Math.min(max, base * factor ** Math.max(0, attempt - 1));
|
|
12717
12761
|
if (cfg?.jitter) {
|
|
12718
|
-
|
|
12719
|
-
ms = ms - jitter / 2;
|
|
12762
|
+
ms = Math.min(max, ms * (0.9 + Math.random() * 0.2));
|
|
12720
12763
|
}
|
|
12721
12764
|
return Math.floor(ms);
|
|
12722
12765
|
}
|
|
@@ -12968,11 +13011,7 @@ function createQueryBuilder(state) {
|
|
|
12968
13011
|
const pivotColumns = new Map;
|
|
12969
13012
|
const pivotConfigRelations = new Set;
|
|
12970
13013
|
let cacheTtl = 60000;
|
|
12971
|
-
const singularize = (name) =>
|
|
12972
|
-
if (config5.relations.singularizeStrategy === "none")
|
|
12973
|
-
return name;
|
|
12974
|
-
return name.endsWith("s") ? name.slice(0, -1) : name;
|
|
12975
|
-
};
|
|
13014
|
+
const singularize = (name) => singularizerFor(config5.relations.singularizeStrategy)(name);
|
|
12976
13015
|
const resolvePivotLocal = (relationKey) => {
|
|
12977
13016
|
if (!meta)
|
|
12978
13017
|
return null;
|
|
@@ -15448,6 +15487,7 @@ function createQueryBuilder(state) {
|
|
|
15448
15487
|
const colCount = keys.length;
|
|
15449
15488
|
const totalParams = rowCount * colCount;
|
|
15450
15489
|
params.length = totalParams;
|
|
15490
|
+
const columnList = isPostgres ? keys.map((k) => quoteId(k)).join(",") : keys.join(",");
|
|
15451
15491
|
if (rowCount === 1) {
|
|
15452
15492
|
if (!isPostgres) {
|
|
15453
15493
|
let cols = quoteId(keys[0]);
|
|
@@ -15460,7 +15500,6 @@ function createQueryBuilder(state) {
|
|
|
15460
15500
|
}
|
|
15461
15501
|
sqlText = `INSERT INTO ${quoteId(table)}(${cols})VALUES(${placeholders})`;
|
|
15462
15502
|
} else {
|
|
15463
|
-
const columnList = keys.map((k) => quoteId(k)).join(",");
|
|
15464
15503
|
sqlText = `INSERT INTO ${quoteId(table)}(${columnList})VALUES(`;
|
|
15465
15504
|
for (let c = 0;c < colCount; c++) {
|
|
15466
15505
|
if (c > 0)
|
|
@@ -15471,8 +15510,8 @@ function createQueryBuilder(state) {
|
|
|
15471
15510
|
sqlText += ")";
|
|
15472
15511
|
}
|
|
15473
15512
|
} else {
|
|
15474
|
-
const
|
|
15475
|
-
sqlText = `INSERT INTO ${quoteId(table)}(${
|
|
15513
|
+
const columnList2 = keys.map((k) => quoteId(k)).join(",");
|
|
15514
|
+
sqlText = `INSERT INTO ${quoteId(table)}(${columnList2})VALUES`;
|
|
15476
15515
|
let pidx = 0;
|
|
15477
15516
|
for (let r = 0;r < rowCount; r++) {
|
|
15478
15517
|
const row = rows[r];
|
|
@@ -16028,11 +16067,13 @@ function createQueryBuilder(state) {
|
|
|
16028
16067
|
}
|
|
16029
16068
|
},
|
|
16030
16069
|
async savepoint(fn) {
|
|
16070
|
+
if (state?.inTransaction !== true)
|
|
16071
|
+
throw new Error("savepoint() must be called inside a transaction");
|
|
16031
16072
|
const s = _sql;
|
|
16032
16073
|
if (!s || typeof s.savepoint !== "function")
|
|
16033
|
-
throw new Error("savepoint()
|
|
16074
|
+
throw new Error("savepoint() is not supported by the active connection");
|
|
16034
16075
|
return await s.savepoint(async (sp) => {
|
|
16035
|
-
const qb = createQueryBuilder({ sql: sp, meta, schema });
|
|
16076
|
+
const qb = createQueryBuilder({ sql: sp, meta, schema, inTransaction: true });
|
|
16036
16077
|
return await fn(qb);
|
|
16037
16078
|
});
|
|
16038
16079
|
},
|
|
@@ -16449,6 +16490,7 @@ var SQL_PATTERNS, SAFE_WHERE_OPERATORS, warnedSqlFragmentContexts, queryCache, r
|
|
|
16449
16490
|
var init_client = __esm(() => {
|
|
16450
16491
|
init_config();
|
|
16451
16492
|
init_db();
|
|
16493
|
+
init_pivot();
|
|
16452
16494
|
SQL_PATTERNS = {
|
|
16453
16495
|
SELECT_STAR: /^SELECT\s+\*/i,
|
|
16454
16496
|
SELECT: /^SELECT\s+/i,
|
|
@@ -17049,7 +17091,7 @@ var init_db_info = __esm(() => {
|
|
|
17049
17091
|
// src/actions/db-optimize.ts
|
|
17050
17092
|
import process22 from "process";
|
|
17051
17093
|
async function dbOptimize(options = {}) {
|
|
17052
|
-
const dialect = options.dialect || process22.env.DB_DIALECT || "postgres";
|
|
17094
|
+
const dialect = options.dialect || process22.env.DB_DIALECT || config5.dialect || "postgres";
|
|
17053
17095
|
const aggressive = options.aggressive || false;
|
|
17054
17096
|
if (options.verbose) {
|
|
17055
17097
|
console.log(`Optimizing ${dialect} database${aggressive ? " (aggressive mode)" : ""}...`);
|
|
@@ -17144,7 +17186,7 @@ var init_db_optimize = __esm(() => {
|
|
|
17144
17186
|
// src/actions/db-wipe.ts
|
|
17145
17187
|
import process23 from "process";
|
|
17146
17188
|
async function dbWipe(options = {}) {
|
|
17147
|
-
const dialect = options.dialect || process23.env.DB_DIALECT || "postgres";
|
|
17189
|
+
const dialect = options.dialect || process23.env.DB_DIALECT || config5.dialect || "postgres";
|
|
17148
17190
|
if (options.verbose) {
|
|
17149
17191
|
console.log(`Wiping all tables from ${dialect} database...`);
|
|
17150
17192
|
}
|
|
@@ -18762,7 +18804,7 @@ async function resetDatabase(dir, opts = {}) {
|
|
|
18762
18804
|
if (!dir) {
|
|
18763
18805
|
dir = join9(process25.cwd(), "app/Models");
|
|
18764
18806
|
}
|
|
18765
|
-
const dialect = opts.dialect || "postgres";
|
|
18807
|
+
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
18766
18808
|
const driver = getDialectDriver(dialect);
|
|
18767
18809
|
const workspaceRoot = getWorkspaceRoot();
|
|
18768
18810
|
try {
|
|
@@ -18862,7 +18904,7 @@ async function deleteMigrationFiles(dir, workspaceRoot, opts = {}) {
|
|
|
18862
18904
|
if (!workspaceRoot) {
|
|
18863
18905
|
workspaceRoot = getWorkspaceRoot();
|
|
18864
18906
|
}
|
|
18865
|
-
const dialect = String(opts.dialect || "postgres");
|
|
18907
|
+
const dialect = String(opts.dialect || config5.dialect || "postgres");
|
|
18866
18908
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18867
18909
|
if (existsSync16(snapshotPath)) {
|
|
18868
18910
|
unlinkSync(snapshotPath);
|
|
@@ -24693,6 +24735,13 @@ function normalizeAttributeKeys(data) {
|
|
|
24693
24735
|
}
|
|
24694
24736
|
return result;
|
|
24695
24737
|
}
|
|
24738
|
+
function normalizeAttributeKeysInPlace(data) {
|
|
24739
|
+
for (const key in data) {
|
|
24740
|
+
if (toSnakeCase(key) !== key)
|
|
24741
|
+
return normalizeAttributeKeys(data);
|
|
24742
|
+
}
|
|
24743
|
+
return data;
|
|
24744
|
+
}
|
|
24696
24745
|
function findAttributeDef(attrs, key) {
|
|
24697
24746
|
if (attrs[key])
|
|
24698
24747
|
return attrs[key];
|
|
@@ -24714,7 +24763,7 @@ class ModelInstance {
|
|
|
24714
24763
|
_relations = {};
|
|
24715
24764
|
constructor(definition, attributes = {}) {
|
|
24716
24765
|
this._definition = definition;
|
|
24717
|
-
this._attributes =
|
|
24766
|
+
this._attributes = normalizeAttributeKeysInPlace({ ...attributes });
|
|
24718
24767
|
this._original = null;
|
|
24719
24768
|
const btmKeys = collectBelongsToManyKeys(definition);
|
|
24720
24769
|
if (btmKeys.size === 0)
|
|
@@ -25015,6 +25064,9 @@ class ModelInstance {
|
|
|
25015
25064
|
return json;
|
|
25016
25065
|
}
|
|
25017
25066
|
}
|
|
25067
|
+
function sqlColumn(name) {
|
|
25068
|
+
return toSnakeCase(name);
|
|
25069
|
+
}
|
|
25018
25070
|
function toSnakeCase(str) {
|
|
25019
25071
|
let cached = snakeCaseCache.get(str);
|
|
25020
25072
|
if (cached !== undefined)
|
|
@@ -25158,12 +25210,12 @@ function resolveRelation(definition, relationName) {
|
|
|
25158
25210
|
}
|
|
25159
25211
|
pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table || toTableName(config6.through);
|
|
25160
25212
|
} else {
|
|
25161
|
-
const a2 =
|
|
25162
|
-
const b2 =
|
|
25213
|
+
const a2 = singularizeWord(parentTable);
|
|
25214
|
+
const b2 = singularizeWord(relatedTable);
|
|
25163
25215
|
pivotTable = [a2, b2].sort().join("_");
|
|
25164
25216
|
}
|
|
25165
|
-
const pivotFkParent = config6?.foreignKey || `${
|
|
25166
|
-
const pivotFkRelated = config6?.relatedKey || `${
|
|
25217
|
+
const pivotFkParent = config6?.foreignKey || `${singularizeWord(parentTable)}_id`;
|
|
25218
|
+
const pivotFkRelated = config6?.relatedKey || `${singularizeWord(relatedTable)}_id`;
|
|
25167
25219
|
const pivotColumns = [];
|
|
25168
25220
|
if (config6?.pivot?.columns) {
|
|
25169
25221
|
for (const k2 of Object.keys(config6.pivot.columns))
|
|
@@ -25231,8 +25283,17 @@ function resolveRelation(definition, relationName) {
|
|
|
25231
25283
|
return hot;
|
|
25232
25284
|
return null;
|
|
25233
25285
|
}
|
|
25286
|
+
function distinctParentIds(instances, pk) {
|
|
25287
|
+
const seen = new Set;
|
|
25288
|
+
for (const i2 of instances) {
|
|
25289
|
+
const v2 = i2.get(pk);
|
|
25290
|
+
if (v2 != null)
|
|
25291
|
+
seen.add(v2);
|
|
25292
|
+
}
|
|
25293
|
+
return [...seen];
|
|
25294
|
+
}
|
|
25234
25295
|
function singularizeWord(table) {
|
|
25235
|
-
return
|
|
25296
|
+
return singularizerFor(config5.relations?.singularizeStrategy)(table);
|
|
25236
25297
|
}
|
|
25237
25298
|
|
|
25238
25299
|
class BelongsToManyRelationBuilder {
|
|
@@ -25635,7 +25696,7 @@ class ModelQueryBuilder {
|
|
|
25635
25696
|
}
|
|
25636
25697
|
whereNotBetween(column, range) {
|
|
25637
25698
|
assertValidIdentifier(column, "whereNotBetween(column)");
|
|
25638
|
-
const col = column;
|
|
25699
|
+
const col = sqlColumn(column);
|
|
25639
25700
|
this._wheres.push({
|
|
25640
25701
|
raw: `(${col} < ? OR ${col} > ?)`,
|
|
25641
25702
|
rawParams: [range[0], range[1]],
|
|
@@ -25700,13 +25761,14 @@ class ModelQueryBuilder {
|
|
|
25700
25761
|
if (w.rawParams && w.rawParams.length > 0)
|
|
25701
25762
|
params.push(...w.rawParams);
|
|
25702
25763
|
} else if (w.value === null) {
|
|
25703
|
-
|
|
25764
|
+
const col = sqlColumn(w.column);
|
|
25765
|
+
clause = w.operator === "=" ? `${col} IS NULL` : `${col} IS NOT NULL`;
|
|
25704
25766
|
} else if (w.operator === "in" || w.operator === "not in") {
|
|
25705
25767
|
const arr = w.value;
|
|
25706
|
-
clause = `${w.column} ${w.operator.toUpperCase()} (${arr.map(() => "?").join(", ")})`;
|
|
25768
|
+
clause = `${sqlColumn(w.column)} ${w.operator.toUpperCase()} (${arr.map(() => "?").join(", ")})`;
|
|
25707
25769
|
params.push(...arr);
|
|
25708
25770
|
} else {
|
|
25709
|
-
clause = `${w.column} ${w.operator} ?`;
|
|
25771
|
+
clause = `${sqlColumn(w.column)} ${w.operator} ?`;
|
|
25710
25772
|
params.push(w.value);
|
|
25711
25773
|
}
|
|
25712
25774
|
clauses.push(i2 === 0 ? clause : `${w.boolean.toUpperCase()} ${clause}`);
|
|
@@ -25727,13 +25789,14 @@ class ModelQueryBuilder {
|
|
|
25727
25789
|
}
|
|
25728
25790
|
buildQuery() {
|
|
25729
25791
|
const params = [];
|
|
25730
|
-
|
|
25792
|
+
const cols = this._select.map((c2) => c2 === "*" ? c2 : sqlColumn(c2));
|
|
25793
|
+
let sql2 = `SELECT ${cols.join(", ")} FROM ${this._definition.table}`;
|
|
25731
25794
|
const whereBody = this.composeWhere(params);
|
|
25732
25795
|
if (whereBody) {
|
|
25733
25796
|
sql2 += ` WHERE ${whereBody}`;
|
|
25734
25797
|
}
|
|
25735
25798
|
if (this._orderBy.length > 0) {
|
|
25736
|
-
sql2 += ` ORDER BY ${this._orderBy.map((o2) => `${o2.column} ${o2.direction.toUpperCase()}`).join(", ")}`;
|
|
25799
|
+
sql2 += ` ORDER BY ${this._orderBy.map((o2) => `${sqlColumn(o2.column)} ${o2.direction.toUpperCase()}`).join(", ")}`;
|
|
25737
25800
|
}
|
|
25738
25801
|
if (this._limit !== undefined)
|
|
25739
25802
|
sql2 += ` LIMIT ${this._limit}`;
|
|
@@ -25747,165 +25810,168 @@ class ModelQueryBuilder {
|
|
|
25747
25810
|
async eagerLoadRelations(instances) {
|
|
25748
25811
|
if (instances.length === 0 || this._withRelations.length === 0)
|
|
25749
25812
|
return;
|
|
25813
|
+
await Promise.all(this._withRelations.map((r2) => this.eagerLoadRelation(r2, instances)));
|
|
25814
|
+
}
|
|
25815
|
+
async eagerLoadRelation(relationName, instances) {
|
|
25750
25816
|
const exec = getExecutor();
|
|
25751
25817
|
const pk = this._definition.primaryKey || "id";
|
|
25752
|
-
|
|
25753
|
-
|
|
25754
|
-
|
|
25755
|
-
|
|
25756
|
-
|
|
25757
|
-
|
|
25758
|
-
|
|
25759
|
-
|
|
25760
|
-
|
|
25761
|
-
|
|
25762
|
-
|
|
25763
|
-
|
|
25764
|
-
|
|
25765
|
-
|
|
25766
|
-
|
|
25767
|
-
|
|
25768
|
-
|
|
25769
|
-
|
|
25770
|
-
|
|
25771
|
-
|
|
25772
|
-
|
|
25773
|
-
|
|
25774
|
-
|
|
25775
|
-
|
|
25776
|
-
|
|
25777
|
-
grouped.get(fkVal).push(row);
|
|
25778
|
-
}
|
|
25779
|
-
for (const instance of instances) {
|
|
25780
|
-
const related = grouped.get(instance.get(pk)) || [];
|
|
25781
|
-
instance.setRelation(relationName, related.map((r2) => new ModelInstance(relDef, r2)));
|
|
25782
|
-
}
|
|
25783
|
-
} else {
|
|
25784
|
-
const byFk = new Map;
|
|
25785
|
-
for (const row of rows) {
|
|
25786
|
-
byFk.set(row[rel.foreignKey], row);
|
|
25787
|
-
}
|
|
25788
|
-
for (const instance of instances) {
|
|
25789
|
-
const row = byFk.get(instance.get(pk));
|
|
25790
|
-
instance.setRelation(relationName, row ? new ModelInstance(relDef, row) : null);
|
|
25791
|
-
}
|
|
25818
|
+
const cacheKey = `${this._definition.name}:${relationName}`;
|
|
25819
|
+
let rel = relationCache.get(cacheKey);
|
|
25820
|
+
if (rel === undefined) {
|
|
25821
|
+
rel = resolveRelation(this._definition, relationName);
|
|
25822
|
+
if (relationCache.size >= RELATION_CACHE_MAX)
|
|
25823
|
+
relationCache.clear();
|
|
25824
|
+
relationCache.set(cacheKey, rel);
|
|
25825
|
+
}
|
|
25826
|
+
if (!rel)
|
|
25827
|
+
return;
|
|
25828
|
+
if (rel.type === "hasMany" || rel.type === "hasOne") {
|
|
25829
|
+
const parentIds = distinctParentIds(instances, pk);
|
|
25830
|
+
if (parentIds.length === 0)
|
|
25831
|
+
return;
|
|
25832
|
+
const placeholders = parentIds.map(() => "?").join(", ");
|
|
25833
|
+
const rows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.foreignKey} IN (${placeholders})`, parentIds);
|
|
25834
|
+
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
25835
|
+
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
25836
|
+
if (rel.type === "hasMany") {
|
|
25837
|
+
const grouped = new Map;
|
|
25838
|
+
for (const row of rows) {
|
|
25839
|
+
const fkVal = row[rel.foreignKey];
|
|
25840
|
+
if (!grouped.has(fkVal))
|
|
25841
|
+
grouped.set(fkVal, []);
|
|
25842
|
+
grouped.get(fkVal).push(row);
|
|
25792
25843
|
}
|
|
25793
|
-
|
|
25794
|
-
|
|
25795
|
-
|
|
25796
|
-
for (const i2 of instances) {
|
|
25797
|
-
const v2 = i2._attributes[rel.foreignKey];
|
|
25798
|
-
if (v2 != null)
|
|
25799
|
-
fkSet.add(v2);
|
|
25844
|
+
for (const instance of instances) {
|
|
25845
|
+
const related = grouped.get(instance.get(pk)) || [];
|
|
25846
|
+
instance.setRelation(relationName, related.map((r2) => new ModelInstance(relDef, r2)));
|
|
25800
25847
|
}
|
|
25801
|
-
|
|
25802
|
-
|
|
25803
|
-
continue;
|
|
25804
|
-
const placeholders = uniqueFkValues.map(() => "?").join(", ");
|
|
25805
|
-
const rows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.localKey} IN (${placeholders})`, uniqueFkValues);
|
|
25806
|
-
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
25807
|
-
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
25808
|
-
const byPk = new Map;
|
|
25848
|
+
} else {
|
|
25849
|
+
const byFk = new Map;
|
|
25809
25850
|
for (const row of rows) {
|
|
25810
|
-
|
|
25851
|
+
const k2 = row[rel.foreignKey];
|
|
25852
|
+
if (!byFk.has(k2))
|
|
25853
|
+
byFk.set(k2, row);
|
|
25811
25854
|
}
|
|
25812
25855
|
for (const instance of instances) {
|
|
25813
|
-
const
|
|
25814
|
-
const row = byPk.get(fkVal);
|
|
25856
|
+
const row = byFk.get(instance.get(pk));
|
|
25815
25857
|
instance.setRelation(relationName, row ? new ModelInstance(relDef, row) : null);
|
|
25816
25858
|
}
|
|
25817
25859
|
}
|
|
25818
|
-
|
|
25819
|
-
|
|
25820
|
-
|
|
25821
|
-
|
|
25822
|
-
|
|
25823
|
-
|
|
25824
|
-
|
|
25825
|
-
const pivotRows = await exec.all(`SELECT * FROM ${rel.pivotTable} WHERE ${rel.pivotFkParent} IN (${pivotPlaceholders})`, parentIds);
|
|
25826
|
-
if (pivotRows.length === 0) {
|
|
25827
|
-
for (const instance of instances)
|
|
25828
|
-
instance.setRelation(relationName, []);
|
|
25829
|
-
continue;
|
|
25830
|
-
}
|
|
25831
|
-
const relatedIdSet = new Set;
|
|
25832
|
-
for (const p2 of pivotRows) {
|
|
25833
|
-
const v2 = p2[rel.pivotFkRelated];
|
|
25834
|
-
if (v2 != null)
|
|
25835
|
-
relatedIdSet.add(v2);
|
|
25836
|
-
}
|
|
25837
|
-
const relatedIds = [...relatedIdSet];
|
|
25838
|
-
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
25839
|
-
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
25840
|
-
const relatedPk = relDef?.primaryKey || "id";
|
|
25841
|
-
let relatedRows = [];
|
|
25842
|
-
if (relatedIds.length > 0) {
|
|
25843
|
-
const relPlaceholders = relatedIds.map(() => "?").join(", ");
|
|
25844
|
-
relatedRows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${relatedPk} IN (${relPlaceholders})`, relatedIds);
|
|
25845
|
-
}
|
|
25846
|
-
const relatedByPk = new Map;
|
|
25847
|
-
for (const r2 of relatedRows)
|
|
25848
|
-
relatedByPk.set(r2[relatedPk], r2);
|
|
25849
|
-
const pivotByParent = new Map;
|
|
25850
|
-
for (const p2 of pivotRows) {
|
|
25851
|
-
const key = p2[rel.pivotFkParent];
|
|
25852
|
-
if (!pivotByParent.has(key))
|
|
25853
|
-
pivotByParent.set(key, []);
|
|
25854
|
-
pivotByParent.get(key).push(p2);
|
|
25855
|
-
}
|
|
25856
|
-
const pivotKnownKeys = new Set([rel.pivotFkParent, rel.pivotFkRelated]);
|
|
25857
|
-
for (const instance of instances) {
|
|
25858
|
-
const parentVal = instance.get(pk);
|
|
25859
|
-
const myPivots = pivotByParent.get(parentVal) || [];
|
|
25860
|
-
const relatedInstances = myPivots.map((p2) => {
|
|
25861
|
-
const relRow = relatedByPk.get(p2[rel.pivotFkRelated]);
|
|
25862
|
-
if (!relRow)
|
|
25863
|
-
return null;
|
|
25864
|
-
const inst = new ModelInstance(relDef, relRow);
|
|
25865
|
-
const extras = {};
|
|
25866
|
-
for (const [k2, v2] of Object.entries(p2)) {
|
|
25867
|
-
if (!pivotKnownKeys.has(k2))
|
|
25868
|
-
extras[k2] = v2;
|
|
25869
|
-
}
|
|
25870
|
-
inst.pivot = extras;
|
|
25871
|
-
return inst;
|
|
25872
|
-
}).filter((x2) => x2 !== null);
|
|
25873
|
-
instance.setRelation(relationName, relatedInstances);
|
|
25874
|
-
}
|
|
25860
|
+
}
|
|
25861
|
+
if (rel.type === "belongsTo") {
|
|
25862
|
+
const fkSet = new Set;
|
|
25863
|
+
for (const i2 of instances) {
|
|
25864
|
+
const v2 = i2._attributes[rel.foreignKey];
|
|
25865
|
+
if (v2 != null)
|
|
25866
|
+
fkSet.add(v2);
|
|
25875
25867
|
}
|
|
25876
|
-
|
|
25877
|
-
|
|
25878
|
-
|
|
25879
|
-
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
25885
|
-
|
|
25868
|
+
const uniqueFkValues = [...fkSet];
|
|
25869
|
+
if (uniqueFkValues.length === 0)
|
|
25870
|
+
return;
|
|
25871
|
+
const placeholders = uniqueFkValues.map(() => "?").join(", ");
|
|
25872
|
+
const rows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.localKey} IN (${placeholders})`, uniqueFkValues);
|
|
25873
|
+
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
25874
|
+
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
25875
|
+
const byPk = new Map;
|
|
25876
|
+
for (const row of rows) {
|
|
25877
|
+
byPk.set(row[rel.localKey], row);
|
|
25878
|
+
}
|
|
25879
|
+
for (const instance of instances) {
|
|
25880
|
+
const fkVal = instance._attributes[rel.foreignKey];
|
|
25881
|
+
const row = byPk.get(fkVal);
|
|
25882
|
+
instance.setRelation(relationName, row ? new ModelInstance(relDef, row) : null);
|
|
25883
|
+
}
|
|
25884
|
+
}
|
|
25885
|
+
if (rel.type === "belongsToMany") {
|
|
25886
|
+
const parentIds = distinctParentIds(instances, pk);
|
|
25887
|
+
if (parentIds.length === 0)
|
|
25888
|
+
return;
|
|
25889
|
+
if (!rel.pivotTable || !rel.pivotFkParent || !rel.pivotFkRelated)
|
|
25890
|
+
return;
|
|
25891
|
+
const pivotPlaceholders = parentIds.map(() => "?").join(", ");
|
|
25892
|
+
const pivotRows = await exec.all(`SELECT * FROM ${rel.pivotTable} WHERE ${rel.pivotFkParent} IN (${pivotPlaceholders})`, parentIds);
|
|
25893
|
+
if (pivotRows.length === 0) {
|
|
25894
|
+
for (const instance of instances)
|
|
25895
|
+
instance.setRelation(relationName, []);
|
|
25896
|
+
return;
|
|
25897
|
+
}
|
|
25898
|
+
const relatedIdSet = new Set;
|
|
25899
|
+
for (const p2 of pivotRows) {
|
|
25900
|
+
const v2 = p2[rel.pivotFkRelated];
|
|
25901
|
+
if (v2 != null)
|
|
25902
|
+
relatedIdSet.add(v2);
|
|
25903
|
+
}
|
|
25904
|
+
const relatedIds = [...relatedIdSet];
|
|
25905
|
+
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
25906
|
+
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
25907
|
+
const relatedPk = relDef?.primaryKey || "id";
|
|
25908
|
+
let relatedRows = [];
|
|
25909
|
+
if (relatedIds.length > 0) {
|
|
25910
|
+
const relPlaceholders = relatedIds.map(() => "?").join(", ");
|
|
25911
|
+
relatedRows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${relatedPk} IN (${relPlaceholders})`, relatedIds);
|
|
25912
|
+
}
|
|
25913
|
+
const relatedByPk = new Map;
|
|
25914
|
+
for (const r2 of relatedRows)
|
|
25915
|
+
relatedByPk.set(r2[relatedPk], r2);
|
|
25916
|
+
const pivotByParent = new Map;
|
|
25917
|
+
for (const p2 of pivotRows) {
|
|
25918
|
+
const key = p2[rel.pivotFkParent];
|
|
25919
|
+
if (!pivotByParent.has(key))
|
|
25920
|
+
pivotByParent.set(key, []);
|
|
25921
|
+
pivotByParent.get(key).push(p2);
|
|
25922
|
+
}
|
|
25923
|
+
const pivotKnownKeys = new Set([rel.pivotFkParent, rel.pivotFkRelated]);
|
|
25924
|
+
for (const instance of instances) {
|
|
25925
|
+
const parentVal = instance.get(pk);
|
|
25926
|
+
const myPivots = pivotByParent.get(parentVal) || [];
|
|
25927
|
+
const relatedInstances = myPivots.map((p2) => {
|
|
25928
|
+
const relRow = relatedByPk.get(p2[rel.pivotFkRelated]);
|
|
25929
|
+
if (!relRow)
|
|
25930
|
+
return null;
|
|
25931
|
+
const inst = new ModelInstance(relDef, relRow);
|
|
25932
|
+
const extras = {};
|
|
25933
|
+
for (const [k2, v2] of Object.entries(p2)) {
|
|
25934
|
+
if (!pivotKnownKeys.has(k2))
|
|
25935
|
+
extras[k2] = v2;
|
|
25936
|
+
}
|
|
25937
|
+
inst.pivot = extras;
|
|
25938
|
+
return inst;
|
|
25939
|
+
}).filter((x2) => x2 !== null);
|
|
25940
|
+
instance.setRelation(relationName, relatedInstances);
|
|
25941
|
+
}
|
|
25942
|
+
}
|
|
25943
|
+
if (rel.type === "hasManyThrough" || rel.type === "hasOneThrough") {
|
|
25944
|
+
const parentIds = distinctParentIds(instances, pk);
|
|
25945
|
+
if (parentIds.length === 0)
|
|
25946
|
+
return;
|
|
25947
|
+
const throughPk = rel.throughLocalKey || "id";
|
|
25948
|
+
const throughPh = parentIds.map(() => "?").join(", ");
|
|
25949
|
+
const throughRows = await exec.all(`SELECT ${throughPk}, ${rel.throughForeignKey} FROM ${rel.throughTable} WHERE ${rel.throughForeignKey} IN (${throughPh})`, parentIds);
|
|
25950
|
+
if (throughRows.length === 0) {
|
|
25951
|
+
for (const instance of instances)
|
|
25952
|
+
instance.setRelation(relationName, rel.type === "hasManyThrough" ? [] : null);
|
|
25953
|
+
return;
|
|
25954
|
+
}
|
|
25955
|
+
const throughToParent = new Map;
|
|
25956
|
+
for (const t2 of throughRows)
|
|
25957
|
+
throughToParent.set(t2[throughPk], t2[rel.throughForeignKey]);
|
|
25958
|
+
const throughIds = [...new Set(throughRows.map((t2) => t2[throughPk]))];
|
|
25959
|
+
const targetPh = throughIds.map(() => "?").join(", ");
|
|
25960
|
+
const targetRows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.targetForeignKey} IN (${targetPh})`, throughIds);
|
|
25961
|
+
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
25962
|
+
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
25963
|
+
const byParent = new Map;
|
|
25964
|
+
for (const row of targetRows) {
|
|
25965
|
+
const parentVal = throughToParent.get(row[rel.targetForeignKey]);
|
|
25966
|
+
if (parentVal == null)
|
|
25886
25967
|
continue;
|
|
25887
|
-
|
|
25888
|
-
|
|
25889
|
-
|
|
25890
|
-
|
|
25891
|
-
|
|
25892
|
-
const
|
|
25893
|
-
|
|
25894
|
-
const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
|
|
25895
|
-
const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
|
|
25896
|
-
const byParent = new Map;
|
|
25897
|
-
for (const row of targetRows) {
|
|
25898
|
-
const parentVal = throughToParent.get(row[rel.targetForeignKey]);
|
|
25899
|
-
if (parentVal == null)
|
|
25900
|
-
continue;
|
|
25901
|
-
if (!byParent.has(parentVal))
|
|
25902
|
-
byParent.set(parentVal, []);
|
|
25903
|
-
byParent.get(parentVal).push(new ModelInstance(relDef, row));
|
|
25904
|
-
}
|
|
25905
|
-
for (const instance of instances) {
|
|
25906
|
-
const group = byParent.get(instance.get(pk)) || [];
|
|
25907
|
-
instance.setRelation(relationName, rel.type === "hasManyThrough" ? group : group[0] ?? null);
|
|
25908
|
-
}
|
|
25968
|
+
if (!byParent.has(parentVal))
|
|
25969
|
+
byParent.set(parentVal, []);
|
|
25970
|
+
byParent.get(parentVal).push(new ModelInstance(relDef, row));
|
|
25971
|
+
}
|
|
25972
|
+
for (const instance of instances) {
|
|
25973
|
+
const group = byParent.get(instance.get(pk)) || [];
|
|
25974
|
+
instance.setRelation(relationName, rel.type === "hasManyThrough" ? group : group[0] ?? null);
|
|
25909
25975
|
}
|
|
25910
25976
|
}
|
|
25911
25977
|
}
|
|
@@ -25965,7 +26031,8 @@ class ModelQueryBuilder {
|
|
|
25965
26031
|
assertValidIdentifier(column, "increment(column)");
|
|
25966
26032
|
const exec = getExecutor();
|
|
25967
26033
|
const params = [amount];
|
|
25968
|
-
|
|
26034
|
+
const incCol = sqlColumn(column);
|
|
26035
|
+
let sql2 = `UPDATE ${this._definition.table} SET ${incCol} = ${incCol} + ?`;
|
|
25969
26036
|
if (timestampsEnabled(this._definition)) {
|
|
25970
26037
|
sql2 += `, updated_at = ?`;
|
|
25971
26038
|
params.push(formatNow());
|
|
@@ -26023,26 +26090,27 @@ class ModelQueryBuilder {
|
|
|
26023
26090
|
assertValidIdentifier(column, "pluck(column)");
|
|
26024
26091
|
const exec = getExecutor();
|
|
26025
26092
|
const params = [];
|
|
26026
|
-
|
|
26093
|
+
const pluckCol = sqlColumn(column);
|
|
26094
|
+
let sql2 = `SELECT ${pluckCol} FROM ${this._definition.table}`;
|
|
26027
26095
|
const whereBody = this.composeWhere(params);
|
|
26028
26096
|
if (whereBody) {
|
|
26029
26097
|
sql2 += ` WHERE ${whereBody}`;
|
|
26030
26098
|
}
|
|
26031
26099
|
if (this._orderBy.length > 0) {
|
|
26032
|
-
sql2 += ` ORDER BY ${this._orderBy.map((o2) => `${o2.column} ${o2.direction.toUpperCase()}`).join(", ")}`;
|
|
26100
|
+
sql2 += ` ORDER BY ${this._orderBy.map((o2) => `${sqlColumn(o2.column)} ${o2.direction.toUpperCase()}`).join(", ")}`;
|
|
26033
26101
|
}
|
|
26034
26102
|
if (this._limit !== undefined)
|
|
26035
26103
|
sql2 += ` LIMIT ${this._limit}`;
|
|
26036
26104
|
if (this._offset !== undefined)
|
|
26037
26105
|
sql2 += ` OFFSET ${this._offset}`;
|
|
26038
26106
|
const rows = await exec.all(sql2, params);
|
|
26039
|
-
return rows.map((r2) => r2[
|
|
26107
|
+
return rows.map((r2) => r2[pluckCol]);
|
|
26040
26108
|
}
|
|
26041
26109
|
async aggregate(fn, column) {
|
|
26042
26110
|
assertValidIdentifier(column, `${fn}(column)`);
|
|
26043
26111
|
const exec = getExecutor();
|
|
26044
26112
|
const params = [];
|
|
26045
|
-
let sql2 = `SELECT ${fn}(${column}) as v FROM ${this._definition.table}`;
|
|
26113
|
+
let sql2 = `SELECT ${fn}(${sqlColumn(column)}) as v FROM ${this._definition.table}`;
|
|
26046
26114
|
const whereBody = this.composeWhere(params);
|
|
26047
26115
|
if (whereBody) {
|
|
26048
26116
|
sql2 += ` WHERE ${whereBody}`;
|
|
@@ -26081,7 +26149,7 @@ class ModelQueryBuilder {
|
|
|
26081
26149
|
async update(data) {
|
|
26082
26150
|
const exec = getExecutor();
|
|
26083
26151
|
const entries = Object.entries(data);
|
|
26084
|
-
const sets = entries.map(([k2]) => `${k2} = ?`).join(", ");
|
|
26152
|
+
const sets = entries.map(([k2]) => `${sqlColumn(k2)} = ?`).join(", ");
|
|
26085
26153
|
const params = entries.map(([, v2]) => v2);
|
|
26086
26154
|
if (timestampsEnabled(this._definition)) {
|
|
26087
26155
|
params.push(formatNow());
|
|
@@ -27930,6 +27998,9 @@ function info2(message) {
|
|
|
27930
27998
|
function snakeCase(str) {
|
|
27931
27999
|
return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").replace(/(\d)([A-Z])/gi, "$1_$2").toLowerCase();
|
|
27932
28000
|
}
|
|
28001
|
+
function singularizeTable(table) {
|
|
28002
|
+
return singularizerFor(config5.relations?.singularizeStrategy)(table);
|
|
28003
|
+
}
|
|
27933
28004
|
function findWorkspaceRoot6(startPath) {
|
|
27934
28005
|
let currentPath = startPath;
|
|
27935
28006
|
while (currentPath !== dirname12(currentPath)) {
|
|
@@ -28318,7 +28389,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28318
28389
|
const model = models[modelName];
|
|
28319
28390
|
const traits = model?.traits ?? {};
|
|
28320
28391
|
const modelTable = model.table || `${String(model.name).toLowerCase()}s`;
|
|
28321
|
-
const singular = modelTable
|
|
28392
|
+
const singular = singularizeTable(modelTable);
|
|
28322
28393
|
if (traits.likeable) {
|
|
28323
28394
|
const opts = typeof traits.likeable === "object" ? traits.likeable : {};
|
|
28324
28395
|
const likeTable = opts.table || `${modelTable}_likes`;
|
|
@@ -28385,7 +28456,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28385
28456
|
if (!btm || typeof btm !== "object" || Array.isArray(btm))
|
|
28386
28457
|
continue;
|
|
28387
28458
|
const parentTable = model.table || `${String(model.name).toLowerCase()}s`;
|
|
28388
|
-
const parentSingular = parentTable
|
|
28459
|
+
const parentSingular = singularizeTable(parentTable);
|
|
28389
28460
|
for (const [relKey, value] of Object.entries(btm)) {
|
|
28390
28461
|
const cfg = value;
|
|
28391
28462
|
if (!cfg || typeof cfg !== "object")
|
|
@@ -28398,7 +28469,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28398
28469
|
const relatedModelName = cfg.model;
|
|
28399
28470
|
const relatedRaw = models[relatedModelName];
|
|
28400
28471
|
const relatedTable = relatedRaw?.table || `${String(relatedModelName).toLowerCase()}s`;
|
|
28401
|
-
const relatedSingular = relatedTable
|
|
28472
|
+
const relatedSingular = singularizeTable(relatedTable);
|
|
28402
28473
|
const pivotTable = cfg.table || [parentSingular, relatedSingular].sort().join("_");
|
|
28403
28474
|
const fkParent = cfg.foreignKey || `${parentSingular}_id`;
|
|
28404
28475
|
const fkRelated = cfg.relatedKey || `${relatedSingular}_id`;
|
|
@@ -29032,6 +29103,7 @@ var init_src2 = __esm(() => {
|
|
|
29032
29103
|
init_loader();
|
|
29033
29104
|
init_meta();
|
|
29034
29105
|
init_migrations();
|
|
29106
|
+
init_pivot();
|
|
29035
29107
|
init_orm();
|
|
29036
29108
|
init_sqlite_pragmas();
|
|
29037
29109
|
});
|
|
@@ -31075,7 +31147,7 @@ function getPrefix() {
|
|
|
31075
31147
|
}
|
|
31076
31148
|
var prefix = getPrefix();
|
|
31077
31149
|
// package.json
|
|
31078
|
-
var version2 = "0.1.
|
|
31150
|
+
var version2 = "0.1.60";
|
|
31079
31151
|
|
|
31080
31152
|
// bin/cli.ts
|
|
31081
31153
|
init_actions();
|