Skip to content

Commit f5208d5

Browse files
committed
View select fix for views with column.as in selection, integration tests for column.as
1 parent 5c2b5b5 commit f5208d5

9 files changed

Lines changed: 847 additions & 8 deletions

File tree

drizzle-orm/src/alias.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,25 @@ import { ViewBaseConfig } from './view-common.ts';
1111
export class ColumnTableAliasProxyHandler<TColumn extends Column> implements ProxyHandler<TColumn> {
1212
static readonly [entityKind]: string = 'ColumnTableAliasProxyHandler';
1313

14-
constructor(private table: Table | View) {}
14+
constructor(private table: Table | View, private ignoreColumnAlias?: boolean) {}
1515

1616
get(columnObj: TColumn, prop: string | symbol): any {
1717
if (prop === 'table') {
1818
return this.table;
1919
}
2020

21+
if (prop === 'isAlias' && this.ignoreColumnAlias) {
22+
return false;
23+
}
24+
2125
return columnObj[prop as keyof TColumn];
2226
}
2327
}
2428

2529
export class TableAliasProxyHandler<T extends Table | View> implements ProxyHandler<T> {
2630
static readonly [entityKind]: string = 'TableAliasProxyHandler';
2731

28-
constructor(private alias: string, private replaceOriginalName: boolean) {}
32+
constructor(private alias: string, private replaceOriginalName: boolean, private ignoreColumnAlias?: boolean) {}
2933

3034
get(target: T, prop: string | symbol): any {
3135
if (prop === Table.Symbol.IsAlias) {
@@ -59,7 +63,7 @@ export class TableAliasProxyHandler<T extends Table | View> implements ProxyHand
5963
Object.keys(columns).map((key) => {
6064
proxiedColumns[key] = new Proxy(
6165
columns[key]!,
62-
new ColumnTableAliasProxyHandler(new Proxy(target, this)),
66+
new ColumnTableAliasProxyHandler(new Proxy(target, this), this.ignoreColumnAlias),
6367
);
6468
});
6569

@@ -68,7 +72,10 @@ export class TableAliasProxyHandler<T extends Table | View> implements ProxyHand
6872

6973
const value = target[prop as keyof typeof target];
7074
if (is(value, Column)) {
71-
return new Proxy(value as AnyColumn, new ColumnTableAliasProxyHandler(new Proxy(target, this)));
75+
return new Proxy(
76+
value as AnyColumn,
77+
new ColumnTableAliasProxyHandler(new Proxy(target, this), this.ignoreColumnAlias),
78+
);
7279
}
7380

7481
return value;
@@ -116,7 +123,7 @@ export class RelationTableAliasProxyHandler<T extends V1.Relation> implements Pr
116123
}
117124

118125
export function aliasedTable<T extends Table | View>(table: T, tableAlias: string): T {
119-
return new Proxy(table, new TableAliasProxyHandler(tableAlias, false));
126+
return new Proxy(table, new TableAliasProxyHandler(tableAlias, false, false));
120127
}
121128

122129
export function aliasedColumn<T extends Column>(column: T, alias: string): T {
@@ -130,7 +137,10 @@ export function aliasedRelation<T extends V1.Relation>(relation: T, tableAlias:
130137
export function aliasedTableColumn<T extends AnyColumn>(column: T, tableAlias: string): T {
131138
return new Proxy(
132139
column,
133-
new ColumnTableAliasProxyHandler(new Proxy(column.table, new TableAliasProxyHandler(tableAlias, false))),
140+
new ColumnTableAliasProxyHandler(
141+
new Proxy(column.table, new TableAliasProxyHandler(tableAlias, false, false)),
142+
false,
143+
),
134144
);
135145
}
136146

drizzle-orm/src/selection-proxy.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,9 @@ export class SelectionProxyHandler<T extends Subquery | Record<string, unknown>
104104
new ColumnTableAliasProxyHandler(
105105
new Proxy(
106106
value.table,
107-
new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false),
107+
new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false, true),
108108
),
109+
true,
109110
),
110111
);
111112
}

integration-tests/tests/cockroach/common.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5899,6 +5899,156 @@ export function tests() {
58995899
]);
59005900
});
59015901

