bun-query-builder 0.1.36 → 0.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/cli.js CHANGED
@@ -24621,8 +24621,45 @@ function resolveRelation(definition, relationName) {
24621
24621
  pivotTimestamps: Boolean(config6?.pivot?.timestamps)
24622
24622
  };
24623
24623
  }
24624
+ const resolveThrough = (field, type) => {
24625
+ if (!field || typeof field !== "object" || Array.isArray(field))
24626
+ return null;
24627
+ const entry = field[relationName] ?? field[Object.keys(field).find((k2) => k2.toLowerCase() === relationName.toLowerCase()) ?? ""];
24628
+ if (!entry || typeof entry !== "object")
24629
+ return null;
24630
+ const throughModelName = entry.through;
24631
+ const targetModelName = entry.target;
24632
+ if (!throughModelName || !targetModelName)
24633
+ return null;
24634
+ const throughModel = getModelFromRegistry(throughModelName);
24635
+ const throughDef = throughModel?.getDefinition?.() || throughModel?.definition;
24636
+ const throughTable = throughModel?.getTable?.() || throughDef?.table || toTableName(throughModelName);
24637
+ const throughPk = throughDef?.primaryKey || "id";
24638
+ const targetModel = getModelFromRegistry(targetModelName);
24639
+ const targetTable = targetModel?.getTable?.() || toTableName(targetModelName);
24640
+ return {
24641
+ type,
24642
+ relatedModelName: targetModelName,
24643
+ relatedTable: targetTable,
24644
+ foreignKey: `${toSnakeCase(parentName)}_id`,
24645
+ localKey: parentPk,
24646
+ throughTable,
24647
+ throughForeignKey: `${toSnakeCase(parentName)}_id`,
24648
+ throughLocalKey: throughPk,
24649
+ targetForeignKey: `${singularizeWord(throughTable)}_id`
24650
+ };
24651
+ };
24652
+ const hmt = resolveThrough(definition.hasManyThrough, "hasManyThrough");
24653
+ if (hmt)
24654
+ return hmt;
24655
+ const hot = resolveThrough(definition.hasOneThrough, "hasOneThrough");
24656
+ if (hot)
24657
+ return hot;
24624
24658
  return null;
24625
24659
  }
24660
+ function singularizeWord(table) {
24661
+ return table.endsWith("s") ? table.slice(0, -1) : table;
24662
+ }
24626
24663
 
24627
24664
  class BelongsToManyRelationBuilder {
24628
24665
  _parent;
@@ -25259,6 +25296,40 @@ class ModelQueryBuilder {
25259
25296
  instance.setRelation(relationName, relatedInstances);
25260
25297
  }
25261
25298
  }
