@vantreeseba/drizzle-graphql 15.1.3 → 15.1.4
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/README.md +6 -1
- package/dist/index.cjs +98 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +98 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1361,6 +1361,9 @@ can count or summarise related rows without fetching them:
|
|
|
1361
1361
|
and applies only to the related rows
|
|
1362
1362
|
- A parent with no related rows gets `count: 0` and `null` for every other aggregate
|
|
1363
1363
|
- To-one relations get no aggregate field — there is nothing to aggregate over
|
|
1364
|
+
- A relation joined on several columns (`from: [a, b], to: [x, y]`) is grouped by all of
|
|
1365
|
+
them, so each parent counts only the rows that match it on every column. A many-to-many
|
|
1366
|
+
(`.through()`) relation whose junction has a composite key gets no aggregate field
|
|
1364
1367
|
- The field is skipped if its name would collide with a column or another relation
|
|
1365
1368
|
- Set `features: { relationAggregates: false }` (globally or per table) to leave these
|
|
1366
1369
|
fields out
|
|
@@ -2447,7 +2450,9 @@ Generated schemas resolve nested relations without N+1 query explosions:
|
|
|
2447
2450
|
(request-scoped, keyed on the GraphQL `context`), preventing N+1. Per-parent
|
|
2448
2451
|
`limit` / `offset` on a to-many relation is applied across the whole batch using a
|
|
2449
2452
|
`ROW_NUMBER() OVER (PARTITION BY …)` window function — still one query, not one per
|
|
2450
|
-
parent.
|
|
2453
|
+
parent. A relation joined on several columns (`from: [a, b], to: [x, y]`) is batched,
|
|
2454
|
+
grouped and partitioned by all of them, matching the parents with
|
|
2455
|
+
`(a = … AND b = …) OR …` instead of `IN (…)`.
|
|
2451
2456
|
|
|
2452
2457
|
```Typescript
|
|
2453
2458
|
// entities.fieldResolvers is keyed by table name, then relation name
|
package/dist/index.cjs
CHANGED
|
@@ -1802,6 +1802,11 @@ const warnUnresolvedJoin = (relEntry, tableName, relationName, omitted) => {
|
|
|
1802
1802
|
* Returns the JS property name of the local column on the parent table and the
|
|
1803
1803
|
* Column object for the foreign column on the target table, or undefined if the
|
|
1804
1804
|
* relation internals are not accessible.
|
|
1805
|
+
*
|
|
1806
|
+
* Only the relation's *first* column pair is reported. A relation joined on several columns
|
|
1807
|
+
* (`from: [a, b], to: [x, y]`) is not described fully by it, so anything that reads rows by
|
|
1808
|
+
* this pair alone mixes up parents that share the first column. Read paths use
|
|
1809
|
+
* {@link extractRelationJoinColumnPairs}, which returns every pair.
|
|
1805
1810
|
*/
|
|
1806
1811
|
const extractRelationJoinColumns = (relEntry, parentTable, targetTable) => {
|
|
1807
1812
|
const rel = relEntry.relation ?? relEntry;
|
|
@@ -1820,6 +1825,48 @@ const extractRelationJoinColumns = (relEntry, parentTable, targetTable) => {
|
|
|
1820
1825
|
};
|
|
1821
1826
|
};
|
|
1822
1827
|
/**
|
|
1828
|
+
* Every column pair the relation joins on, in declaration order — one for an ordinary relation,
|
|
1829
|
+
* several for one declared `from: [a, b], to: [x, y]`. A row of the target belongs to a parent
|
|
1830
|
+
* only when *all* pairs match, so a read path has to correlate on every one of them.
|
|
1831
|
+
*
|
|
1832
|
+
* `undefined` when the relation's columns cannot be matched to the two tables, or when its two
|
|
1833
|
+
* sides list a different number of columns.
|
|
1834
|
+
*/
|
|
1835
|
+
const extractRelationJoinColumnPairs = (relEntry, parentTable, targetTable) => {
|
|
1836
|
+
const rel = relEntry.relation ?? relEntry;
|
|
1837
|
+
const sourceCols = relationColumns(rel, "source");
|
|
1838
|
+
const targetCols = relationColumns(rel, "target");
|
|
1839
|
+
if (!sourceCols?.length || sourceCols.length !== targetCols?.length) return;
|
|
1840
|
+
const parentEntries = Object.entries((0, drizzle_orm.getColumns)(parentTable));
|
|
1841
|
+
const targetEntries = Object.entries((0, drizzle_orm.getColumns)(targetTable));
|
|
1842
|
+
const pairs = [];
|
|
1843
|
+
for (let i = 0; i < sourceCols.length; i++) {
|
|
1844
|
+
const localCol = sourceCols[i];
|
|
1845
|
+
const foreignCol = targetCols[i];
|
|
1846
|
+
const localColPropName = parentEntries.find(([, c]) => c === localCol)?.[0];
|
|
1847
|
+
const foreignColPropName = targetEntries.find(([, c]) => c === foreignCol)?.[0];
|
|
1848
|
+
if (!localColPropName || !foreignColPropName) return;
|
|
1849
|
+
pairs.push({
|
|
1850
|
+
localColPropName,
|
|
1851
|
+
localCol,
|
|
1852
|
+
foreignColPropName,
|
|
1853
|
+
foreignCol
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
return pairs;
|
|
1857
|
+
};
|
|
1858
|
+
/**
|
|
1859
|
+
* A string identifying one combination of join-column values, for grouping a batch's rows by
|
|
1860
|
+
* parent. Values are compared by their string form, as a single-column key always has been.
|
|
1861
|
+
*/
|
|
1862
|
+
const joinKeyOf = (values) => values.length === 1 ? String(values[0]) : JSON.stringify(values.map((value) => String(value)));
|
|
1863
|
+
/**
|
|
1864
|
+
* The rows whose `cols` hold one of `keys`: `col IN (…)` for a single join column, and an `OR`
|
|
1865
|
+
* of per-parent equalities for several — `(a = 1 AND b = 1) OR (a = 1 AND b = 2)` — which
|
|
1866
|
+
* every dialect accepts, unlike a row-value `IN` list.
|
|
1867
|
+
*/
|
|
1868
|
+
const parentKeyCondition = (cols, keys) => cols.length === 1 ? (0, drizzle_orm.inArray)(cols[0], keys.map((key) => key[0])) : (0, drizzle_orm.or)(...keys.map((key) => (0, drizzle_orm.and)(...cols.map((col, i) => (0, drizzle_orm.eq)(col, key[i])))));
|
|
1869
|
+
/**
|
|
1823
1870
|
* The junction table and its two columns for a `.through()` (many-to-many) relation:
|
|
1824
1871
|
* `sourceCol` holds the parent's key, `targetCol` the target's. `undefined` for a relation
|
|
1825
1872
|
* with no junction; `null` for one whose junction cannot be used here — more than one column
|
|
@@ -1850,16 +1897,18 @@ const extractJunctionColumns = (relEntry) => {
|
|
|
1850
1897
|
*
|
|
1851
1898
|
* A reversed filter (inherited from the relation on the other side) is written against the
|
|
1852
1899
|
* parent table, so it is applied as "the row's parent key belongs to a parent that passes it".
|
|
1853
|
-
* `
|
|
1854
|
-
* the parent key for each row — the target's foreign key, or the junction's source
|
|
1900
|
+
* `parentKeyCols` are the parent's join columns and `groupCols` the columns in the query that
|
|
1901
|
+
* hold the parent key for each row — the target's foreign key, or the junction's source
|
|
1902
|
+
* column — in the same order. A key of several columns is compared as a row value.
|
|
1855
1903
|
*/
|
|
1856
|
-
const relationOwnCondition = (relEntry, parentTable, targetTable,
|
|
1904
|
+
const relationOwnCondition = (relEntry, parentTable, targetTable, parentKeyCols, groupCols) => {
|
|
1857
1905
|
const rel = relEntry.relation ?? relEntry;
|
|
1858
1906
|
const ownWhere = relationOwnWhere(rel);
|
|
1859
1907
|
if (!ownWhere) return;
|
|
1860
1908
|
if (!isRelationFilterReversed(rel)) return (0, drizzle_orm.relationsFilterToSQL)(targetTable, ownWhere);
|
|
1861
1909
|
const parentFilter = (0, drizzle_orm.relationsFilterToSQL)(parentTable, ownWhere);
|
|
1862
|
-
return drizzle_orm.sql`${
|
|
1910
|
+
if (groupCols.length === 1) return drizzle_orm.sql`${groupCols[0]} in (select ${parentKeyCols[0]} from ${parentTable} where ${parentFilter})`;
|
|
1911
|
+
return drizzle_orm.sql`(${drizzle_orm.sql.join([...groupCols], drizzle_orm.sql`, `)}) in (select ${drizzle_orm.sql.join([...parentKeyCols], drizzle_orm.sql`, `)} from ${parentTable} where ${parentFilter})`;
|
|
1863
1912
|
};
|
|
1864
1913
|
/**
|
|
1865
1914
|
* Whether a to-one relation can back a relation orderBy hop. `.through()` (junction)
|
|
@@ -3845,8 +3894,7 @@ const relationJoinColumns = (tree, table, selectionCtx) => {
|
|
|
3845
3894
|
const relEntry = fieldData.name.endsWith(AGGREGATE_FIELD_SUFFIX) ? relations[fieldData.name.slice(0, -9)] : relations[fieldData.name];
|
|
3846
3895
|
const targetTable = relEntry ? selectionCtx.tables[relEntry.targetTableName] : void 0;
|
|
3847
3896
|
if (!relEntry || !targetTable) continue;
|
|
3848
|
-
const
|
|
3849
|
-
if (joinCols) needed.push(joinCols.localColPropName);
|
|
3897
|
+
for (const pair of extractRelationJoinColumnPairs(relEntry, table, targetTable) ?? []) needed.push(pair.localColPropName);
|
|
3850
3898
|
}
|
|
3851
3899
|
return needed;
|
|
3852
3900
|
};
|
|
@@ -4867,13 +4915,12 @@ const identifyRows = (field, args) => {
|
|
|
4867
4915
|
* Window functions require PostgreSQL, MySQL >= 8.0, or SQLite >= 3.25.
|
|
4868
4916
|
* Returns raw rows (NOT remapped); the caller groups + remaps them.
|
|
4869
4917
|
*/
|
|
4870
|
-
const batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, whereCondition, orderByArg, limit, offset, pkNames, columns, orderCtx, whereArgs, junction) => {
|
|
4918
|
+
const batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, partitionCols, whereCondition, orderByArg, limit, offset, pkNames, columns, orderCtx, whereArgs, junction) => {
|
|
4871
4919
|
const cols = columns ?? (0, drizzle_orm.getColumns)(targetTable);
|
|
4872
4920
|
const orderExprs = [...orderByArg ? extractOrderBy(targetTable, orderByArg, orderCtx, whereArgs) : [], ...primaryKeyOrderExprs(targetTable, pkNames)];
|
|
4873
4921
|
const orderClause = orderExprs.length ? drizzle_orm.sql` order by ${drizzle_orm.sql.join(orderExprs, drizzle_orm.sql`, `)}` : drizzle_orm.sql``;
|
|
4874
4922
|
const RN = "__drizzle_graphql_rn";
|
|
4875
|
-
const
|
|
4876
|
-
const rowNumber = drizzle_orm.sql`row_number() over (partition by ${partitionCol}${orderClause})`.as(RN);
|
|
4923
|
+
const rowNumber = drizzle_orm.sql`row_number() over (partition by ${drizzle_orm.sql.join([...partitionCols], drizzle_orm.sql`, `)}${orderClause})`.as(RN);
|
|
4877
4924
|
const sub = withJunction(db.select({
|
|
4878
4925
|
...cols,
|
|
4879
4926
|
[RN]: rowNumber
|
|
@@ -4912,13 +4959,14 @@ const createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limi
|
|
|
4912
4959
|
const targetTableName = relEntry.targetTableName;
|
|
4913
4960
|
const targetTable = tables[targetTableName];
|
|
4914
4961
|
if (!parentTable || !targetTable) return;
|
|
4915
|
-
const
|
|
4916
|
-
if (!
|
|
4917
|
-
const
|
|
4962
|
+
const joinPairs = extractRelationJoinColumnPairs(relEntry, parentTable, targetTable);
|
|
4963
|
+
if (!joinPairs) return;
|
|
4964
|
+
const localColPropNames = joinPairs.map((pair) => pair.localColPropName);
|
|
4965
|
+
const foreignCol = joinPairs[0].foreignCol;
|
|
4918
4966
|
const junction = extractJunctionColumns(relEntry);
|
|
4919
|
-
const
|
|
4920
|
-
const
|
|
4921
|
-
const ownCondition = relationOwnCondition(relEntry, parentTable, targetTable, (
|
|
4967
|
+
const groupCols = junction ? [junction.sourceCol] : joinPairs.map((pair) => pair.foreignCol);
|
|
4968
|
+
const groupKeys = junction ? [PARENT_KEY] : joinPairs.map((pair) => pair.foreignColPropName);
|
|
4969
|
+
const ownCondition = relationOwnCondition(relEntry, parentTable, targetTable, joinPairs.map((pair) => pair.localCol), groupCols);
|
|
4922
4970
|
const defaultDeleted = relationDeletedDefault(policies?.softDelete, targetTableName, isOne && relEntry.relation?.optional === false);
|
|
4923
4971
|
const limitPolicy = isOne ? void 0 : limits?.(targetTableName);
|
|
4924
4972
|
const targetPkNames = relEntry.targetPkNames ?? [];
|
|
@@ -4947,7 +4995,7 @@ const createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limi
|
|
|
4947
4995
|
allRelations: filterCtx?.relationMap
|
|
4948
4996
|
});
|
|
4949
4997
|
const targetColumns = (0, drizzle_orm.getColumns)(targetTable);
|
|
4950
|
-
columns[foreignColPropName] = foreignCol;
|
|
4998
|
+
for (const pair of joinPairs) columns[pair.foreignColPropName] = pair.foreignCol;
|
|
4951
4999
|
for (const [columnName] of cursorEntries ?? []) {
|
|
4952
5000
|
const column = targetColumns[columnName];
|
|
4953
5001
|
if (column) columns[columnName] = column;
|
|
@@ -4959,8 +5007,8 @@ const createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limi
|
|
|
4959
5007
|
};
|
|
4960
5008
|
const resolve = async (parent, args, context, info) => {
|
|
4961
5009
|
if (parent[relationName] !== void 0) return parent[relationName];
|
|
4962
|
-
const
|
|
4963
|
-
if (
|
|
5010
|
+
const localValues = localColPropNames.map((name) => parent[name]);
|
|
5011
|
+
if (localValues.some((value) => value == null)) return isOne ? null : [];
|
|
4964
5012
|
const { where: whereArg, limit: requestedLimit, offset, after, deleted } = args ?? {};
|
|
4965
5013
|
const { orderByArg, limit, distinct, cursorEntries, cursorValues, columns, loaderKey } = getOrCreateRequestValue(context, info?.fieldNodes?.[0], `relation:${tableName}::${relationName}`, () => {
|
|
4966
5014
|
const orderByArg = isOne ? args?.orderBy : withDefaultOrderBy(args ?? {}, targetTableName, policies?.defaultOrderBy).orderBy;
|
|
@@ -5001,11 +5049,11 @@ const createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limi
|
|
|
5001
5049
|
};
|
|
5002
5050
|
});
|
|
5003
5051
|
if (junction === null) throw drizzleError(`Relation '${tableName}.${relationName}' goes through a junction with a composite key, which can only be loaded together with its parent. Leave it to eager loading (eagerLoadRelations).`, { code: "DRIZZLE_UNSUPPORTED_RELATION" });
|
|
5004
|
-
return getOrCreateLoader(context, loaderKey, async (
|
|
5052
|
+
return getOrCreateLoader(context, loaderKey, async (parentKeys) => {
|
|
5005
5053
|
const executor = resolveExecutor(db, context);
|
|
5006
|
-
const
|
|
5054
|
+
const uniqueKeys = [...new Map(parentKeys.map((key) => [joinKeyOf(key), key])).values()];
|
|
5007
5055
|
const scope = resolveScope(policies, context, filterCtx);
|
|
5008
|
-
let whereCondition = withScope(scope, targetTableName, targetTable, (0, drizzle_orm.and)((
|
|
5056
|
+
let whereCondition = withScope(scope, targetTableName, targetTable, (0, drizzle_orm.and)(parentKeyCondition(groupCols, uniqueKeys), ownCondition, whereArg ? extractFilters(targetTable, targetTableName, whereArg, relationFilterCtx(filterCtx, targetTableName, scope)) : void 0, cursorValues ? buildCursorCondition(targetTable, cursorEntries, cursorValues, nullOrdering) : void 0), deleted ?? defaultDeleted);
|
|
5009
5057
|
if (distinct) {
|
|
5010
5058
|
const keys = await selectDistinctKeys({
|
|
5011
5059
|
db: executor,
|
|
@@ -5015,22 +5063,22 @@ const createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limi
|
|
|
5015
5063
|
pkNames: targetPkNames,
|
|
5016
5064
|
where: whereCondition,
|
|
5017
5065
|
orderBy: orderByArg,
|
|
5018
|
-
partitionBy:
|
|
5066
|
+
partitionBy: groupCols,
|
|
5019
5067
|
junction: junction ? {
|
|
5020
5068
|
table: junction.table,
|
|
5021
5069
|
on: (0, drizzle_orm.eq)(junction.targetCol, foreignCol),
|
|
5022
|
-
parentKey:
|
|
5070
|
+
parentKey: junction.sourceCol
|
|
5023
5071
|
} : void 0
|
|
5024
5072
|
});
|
|
5025
|
-
if (!keys.length) return
|
|
5026
|
-
whereCondition = (0, drizzle_orm.and)(whereCondition, junction ? (0, drizzle_orm.or)(...keys.map((key) => (0, drizzle_orm.and)((0, drizzle_orm.eq)(
|
|
5073
|
+
if (!keys.length) return parentKeys.map(() => isOne ? null : []);
|
|
5074
|
+
whereCondition = (0, drizzle_orm.and)(whereCondition, junction ? (0, drizzle_orm.or)(...keys.map((key) => (0, drizzle_orm.and)((0, drizzle_orm.eq)(junction.sourceCol, key[DISTINCT_PARENT]), primaryKeyRestriction(targetTable, targetPkNames, [key])))) : primaryKeyRestriction(targetTable, targetPkNames, keys));
|
|
5027
5075
|
}
|
|
5028
5076
|
const selection = junction ? {
|
|
5029
5077
|
...columns ?? (0, drizzle_orm.getColumns)(targetTable),
|
|
5030
|
-
[PARENT_KEY]:
|
|
5078
|
+
[PARENT_KEY]: junction.sourceCol
|
|
5031
5079
|
} : columns;
|
|
5032
5080
|
let rows;
|
|
5033
|
-
if (limit != null || offset != null) rows = await batchedPaginatedRelationQuery(executor, targetTable, foreignCol, whereCondition, orderByArg, limit ?? null, offset ?? null, targetPkNames, selection, relationFilterCtx(filterCtx, targetTableName, scope), whereArg, junction);
|
|
5081
|
+
if (limit != null || offset != null) rows = await batchedPaginatedRelationQuery(executor, targetTable, foreignCol, groupCols, whereCondition, orderByArg, limit ?? null, offset ?? null, targetPkNames, selection, relationFilterCtx(filterCtx, targetTableName, scope), whereArg, junction);
|
|
5034
5082
|
else {
|
|
5035
5083
|
let q = withJunction((selection ? executor.select(selection) : executor.select()).from(targetTable), junction, foreignCol).where(whereCondition);
|
|
5036
5084
|
const orderExprs = cursorEntries ? cursorOrderExprs(targetTable, cursorEntries) : orderByArg ? extractOrderBy(targetTable, orderByArg, relationFilterCtx(filterCtx, targetTableName, scope), whereArg) : [];
|
|
@@ -5039,20 +5087,20 @@ const createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limi
|
|
|
5039
5087
|
}
|
|
5040
5088
|
if (cursorEntries) attachRowCursors(rows, cursorEntries);
|
|
5041
5089
|
const keyOf = (row) => {
|
|
5042
|
-
const key =
|
|
5090
|
+
const key = joinKeyOf(groupKeys.map((name) => row[name]));
|
|
5043
5091
|
if (junction) delete row[PARENT_KEY];
|
|
5044
5092
|
return key;
|
|
5045
5093
|
};
|
|
5046
5094
|
if (isOne) {
|
|
5047
5095
|
const byKey = new Map(rows.map((row) => [keyOf(row), row]));
|
|
5048
5096
|
remapToGraphQLArrayOutput(rows, targetTableName, targetTable);
|
|
5049
|
-
return
|
|
5097
|
+
return parentKeys.map((key) => byKey.get(joinKeyOf(key)) ?? null);
|
|
5050
5098
|
}
|
|
5051
|
-
const grouped = new Map(
|
|
5099
|
+
const grouped = new Map(uniqueKeys.map((key) => [joinKeyOf(key), []]));
|
|
5052
5100
|
for (const row of rows) grouped.get(keyOf(row))?.push(row);
|
|
5053
5101
|
remapToGraphQLArrayOutput(rows, targetTableName, targetTable);
|
|
5054
|
-
return
|
|
5055
|
-
}).load(
|
|
5102
|
+
return parentKeys.map((key) => grouped.get(joinKeyOf(key)) ?? []);
|
|
5103
|
+
}).load(localValues);
|
|
5056
5104
|
};
|
|
5057
5105
|
return async (parent, args, context, info) => {
|
|
5058
5106
|
try {
|
|
@@ -6128,8 +6176,8 @@ const createRelationAggregateFactory = (db, tables, cacheCtx, typeNameMapper, fi
|
|
|
6128
6176
|
const targetTableName = relEntry.targetTableName;
|
|
6129
6177
|
const targetTable = tables[targetTableName];
|
|
6130
6178
|
if (!parentTable || !targetTable) return;
|
|
6131
|
-
const
|
|
6132
|
-
if (!
|
|
6179
|
+
const joinPairs = extractRelationJoinColumnPairs(relEntry, parentTable, targetTable);
|
|
6180
|
+
if (!joinPairs) {
|
|
6133
6181
|
const key = `${tableName}.${relationName}`;
|
|
6134
6182
|
if (!warned.has(key)) {
|
|
6135
6183
|
warned.add(key);
|
|
@@ -6137,11 +6185,13 @@ const createRelationAggregateFactory = (db, tables, cacheCtx, typeNameMapper, fi
|
|
|
6137
6185
|
}
|
|
6138
6186
|
return;
|
|
6139
6187
|
}
|
|
6140
|
-
const
|
|
6188
|
+
const localColPropNames = joinPairs.map((pair) => pair.localColPropName);
|
|
6189
|
+
const foreignCol = joinPairs[0].foreignCol;
|
|
6141
6190
|
const junction = extractJunctionColumns(relEntry);
|
|
6142
6191
|
if (junction === null) return;
|
|
6143
|
-
const
|
|
6144
|
-
const
|
|
6192
|
+
const groupCols = junction ? [junction.sourceCol] : joinPairs.map((pair) => pair.foreignCol);
|
|
6193
|
+
const groupAliases = groupCols.map((_, i) => `${GROUP_KEY}${i}`);
|
|
6194
|
+
const ownCondition = relationOwnCondition(relEntry, parentTable, targetTable, joinPairs.map((pair) => pair.localCol), groupCols);
|
|
6145
6195
|
const defaultDeleted = relationDeletedDefault(policies?.softDelete, targetTableName, false);
|
|
6146
6196
|
const targetTypeName = resolveTypeName(targetTableName, typeNameMapper);
|
|
6147
6197
|
const type = generateAggregateTypes(targetTable, targetTableName, targetTypeName, cacheCtx);
|
|
@@ -6165,24 +6215,25 @@ const createRelationAggregateFactory = (db, tables, cacheCtx, typeNameMapper, fi
|
|
|
6165
6215
|
};
|
|
6166
6216
|
});
|
|
6167
6217
|
if (!Object.keys(request.selection).length) return {};
|
|
6168
|
-
const
|
|
6169
|
-
if (
|
|
6218
|
+
const localValues = localColPropNames.map((name) => parent[name]);
|
|
6219
|
+
if (localValues.some((value) => value == null)) return assembleAggregateRow({}, request, target);
|
|
6170
6220
|
const whereArg = args?.where;
|
|
6171
6221
|
const deleted = args?.deleted;
|
|
6172
|
-
const loader = getOrCreateLoader(context, loaderKey, async (
|
|
6222
|
+
const loader = getOrCreateLoader(context, loaderKey, async (parentKeys) => {
|
|
6173
6223
|
const executor = resolveExecutor(db, context);
|
|
6174
|
-
const
|
|
6224
|
+
const uniqueKeys = [...new Map(parentKeys.map((key) => [joinKeyOf(key), key])).values()];
|
|
6175
6225
|
const scope = resolveScope(policies, context, filterCtx);
|
|
6176
|
-
const whereCondition = withScope(scope, targetTableName, targetTable, (0, drizzle_orm.and)((
|
|
6226
|
+
const whereCondition = withScope(scope, targetTableName, targetTable, (0, drizzle_orm.and)(parentKeyCondition(groupCols, uniqueKeys), ownCondition, whereArg ? extractFilters(targetTable, targetTableName, whereArg, relationFilterCtx(filterCtx, targetTableName, scope)) : void 0), deleted ?? defaultDeleted);
|
|
6227
|
+
const groupSelection = Object.fromEntries(groupAliases.map((alias, i) => [alias, groupCols[i]]));
|
|
6177
6228
|
const selected = executor.select({
|
|
6178
|
-
|
|
6229
|
+
...groupSelection,
|
|
6179
6230
|
...request.selection
|
|
6180
6231
|
}).from(targetTable);
|
|
6181
|
-
const rows = await (junction ? selected.innerJoin(junction.table, (0, drizzle_orm.eq)(junction.targetCol, foreignCol)) : selected).where(whereCondition).groupBy(
|
|
6182
|
-
const byKey = new Map(rows.map((row) => [row[
|
|
6183
|
-
return
|
|
6232
|
+
const rows = await (junction ? selected.innerJoin(junction.table, (0, drizzle_orm.eq)(junction.targetCol, foreignCol)) : selected).where(whereCondition).groupBy(...groupCols);
|
|
6233
|
+
const byKey = new Map(rows.map((row) => [joinKeyOf(groupAliases.map((alias) => row[alias])), row]));
|
|
6234
|
+
return parentKeys.map((key) => byKey.get(joinKeyOf(key)) ?? {});
|
|
6184
6235
|
});
|
|
6185
|
-
return assembleAggregateRow(await loader.load(
|
|
6236
|
+
return assembleAggregateRow(await loader.load(localValues), request, target);
|
|
6186
6237
|
} catch (e) {
|
|
6187
6238
|
throw withErrorContext(toGraphQLError(e), errorCtx);
|
|
6188
6239
|
}
|