linkgress-orm 0.4.54 → 0.4.56
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/entity/db-context.d.ts +100 -0
- package/dist/entity/db-context.d.ts.map +1 -1
- package/dist/entity/db-context.js +386 -94
- package/dist/entity/db-context.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/query/mutation-batch.d.ts +101 -0
- package/dist/query/mutation-batch.d.ts.map +1 -0
- package/dist/query/mutation-batch.js +154 -0
- package/dist/query/mutation-batch.js.map +1 -0
- package/dist/query/query-batch.d.ts +6 -0
- package/dist/query/query-batch.d.ts.map +1 -1
- package/dist/query/query-batch.js +8 -9
- package/dist/query/query-batch.js.map +1 -1
- package/dist/query/query-builder.d.ts.map +1 -1
- package/dist/query/query-builder.js +78 -31
- package/dist/query/query-builder.js.map +1 -1
- package/dist/query/sql-utils.d.ts +1 -0
- package/dist/query/sql-utils.d.ts.map +1 -1
- package/dist/query/sql-utils.js +12 -1
- package/dist/query/sql-utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -3021,11 +3021,11 @@ class SelectQueryBuilder {
|
|
|
3021
3021
|
joinClauses.push(collection.joinClause);
|
|
3022
3022
|
}
|
|
3023
3023
|
// Build the final CTE query
|
|
3024
|
-
const sql = `WITH "__mutation__" AS (
|
|
3025
|
-
${mutationWithReturning}
|
|
3026
|
-
)
|
|
3027
|
-
SELECT ${selectParts.join(', ')}
|
|
3028
|
-
FROM "__mutation__"
|
|
3024
|
+
const sql = `WITH "__mutation__" AS (
|
|
3025
|
+
${mutationWithReturning}
|
|
3026
|
+
)
|
|
3027
|
+
SELECT ${selectParts.join(', ')}
|
|
3028
|
+
FROM "__mutation__"
|
|
3029
3029
|
${joinClauses.join('\n')}`;
|
|
3030
3030
|
return { sql, params: allParams, nestedPaths };
|
|
3031
3031
|
}
|
|
@@ -6019,6 +6019,23 @@ class CollectionQueryBuilder {
|
|
|
6019
6019
|
if (!tableAlias || tableAlias === this.targetTable) {
|
|
6020
6020
|
return;
|
|
6021
6021
|
}
|
|
6022
|
+
// Seed the chain the projection ACTUALLY navigated, not just its terminal alias.
|
|
6023
|
+
// Without this, a projection that names only the deep leaf (e.g. `oi.productPrice.product.resort.name`
|
|
6024
|
+
// with no sibling scalar off `productPrice` / `product`) leaves the intermediates out of
|
|
6025
|
+
// `allTableAliases` entirely, so resolveNavigationJoins' direct-relation phase has nothing to
|
|
6026
|
+
// anchor on and falls through to the name-based schema-graph BFS - which happily reaches
|
|
6027
|
+
// `resort` one hop sooner through an unrelated same-table FK (`order_item.cashback_product_id`)
|
|
6028
|
+
// and silently returns another row's data.
|
|
6029
|
+
// This is the same `__navigationAliases` signal QueryBuilder.collectTableAliasesFromSelection,
|
|
6030
|
+
// GroupedQueryBuilder and DbContext already consume, and the same treatment nested
|
|
6031
|
+
// CollectionQueryBuilder values already get in detectNavigationJoins.
|
|
6032
|
+
if (Array.isArray(fieldRef.__navigationAliases)) {
|
|
6033
|
+
for (const navAlias of fieldRef.__navigationAliases) {
|
|
6034
|
+
if (navAlias && navAlias !== this.targetTable) {
|
|
6035
|
+
allTableAliases.add(navAlias);
|
|
6036
|
+
}
|
|
6037
|
+
}
|
|
6038
|
+
}
|
|
6022
6039
|
// Collect this table alias for later resolution
|
|
6023
6040
|
allTableAliases.add(tableAlias);
|
|
6024
6041
|
// Check if we already have this join
|
|
@@ -6087,39 +6104,69 @@ class CollectionQueryBuilder {
|
|
|
6087
6104
|
joinedSchemas.set(join.alias, schema);
|
|
6088
6105
|
}
|
|
6089
6106
|
}
|
|
6090
|
-
//
|
|
6107
|
+
// PHASE 1 - direct relation lookups, run to a FIXPOINT.
|
|
6108
|
+
// A join added here immediately becomes an anchor candidate for the remaining aliases in
|
|
6109
|
+
// this very pass, so a parent that is itself several hops away from the root (e.g.
|
|
6110
|
+
// order_item -> product_price -> product) can still anchor its own children. Without the
|
|
6111
|
+
// fixpoint those children never see their real parent (joinedSchemas was snapshotted before
|
|
6112
|
+
// the parent was joined) and fall through to the BFS below, which anchors them on whatever
|
|
6113
|
+
// other relation happens to point at the same table - e.g.
|
|
6114
|
+
// order_item.cashback_product_id -> product - silently returning another row's data.
|
|
6115
|
+
let progressed = true;
|
|
6116
|
+
// Termination (why no maxIterations guard is needed here, unlike every other loop in this
|
|
6117
|
+
// file): `progressed` is only ever set on a path that also adds a NEW alias to `resolved`
|
|
6118
|
+
// - every other path `continue`s - so `resolved` grows strictly monotonically and is
|
|
6119
|
+
// bounded above by `allTableAliases.size`. The loop therefore runs at most
|
|
6120
|
+
// `allTableAliases.size + 1` times.
|
|
6121
|
+
while (progressed) {
|
|
6122
|
+
progressed = false;
|
|
6123
|
+
for (const alias of allTableAliases) {
|
|
6124
|
+
if (resolved.has(alias)) {
|
|
6125
|
+
continue;
|
|
6126
|
+
}
|
|
6127
|
+
if (joins.some(j => j.alias === alias)) {
|
|
6128
|
+
resolved.add(alias);
|
|
6129
|
+
continue;
|
|
6130
|
+
}
|
|
6131
|
+
// Look for this alias in any of the already joined schemas (direct lookup)
|
|
6132
|
+
for (const [schemaAlias, schema] of joinedSchemas) {
|
|
6133
|
+
const relation = schema.relations?.[alias];
|
|
6134
|
+
if (!relation || relation.type !== 'one') {
|
|
6135
|
+
continue;
|
|
6136
|
+
}
|
|
6137
|
+
const targetSchema = this.addNavigationJoin(alias, relation, joins, schemaAlias);
|
|
6138
|
+
if (targetSchema) {
|
|
6139
|
+
// Keep the anchor map current so the alias we just joined can serve as the
|
|
6140
|
+
// source for further direct lookups in the next fixpoint round
|
|
6141
|
+
joinedSchemas.set(alias, targetSchema);
|
|
6142
|
+
}
|
|
6143
|
+
resolved.add(alias);
|
|
6144
|
+
progressed = true;
|
|
6145
|
+
break;
|
|
6146
|
+
}
|
|
6147
|
+
}
|
|
6148
|
+
}
|
|
6149
|
+
// PHASE 2 - only aliases with no direct relation path at all fall back to the transitive
|
|
6150
|
+
// schema-graph BFS, which searches by relation NAME and therefore cannot tell which of
|
|
6151
|
+
// several relations pointing at the same table the projection actually meant
|
|
6091
6152
|
for (const alias of allTableAliases) {
|
|
6092
|
-
if (resolved.has(alias) ||
|
|
6093
|
-
resolved.add(alias);
|
|
6153
|
+
if (resolved.has(alias) || !this.schemaRegistry) {
|
|
6094
6154
|
continue;
|
|
6095
6155
|
}
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
if (schema.relations && schema.relations[alias]) {
|
|
6100
|
-
const relation = schema.relations[alias];
|
|
6101
|
-
if (relation.type === 'one') {
|
|
6102
|
-
this.addNavigationJoin(alias, relation, joins, schemaAlias);
|
|
6103
|
-
resolved.add(alias);
|
|
6104
|
-
found = true;
|
|
6105
|
-
break;
|
|
6106
|
-
}
|
|
6107
|
-
}
|
|
6156
|
+
const path = this.findNavigationPath(alias, joinedSchemas, startSchema);
|
|
6157
|
+
if (path.length === 0) {
|
|
6158
|
+
continue;
|
|
6108
6159
|
}
|
|
6109
|
-
//
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
for (const step of path) {
|
|
6116
|
-
if (!joins.some(j => j.alias === step.alias)) {
|
|
6117
|
-
this.addNavigationJoin(step.alias, step.relation, joins, step.sourceAlias);
|
|
6118
|
-
}
|
|
6160
|
+
// Add all intermediate joins
|
|
6161
|
+
for (const step of path) {
|
|
6162
|
+
if (!joins.some(j => j.alias === step.alias)) {
|
|
6163
|
+
const stepSchema = this.addNavigationJoin(step.alias, step.relation, joins, step.sourceAlias);
|
|
6164
|
+
if (stepSchema) {
|
|
6165
|
+
joinedSchemas.set(step.alias, stepSchema);
|
|
6119
6166
|
}
|
|
6120
|
-
resolved.add(alias);
|
|
6121
6167
|
}
|
|
6122
6168
|
}
|
|
6169
|
+
resolved.add(alias);
|
|
6123
6170
|
}
|
|
6124
6171
|
}
|
|
6125
6172
|
}
|