Skip to content

Commit 9a9766b

Browse files
committed
fix(gb-9103): fix aliases in queries/mutations
1 parent 7b6fc6a commit 9a9766b

File tree

15 files changed

+484
-72
lines changed

15 files changed

+484
-72
lines changed

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ futures = "0.3"
6666
futures-util = "0.3.31"
6767
grafbase-database-definition = { version = "0.1.0", path = "crates/database-definition" }
6868
grafbase-postgres-introspection = { version = "0.1.0", path = "crates/postgres-introspection" }
69-
grafbase-sdk = "0.15.4"
69+
grafbase-sdk = "0.15.7"
7070
http = "1.3"
7171
indexmap = "2.9.0"
7272
indoc = "2.0.6"

crates/database-definition/src/walkers/table_column.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ impl<'a> TableColumnWalker<'a> {
2424
self.get_name(self.get().client_name())
2525
}
2626

27+
/// Returns the provided alias if present, otherwise falls back to the client name.
28+
pub fn alias(self, alias: Option<&'a str>) -> &'a str {
29+
alias.unwrap_or_else(|| self.client_name())
30+
}
31+
2732
/// The type of the column in the database.
2833
pub fn database_type(self) -> DatabaseType<'a> {
2934
match self.get().database_type() {

extensions/postgres/extension.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[extension]
22
name = "postgres"
3-
version = "0.4.8"
3+
version = "0.4.9"
44
description = """
55
Integrate your Postgres database directly into Grafbase Gateway. This extension exposes your database schema and with the help of the introspection tool, automatically generates a fully-functional GraphQL subgraph, eliminating the need to build and maintain a separate service.
66
"""

extensions/postgres/src/context/selection_iterator.rs

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,31 @@ use std::{borrow::Cow, collections::HashMap};
1212
use super::{Context, PageInfo};
1313

1414
#[derive(Clone)]
15-
pub struct SelectColumn<'a>(TableColumnWalker<'a>);
15+
pub struct SelectColumn<'a> {
16+
column: TableColumnWalker<'a>,
17+
alias: Option<&'a str>,
18+
}
1619

1720
impl<'a> SelectColumn<'a> {
18-
pub fn into_expression(self, table_name: Option<Cow<'a, str>>) -> (TableColumnWalker<'a>, Expression<'a>) {
21+
pub fn into_expression(
22+
self,
23+
table_name: Option<Cow<'a, str>>,
24+
) -> (TableColumnWalker<'a>, Expression<'a>, Option<&'a str>) {
1925
let table_name = match table_name {
2026
Some(name) => name,
21-
None => Cow::Borrowed(self.0.table().database_name()),
27+
None => Cow::Borrowed(self.column.table().database_name()),
2228
};
2329

24-
let sql_col = Column::new(self.0.database_name()).table(table_name);
30+
let sql_col = Column::new(self.column.database_name()).table(table_name);
2531

26-
let r#enum = match self.0.database_type() {
32+
let r#enum = match self.column.database_type() {
2733
DatabaseType::Scalar(scalar_type) => {
2834
let expr = match scalar_type.from_db_to_client_cast() {
2935
Some(cast) => Expression::from(ast::cast(sql_col, cast)),
3036
None => Expression::from(sql_col),
3137
};
3238

33-
return (self.0, expr);
39+
return (self.column, expr, self.alias);
3440
}
3541
DatabaseType::Enum(walker) => walker,
3642
};
@@ -46,15 +52,15 @@ impl<'a> SelectColumn<'a> {
4652

4753
let expr = builder.r#else(Expression::from(col)).into();
4854

49-
(self.0, expr)
55+
(self.column, expr, self.alias)
5056
}
5157
}
5258

5359
#[derive(Clone)]
54-
pub struct Unnest<'a>(TableColumnWalker<'a>, EnumWalker<'a>);
60+
pub struct Unnest<'a>(TableColumnWalker<'a>, EnumWalker<'a>, Option<&'a str>);
5561

