1use sql_orm_core::{Entity, EntityColumn};
2use sql_orm_query::{ColumnRef, Expr, SelectProjection, TableRef};
3use std::marker::PhantomData;
4
5#[derive(Debug)]
7pub struct AliasedEntityColumn<E: Entity> {
8 rust_field: &'static str,
9 column_name: &'static str,
10 alias: &'static str,
11 _entity: PhantomData<fn() -> E>,
12}
13
14impl<E: Entity> Copy for AliasedEntityColumn<E> {}
15
16impl<E: Entity> Clone for AliasedEntityColumn<E> {
17 fn clone(&self) -> Self {
18 *self
19 }
20}
21
22impl<E: Entity> PartialEq for AliasedEntityColumn<E> {
23 fn eq(&self, other: &Self) -> bool {
24 self.rust_field == other.rust_field
25 && self.column_name == other.column_name
26 && self.alias == other.alias
27 }
28}
29
30impl<E: Entity> Eq for AliasedEntityColumn<E> {}
31
32impl<E: Entity> AliasedEntityColumn<E> {
33 pub const fn new(column: EntityColumn<E>, alias: &'static str) -> Self {
34 Self {
35 rust_field: column.rust_field(),
36 column_name: column.column_name(),
37 alias,
38 _entity: PhantomData,
39 }
40 }
41
42 pub const fn column(&self) -> EntityColumn<E> {
43 EntityColumn::new(self.rust_field, self.column_name)
44 }
45
46 pub const fn alias(&self) -> &'static str {
47 self.alias
48 }
49
50 pub fn column_ref(self) -> ColumnRef {
51 ColumnRef::new(
52 TableRef::for_entity_as::<E>(self.alias),
53 self.rust_field,
54 self.column_name,
55 )
56 }
57
58 pub fn expr(self) -> Expr {
59 Expr::Column(self.column_ref())
60 }
61
62 pub fn table_ref(self) -> TableRef {
63 TableRef::for_entity_as::<E>(self.alias)
64 }
65}
66
67impl<E: Entity> From<AliasedEntityColumn<E>> for ColumnRef {
68 fn from(value: AliasedEntityColumn<E>) -> Self {
69 value.column_ref()
70 }
71}
72
73impl<E: Entity> From<AliasedEntityColumn<E>> for Expr {
74 fn from(value: AliasedEntityColumn<E>) -> Self {
75 value.expr()
76 }
77}
78
79impl<E: Entity> From<AliasedEntityColumn<E>> for SelectProjection {
80 fn from(value: AliasedEntityColumn<E>) -> Self {
81 let column_name = value.column_name;
82 SelectProjection::expr_as(value.expr(), column_name)
83 }
84}
85
86pub trait EntityColumnAliasExt<E: Entity> {
87 fn aliased(self, alias: &'static str) -> AliasedEntityColumn<E>;
88}
89
90impl<E: Entity> EntityColumnAliasExt<E> for EntityColumn<E> {
91 fn aliased(self, alias: &'static str) -> AliasedEntityColumn<E> {
92 AliasedEntityColumn::new(self, alias)
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::{AliasedEntityColumn, EntityColumnAliasExt};
99 use sql_orm_core::{
100 ColumnMetadata, Entity, EntityColumn, EntityMetadata, PrimaryKeyMetadata, SqlServerType,
101 };
102 use sql_orm_query::{ColumnRef, Expr, SelectProjection, TableRef};
103
104 struct TestEntity;
105
106 static TEST_ENTITY_COLUMNS: [ColumnMetadata; 1] = [ColumnMetadata {
107 rust_field: "name",
108 column_name: "name",
109 renamed_from: None,
110 sql_type: SqlServerType::NVarChar,
111 nullable: false,
112 primary_key: true,
113 identity: None,
114 default_sql: None,
115 computed_sql: None,
116 rowversion: false,
117 insertable: false,
118 updatable: false,
119 max_length: Some(120),
120 precision: None,
121 scale: None,
122 }];
123
124 static TEST_ENTITY_METADATA: EntityMetadata = EntityMetadata {
125 rust_name: "TestEntity",
126 schema: "dbo",
127 table: "test_entities",
128 renamed_from: None,
129 columns: &TEST_ENTITY_COLUMNS,
130 primary_key: PrimaryKeyMetadata {
131 name: None,
132 columns: &["name"],
133 },
134 indexes: &[],
135 foreign_keys: &[],
136 navigations: &[],
137 };
138
139 impl Entity for TestEntity {
140 fn metadata() -> &'static EntityMetadata {
141 &TEST_ENTITY_METADATA
142 }
143 }
144
145 #[allow(non_upper_case_globals)]
146 impl TestEntity {
147 const name: EntityColumn<TestEntity> = EntityColumn::new("name", "name");
148 }
149
150 #[test]
151 fn entity_column_can_be_bound_to_table_alias() {
152 let aliased: AliasedEntityColumn<TestEntity> = TestEntity::name.aliased("t");
153
154 assert_eq!(aliased.alias(), "t");
155 assert_eq!(aliased.column().rust_field(), TestEntity::name.rust_field());
156 assert_eq!(
157 aliased.column().column_name(),
158 TestEntity::name.column_name()
159 );
160 assert_eq!(
161 aliased.table_ref(),
162 TableRef::with_alias("dbo", "test_entities", "t")
163 );
164 assert_eq!(
165 aliased.column_ref(),
166 ColumnRef::new(
167 TableRef::with_alias("dbo", "test_entities", "t"),
168 "name",
169 "name"
170 )
171 );
172 assert_eq!(Expr::from(aliased), Expr::Column(aliased.column_ref()));
173 assert_eq!(
174 SelectProjection::from(aliased),
175 SelectProjection::expr_as(Expr::Column(aliased.column_ref()), "name")
176 );
177 }
178}