Skip to main content

reinhardt_query/types/
table_ref.rs

1//! Table reference types for SQL queries.
2//!
3//! This module provides types for referencing tables:
4//!
5//! - [`TableRef`]: Reference to a table (simple, qualified, aliased, subquery)
6//! - [`IntoTableRef`]: Conversion trait for table references
7
8use super::iden::{DynIden, IntoIden};
9
10/// Reference to a table in a SQL query.
11///
12/// This enum represents different ways to reference a table,
13/// from simple table names to subqueries.
14#[derive(Debug, Clone)]
15pub enum TableRef {
16	/// Simple table reference (e.g., `users`)
17	Table(DynIden),
18	/// Schema-qualified table reference (e.g., `public.users`)
19	SchemaTable(DynIden, DynIden),
20	/// Database, schema, and table reference (e.g., `mydb.public.users`)
21	DatabaseSchemaTable(DynIden, DynIden, DynIden),
22	/// Table with alias (e.g., `users AS u`)
23	TableAlias(DynIden, DynIden),
24	/// Schema-qualified table with alias (e.g., `public.users AS u`)
25	SchemaTableAlias(DynIden, DynIden, DynIden),
26	/// Subquery with alias (e.g., `(SELECT ...) AS alias`)
27	SubQuery(Box<crate::query::SelectStatement>, DynIden),
28}
29
30impl TableRef {
31	/// Create a simple table reference.
32	///
33	/// # Example
34	///
35	/// ```rust
36	/// use reinhardt_query::TableRef;
37	///
38	/// let table = TableRef::table("users");
39	/// ```
40	pub fn table<I: IntoIden>(table: I) -> Self {
41		Self::Table(table.into_iden())
42	}
43
44	/// Create a schema-qualified table reference.
45	///
46	/// # Example
47	///
48	/// ```rust
49	/// use reinhardt_query::TableRef;
50	///
51	/// let table = TableRef::schema_table("public", "users");
52	/// ```
53	pub fn schema_table<S: IntoIden, T: IntoIden>(schema: S, table: T) -> Self {
54		Self::SchemaTable(schema.into_iden(), table.into_iden())
55	}
56
57	/// Create a database, schema, and table reference.
58	///
59	/// # Example
60	///
61	/// ```rust
62	/// use reinhardt_query::TableRef;
63	///
64	/// let table = TableRef::database_schema_table("mydb", "public", "users");
65	/// ```
66	pub fn database_schema_table<D: IntoIden, S: IntoIden, T: IntoIden>(
67		database: D,
68		schema: S,
69		table: T,
70	) -> Self {
71		Self::DatabaseSchemaTable(database.into_iden(), schema.into_iden(), table.into_iden())
72	}
73
74	/// Create a table reference with an alias.
75	///
76	/// # Example
77	///
78	/// ```rust
79	/// use reinhardt_query::TableRef;
80	///
81	/// let table = TableRef::table_alias("users", "u");
82	/// ```
83	pub fn table_alias<T: IntoIden, A: IntoIden>(table: T, alias: A) -> Self {
84		Self::TableAlias(table.into_iden(), alias.into_iden())
85	}
86
87	/// Create a schema-qualified table reference with an alias.
88	///
89	/// # Example
90	///
91	/// ```rust
92	/// use reinhardt_query::TableRef;
93	///
94	/// let table = TableRef::schema_table_alias("public", "users", "u");
95	/// ```
96	pub fn schema_table_alias<S: IntoIden, T: IntoIden, A: IntoIden>(
97		schema: S,
98		table: T,
99		alias: A,
100	) -> Self {
101		Self::SchemaTableAlias(schema.into_iden(), table.into_iden(), alias.into_iden())
102	}
103}
104
105/// Conversion trait for table references.
106///
107/// This trait allows various types to be converted into `TableRef`.
108pub trait IntoTableRef {
109	/// Convert this type into a `TableRef`.
110	fn into_table_ref(self) -> TableRef;
111}
112
113// Implementation for TableRef itself
114impl IntoTableRef for TableRef {
115	fn into_table_ref(self) -> TableRef {
116		self
117	}
118}
119
120// Implementation for DynIden (simple table reference)
121impl IntoTableRef for DynIden {
122	fn into_table_ref(self) -> TableRef {
123		TableRef::Table(self)
124	}
125}
126
127// Implementation for &'static str (simple table reference)
128impl IntoTableRef for &'static str {
129	fn into_table_ref(self) -> TableRef {
130		TableRef::Table(self.into_iden())
131	}
132}
133
134// Implementation for String (simple table reference)
135impl IntoTableRef for String {
136	fn into_table_ref(self) -> TableRef {
137		TableRef::Table(self.into_iden())
138	}
139}
140
141// Implementation for tuple (schema, table)
142impl<S, T> IntoTableRef for (S, T)
143where
144	S: IntoIden,
145	T: IntoIden,
146{
147	fn into_table_ref(self) -> TableRef {
148		TableRef::SchemaTable(self.0.into_iden(), self.1.into_iden())
149	}
150}
151
152// Implementation for triple (database, schema, table)
153impl<D, S, T> IntoTableRef for (D, S, T)
154where
155	D: IntoIden,
156	S: IntoIden,
157	T: IntoIden,
158{
159	fn into_table_ref(self) -> TableRef {
160		TableRef::DatabaseSchemaTable(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
161	}
162}
163
164// Implementation for Alias
165impl IntoTableRef for super::alias::Alias {
166	fn into_table_ref(self) -> TableRef {
167		TableRef::Table(self.into_iden())
168	}
169}
170
171#[cfg(test)]
172mod tests {
173	use super::*;
174	use crate::types::Alias;
175	use rstest::rstest;
176
177	#[rstest]
178	fn test_table_ref_simple() {
179		let table = TableRef::table("users");
180		if let TableRef::Table(iden) = table {
181			assert_eq!(iden.to_string(), "users");
182		} else {
183			panic!("Expected Table variant");
184		}
185	}
186
187	#[rstest]
188	fn test_table_ref_schema_qualified() {
189		let table = TableRef::schema_table("public", "users");
190		if let TableRef::SchemaTable(schema, tbl) = table {
191			assert_eq!(schema.to_string(), "public");
192			assert_eq!(tbl.to_string(), "users");
193		} else {
194			panic!("Expected SchemaTable variant");
195		}
196	}
197
198	#[rstest]
199	fn test_table_ref_database_schema_qualified() {
200		let table = TableRef::database_schema_table("mydb", "public", "users");
201		if let TableRef::DatabaseSchemaTable(db, schema, tbl) = table {
202			assert_eq!(db.to_string(), "mydb");
203			assert_eq!(schema.to_string(), "public");
204			assert_eq!(tbl.to_string(), "users");
205		} else {
206			panic!("Expected DatabaseSchemaTable variant");
207		}
208	}
209
210	#[rstest]
211	fn test_table_ref_with_alias() {
212		let table = TableRef::table_alias("users", "u");
213		if let TableRef::TableAlias(tbl, alias) = table {
214			assert_eq!(tbl.to_string(), "users");
215			assert_eq!(alias.to_string(), "u");
216		} else {
217			panic!("Expected TableAlias variant");
218		}
219	}
220
221	#[rstest]
222	fn test_table_ref_schema_with_alias() {
223		let table = TableRef::schema_table_alias("public", "users", "u");
224		if let TableRef::SchemaTableAlias(schema, tbl, alias) = table {
225			assert_eq!(schema.to_string(), "public");
226			assert_eq!(tbl.to_string(), "users");
227			assert_eq!(alias.to_string(), "u");
228		} else {
229			panic!("Expected SchemaTableAlias variant");
230		}
231	}
232
233	#[rstest]
234	fn test_into_table_ref_from_str() {
235		let table: TableRef = "users".into_table_ref();
236		if let TableRef::Table(iden) = table {
237			assert_eq!(iden.to_string(), "users");
238		} else {
239			panic!("Expected Table variant");
240		}
241	}
242
243	#[rstest]
244	fn test_into_table_ref_from_alias() {
245		let alias = Alias::new("my_table");
246		let table: TableRef = alias.into_table_ref();
247		if let TableRef::Table(iden) = table {
248			assert_eq!(iden.to_string(), "my_table");
249		} else {
250			panic!("Expected Table variant");
251		}
252	}
253}