25299
+ if (rel.type === "hasManyThrough" || rel.type === "hasOneThrough") {
25300
+ const parentIds = instances.map((i2) => i2.get(pk)).filter((id) => id != null);
25301
+ if (parentIds.length === 0)
25302
+ continue;
25303
+ const throughPk = rel.throughLocalKey || "id";
25304
+ const throughPh = parentIds.map(() => "?").join(", ");
25305
+ const throughRows = await exec.all(`SELECT ${throughPk}, ${rel.throughForeignKey} FROM ${rel.throughTable} WHERE ${rel.throughForeignKey} IN (${throughPh})`, parentIds);
25306
+ if (throughRows.length === 0) {
25307
+ for (const instance of instances)
25308
+ instance.setRelation(relationName, rel.type === "hasManyThrough" ? [] : null);
25309
+ continue;
25310
+ }
25311
+ const throughToParent = new Map;
25312
+ for (const t2 of throughRows)
25313
+ throughToParent.set(t2[throughPk], t2[rel.throughForeignKey]);
25314
+ const throughIds = [...new Set(throughRows.map((t2) => t2[throughPk]))];
25315
+ const targetPh = throughIds.map(() => "?").join(", ");
25316
+ const targetRows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.targetForeignKey} IN (${targetPh})`, throughIds);
25317
+ const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
25318
+ const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
25319
+ const byParent = new Map;
25320
+ for (const row of targetRows) {
25321
+ const parentVal = throughToParent.get(row[rel.targetForeignKey]);
25322
+ if (parentVal == null)
25323
+ continue;
25324
+ if (!byParent.has(parentVal))
25325
+ byParent.set(parentVal, []);
25326
+ byParent.get(parentVal).push(new ModelInstance(relDef, row));
25327
+ }
25328
+ for (const instance of instances) {
25329
+ const group = byParent.get(instance.get(pk)) || [];
25330
+ instance.setRelation(relationName, rel.type === "hasManyThrough" ? group : group[0] ?? null);
25331
+ }
25332
+ }
25262
25333
  }
25263
25334
  }
25264
25335
  async get() {
@@ -30135,7 +30206,7 @@ function getPrefix() {
30135
30206
  }
30136
30207
  var prefix = getPrefix();
30137
30208
  // package.json
30138
- var version2 = "0.1.36";
30209
+ var version2 = "0.1.37";
30139
30210
 
30140
30211
  // bin/cli.ts
30141
30212
  init_actions();
package/dist/orm.d.ts CHANGED
@@ -163,11 +163,15 @@ declare interface OrmExecutor {
163
163
  * populated only for `belongsToMany` relations.
164
164
  */
165
165
  declare interface ResolvedRelation {
166
- type: 'hasMany' | 'hasOne' | 'belongsTo' | 'belongsToMany'
166
+ type: 'hasMany' | 'hasOne' | 'belongsTo' | 'belongsToMany' | 'hasManyThrough' | 'hasOneThrough'
167
167
  relatedModelName: string
168
168
  relatedTable: string
169
169
  foreignKey: string
170
170
  localKey: string
171
+ throughTable?: string
172
+ throughForeignKey?: string
173
+ throughLocalKey?: string
174
+ targetForeignKey?: string
171
175
  pivotTable?: string
172
176
  pivotFkParent?: string
173
177
  pivotFkRelated?: string
package/dist/src/index.js CHANGED
@@ -24621,8 +24621,45 @@ function resolveRelation(definition, relationName) {
24621
24621
  pivotTimestamps: Boolean(config6?.pivot?.timestamps)
24622
24622
  };
24623
24623
  }
24624
+ const resolveThrough = (field, type) => {
24625
+ if (!field || typeof field !== "object" || Array.isArray(field))
24626
+ return null;
24627
+ const entry = field[relationName] ?? field[Object.keys(field).find((k2) => k2.toLowerCase() === relationName.toLowerCase()) ?? ""];
24628
+ if (!entry || typeof entry !== "object")
24629
+ return null;
24630
+ const throughModelName = entry.through;
24631
+ const targetModelName = entry.target;
24632
+ if (!throughModelName || !targetModelName)
24633
+ return null;
24634
+ const throughModel = getModelFromRegistry(throughModelName);
24635
+ const throughDef = throughModel?.getDefinition?.() || throughModel?.definition;
24636
+ const throughTable = throughModel?.getTable?.() || throughDef?.table || toTableName(throughModelName);
24637
+ const throughPk = throughDef?.primaryKey || "id";
24638
+ const targetModel = getModelFromRegistry(targetModelName);
24639
+ const targetTable = targetModel?.getTable?.() || toTableName(targetModelName);
24640
+ return {
24641
+ type,
24642
+ relatedModelName: targetModelName,
24643
+ relatedTable: targetTable,
24644
+ foreignKey: `${toSnakeCase(parentName)}_id`,
24645
+ localKey: parentPk,
24646
+ throughTable,
24647
+ throughForeignKey: `${toSnakeCase(parentName)}_id`,
24648
+ throughLocalKey: throughPk,
24649
+ targetForeignKey: `${singularizeWord(throughTable)}_id`
24650
+ };
24651
+ };
24652
+ const hmt = resolveThrough(definition.hasManyThrough, "hasManyThrough");
24653
+ if (hmt)
24654
+ return hmt;
24655
+ const hot = resolveThrough(definition.hasOneThrough, "hasOneThrough");
24656
+ if (hot)
24657
+ return hot;
24624
24658
  return null;
24625
24659
  }
24660
+ function singularizeWord(table) {
24661
+ return table.endsWith("s") ? table.slice(0, -1) : table;
24662
+ }
24626
24663
 
24627
24664
  class BelongsToManyRelationBuilder {
24628
24665
  _parent;
@@ -25259,6 +25296,40 @@ class ModelQueryBuilder {
25259
25296
  instance.setRelation(relationName, relatedInstances);
25260
25297
  }
25261
25298
  }
25299
+ if (rel.type === "hasManyThrough" || rel.type === "hasOneThrough") {
25300
+ const parentIds = instances.map((i2) => i2.get(pk)).filter((id) => id != null);
25301
+ if (parentIds.length === 0)
25302
+ continue;
25303
+ const throughPk = rel.throughLocalKey || "id";
25304
+ const throughPh = parentIds.map(() => "?").join(", ");
25305
+ const throughRows = await exec.all(`SELECT ${throughPk}, ${rel.throughForeignKey} FROM ${rel.throughTable} WHERE ${rel.throughForeignKey} IN (${throughPh})`, parentIds);
25306
+ if (throughRows.length === 0) {
25307
+ for (const instance of instances)
25308
+ instance.setRelation(relationName, rel.type === "hasManyThrough" ? [] : null);
25309
+ continue;
25310
+ }
25311
+ const throughToParent = new Map;
25312
+ for (const t2 of throughRows)
25313
+ throughToParent.set(t2[throughPk], t2[rel.throughForeignKey]);
25314
+ const throughIds = [...new Set(throughRows.map((t2) => t2[throughPk]))];
25315
+ const targetPh = throughIds.map(() => "?").join(", ");
25316
+ const targetRows = await exec.all(`SELECT * FROM ${rel.relatedTable} WHERE ${rel.targetForeignKey} IN (${targetPh})`, throughIds);
25317
+ const relatedModelDef = getModelFromRegistry(rel.relatedModelName);
25318
+ const relDef = relatedModelDef?.getDefinition?.() || relatedModelDef?.definition || this._definition;
25319
+ const byParent = new Map;
25320
+ for (const row of targetRows) {
25321
+ const parentVal = throughToParent.get(row[rel.targetForeignKey]);
25322
+ if (parentVal == null)
25323
+ continue;
25324
+ if (!byParent.has(parentVal))
25325
+ byParent.set(parentVal, []);
25326
+ byParent.get(parentVal).push(new ModelInstance(relDef, row));
25327
+ }
25328
+ for (const instance of instances) {
25329
+ const group = byParent.get(instance.get(pk)) || [];
25330
+ instance.setRelation(relationName, rel.type === "hasManyThrough" ? group : group[0] ?? null);
25331
+ }
25332
+ }
25262
25333
  }
25263
25334
  }
25264
25335
  async get() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bun-query-builder",
3
3
  "type": "module",
4
- "version": "0.1.36",
4
+ "version": "0.1.37",
5
5
  "description": "A simple yet performant query builder for TypeScript. Built with Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",