5662
impl<'a> Unnest<'a> {
57-
pub fn into_select(self, table_name: Option<Cow<'a, str>>) -> (TableColumnWalker<'a>, Select<'a>) {
63+
pub fn into_select(self, table_name: Option<Cow<'a, str>>) -> (TableColumnWalker<'a>, Select<'a>, Option<&'a str>) {
5864
let unnest_col = Column::new(format!("unnest_{}", self.0.database_name()));
5965
let unnest_col = ast::cast(unnest_col, "text");
6066

@@ -79,7 +85,7 @@ impl<'a> Unnest<'a> {
7985
let mut select = Select::from_table(expr);
8086
select.value(aggregate);
8187

82-
(self.0, select)
88+
(self.0, select, self.2)
8389
}
8490
}
8591

@@ -91,9 +97,14 @@ pub enum TableSelection<'a> {
9197
/// GraphQL enum values, renamed.
9298
ColumnUnnest(Unnest<'a>),
9399
/// Joins a unique row with a nested selection.
94-
JoinUnique(RelationWalker<'a>, SelectionIterator<'a>),
100+
JoinUnique(RelationWalker<'a>, SelectionIterator<'a>, Option<&'a str>),
95101
/// Joins a collection of rows with a nested selection.
96-
JoinMany(RelationWalker<'a>, SelectionIterator<'a>, CollectionArgs<'a>),
102+
JoinMany(
103+
RelationWalker<'a>,
104+
SelectionIterator<'a>,
105+
CollectionArgs<'a>,
106+
Option<&'a str>,
107+
),
97108
}
98109

99110
/// An iterator over a GraphQL selection. Returns either a column or a
@@ -251,7 +262,12 @@ impl<'a> Iterator for SelectionIterator<'a> {
251262
let extra = self.extra_columns.get(self.extra_column_index);
252263
self.extra_column_index += 1;
253264

254-
return extra.map(|column| Ok(TableSelection::Column(SelectColumn(*column))));
265+
return extra.map(|column| {
266+
Ok(TableSelection::Column(SelectColumn {
267+
column: *column,
268+
alias: None,
269+
}))
270+
});
255271
};
256272

257273
self.index += 1;
@@ -264,10 +280,17 @@ impl<'a> Iterator for SelectionIterator<'a> {
264280
{
265281
match column.database_type() {
266282
DatabaseType::Enum(r#enum) if column.is_array() => {
267-
return Some(Ok(TableSelection::ColumnUnnest(Unnest(column, r#enum))));
283+
return Some(Ok(TableSelection::ColumnUnnest(Unnest(
284+
column,
285+
r#enum,
286+
selection_field.alias(),
287+
))));
268288
}
269289
_ => {
270-
return Some(Ok(TableSelection::Column(SelectColumn(column))));
290+
return Some(Ok(TableSelection::Column(SelectColumn {
291+
column,
292+
alias: selection_field.alias(),
293+
})));
271294
}
272295
}
273296
}
@@ -299,7 +322,11 @@ impl<'a> Iterator for SelectionIterator<'a> {
299322
Err(err) => return Some(Err(err)),
300323
};
301324

302-
Some(Ok(TableSelection::JoinUnique(relation, iterator)))
325+
Some(Ok(TableSelection::JoinUnique(
326+
relation,
327+
iterator,
328+
selection_field.alias(),
329+
)))
303330
} else {
304331
let params = selection_field
305332
.arguments::<CollectionParameters>(self.ctx.arguments)
@@ -327,7 +354,12 @@ impl<'a> Iterator for SelectionIterator<'a> {
327354
let args = CollectionArgs::new(self.ctx.database_definition, relation.referenced_table(), params);
328355

329356
match args {
330-
Ok(args) => Some(Ok(TableSelection::JoinMany(relation, iterator, args))),
357+
Ok(args) => Some(Ok(TableSelection::JoinMany(
358+
relation,
359+
iterator,
360+
args,
361+
selection_field.alias(),
362+
))),
331363
Err(error) => Some(Err(error)),
332364
}
333365
}

extensions/postgres/src/resolve/query/delete.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,16 @@ pub fn build<'a>(
3232
for selection in selection {
3333
match selection? {
3434
TableSelection::Column(select) => {
35-
let (column, expr) = select.into_expression(None);
36-
returning.push((column.client_name(), expr));
35+
let (column, expr, alias) = select.into_expression(None);
36+
let alias = alias.unwrap_or_else(|| column.client_name());
37+
38+
returning.push((alias, expr));
3739
}
3840
TableSelection::ColumnUnnest(unnest) => {
39-
let (column, nested) = unnest.into_select(None);
40-
returning.push((column.client_name(), Expression::from(nested)));
41+
let (column, nested, alias) = unnest.into_select(None);
42+
let alias = alias.unwrap_or_else(|| column.client_name());
43+
44+
returning.push((alias, Expression::from(nested)));
4145
}
4246
// our output type doesn't have relations, so this is never reachable
4347
TableSelection::JoinMany(..) | TableSelection::JoinUnique(..) => {

extensions/postgres/src/resolve/query/insert.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,17 @@ pub fn build<'a>(
5858
for selection in selection {
5959
match selection? {
6060
TableSelection::Column(select) => {
61-
let (column, expr) = select.into_expression(Some(insert_name.clone().into()));
61+
let (column, expr, alias) = select.into_expression(Some(insert_name.clone().into()));
6262

63-
selected_data.push((column.client_name(), expr));
63+
selected_data.push((alias.unwrap_or_else(|| column.client_name()), expr));
6464
returning.push(column.database_name());
6565
}
6666
TableSelection::ColumnUnnest(unnest) => {
67-
let (column, nested) = unnest.into_select(Some(insert_name.clone().into()));
67+
let (column, nested, field_alias) = unnest.into_select(Some(insert_name.clone().into()));
6868
let alias = format!("transformed_{}", column.database_name());
6969

7070
selected_data.push((
71-
column.client_name(),
71+
field_alias.unwrap_or_else(|| column.client_name()),
7272
Column::new("json_array").table(alias.clone()).into(),
7373
));
7474

extensions/postgres/src/resolve/query/lookup.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::borrow::Cow;
2+
13
use grafbase_database_definition::{RelationWalker, TableColumnWalker};
24
use grafbase_sdk::{SdkError, host_io::postgres::types::DatabaseValue};
35
use indexmap::{IndexMap, map::Entry};
@@ -93,35 +95,38 @@ pub fn build(builder: SelectBuilder<'_>) -> Result<Select<'_>, SdkError> {
9395
match selection? {
9496
// Base columns from the main table (e.g., User.id, User.name)
9597
TableSelection::Column(select) => {
96-
let (column, _) = select.into_expression(None); // We only need column names here
98+
let (column, _, _) = select.into_expression(None); // We only need column names here
9799
// Reference the column from the aliased main table (e.g., "User"."name")
98100
let col_expr = Column::from((builder.table().client_name(), column.database_name()));
99101
columns_for_json.push((column.client_name().to_string(), col_expr.into()));
100102
}
101103
// Nested object/array fetched via LATERAL JOIN (e.g., blogs, author)
102-
TableSelection::JoinUnique(relation, nested_selection) => {
104+
TableSelection::JoinUnique(relation, nested_selection, alias) => {
103105
inject_relation(
104106
&mut main_select,
105107
&mut columns_for_json,
106108
relation,
107109
nested_selection,
108110
None,
111+
alias,
109112
)?;
110113
}
111-
TableSelection::JoinMany(relation, nested_selection, args) => {
114+
TableSelection::JoinMany(relation, nested_selection, args, alias) => {
112115
inject_relation(
113116
&mut main_select,
114117
&mut columns_for_json,
115118
relation,
116119
nested_selection,
117120
Some(args),
121+
alias,
118122
)?;
119123
}
120124
TableSelection::ColumnUnnest(unnest) => {
121125
// Handle array unnesting if required in the final object structure.
122126
// This might involve adding a subquery result similar to lateral joins.
123-
let (column, nested_select) = unnest.into_select(None);
124-
columns_for_json.push((column.client_name().to_string(), Expression::from(nested_select)));
127+
let (column, nested_select, alias) = unnest.into_select(None);
128+
let alias = alias.unwrap_or_else(|| column.database_name());
129+
columns_for_json.push((alias.to_string(), Expression::from(nested_select)));
125130
}
126131
}
127132
}
@@ -189,11 +194,13 @@ fn inject_relation<'a>(
189194
relation: RelationWalker<'a>,
190195
nested_selection: SelectionIterator<'a>,
191196
args: Option<CollectionArgs<'a>>,
197+
alias: Option<&'a str>,
192198
) -> Result<(), SdkError> {
193-
let client_field_name = relation.client_field_name();
194-
let join_alias = client_field_name;
199+
let join_alias = alias
200+
.map(Cow::Borrowed)
201+
.unwrap_or_else(|| Cow::Owned(relation.client_field_name()));
195202

196-
let mut join_builder = SelectBuilder::new(relation.referenced_table(), nested_selection, join_alias.clone());
203+
let mut join_builder = SelectBuilder::new(relation.referenced_table(), nested_selection, join_alias.to_string());
197204
join_builder.set_relation(relation);
198205

199206
let nested_select = match args {
@@ -211,7 +218,7 @@ fn inject_relation<'a>(
211218

212219
columns_for_json.push((
213220
join_alias.to_string(), // Alias in the final JSON object (e.g., "blogs")
214-
Column::from((join_alias.clone(), join_alias)).into(), // Column from lateral join result
221+
Column::from((join_alias.to_string(), join_alias.to_string())).into(), // Column from lateral join result
215222
));
216223

217224
Ok(())

0 commit comments

Comments
 (0)