Skip to main content

reinhardt_query/types/
column_ref.rs

1//! Column reference types for SQL queries.
2//!
3//! This module provides types for referencing columns:
4//!
5//! - [`ColumnRef`]: Reference to a column (simple, qualified, asterisk)
6//! - [`IntoColumnRef`]: Conversion trait for column references
7
8use super::iden::{DynIden, IntoIden};
9
10/// Reference to a column in a SQL query.
11///
12/// This enum represents different ways to reference a column,
13/// from simple column names to fully qualified references.
14#[derive(Debug, Clone)]
15pub enum ColumnRef {
16	/// Simple column reference (e.g., `name`)
17	Column(DynIden),
18	/// Table-qualified column reference (e.g., `users.name`)
19	TableColumn(DynIden, DynIden),
20	/// Schema and table-qualified column reference (e.g., `public.users.name`)
21	SchemaTableColumn(DynIden, DynIden, DynIden),
22	/// Asterisk for selecting all columns (e.g., `*`)
23	Asterisk,
24	/// Table-qualified asterisk (e.g., `users.*`)
25	TableAsterisk(DynIden),
26}
27
28impl ColumnRef {
29	/// Create a simple column reference.
30	///
31	/// # Example
32	///
33	/// ```rust
34	/// use reinhardt_query::ColumnRef;
35	///
36	/// let col = ColumnRef::column("name");
37	/// ```
38	pub fn column<I: IntoIden>(column: I) -> Self {
39		Self::Column(column.into_iden())
40	}
41
42	/// Create a table-qualified column reference.
43	///
44	/// # Example
45	///
46	/// ```rust
47	/// use reinhardt_query::ColumnRef;
48	///
49	/// let col = ColumnRef::table_column("users", "name");
50	/// ```
51	pub fn table_column<T: IntoIden, C: IntoIden>(table: T, column: C) -> Self {
52		Self::TableColumn(table.into_iden(), column.into_iden())
53	}
54
55	/// Create a schema and table-qualified column reference.
56	///
57	/// # Example
58	///
59	/// ```rust
60	/// use reinhardt_query::ColumnRef;
61	///
62	/// let col = ColumnRef::schema_table_column("public", "users", "name");
63	/// ```
64	pub fn schema_table_column<S: IntoIden, T: IntoIden, C: IntoIden>(
65		schema: S,
66		table: T,
67		column: C,
68	) -> Self {
69		Self::SchemaTableColumn(schema.into_iden(), table.into_iden(), column.into_iden())
70	}
71
72	/// Create an asterisk reference for all columns.
73	///
74	/// # Example
75	///
76	/// ```rust
77	/// use reinhardt_query::ColumnRef;
78	///
79	/// let col = ColumnRef::asterisk();
80	/// ```
81	pub fn asterisk() -> Self {
82		Self::Asterisk
83	}
84
85	/// Create a table-qualified asterisk reference.
86	///
87	/// # Example
88	///
89	/// ```rust
90	/// use reinhardt_query::ColumnRef;
91	///
92	/// let col = ColumnRef::table_asterisk("users");
93	/// ```
94	pub fn table_asterisk<T: IntoIden>(table: T) -> Self {
95		Self::TableAsterisk(table.into_iden())
96	}
97}
98
99/// Conversion trait for column references.
100///
101/// This trait allows various types to be converted into `ColumnRef`.
102pub trait IntoColumnRef {
103	/// Convert this type into a `ColumnRef`.
104	fn into_column_ref(self) -> ColumnRef;
105}
106
107// Implementation for ColumnRef itself
108impl IntoColumnRef for ColumnRef {
109	fn into_column_ref(self) -> ColumnRef {
110		self
111	}
112}
113
114// Blanket implementation for all types that can be converted to an identifier.
115// This covers DynIden, &'static str, String, Alias, and any #[derive(Iden)] enum.
116impl<T: IntoIden> IntoColumnRef for T {
117	fn into_column_ref(self) -> ColumnRef {
118		ColumnRef::Column(self.into_iden())
119	}
120}
121
122// Implementation for tuple (table, column)
123impl<T, C> IntoColumnRef for (T, C)
124where
125	T: IntoIden,
126	C: IntoIden,
127{
128	fn into_column_ref(self) -> ColumnRef {
129		ColumnRef::TableColumn(self.0.into_iden(), self.1.into_iden())
130	}
131}
132
133// Implementation for triple (schema, table, column)
134impl<S, T, C> IntoColumnRef for (S, T, C)
135where
136	S: IntoIden,
137	T: IntoIden,
138	C: IntoIden,
139{
140	fn into_column_ref(self) -> ColumnRef {
141		ColumnRef::SchemaTableColumn(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
142	}
143}
144
145#[cfg(test)]
146mod tests {
147	use super::*;
148	use crate::types::Alias;
149	use rstest::rstest;
150
151	#[rstest]
152	fn test_column_ref_simple() {
153		let col = ColumnRef::column("name");
154		if let ColumnRef::Column(iden) = col {
155			assert_eq!(iden.to_string(), "name");
156		} else {
157			panic!("Expected Column variant");
158		}
159	}
160
161	#[rstest]
162	fn test_column_ref_table_qualified() {
163		let col = ColumnRef::table_column("users", "name");
164		if let ColumnRef::TableColumn(table, column) = col {
165			assert_eq!(table.to_string(), "users");
166			assert_eq!(column.to_string(), "name");
167		} else {
168			panic!("Expected TableColumn variant");
169		}
170	}
171
172	#[rstest]
173	fn test_column_ref_schema_qualified() {
174		let col = ColumnRef::schema_table_column("public", "users", "name");
175		if let ColumnRef::SchemaTableColumn(schema, table, column) = col {
176			assert_eq!(schema.to_string(), "public");
177			assert_eq!(table.to_string(), "users");
178			assert_eq!(column.to_string(), "name");
179		} else {
180			panic!("Expected SchemaTableColumn variant");
181		}
182	}
183
184	#[rstest]
185	fn test_column_ref_asterisk() {
186		let col = ColumnRef::asterisk();
187		assert!(matches!(col, ColumnRef::Asterisk));
188	}
189
190	#[rstest]
191	fn test_column_ref_table_asterisk() {
192		let col = ColumnRef::table_asterisk("users");
193		if let ColumnRef::TableAsterisk(table) = col {
194			assert_eq!(table.to_string(), "users");
195		} else {
196			panic!("Expected TableAsterisk variant");
197		}
198	}
199
200	#[rstest]
201	fn test_into_column_ref_from_str() {
202		let col: ColumnRef = "name".into_column_ref();
203		if let ColumnRef::Column(iden) = col {
204			assert_eq!(iden.to_string(), "name");
205		} else {
206			panic!("Expected Column variant");
207		}
208	}
209
210	#[rstest]
211	fn test_into_column_ref_from_alias() {
212		let alias = Alias::new("my_column");
213		let col: ColumnRef = alias.into_column_ref();
214		if let ColumnRef::Column(iden) = col {
215			assert_eq!(iden.to_string(), "my_column");
216		} else {
217			panic!("Expected Column variant");
218		}
219	}
220}