5902+
test('column.as', async (ctx) => {
5903+
const { db } = ctx.cockroach;
5904+
5905+
const users = cockroachTable('users_column_as', {
5906+
id: int4('id').primaryKey().generatedByDefaultAsIdentity(),
5907+
name: text('name').notNull(),
5908+
cityId: int4('city_id').references(() => cities.id),
5909+
});
5910+
5911+
const cities = cockroachTable('cities_column_as', {
5912+
id: int4('id').primaryKey().generatedByDefaultAsIdentity(),
5913+
name: text('name').notNull(),
5914+
});
5915+
5916+
const ucView = cockroachView('cities_users_column_as_view').as((qb) =>
5917+
qb.select({
5918+
userId: users.id.as('user_id'),
5919+
cityId: cities.id.as('city_id'),
5920+
userName: users.name.as('user_name'),
5921+
cityName: cities.name.as('city_name'),
5922+
}).from(users).leftJoin(cities, eq(cities.id, users.cityId))
5923+
);
5924+
5925+
await db.execute(sql`CREATE TABLE ${cities} (
5926+
"id" INT4 PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
5927+
"name" TEXT NOT NULL
5928+
);`);
5929+
5930+
await db.execute(sql`CREATE TABLE ${users} (
5931+
"id" INT4 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
5932+
"name" TEXT NOT NULL,
5933+
"city_id" INT4 REFERENCES ${cities}("id")
5934+
);`);
5935+
5936+
await db.execute(
5937+
sql`CREATE VIEW ${ucView} AS SELECT ${users.id} as "user_id", ${cities.id} as "city_id", ${users.name} as "user_name", ${cities.name} as "city_name" FROM ${users} LEFT JOIN ${cities} ON ${
5938+
eq(cities.id, users.cityId)
5939+
};`,
5940+
);
5941+
5942+
const citiesInsRet = await db.insert(cities).values([{
5943+
id: 1,
5944+
name: 'Firstistan',
5945+
}, {
5946+
id: 2,
5947+
name: 'Secondaria',
5948+
}]).returning({
5949+
cityId: cities.id.as('city_id'),
5950+
cityName: cities.name.as('city_name'),
5951+
});
5952+
5953+
expect(citiesInsRet).toStrictEqual(expect.arrayContaining([{
5954+
cityId: 1,
5955+
cityName: 'Firstistan',
5956+
}, {
5957+
cityId: 2,
5958+
cityName: 'Secondaria',
5959+
}]));
5960+
5961+
const usersInsRet = await db.insert(users).values([{ id: 1, name: 'First', cityId: 1 }, {
5962+
id: 2,
5963+
name: 'Second',
5964+
cityId: 2,
5965+
}, {
5966+
id: 3,
5967+
name: 'Third',
5968+
}]).returning({
5969+
userId: users.id.as('user_id'),
5970+
userName: users.name.as('users_name'),
5971+
userCityId: users.cityId,
5972+
});
5973+
5974+
expect(usersInsRet).toStrictEqual(expect.arrayContaining([{ userId: 1, userName: 'First', userCityId: 1 }, {
5975+
userId: 2,
5976+
userName: 'Second',
5977+
userCityId: 2,
5978+
}, {
5979+
userId: 3,
5980+
userName: 'Third',
5981+
userCityId: null,
5982+
}]));
5983+
5984+
const joinSelectReturn = await db.select({
5985+
userId: users.id.as('user_id'),
5986+
cityId: cities.id.as('city_id'),
5987+
userName: users.name.as('user_name'),
5988+
cityName: cities.name.as('city_name'),
5989+
}).from(users).leftJoin(cities, eq(cities.id, users.cityId));
5990+
5991+
expect(joinSelectReturn).toStrictEqual(expect.arrayContaining([{
5992+
userId: 1,
5993+
userName: 'First',
5994+
cityId: 1,
5995+
cityName: 'Firstistan',
5996+
}, {
5997+
userId: 2,
5998+
userName: 'Second',
5999+
cityId: 2,
6000+
cityName: 'Secondaria',
6001+
}, {
6002+
userId: 3,
6003+
userName: 'Third',
6004+
cityId: null,
6005+
cityName: null,
6006+
}]));
6007+
6008+
const viewSelectReturn = await db.select().from(ucView);
6009+
6010+
expect(viewSelectReturn).toStrictEqual(expect.arrayContaining([{
6011+
userId: 1,
6012+
userName: 'First',
6013+
cityId: 1,
6014+
cityName: 'Firstistan',
6015+
}, {
6016+
userId: 2,
6017+
userName: 'Second',
6018+
cityId: 2,
6019+
cityName: 'Secondaria',
6020+
}, {
6021+
userId: 3,
6022+
userName: 'Third',
6023+
cityId: null,
6024+
cityName: null,
6025+
}]));
6026+
6027+
const viewJoinReturn = await db.select({
6028+
userId: ucView.userId.as('user_id_ucv'),
6029+
cityId: cities.id.as('city_id'),
6030+
userName: ucView.userName.as('user_name_ucv'),
6031+
cityName: cities.name.as('city_name'),
6032+
}).from(ucView).leftJoin(cities, eq(cities.id, ucView.cityId));
6033+
6034+
expect(viewJoinReturn).toStrictEqual(expect.arrayContaining([{
6035+
userId: 1,
6036+
userName: 'First',
6037+
cityId: 1,
6038+
cityName: 'Firstistan',
6039+
}, {
6040+
userId: 2,
6041+
userName: 'Second',
6042+
cityId: 2,
6043+
cityName: 'Secondaria',
6044+
}, {
6045+
userId: 3,
6046+
userName: 'Third',
6047+
cityId: null,
6048+
cityName: null,
6049+
}]));
6050+
});
6051+
59026052
test('all types', async (ctx) => {
59036053
const { db } = ctx.cockroach;
59046054

integration-tests/tests/gel/gel.test.ts

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ describe('some', async () => {
254254
create constraint exclusive;
255255
};
256256
create required property name: str;
257-
create required property cityId: int32;
257+
create property cityId: int32;
258258
};
259259
CREATE TYPE default::users_with_undefined {
260260
create property id1: int16 {
@@ -5717,4 +5717,85 @@ describe('some', async () => {
57175717
// @ts-expect-error
57185718
expect(db.select().from(sq).getUsedTables()).toStrictEqual(['users']);
57195719
});
5720+
5721+
test('column.as', async (ctx) => {
5722+
const { db } = ctx.gel;
5723+
5724+
const users = gelTable('users_with_cities', {
5725+
id: integer('id1').primaryKey(),
5726+
name: text('name').notNull(),
5727+
cityId: integer('cityId').references(() => cities.id),
5728+
});
5729+
5730+
const cities = gelTable('cities', {
5731+
id: integer('id1').primaryKey(),
5732+
name: text('name').notNull(),
5733+
});
5734+
5735+
const citiesInsRet = await db.insert(cities).values([{
5736+
id: 1,
5737+
name: 'Firstistan',
5738+
}, {
5739+
id: 2,
5740+
name: 'Secondaria',
5741+
}]).returning({
5742+
cityId: cities.id.as('city_id'),
5743+
cityName: cities.name.as('city_name'),
5744+
});
5745+
5746+
expect(citiesInsRet).toStrictEqual(expect.arrayContaining([{
5747+
cityId: 1,
5748+
cityName: 'Firstistan',
5749+
}, {
5750+
cityId: 2,
5751+
cityName: 'Secondaria',
5752+
}]));
5753+
5754+
const usersInsRet = await db.insert(users).values([{ id: 1, name: 'First', cityId: 1 }, {
5755+
id: 2,
5756+
name: 'Second',
5757+
cityId: 2,
5758+
}, {
5759+
id: 3,
5760+
name: 'Third',
5761+
}]).returning({
5762+
userId: users.id.as('user_id'),
5763+
userName: users.name.as('users_name'),
5764+
userCityId: users.cityId,
5765+
});
5766+
5767+
expect(usersInsRet).toStrictEqual(expect.arrayContaining([{ userId: 1, userName: 'First', userCityId: 1 }, {
5768+
userId: 2,
5769+
userName: 'Second',
5770+
userCityId: 2,
5771+
}, {
5772+
userId: 3,
5773+
userName: 'Third',
5774+
userCityId: null,
5775+
}]));
5776+
5777+
const joinSelectReturn = await db.select({
5778+
userId: users.id.as('user_id'),
5779+
cityId: cities.id.as('city_id'),
5780+
userName: users.name.as('user_name'),
5781+
cityName: cities.name.as('city_name'),
5782+
}).from(users).leftJoin(cities, eq(cities.id, users.cityId));
5783+
5784+
expect(joinSelectReturn).toStrictEqual(expect.arrayContaining([{
5785+
userId: 1,
5786+
userName: 'First',
5787+
cityId: 1,
5788+
cityName: 'Firstistan',
5789+
}, {
5790+
userId: 2,
5791+
userName: 'Second',
5792+
cityId: 2,
5793+
cityName: 'Secondaria',
5794+
}, {
5795+
userId: 3,
5796+
userName: 'Third',
5797+
cityId: null,
5798+
cityName: null,
5799+
}]));
5800+
});
57205801
});

0 commit comments

Comments
 (0)