1pub mod from_value;
4pub mod marker;
5pub mod row_access;
6pub mod typed;
7
8pub use from_value::FromValue;
9pub use marker::ColumnMarker;
10pub use row_access::RowAccess;
11pub use typed::{Column, OrderField, SelectColumns};
12
13#[cfg(test)]
14mod tests {
15 use std::borrow::Cow;
16
17 use super::*;
18 use crate::expr::Expr;
19 use crate::select::OrderDir;
20 use crate::value::Value;
21
22 #[test]
23 fn test_column_new() {
24 let col: Column<i64> = Column::new("users", "id");
25 assert_eq!(col.table(), "users");
26 assert_eq!(col.name(), "id");
27
28 let col: Column<String> = Column::new("users", "email");
29 assert_eq!(col.table(), "users");
30 assert_eq!(col.name(), "email");
31 }
32
33 #[test]
34 fn test_column_alias() {
35 let col: Column<i64> = Column::new("users", "id");
36 assert_eq!(col.alias(), "users__id");
37
38 let col: Column<String> = Column::new("posts", "title");
39 assert_eq!(col.alias(), "posts__title");
40 }
41
42 #[test]
43 fn test_column_marker() {
44 let col: Column<i64> = Column::new("users", "id");
45 let marker = col.marker();
46 assert_eq!(marker.table, "users");
47 assert_eq!(marker.name, "id");
48 assert!(matches!(marker.table, Cow::Borrowed("users")));
49 assert!(matches!(marker.name, Cow::Borrowed("id")));
50 }
51
52 #[test]
53 fn test_column_to_expr() {
54 let col: Column<i64> = Column::new("users", "id");
55 let expr: Expr = col.into();
56 assert_eq!(expr, Expr::Column("users__id".to_string()));
57 }
58
59 #[test]
60 fn test_eq_operator() {
61 let col: Column<i64> = Column::new("users", "id");
62 let expr = col.eq(42i64);
63 assert_eq!(
64 expr,
65 Expr::column("users__id").eq(Expr::param(Value::I64(42)))
66 );
67 }
68
69 #[test]
70 fn test_eq_operator_string() {
71 let col: Column<String> = Column::new("users", "email");
72 let expr = col.eq("test@example.com");
73 assert_eq!(
74 expr,
75 Expr::column("users__email")
76 .eq(Expr::param(Value::String("test@example.com".to_string())))
77 );
78 }
79
80 #[test]
81 fn test_desc_order() {
82 let col: Column<String> = Column::new("users", "email");
83 let order = col.desc();
84 assert_eq!(order.column, "users__email");
85 assert_eq!(order.direction, OrderDir::Desc);
86 }
87
88 #[test]
89 fn test_asc_order() {
90 let col: Column<i64> = Column::new("users", "id");
91 let order = col.asc();
92 assert_eq!(order.column, "users__id");
93 assert_eq!(order.direction, OrderDir::Asc);
94 }
95
96 #[test]
97 fn test_nested_order_field() {
98 let field: OrderField<i32> = OrderField::new("shipments", "delivery.etaMinutes");
99 assert_eq!(field.table(), "shipments");
100 assert_eq!(field.path(), "delivery.etaMinutes");
101
102 let order = field.asc();
103 assert_eq!(order.column, "shipments__delivery.etaMinutes");
104 assert_eq!(order.direction, OrderDir::Asc);
105 }
106
107 #[test]
108 fn test_ends_with() {
109 let col: Column<String> = Column::new("users", "email");
110 let expr = col.ends_with("example.com");
111 assert_eq!(
112 expr,
113 Expr::column("users__email")
114 .like(Expr::param(Value::String("%example.com".to_string())))
115 );
116 }
117
118 #[test]
119 fn test_starts_with() {
120 let col: Column<String> = Column::new("users", "email");
121 let expr = col.starts_with("admin");
122 assert_eq!(
123 expr,
124 Expr::column("users__email").like(Expr::param(Value::String("admin%".to_string())))
125 );
126 }
127
128 #[test]
129 fn test_contains() {
130 let col: Column<String> = Column::new("users", "email");
131 let expr = col.contains("example");
132 assert_eq!(
133 expr,
134 Expr::column("users__email").like(Expr::param(Value::String("%example%".to_string())))
135 );
136 }
137
138 #[test]
139 fn test_from_value_i64() {
140 assert_eq!(i64::from_value(&Value::I64(42)).unwrap(), 42);
141 assert!(i64::from_value(&Value::Null).is_err());
142 assert!(i64::from_value(&Value::String("test".to_string())).is_err());
143 }
144
145 #[test]
146 fn test_from_value_string() {
147 assert_eq!(
148 String::from_value(&Value::String("test".to_string())).unwrap(),
149 "test"
150 );
151 assert!(String::from_value(&Value::Null).is_err());
152 assert!(String::from_value(&Value::I64(42)).is_err());
153 }
154
155 #[test]
156 fn test_from_value_bool() {
157 assert!(bool::from_value(&Value::Bool(true)).unwrap());
158 assert!(!bool::from_value(&Value::Bool(false)).unwrap());
159 assert!(bool::from_value(&Value::I64(1)).unwrap());
160 assert!(!bool::from_value(&Value::I64(0)).unwrap());
161 assert!(bool::from_value(&Value::Null).is_err());
162 assert!(bool::from_value(&Value::I64(2)).is_err());
163 }
164
165 #[test]
166 fn test_select_columns_single() {
167 let selection = (Column::<i64>::new("users", "id"),);
168 let columns = selection.columns();
169 assert_eq!(columns.len(), 1);
170 assert_eq!(columns[0].table, "users");
171 assert_eq!(columns[0].name, "id");
172 }
173
174 #[test]
175 fn test_select_columns_two() {
176 let selection = (
177 Column::<i64>::new("users", "id"),
178 Column::<String>::new("users", "email"),
179 );
180 let columns = selection.columns();
181 assert_eq!(columns.len(), 2);
182 assert_eq!(columns[0].table, "users");
183 assert_eq!(columns[0].name, "id");
184 assert_eq!(columns[1].table, "users");
185 assert_eq!(columns[1].name, "email");
186 }
187
188 #[test]
189 fn test_select_columns_multiple_tables() {
190 let selection = (
191 Column::<i64>::new("users", "id"),
192 Column::<String>::new("posts", "title"),
193 );
194 let columns = selection.columns();
195 assert_eq!(columns.len(), 2);
196 assert_eq!(columns[0].table, "users");
197 assert_eq!(columns[0].name, "id");
198 assert_eq!(columns[1].table, "posts");
199 assert_eq!(columns[1].name, "title");
200 }
201
202 #[test]
203 fn test_column_copy() {
204 let col1: Column<i64> = Column::new("users", "id");
205 let col2 = col1;
206 let col3 = col1;
207 assert_eq!(col1.name(), col2.name());
208 assert_eq!(col2.name(), col3.name());
209 }
210
211 #[test]
212 fn test_column_marker_from() {
213 let col: Column<i64> = Column::new("users", "id");
214 let marker: ColumnMarker = col.into();
215 assert_eq!(marker.table, "users");
216 assert_eq!(marker.name, "id");
217 }
218
219 #[test]
220 fn test_column_marker_alias() {
221 let marker = ColumnMarker::new("users", "id");
222 assert_eq!(marker.alias(), "users__id");
223
224 let marker = ColumnMarker::new("posts", "title");
225 assert_eq!(marker.alias(), "posts__title");
226 }
227
228 #[test]
229 fn test_dynamic_column_marker_owns_runtime_strings() {
230 let table = String::from("users");
231 let name = String::from("email");
232 let marker = ColumnMarker::new(table, name);
233
234 assert!(matches!(marker.table, Cow::Owned(_)));
235 assert!(matches!(marker.name, Cow::Owned(_)));
236 }
237
238 struct MockRow {
239 values: Vec<Value>,
240 }
241
242 impl<'row> RowAccess<'row> for MockRow {
243 fn get_by_pos(&'row self, idx: usize) -> Option<&'row Value> {
244 self.values.get(idx)
245 }
246
247 fn get(&'row self, _name: &str) -> Option<&'row Value> {
248 None
249 }
250
251 fn column_name(&'row self, _idx: usize) -> Option<&'row str> {
252 None
253 }
254
255 fn len(&self) -> usize {
256 self.values.len()
257 }
258 }
259
260 #[test]
261 fn test_select_columns_decode_single() {
262 let selection = (Column::<i64>::new("users", "id"),);
263 let mock_row = MockRow {
264 values: vec![Value::I64(42)],
265 };
266
267 let result = selection.decode(&mock_row).unwrap();
268 assert_eq!(result, (42,));
269 }
270
271 #[test]
272 fn test_select_columns_decode_two() {
273 let selection = (
274 Column::<i64>::new("users", "id"),
275 Column::<String>::new("users", "email"),
276 );
277 let mock_row = MockRow {
278 values: vec![
279 Value::I64(42),
280 Value::String("test@example.com".to_string()),
281 ],
282 };
283
284 let result = selection.decode(&mock_row).unwrap();
285 assert_eq!(result, (42, "test@example.com".to_string()));
286 }
287
288 #[test]
289 fn test_select_columns_decode_three() {
290 let selection = (
291 Column::<i64>::new("users", "id"),
292 Column::<String>::new("users", "email"),
293 Column::<bool>::new("users", "active"),
294 );
295 let mock_row = MockRow {
296 values: vec![
297 Value::I64(99),
298 Value::String("admin@example.com".to_string()),
299 Value::Bool(true),
300 ],
301 };
302
303 let result = selection.decode(&mock_row).unwrap();
304 assert_eq!(result, (99, "admin@example.com".to_string(), true));
305 }
306
307 #[test]
308 fn test_select_columns_decode_missing_column() {
309 let selection = (
310 Column::<i64>::new("users", "id"),
311 Column::<String>::new("users", "email"),
312 );
313 let mock_row = MockRow {
314 values: vec![Value::I64(42)],
315 };
316
317 let result = selection.decode(&mock_row);
318 assert!(result.is_err());
319 }
320
321 #[test]
322 fn test_select_columns_decode_type_error() {
323 let selection = (Column::<i64>::new("users", "id"),);
324 let mock_row = MockRow {
325 values: vec![Value::String("not a number".to_string())],
326 };
327
328 let result = selection.decode(&mock_row);
329 assert!(result.is_err());
330 }
331}