Skip to content

Commit 466a2f4

Browse files
committed
update
1 parent 9cc65ad commit 466a2f4

File tree

1 file changed

+52
-8
lines changed

1 file changed

+52
-8
lines changed

packages/runtime/src/client/executor/name-mapper.ts

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,16 @@ export class QueryNameMapper extends OperationNodeTransformer {
5454
if (!node.from?.froms) {
5555
return super.transformSelectQuery(node);
5656
}
57+
58+
// all table names in "from" are pushed as scopes, each "from" is expanded
59+
// as nested query to apply column name mapping, so the scopes are marked
60+
// "namesMapped" so no additional name mapping is applied when resolving
61+
// columns
5762
const scopes = this.createScopesFromFroms(node.from, true);
5863
return this.withScopes(scopes, () => {
5964
return {
6065
...super.transformSelectQuery(node),
66+
// convert "from" to nested query as needed
6167
from: this.processFrom(node.from!),
6268
};
6369
});
@@ -69,10 +75,11 @@ export class QueryNameMapper extends OperationNodeTransformer {
6975
}
7076

7177
return this.withScope(
72-
{ model: node.into.table.identifier.name, alias: undefined },
78+
{ model: node.into.table.identifier.name },
7379
() =>
7480
({
7581
...super.transformInsertQuery(node),
82+
// map table name
7683
into: this.processTableRef(node.into!),
7784
}) satisfies InsertQueryNode,
7885
);
@@ -81,6 +88,7 @@ export class QueryNameMapper extends OperationNodeTransformer {
8188
protected override transformReturning(node: ReturningNode) {
8289
return {
8390
kind: node.kind,
91+
// map column names in returning selections (include returningAll)
8492
selections: this.processSelections(node.selections),
8593
};
8694
}
@@ -89,8 +97,11 @@ export class QueryNameMapper extends OperationNodeTransformer {
8997
const { alias, node: innerNode } = this.stripAlias(node.table);
9098
if (TableNode.is(innerNode!)) {
9199
const modelName = innerNode.table.identifier.name;
92-
const select = this.createSelectAll(modelName);
93-
return { ...super.transformJoin(node), table: this.wrapAlias(select, alias ?? modelName) };
100+
if (this.hasMappedColumns(modelName)) {
101+
// create a nested query with all fields selected and names mapped
102+
const select = this.createSelectAll(modelName);
103+
return { ...super.transformJoin(node), table: this.wrapAlias(select, alias ?? modelName) };
104+
}
94105
}
95106
return super.transformJoin(node);
96107
}
@@ -99,15 +110,30 @@ export class QueryNameMapper extends OperationNodeTransformer {
99110
if (!ColumnNode.is(node.column)) {
100111
return super.transformReference(node);
101112
}
113+
114+
// resolve the reference to a field from outer scopes
102115
const { fieldDef, modelDef, scope } = this.resolveFieldFromScopes(
103116
node.column.column.name,
104117
node.table?.table.identifier.name,
105118
);
106119
if (fieldDef && !scope.namesMapped) {
107-
const mappedName = this.mapFieldName(modelDef.name, fieldDef.name);
120+
// map column name and table name as needed
121+
const mappedFieldName = this.mapFieldName(modelDef.name, fieldDef.name);
122+
123+
// map table name depending on how it is resolved
124+
let mappedTableName = node.table?.table.identifier.name;
125+
if (mappedTableName) {
126+
if (scope.alias === mappedTableName) {
127+
// table name is resolved to an alias, no mapping needed
128+
} else if (scope.model === mappedTableName) {
129+
// table name is resolved to a model, map the name as needed
130+
mappedTableName = this.mapTableName(scope.model);
131+
}
132+
}
133+
108134
return ReferenceNode.create(
109-
ColumnNode.create(mappedName),
110-
node.table ? this.processTableRef(node.table) : undefined,
135+
ColumnNode.create(mappedFieldName),
136+
mappedTableName ? TableNode.create(mappedTableName) : undefined,
111137
);
112138
} else {
113139
return super.transformReference(node);
@@ -132,21 +158,27 @@ export class QueryNameMapper extends OperationNodeTransformer {
132158
return this.withScope({ model: innerTable.table.identifier.name, alias }, () => {
133159
return {
134160
...super.transformUpdateQuery(node),
161+
// map table name
135162
table: this.wrapAlias(this.processTableRef(innerTable), alias),
136163
};
137164
});
138165
}
139166

140167
protected override transformDeleteQuery(node: DeleteQueryNode) {
168+
// all "from" nodes are pushed as scopes
141169
const scopes = this.createScopesFromFroms(node.from, false);
170+
171+
// process name mapping in each "from"
142172
const froms = node.from.froms.map((from) => {
143173
const { alias, node: innerNode } = this.stripAlias(from);
144174
if (TableNode.is(innerNode!)) {
175+
// map table name
145176
return this.wrapAlias(this.processTableRef(innerNode), alias);
146177
} else {
147178
return super.transformNode(from);
148179
}
149180
});
181+
150182
return this.withScopes(scopes, () => {
151183
return {
152184
...super.transformDeleteQuery(node),
@@ -285,7 +317,8 @@ export class QueryNameMapper extends OperationNodeTransformer {
285317
.filter((s) => !!s);
286318
}
287319

288-
private processFrom(node: FromNode) {
320+
// convert a "from" node to a nested query if there are columns with name mapping
321+
private processFrom(node: FromNode): FromNode {
289322
return {
290323
...super.transformFrom(node),
291324
froms: node.froms.map((from) => {
@@ -295,15 +328,20 @@ export class QueryNameMapper extends OperationNodeTransformer {
295328
}
296329
if (TableNode.is(innerNode)) {
297330
if (this.hasMappedColumns(innerNode.table.identifier.name)) {
331+
// create a nested query with all fields selected and names mapped
298332
const selectAll = this.createSelectAll(innerNode.table.identifier.name);
333+
334+
// use the original alias or table name as the alias for the nested query
335+
// so its transparent to the outer scope
299336
return this.ensureAlias(selectAll, alias, innerNode.table.identifier.name);
300337
}
301338
}
302339
return this.transformNode(from);
303340
}),
304-
} satisfies FromNode;
341+
};
305342
}
306343

344+
// create a `SelectQueryNode` for the given model with all columns mapped
307345
private createSelectAll(model: string): SelectQueryNode {
308346
const modelDef = requireModel(this.schema, model);
309347
const tableName = this.mapTableName(model);
@@ -331,10 +369,13 @@ export class QueryNameMapper extends OperationNodeTransformer {
331369
const result: SelectionNode[] = [];
332370
selections.forEach((selection) => {
333371
if (SelectAllNode.is(selection.selection)) {
372+
// expand "select *" to a list of selections if name mapping is needed
334373
const processed = this.processSelectAll(selection.selection);
335374
if (Array.isArray(processed)) {
375+
// expanded and names mapped
336376
result.push(...processed.map((s) => SelectionNode.create(s)));
337377
} else {
378+
// not expanded
338379
result.push(SelectionNode.create(processed));
339380
}
340381
} else {
@@ -356,10 +397,13 @@ export class QueryNameMapper extends OperationNodeTransformer {
356397
private processSelectAll(node: SelectAllNode) {
357398
const scope = this.modelScopes[this.modelScopes.length - 1];
358399
invariant(scope);
400+
359401
if (!this.hasMappedColumns(scope.model)) {
402+
// no name mapping needed, preserve the select all
360403
return super.transformSelectAll(node);
361404
}
362405

406+
// expand select all to a list of selections with name mapping
363407
const modelDef = requireModel(this.schema, scope.model);
364408
return this.getModelFields(modelDef).map((fieldDef) => {
365409
const columnName = this.mapFieldName(scope.model, fieldDef.name);

0 commit comments

Comments
 (0)