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