Skip to content

Commit c7d26d1

Browse files
committed
Select from alias
1 parent 9143617 commit c7d26d1

File tree

2 files changed

+85
-39
lines changed

2 files changed

+85
-39
lines changed

sea-orm-macros/src/derives/partial_model.rs

+36-38
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,9 @@ enum Error {
2929

3030
#[derive(Debug, PartialEq, Eq)]
3131
enum ColumnAs {
32-
/// column in the model
33-
Col(syn::Ident),
3432
/// alias from a column in model
3533
ColAlias {
36-
col: syn::Ident,
34+
col: Option<syn::Ident>,
3735
field: syn::Ident,
3836
},
3937
/// from an expr
@@ -51,6 +49,7 @@ enum ColumnAs {
5149

5250
struct DerivePartialModel {
5351
entity: Option<syn::Type>,
52+
alias: Option<String>,
5453
ident: syn::Ident,
5554
fields: Vec<ColumnAs>,
5655
from_query_result: bool,
@@ -74,6 +73,7 @@ impl DerivePartialModel {
7473
};
7574

7675
let mut entity = None;
76+
let mut alias = None;
7777
let mut from_query_result = false;
7878

7979
for attr in input.attrs.iter() {
@@ -85,6 +85,8 @@ impl DerivePartialModel {
8585
for meta in list {
8686
if let Some(s) = meta.get_as_kv("entity") {
8787
entity = Some(syn::parse_str::<syn::Type>(&s).map_err(Error::Syn)?);
88+
} else if let Some(s) = meta.get_as_kv("alias") {
89+
alias = Some(s);
8890
} else if meta.exists("from_query_result") {
8991
from_query_result = true;
9092
}
@@ -132,7 +134,7 @@ impl DerivePartialModel {
132134
}
133135

134136
ColumnAs::ColAlias {
135-
col,
137+
col: Some(col),
136138
field: field_name,
137139
}
138140
}
@@ -142,7 +144,7 @@ impl DerivePartialModel {
142144
},
143145
(None, None, true) => ColumnAs::Nested {
144146
typ: field.ty,
145-
field: field_name.unraw(),
147+
field: field_name,
146148
},
147149
(None, None, false) => {
148150
if entity.is_none() {
@@ -151,7 +153,10 @@ impl DerivePartialModel {
151153
if skip {
152154
ColumnAs::Skip(field_name)
153155
} else {
154-
ColumnAs::Col(field_name)
156+
ColumnAs::ColAlias {
157+
col: None,
158+
field: field_name,
159+
}
155160
}
156161
}
157162
(_, _, _) => return Err(Error::OverlappingAttributes(field_span)),
@@ -161,6 +166,7 @@ impl DerivePartialModel {
161166

162167
Ok(Self {
163168
entity,
169+
alias,
164170
ident: input.ident,
165171
fields: column_as_list,
166172
from_query_result,
@@ -184,7 +190,6 @@ impl DerivePartialModel {
184190
_ => FqrItemType::Flat,
185191
},
186192
ident: match col_as {
187-
ColumnAs::Col(field) => field,
188193
ColumnAs::ColAlias { field, .. } => field,
189194
ColumnAs::Expr { field, .. } => field,
190195
ColumnAs::Nested { field, .. } => field,
@@ -210,43 +215,36 @@ impl DerivePartialModel {
210215
let select_ident = format_ident!("select");
211216
let DerivePartialModel {
212217
entity,
218+
alias,
213219
ident,
214220
fields,
215221
..
216222
} = self;
217223
let select_col_code_gen = fields.iter().map(|col_as| match col_as {
218-
ColumnAs::Col(ident) => {
219-
let entity = entity.as_ref().unwrap();
220-
let uppercase_ident = format_ident!(
221-
"{}",
222-
ident.to_string().to_upper_camel_case()
223-
);
224-
let col_value = quote!( <#entity as sea_orm::EntityTrait>::Column:: #uppercase_ident);
225-
let ident_stringified = ident.unraw().to_string();
226-
quote!(let #select_ident =
227-
if let Some(prefix) = pre {
228-
let ident = format!("{prefix}{}", #ident_stringified);
229-
sea_orm::SelectColumns::select_column_as(#select_ident, #col_value, ident)
230-
} else {
231-
sea_orm::SelectColumns::select_column_as(#select_ident, #col_value, #ident_stringified)
232-
};
233-
)
234-
},
235224
ColumnAs::ColAlias { col, field } => {
236-
let field = field.to_string();
225+
let field = field.unraw().to_string();
237226
let entity = entity.as_ref().unwrap();
238-
let col_value = quote!( <#entity as sea_orm::EntityTrait>::Column:: #col);
227+
let col_name = if let Some(col) = col {
228+
col
229+
} else {
230+
&format_ident!("{}", field.to_upper_camel_case())
231+
};
232+
let col_value = if let Some(alias) = alias {
233+
quote!( Expr::col((Alias::new(#alias), <#entity as sea_orm::EntityTrait>::Column:: #col_name)) )
234+
} else {
235+
quote!( <#entity as sea_orm::EntityTrait>::Column:: #col_name)
236+
};
239237
quote!(let #select_ident =
240-
if let Some(prefix) = pre {
241-
let ident = format!("{prefix}{}", #field);
242-
sea_orm::SelectColumns::select_column_as(#select_ident, #col_value, ident)
243-
} else {
244-
sea_orm::SelectColumns::select_column_as(#select_ident, #col_value, #field)
245-
};
238+
if let Some(prefix) = pre {
239+
let ident = format!("{prefix}{}", #field);
240+
sea_orm::SelectColumns::select_column_as(#select_ident, #col_value, ident)
241+
} else {
242+
sea_orm::SelectColumns::select_column_as(#select_ident, #col_value, #field)
243+
};
246244
)
247-
},
245+
}
248246
ColumnAs::Expr { expr, field } => {
249-
let field = field.to_string();
247+
let field = field.unraw().to_string();
250248
quote!(let #select_ident =
251249
if let Some(prefix) = pre {
252250
let ident = format!("{prefix}{}", #field);
@@ -255,19 +253,19 @@ impl DerivePartialModel {
255253
sea_orm::SelectColumns::select_column_as(#select_ident, #expr, #field)
256254
};
257255
)
258-
},
256+
}
259257
ColumnAs::Nested { typ, field } => {
260-
let field = field.to_string();
258+
let field = field.unraw().to_string();
261259
quote!(let #select_ident =
262260
<#typ as sea_orm::PartialModelTrait>::select_cols_nested(#select_ident,
263261
Some(&if let Some(prefix) = pre {
264-
format!("{prefix}{}_", #field) }
262+
format!("{prefix}{}_", #field) }
265263
else {
266264
format!("{}_", #field)
267265
}
268266
));
269267
)
270-
},
268+
}
271269
ColumnAs::Skip(_) => quote!(),
272270
});
273271

tests/partial_model_tests.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#![allow(unused_imports, dead_code)]
22

33
use entity::{Column, Entity};
4-
use sea_orm::{prelude::*, DerivePartialModel, FromQueryResult, Set};
4+
use sea_orm::{
5+
prelude::*, sea_query::Alias, DerivePartialModel, FromQueryResult, JoinType, QuerySelect, Set,
6+
};
57

68
use crate::common::TestContext;
79
use common::bakery_chain::*;
@@ -172,6 +174,51 @@ async fn partial_model_left_join_exists() {
172174
ctx.delete().await;
173175
}
174176

177+
#[derive(DerivePartialModel)]
178+
#[sea_orm(entity = "bakery::Entity", alias = "factory", from_query_result)]
179+
struct Factory {
180+
id: i32,
181+
#[sea_orm(from_col = "Name")]
182+
plant: String,
183+
}
184+
185+
#[derive(DerivePartialModel)]
186+
#[sea_orm(entity = "cake::Entity", from_query_result)]
187+
struct CakeFactory {
188+
id: i32,
189+
name: String,
190+
#[sea_orm(nested)]
191+
bakery: Option<Factory>,
192+
}
193+
194+
#[sea_orm_macros::test]
195+
async fn partial_model_left_join_alias() {
196+
// SELECT "cake"."id" AS "id", "cake"."name" AS "name", "factory"."id" AS "bakery_id", "factory"."name" AS "bakery_plant" FROM "cake" LEFT JOIN "bakery" AS "factory" ON "cake"."bakery_id" = "factory"."id" LIMIT 1
197+
let ctx = TestContext::new("partial_model_left_join_alias").await;
198+
create_tables(&ctx.db).await.unwrap();
199+
200+
fill_data(&ctx, true).await;
201+
202+
let cake: CakeFactory = cake::Entity::find()
203+
.join_as(
204+
JoinType::LeftJoin,
205+
cake::Relation::Bakery.def(),
206+
Alias::new("factory"),
207+
)
208+
.into_partial_model()
209+
.one(&ctx.db)
210+
.await
211+
.expect("succeeds to get the result")
212+
.expect("exactly one model in DB");
213+
214+
assert_eq!(cake.id, 13);
215+
assert_eq!(cake.name, "Test Cake");
216+
assert!(matches!(cake.bakery, Some(Factory { id: 42, .. })));
217+
assert_eq!(cake.bakery.unwrap().plant, "cool little bakery");
218+
219+
ctx.delete().await;
220+
}
221+
175222
#[sea_orm_macros::test]
176223
async fn partial_model_flat() {
177224
let ctx = TestContext::new("partial_model_flat").await;
@@ -194,6 +241,7 @@ async fn partial_model_flat() {
194241

195242
#[sea_orm_macros::test]
196243
async fn partial_model_nested() {
244+
// SELECT "bakery"."id" AS "basics_id", "bakery"."name" AS "basics_title", "bakery"."profit_margin" AS "profit" FROM "bakery" LIMIT 1
197245
let ctx = TestContext::new("partial_model_nested").await;
198246
create_tables(&ctx.db).await.unwrap();
199247

0 commit comments

Comments
 (0)