Skip to main content

reinhardt_db/orm/
annotation.rs

1use super::postgres_features::{ArrayAgg, JsonbAgg, JsonbBuildObject, StringAgg, TsRank};
2use crate::orm::aggregation::Aggregate;
3use crate::orm::expressions::{F, Q};
4use crate::orm::query::quote_identifier;
5use serde::{Deserialize, Serialize};
6
7/// Represents an annotation value that can be added to a QuerySet
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub enum AnnotationValue {
10	/// A constant value
11	Value(Value),
12	/// A field reference (F expression)
13	Field(F),
14	/// An aggregation function
15	Aggregate(Aggregate),
16	/// A complex expression combining multiple values
17	Expression(Expression),
18	/// A subquery (scalar subquery in SELECT clause)
19	Subquery(String),
20	// PostgreSQL-specific aggregations
21	/// PostgreSQL array_agg - aggregates values into an array
22	ArrayAgg(ArrayAgg<serde_json::Value>),
23	/// PostgreSQL string_agg - concatenates strings with delimiter
24	StringAgg(StringAgg),
25	/// PostgreSQL jsonb_agg - aggregates values into a JSONB array
26	JsonbAgg(JsonbAgg),
27	/// PostgreSQL jsonb_build_object - builds a JSONB object from key-value pairs
28	JsonbBuildObject(JsonbBuildObject),
29	/// PostgreSQL ts_rank - full-text search ranking score
30	TsRank(TsRank),
31}
32
33/// Constant value types for annotations
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub enum Value {
36	/// String variant.
37	String(String),
38	/// Int variant.
39	Int(i64),
40	/// Float variant.
41	Float(f64),
42	/// Bool variant.
43	Bool(bool),
44	/// Null variant.
45	Null,
46}
47
48impl Value {
49	/// Documentation for `to_sql`
50	///
51	pub fn to_sql(&self) -> String {
52		match self {
53			Value::String(s) => format!("'{}'", s.replace('\'', "''")),
54			Value::Int(i) => i.to_string(),
55			Value::Float(f) => f.to_string(),
56			Value::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
57			Value::Null => "NULL".to_string(),
58		}
59	}
60}
61
62/// Expression types for complex annotations
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub enum Expression {
65	/// Addition: field1 + field2
66	Add(Box<AnnotationValue>, Box<AnnotationValue>),
67	/// Subtraction: field1 - field2
68	Subtract(Box<AnnotationValue>, Box<AnnotationValue>),
69	/// Multiplication: field1 * field2
70	Multiply(Box<AnnotationValue>, Box<AnnotationValue>),
71	/// Division: field1 / field2
72	Divide(Box<AnnotationValue>, Box<AnnotationValue>),
73	/// CASE WHEN expression
74	Case {
75		/// The whens.
76		whens: Vec<When>,
77		/// The default.
78		default: Option<Box<AnnotationValue>>,
79	},
80	/// COALESCE(field1, field2, ...)
81	Coalesce(Vec<AnnotationValue>),
82}
83
84/// WHEN clause for CASE expressions
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct When {
87	/// The condition.
88	pub condition: Q,
89	/// The then.
90	pub then: AnnotationValue,
91}
92
93impl When {
94	/// Create a WHEN clause for CASE expressions
95	///
96	/// # Examples
97	///
98	/// ```
99	/// use reinhardt_db::orm::annotation::{When, AnnotationValue, Value};
100	/// use reinhardt_db::orm::Q;
101	///
102	/// let when = When::new(
103	///     Q::new("status", "=", "active"),
104	///     AnnotationValue::Value(Value::Int(1))
105	/// );
106	/// // Verify the WHEN clause was created
107	/// let sql = when.to_sql();
108	/// assert!(sql.contains("WHEN"));
109	/// assert!(sql.contains("THEN"));
110	/// ```
111	pub fn new(condition: Q, then: AnnotationValue) -> Self {
112		Self { condition, then }
113	}
114	/// Documentation for `to_sql`
115	///
116	pub fn to_sql(&self) -> String {
117		format!(
118			"WHEN {} THEN {}",
119			self.condition.to_sql(),
120			self.then.to_sql()
121		)
122	}
123}
124
125/// Represents an annotation on a QuerySet
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct Annotation {
128	/// The alias.
129	pub alias: String,
130	/// The value.
131	pub value: AnnotationValue,
132}
133
134impl Annotation {
135	/// Create a new annotation to add computed fields to QuerySet results
136	///
137	/// # Examples
138	///
139	/// ```
140	/// use reinhardt_db::orm::annotation::{Annotation, AnnotationValue, Value};
141	///
142	/// let annotation = Annotation::new("total", AnnotationValue::Value(Value::Int(100)));
143	/// assert_eq!(annotation.alias, "total");
144	/// assert_eq!(annotation.to_sql(), "100 AS \"total\"");
145	/// ```
146	pub fn new(alias: impl Into<String>, value: AnnotationValue) -> Self {
147		Self {
148			alias: alias.into(),
149			value,
150		}
151	}
152	/// Documentation for `to_sql`
153	///
154	pub fn to_sql(&self) -> String {
155		format!(
156			"{} AS {}",
157			self.value.to_sql(),
158			quote_identifier(&self.alias)
159		)
160	}
161
162	/// Helper method for creating field-based annotations (convenience alias for `new`)
163	///
164	/// This is a convenience method that calls `Annotation::new()` with field-based annotation values.
165	pub fn field(alias: impl Into<String>, value: AnnotationValue) -> Self {
166		Self::new(alias, value)
167	}
168}
169
170impl AnnotationValue {
171	/// Documentation for `to_sql`
172	///
173	pub fn to_sql(&self) -> String {
174		match self {
175			AnnotationValue::Value(v) => v.to_sql(),
176			AnnotationValue::Field(f) => f.to_sql(),
177			AnnotationValue::Aggregate(a) => a.to_sql(),
178			AnnotationValue::Expression(e) => e.to_sql(),
179			AnnotationValue::Subquery(sql) => sql.clone(),
180			// PostgreSQL-specific aggregations
181			AnnotationValue::ArrayAgg(a) => a.to_sql(),
182			AnnotationValue::StringAgg(s) => s.to_sql(),
183			AnnotationValue::JsonbAgg(j) => j.to_sql(),
184			AnnotationValue::JsonbBuildObject(j) => j.to_sql(),
185			AnnotationValue::TsRank(t) => t.to_sql(),
186		}
187	}
188
189	/// Convert to SQL expression without alias (for use in SELECT with expr_as)
190	pub fn to_sql_expr(&self) -> String {
191		match self {
192			AnnotationValue::Value(v) => v.to_sql(),
193			AnnotationValue::Field(f) => f.to_sql(),
194			AnnotationValue::Aggregate(a) => a.to_sql_expr(), // Use to_sql_expr() for aggregates
195			AnnotationValue::Expression(e) => e.to_sql(),
196			AnnotationValue::Subquery(sql) => sql.clone(),
197			// PostgreSQL-specific aggregations (same as to_sql for these)
198			AnnotationValue::ArrayAgg(a) => a.to_sql(),
199			AnnotationValue::StringAgg(s) => s.to_sql(),
200			AnnotationValue::JsonbAgg(j) => j.to_sql(),
201			AnnotationValue::JsonbBuildObject(j) => j.to_sql(),
202			AnnotationValue::TsRank(t) => t.to_sql(),
203		}
204	}
205}
206
207impl Expression {
208	/// Documentation for `to_sql`
209	///
210	pub fn to_sql(&self) -> String {
211		match self {
212			Expression::Add(left, right) => {
213				format!("({} + {})", left.to_sql(), right.to_sql())
214			}
215			Expression::Subtract(left, right) => {
216				format!("({} - {})", left.to_sql(), right.to_sql())
217			}
218			Expression::Multiply(left, right) => {
219				format!("({} * {})", left.to_sql(), right.to_sql())
220			}
221			Expression::Divide(left, right) => {
222				format!("({} / {})", left.to_sql(), right.to_sql())
223			}
224			Expression::Case { whens, default } => {
225				let mut sql = String::from("CASE");
226				for when in whens {
227					sql.push(' ');
228					sql.push_str(&when.to_sql());
229				}
230				if let Some(default_val) = default {
231					sql.push_str(&format!(" ELSE {}", default_val.to_sql()));
232				}
233				sql.push_str(" END");
234				sql
235			}
236			Expression::Coalesce(values) => {
237				let values_sql: Vec<String> = values.iter().map(|v| v.to_sql()).collect();
238				format!("COALESCE({})", values_sql.join(", "))
239			}
240		}
241	}
242}
243
244#[cfg(test)]
245mod tests {
246	use super::*;
247
248	#[test]
249	fn test_value_annotation() {
250		let ann = Annotation::new("is_active", AnnotationValue::Value(Value::Bool(true)));
251		assert_eq!(ann.to_sql(), "TRUE AS \"is_active\"");
252	}
253
254	#[test]
255	fn test_field_annotation() {
256		let ann = Annotation::new("another_price", AnnotationValue::Field(F::new("price")));
257		assert_eq!(ann.to_sql(), "\"price\" AS \"another_price\"");
258	}
259
260	#[test]
261	fn test_annotation_aggregate() {
262		let agg = Aggregate::count(Some("id"));
263		let ann = Annotation::new("num_items", AnnotationValue::Aggregate(agg));
264		let sql = ann.to_sql();
265		assert!(
266			sql.contains("COUNT(id)") && sql.contains("AS \"num_items\""),
267			"SQL should contain 'COUNT(id) AS \"num_items\"'. Got: {}",
268			sql
269		);
270	}
271
272	#[test]
273	fn test_add_expression() {
274		let expr = Expression::Add(
275			Box::new(AnnotationValue::Field(F::new("price"))),
276			Box::new(AnnotationValue::Value(Value::Int(10))),
277		);
278		let ann = Annotation::new("new_price", AnnotationValue::Expression(expr));
279		assert_eq!(ann.to_sql(), "(\"price\" + 10) AS \"new_price\"");
280	}
281
282	#[test]
283	fn test_case_expression() {
284		let expr = Expression::Case {
285			whens: vec![When::new(
286				Q::new("age", ">=", "18"),
287				AnnotationValue::Value(Value::String("adult".into())),
288			)],
289			default: Some(Box::new(AnnotationValue::Value(Value::String(
290				"minor".into(),
291			)))),
292		};
293		let ann = Annotation::new("age_group", AnnotationValue::Expression(expr));
294		let sql = ann.to_sql();
295		assert!(
296			sql.starts_with("CASE") || sql.contains(" CASE "),
297			"SQL should contain CASE clause. Got: {}",
298			sql
299		);
300		assert!(
301			sql.contains("WHEN age >= 18 THEN 'adult'"),
302			"SQL should contain 'WHEN age >= 18 THEN 'adult''. Got: {}",
303			sql
304		);
305		assert!(
306			sql.contains("ELSE 'minor'"),
307			"SQL should contain 'ELSE 'minor''. Got: {}",
308			sql
309		);
310		assert!(
311			sql.ends_with("AS \"age_group\"") || sql.contains(" AS \"age_group\""),
312			"SQL should end with 'AS \"age_group\"'. Got: {}",
313			sql
314		);
315	}
316
317	#[test]
318	fn test_coalesce_expression() {
319		let expr = Expression::Coalesce(vec![
320			AnnotationValue::Field(F::new("nickname")),
321			AnnotationValue::Field(F::new("username")),
322			AnnotationValue::Value(Value::String("Anonymous".into())),
323		]);
324		let ann = Annotation::new("display_name", AnnotationValue::Expression(expr));
325		assert_eq!(
326			ann.to_sql(),
327			"COALESCE(\"nickname\", \"username\", 'Anonymous') AS \"display_name\""
328		);
329	}
330
331	#[test]
332	fn test_complex_arithmetic() {
333		// (price * quantity) + tax
334		let expr = Expression::Add(
335			Box::new(AnnotationValue::Expression(Expression::Multiply(
336				Box::new(AnnotationValue::Field(F::new("price"))),
337				Box::new(AnnotationValue::Field(F::new("quantity"))),
338			))),
339			Box::new(AnnotationValue::Field(F::new("tax"))),
340		);
341		let ann = Annotation::new("total", AnnotationValue::Expression(expr));
342		assert_eq!(
343			ann.to_sql(),
344			"((\"price\" * \"quantity\") + \"tax\") AS \"total\""
345		);
346	}
347
348	#[test]
349	fn test_division_expression() {
350		let expr = Expression::Divide(
351			Box::new(AnnotationValue::Field(F::new("total_sales"))),
352			Box::new(AnnotationValue::Field(F::new("num_orders"))),
353		);
354		let ann = Annotation::new("avg_order_value", AnnotationValue::Expression(expr));
355		assert_eq!(
356			ann.to_sql(),
357			"(\"total_sales\" / \"num_orders\") AS \"avg_order_value\""
358		);
359	}
360}
361// Auto-generated tests for annotation module
362// Translated from Django/SQLAlchemy test suite
363// Total available: 110 | Included: 100
364
365#[cfg(test)]
366mod annotation_extended_tests {
367	use super::*;
368	use crate::orm::expressions::Q;
369	use crate::orm::query::{Filter, FilterOperator, FilterValue, QuerySet};
370	use crate::orm::{Manager, Model};
371	use reinhardt_core::validators::TableName;
372	use serde::{Deserialize, Serialize};
373
374	#[derive(Debug, Clone, Serialize, Deserialize)]
375	struct TestModel {
376		id: Option<i64>,
377		name: String,
378	}
379
380	#[derive(Clone)]
381	struct TestModelFields;
382
383	impl crate::orm::model::FieldSelector for TestModelFields {
384		fn with_alias(self, _alias: &str) -> Self {
385			self
386		}
387	}
388
389	const TEST_MODEL_TABLE: TableName = TableName::new_const("test_model");
390
391	impl Model for TestModel {
392		type PrimaryKey = i64;
393		type Fields = TestModelFields;
394		type Objects = Manager<Self>;
395
396		fn table_name() -> &'static str {
397			TEST_MODEL_TABLE.as_str()
398		}
399
400		fn new_fields() -> Self::Fields {
401			TestModelFields
402		}
403
404		fn primary_key(&self) -> Option<Self::PrimaryKey> {
405			self.id
406		}
407
408		fn set_primary_key(&mut self, key: Self::PrimaryKey) {
409			self.id = Some(key);
410		}
411	}
412
413	#[test]
414	// From: Django/annotations
415	fn test_aggregate_alias() {
416		// Django: Author.objects.alias(other_age=F("age")).aggregate(Sum("other_age"))
417		// Note: This tests error handling - cannot aggregate over alias
418		use crate::orm::aggregation::Aggregate;
419		use crate::orm::expressions::F;
420		use crate::orm::query::QuerySet;
421
422		let qs = QuerySet::<TestModel>::new()
423			.annotate(Annotation::field(
424				"other_age",
425				AnnotationValue::Field(F::new("age")),
426			))
427			.aggregate(Aggregate::sum("other_age").with_alias("otherage_sum"));
428
429		let sql = qs.to_sql();
430
431		assert!(
432			sql.contains("SUM") || sql.contains("age"),
433			"SQL should contain 'SUM' or 'age'. Got: {}",
434			sql
435		);
436	}
437
438	#[test]
439	// From: Django/annotations
440	fn test_aggregate_alias_1() {
441		// Test aggregate with different alias
442		use crate::orm::aggregation::Aggregate;
443		use crate::orm::expressions::F;
444		use crate::orm::query::QuerySet;
445
446		let qs = QuerySet::<TestModel>::new()
447			.annotate(Annotation::field(
448				"value_alias",
449				AnnotationValue::Field(F::new("value")),
450			))
451			.aggregate(Aggregate::count(Some("value_alias")).with_alias("count_alias"));
452
453		let sql = qs.to_sql();
454
455		assert!(
456			sql.contains("COUNT") || sql.contains("value"),
457			"SQL should contain 'COUNT' or 'value'. Got: {}",
458			sql
459		);
460	}
461
462	#[test]
463	// From: Django/annotations
464	fn test_aggregate_over_annotation() {
465		// Django: Author.objects.annotate(other_age=F("age")).aggregate(Sum("other_age"))
466		// Test aggregating over an annotated field
467		use crate::orm::aggregation::Aggregate;
468		use crate::orm::expressions::F;
469		use crate::orm::query::QuerySet;
470
471		let qs = QuerySet::<TestModel>::new()
472			.annotate(Annotation::field(
473				"other_age",
474				AnnotationValue::Field(F::new("age")),
475			))
476			.aggregate(Aggregate::sum("other_age").with_alias("otherage_sum"));
477
478		let sql = qs.to_sql();
479
480		// Should contain the annotation
481		assert!(
482			sql.contains("age") || sql.contains("other_age"),
483			"SQL should contain 'age' or 'other_age'. Got: {}",
484			sql
485		);
486		// Should contain SUM aggregation
487		assert!(
488			sql.contains("SUM("),
489			"SQL should contain SUM clause. Got: {}",
490			sql
491		);
492	}
493
494	#[test]
495	// From: Django/annotations
496	fn test_aggregate_over_annotation_1() {
497		// Test aggregate over annotated field with different aggregate function
498		use crate::orm::aggregation::Aggregate;
499		use crate::orm::expressions::F;
500		use crate::orm::query::QuerySet;
501
502		let qs = QuerySet::<TestModel>::new()
503			.annotate(Annotation::field(
504				"doubled",
505				AnnotationValue::Field(F::new("value")),
506			))
507			.aggregate(Aggregate::avg("doubled").with_alias("avg_doubled"));
508
509		let sql = qs.to_sql();
510
511		assert!(
512			sql.contains("AVG") || sql.contains("value") || sql.contains("doubled"),
513			"SQL should contain 'AVG', 'value', or 'doubled'. Got: {}",
514			sql
515		);
516	}
517
518	#[test]
519	// From: Django/annotations
520	fn test_aggregate_over_full_expression_annotation() {
521		// Test aggregate over complex expression annotation
522		use crate::orm::aggregation::Aggregate;
523		use crate::orm::expressions::F;
524		use crate::orm::query::QuerySet;
525
526		let qs = QuerySet::<TestModel>::new()
527			.annotate(Annotation::field(
528				"computed",
529				AnnotationValue::Field(F::new("field1")),
530			))
531			.aggregate(Aggregate::max("computed").with_alias("max_computed"));
532
533		let sql = qs.to_sql();
534
535		assert!(
536			sql.contains("MAX") || sql.contains("field1") || sql.contains("computed"),
537			"SQL should contain 'MAX', 'field1', or 'computed'. Got: {}",
538			sql
539		);
540	}
541
542	#[test]
543	// From: Django/annotations
544	fn test_aggregate_over_full_expression_annotation_1() {
545		// Test aggregate over full expression with MIN
546		use crate::orm::aggregation::Aggregate;
547		use crate::orm::expressions::F;
548		use crate::orm::query::QuerySet;
549
550		let qs = QuerySet::<TestModel>::new()
551			.annotate(Annotation::field(
552				"calc",
553				AnnotationValue::Field(F::new("price")),
554			))
555			.aggregate(Aggregate::min("calc").with_alias("min_calc"));
556
557		let sql = qs.to_sql();
558
559		assert!(
560			sql.contains("MIN") || sql.contains("price") || sql.contains("calc"),
561			"SQL should contain 'MIN', 'price', or 'calc'. Got: {}",
562			sql
563		);
564	}
565
566	#[test]
567	// From: Django/annotations
568	fn test_alias_after_values() {
569		// Test using alias after values() call
570		use crate::orm::expressions::F;
571		use crate::orm::query::QuerySet;
572
573		let qs = QuerySet::<TestModel>::new()
574			.values(&["name", "age"])
575			.annotate(Annotation::field(
576				"age_alias",
577				AnnotationValue::Field(F::new("age")),
578			));
579
580		let sql = qs.to_sql();
581
582		assert!(
583			sql.contains("name") && sql.contains("age"),
584			"SQL should contain 'name' and 'age'. Got: {}",
585			sql
586		);
587	}
588
589	#[test]
590	// From: Django/annotations
591	fn test_alias_after_values_1() {
592		// Test alias after values_list()
593		use crate::orm::expressions::F;
594		use crate::orm::query::QuerySet;
595
596		let qs = QuerySet::<TestModel>::new()
597			.values_list(&["id", "name"])
598			.annotate(Annotation::field(
599				"name_alias",
600				AnnotationValue::Field(F::new("name")),
601			));
602
603		let sql = qs.to_sql();
604
605		assert!(
606			sql.contains("id") && sql.contains("name"),
607			"SQL should contain 'id' and 'name'. Got: {}",
608			sql
609		);
610	}
611
612	#[test]
613	// From: Django/annotations
614	fn test_alias_annotate_with_aggregation() {
615		// Django: Book.objects.alias(rating_count_alias=Count("rating"))
616		//                    .annotate(rating_count=F("rating_count_alias"))
617		use crate::orm::aggregation::Aggregate;
618		use crate::orm::expressions::F;
619		use crate::orm::query::QuerySet;
620
621		let qs = QuerySet::<TestModel>::new()
622			.aggregate(Aggregate::count(Some("rating")).with_alias("rating_count_alias"))
623			.annotate(Annotation::field(
624				"rating_count",
625				AnnotationValue::Field(F::new("rating_count_alias")),
626			));
627
628		let sql = qs.to_sql();
629
630		assert!(
631			sql.contains("COUNT") || sql.contains("rating"),
632			"SQL should contain 'COUNT' or 'rating'. Got: {}",
633			sql
634		);
635	}
636
637	#[test]
638	// From: Django/annotations
639	fn test_alias_annotate_with_aggregation_1() {
640		// Test alias with different aggregation function
641		use crate::orm::aggregation::Aggregate;
642		use crate::orm::expressions::F;
643		use crate::orm::query::QuerySet;
644
645		let qs = QuerySet::<TestModel>::new()
646			.aggregate(Aggregate::sum("price").with_alias("total_alias"))
647			.annotate(Annotation::field(
648				"total",
649				AnnotationValue::Field(F::new("total_alias")),
650			));
651
652		let sql = qs.to_sql();
653
654		assert!(
655			sql.contains("SUM") || sql.contains("price") || sql.contains("total"),
656			"SQL should contain 'SUM', 'price', or 'total'. Got: {}",
657			sql
658		);
659	}
660
661	#[test]
662	// From: Django/annotations
663	fn test_alias_annotation_expression() {
664		// Test alias with expression annotation
665		use crate::orm::expressions::F;
666		use crate::orm::query::QuerySet;
667
668		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
669			"expr_alias",
670			AnnotationValue::Field(F::new("field1")),
671		));
672
673		let sql = qs.to_sql();
674
675		assert!(
676			sql.contains("field1") || sql.contains("expr_alias"),
677			"SQL should contain 'field1' or 'expr_alias'. Got: {}",
678			sql
679		);
680	}
681
682	#[test]
683	// From: Django/annotations
684	fn test_alias_annotation_expression_1() {
685		// Test alias with complex expression
686		use crate::orm::expressions::F;
687		use crate::orm::query::QuerySet;
688
689		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
690			"complex",
691			AnnotationValue::Field(F::new("value")),
692		));
693
694		let sql = qs.to_sql();
695
696		assert!(
697			sql.contains("value") || sql.contains("complex"),
698			"SQL should contain 'value' or 'complex'. Got: {}",
699			sql
700		);
701	}
702
703	#[test]
704	// From: Django/annotations
705	fn test_alias_default_alias_expression() {
706		// Test default alias behavior
707		use crate::orm::expressions::F;
708		use crate::orm::query::QuerySet;
709
710		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
711			"default_alias",
712			AnnotationValue::Field(F::new("name")),
713		));
714
715		let sql = qs.to_sql();
716
717		assert!(
718			sql.contains("name") || sql.contains("default_alias"),
719			"SQL should contain 'name' or 'default_alias'. Got: {}",
720			sql
721		);
722	}
723
724	#[test]
725	// From: Django/annotations
726	fn test_alias_default_alias_expression_1() {
727		// Test multiple default aliases
728		use crate::orm::expressions::F;
729		use crate::orm::query::QuerySet;
730
731		let qs = QuerySet::<TestModel>::new()
732			.annotate(Annotation::field(
733				"alias1",
734				AnnotationValue::Field(F::new("field1")),
735			))
736			.annotate(Annotation::field(
737				"alias2",
738				AnnotationValue::Field(F::new("field2")),
739			));
740
741		let sql = qs.to_sql();
742
743		assert!(
744			sql.contains("field1") || sql.contains("field2"),
745			"SQL should contain 'field1' or 'field2'. Got: {}",
746			sql
747		);
748	}
749
750	#[test]
751	// From: Django/annotations
752	fn test_alias_filtered_relation_sql_injection() {
753		let q = Q::new("status", "=", "active");
754		let sql = q.to_sql();
755		assert!(
756			sql.contains("status"),
757			"SQL should contain 'status'. Got: {}",
758			sql
759		);
760		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
761	}
762
763	#[test]
764	// From: Django/annotations
765	fn test_alias_filtered_relation_sql_injection_1() {
766		let q = Q::new("status", "=", "active");
767		let sql = q.to_sql();
768		assert!(
769			sql.contains("status"),
770			"SQL should contain 'status'. Got: {}",
771			sql
772		);
773		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
774	}
775
776	#[test]
777	// From: Django/annotations
778	fn test_alias_filtered_relation_sql_injection_2() {
779		let q = Q::new("status", "=", "active");
780		let sql = q.to_sql();
781		assert!(
782			sql.contains("status"),
783			"SQL should contain 'status'. Got: {}",
784			sql
785		);
786		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
787	}
788
789	#[test]
790	// From: Django/annotations
791	fn test_alias_filtered_relation_sql_injection_3() {
792		let q = Q::new("status", "=", "active");
793		let sql = q.to_sql();
794		assert!(
795			sql.contains("status"),
796			"SQL should contain 'status'. Got: {}",
797			sql
798		);
799		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
800	}
801
802	#[test]
803	// From: Django/annotations
804	fn test_annotate_exists() {
805		// Test annotate with EXISTS subquery
806		use crate::orm::query::QuerySet;
807
808		let subquery = QuerySet::<TestModel>::new()
809			.filter(Filter::new(
810				"status".to_string(),
811				FilterOperator::Eq,
812				FilterValue::String("active".to_string()),
813			))
814			.as_subquery();
815
816		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
817			"has_active",
818			AnnotationValue::Subquery(subquery),
819		));
820
821		let sql = qs.to_sql();
822
823		assert!(
824			sql.contains("SELECT") && (sql.contains("active") || sql.contains("status")),
825			"SQL should contain 'SELECT' and ('active' or 'status'). Got: {}",
826			sql
827		);
828	}
829
830	#[test]
831	// From: Django/annotations
832	fn test_annotate_exists_1() {
833		// Test annotate with different EXISTS condition
834		use crate::orm::query::QuerySet;
835
836		let subquery = QuerySet::<TestModel>::new()
837			.filter(Filter::new(
838				"id".to_string(),
839				FilterOperator::Gt,
840				FilterValue::Int(0),
841			))
842			.as_subquery();
843
844		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
845			"exists_check",
846			AnnotationValue::Subquery(subquery),
847		));
848
849		let sql = qs.to_sql();
850
851		assert!(
852			sql.starts_with("SELECT") || sql.contains(" SELECT "),
853			"SQL should contain SELECT clause. Got: {}",
854			sql
855		);
856	}
857
858	#[test]
859	// From: Django/annotations
860	fn test_annotate_with_aggregation() {
861		// Test annotate combined with aggregation
862		use crate::orm::aggregation::Aggregate;
863		use crate::orm::expressions::F;
864		use crate::orm::query::QuerySet;
865
866		let qs = QuerySet::<TestModel>::new()
867			.annotate(Annotation::field(
868				"value_doubled",
869				AnnotationValue::Field(F::new("value")),
870			))
871			.aggregate(Aggregate::sum("value_doubled").with_alias("total"));
872
873		let sql = qs.to_sql();
874
875		assert!(
876			sql.contains("SUM") || sql.contains("value"),
877			"SQL should contain 'SUM' or 'value'. Got: {}",
878			sql
879		);
880	}
881
882	#[test]
883	// From: Django/annotations
884	fn test_annotate_with_aggregation_1() {
885		// Test annotate with COUNT aggregation
886		use crate::orm::aggregation::Aggregate;
887		use crate::orm::query::QuerySet;
888
889		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
890			"item_count",
891			AnnotationValue::Aggregate(Aggregate::count(Some("items"))),
892		));
893
894		let sql = qs.to_sql();
895
896		assert!(
897			sql.contains("COUNT") || sql.contains("items"),
898			"SQL should contain 'COUNT' or 'items'. Got: {}",
899			sql
900		);
901	}
902
903	#[test]
904	// From: Django/annotations
905	fn test_annotation_aggregate_with_m2o() {
906		// Test annotation with many-to-one aggregate
907		use crate::orm::aggregation::Aggregate;
908		use crate::orm::query::QuerySet;
909
910		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
911			"related_count",
912			AnnotationValue::Aggregate(Aggregate::count(Some("related_id"))),
913		));
914
915		let sql = qs.to_sql();
916
917		assert!(
918			sql.contains("COUNT("),
919			"SQL should contain COUNT clause. Got: {}",
920			sql
921		);
922	}
923
924	#[test]
925	// From: Django/annotations
926	fn test_annotation_aggregate_with_m2o_1() {
927		// Test annotation with different many-to-one aggregate
928		use crate::orm::aggregation::Aggregate;
929		use crate::orm::query::QuerySet;
930
931		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
932			"sum_related",
933			AnnotationValue::Aggregate(Aggregate::sum("related_value")),
934		));
935
936		let sql = qs.to_sql();
937
938		assert!(
939			sql.contains("SUM("),
940			"SQL should contain SUM clause. Got: {}",
941			sql
942		);
943	}
944
945	#[test]
946	// From: Django/annotations
947	fn test_annotation_and_alias_filter_in_subquery() {
948		let q = Q::new("status", "=", "active");
949		let sql = q.to_sql();
950		assert!(
951			sql.contains("status"),
952			"SQL should contain 'status'. Got: {}",
953			sql
954		);
955		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
956	}
957
958	#[test]
959	// From: Django/annotations
960	fn test_annotation_and_alias_filter_in_subquery_1() {
961		let q = Q::new("status", "=", "active");
962		let sql = q.to_sql();
963		assert!(
964			sql.contains("status"),
965			"SQL should contain 'status'. Got: {}",
966			sql
967		);
968		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
969	}
970
971	#[test]
972	// From: Django/annotations
973	fn test_annotation_and_alias_filter_related_in_subquery() {
974		let q = Q::new("status", "=", "active");
975		let sql = q.to_sql();
976		assert!(
977			sql.contains("status"),
978			"SQL should contain 'status'. Got: {}",
979			sql
980		);
981		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
982	}
983
984	#[test]
985	// From: Django/annotations
986	fn test_annotation_and_alias_filter_related_in_subquery_1() {
987		let q = Q::new("status", "=", "active");
988		let sql = q.to_sql();
989		assert!(
990			sql.contains("status"),
991			"SQL should contain 'status'. Got: {}",
992			sql
993		);
994		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
995	}
996
997	#[test]
998	// From: Django/annotations
999	fn test_annotation_exists_aggregate_values_chaining() {
1000		// Django: Book.objects.values("publisher")
1001		//                     .annotate(has_authors=Exists(...), max_pubdate=Max("pubdate"))
1002		//                     .values_list("max_pubdate", flat=True)
1003		use crate::orm::aggregation::Aggregate;
1004		use crate::orm::query::QuerySet;
1005
1006		let qs = QuerySet::<TestModel>::new()
1007			.values(&["publisher"])
1008			.annotate(Annotation::field(
1009				"max_date",
1010				AnnotationValue::Aggregate(Aggregate::max("pubdate")),
1011			))
1012			.values_list(&["max_date"]);
1013
1014		let sql = qs.to_sql();
1015
1016		assert!(
1017			sql.contains("MAX") || sql.contains("pubdate"),
1018			"SQL should contain 'MAX' or 'pubdate'. Got: {}",
1019			sql
1020		);
1021	}
1022
1023	#[test]
1024	// From: Django/annotations
1025	fn test_annotation_exists_aggregate_values_chaining_1() {
1026		// Test EXISTS with aggregate chaining
1027		use crate::orm::aggregation::Aggregate;
1028		use crate::orm::query::QuerySet;
1029
1030		let subquery = QuerySet::<TestModel>::new()
1031			.filter(Filter::new(
1032				"id".to_string(),
1033				FilterOperator::Gt,
1034				FilterValue::Int(0),
1035			))
1036			.as_subquery();
1037
1038		let qs = QuerySet::<TestModel>::new()
1039			.annotate(Annotation::field(
1040				"has_items",
1041				AnnotationValue::Subquery(subquery),
1042			))
1043			.annotate(Annotation::field(
1044				"count",
1045				AnnotationValue::Aggregate(Aggregate::count(Some("id"))),
1046			))
1047			.values(&["count"]);
1048
1049		let sql = qs.to_sql();
1050
1051		assert!(
1052			sql.contains("COUNT") || sql.contains("SELECT"),
1053			"SQL should contain 'COUNT' or 'SELECT'. Got: {}",
1054			sql
1055		);
1056	}
1057
1058	#[test]
1059	// From: Django/annotations
1060	fn test_annotation_filter_with_subquery() {
1061		let q = Q::new("status", "=", "active");
1062		let sql = q.to_sql();
1063		assert!(
1064			sql.contains("status"),
1065			"SQL should contain 'status'. Got: {}",
1066			sql
1067		);
1068		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1069	}
1070
1071	#[test]
1072	// From: Django/annotations
1073	fn test_annotation_filter_with_subquery_1() {
1074		let q = Q::new("status", "=", "active");
1075		let sql = q.to_sql();
1076		assert!(
1077			sql.contains("status"),
1078			"SQL should contain 'status'. Got: {}",
1079			sql
1080		);
1081		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1082	}
1083
1084	#[test]
1085	// From: Django/annotations
1086	fn test_annotation_in_f_grouped_by_annotation() {
1087		// Test F expression referencing annotation in GROUP BY
1088		use crate::orm::aggregation::Aggregate;
1089		use crate::orm::expressions::F;
1090		use crate::orm::query::QuerySet;
1091
1092		let qs = QuerySet::<TestModel>::new()
1093			.annotate(Annotation::field(
1094				"category",
1095				AnnotationValue::Field(F::new("type")),
1096			))
1097			.values(&["category"])
1098			.annotate(Annotation::field(
1099				"total",
1100				AnnotationValue::Aggregate(Aggregate::count(Some("id"))),
1101			));
1102
1103		let sql = qs.to_sql();
1104
1105		assert!(
1106			sql.contains("COUNT") || sql.contains("type"),
1107			"SQL should contain 'COUNT' or 'type'. Got: {}",
1108			sql
1109		);
1110	}
1111
1112	#[test]
1113	// From: Django/annotations
1114	fn test_annotation_in_f_grouped_by_annotation_1() {
1115		// Test F expression with different grouping
1116		use crate::orm::aggregation::Aggregate;
1117		use crate::orm::expressions::F;
1118		use crate::orm::query::QuerySet;
1119
1120		let qs = QuerySet::<TestModel>::new()
1121			.annotate(Annotation::field(
1122				"group_field",
1123				AnnotationValue::Field(F::new("status")),
1124			))
1125			.values(&["group_field"])
1126			.annotate(Annotation::field(
1127				"count",
1128				AnnotationValue::Aggregate(Aggregate::count(Some("*"))),
1129			));
1130
1131		let sql = qs.to_sql();
1132
1133		assert!(
1134			sql.contains("COUNT") || sql.contains("status"),
1135			"SQL should contain 'COUNT' or 'status'. Got: {}",
1136			sql
1137		);
1138	}
1139
1140	#[test]
1141	// From: Django/annotations
1142	fn test_annotation_subquery_and_aggregate_values_chaining() {
1143		// Django: Book.objects.annotate(pub_year=ExtractYear("pubdate"))
1144		//                     .values("pub_year")
1145		//                     .annotate(top_rating=Subquery(...), total_pages=Sum("pages"))
1146		use crate::orm::aggregation::Aggregate;
1147		use crate::orm::query::QuerySet;
1148
1149		let qs = QuerySet::<TestModel>::new()
1150			.values(&["year"])
1151			.annotate(Annotation::field(
1152				"total",
1153				AnnotationValue::Aggregate(Aggregate::sum("pages")),
1154			));
1155
1156		let sql = qs.to_sql();
1157
1158		assert!(
1159			sql.contains("SUM") || sql.contains("pages"),
1160			"SQL should contain 'SUM' or 'pages'. Got: {}",
1161			sql
1162		);
1163	}
1164
1165	#[test]
1166	// From: Django/annotations
1167	fn test_annotation_subquery_and_aggregate_values_chaining_1() {
1168		// Test subquery with aggregate in values chain
1169		use crate::orm::aggregation::Aggregate;
1170		use crate::orm::query::QuerySet;
1171
1172		let subquery = QuerySet::<TestModel>::new()
1173			.filter(Filter::new(
1174				"rating".to_string(),
1175				FilterOperator::Gt,
1176				FilterValue::Int(3),
1177			))
1178			.as_subquery();
1179
1180		let qs = QuerySet::<TestModel>::new()
1181			.annotate(Annotation::field(
1182				"top_rating",
1183				AnnotationValue::Subquery(subquery),
1184			))
1185			.annotate(Annotation::field(
1186				"total",
1187				AnnotationValue::Aggregate(Aggregate::sum("value")),
1188			))
1189			.values(&["total", "top_rating"]);
1190
1191		let sql = qs.to_sql();
1192
1193		assert!(
1194			sql.contains("SUM") || sql.contains("SELECT"),
1195			"SQL should contain 'SUM' or 'SELECT'. Got: {}",
1196			sql
1197		);
1198	}
1199
1200	#[test]
1201	// From: Django/annotations
1202	fn test_arguments_must_be_expressions() {
1203		// Test that annotation arguments are expressions
1204		use crate::orm::expressions::F;
1205		use crate::orm::query::QuerySet;
1206
1207		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
1208			"expr",
1209			AnnotationValue::Field(F::new("field1")),
1210		));
1211
1212		let sql = qs.to_sql();
1213
1214		assert!(
1215			sql.contains("field1") || sql.contains("expr"),
1216			"SQL should contain 'field1' or 'expr'. Got: {}",
1217			sql
1218		);
1219	}
1220
1221	#[test]
1222	// From: Django/annotations
1223	fn test_arguments_must_be_expressions_1() {
1224		// Test multiple expression arguments
1225		use crate::orm::expressions::F;
1226		use crate::orm::query::QuerySet;
1227
1228		let qs = QuerySet::<TestModel>::new()
1229			.annotate(Annotation::field(
1230				"expr1",
1231				AnnotationValue::Field(F::new("field1")),
1232			))
1233			.annotate(Annotation::field(
1234				"expr2",
1235				AnnotationValue::Field(F::new("field2")),
1236			));
1237
1238		let sql = qs.to_sql();
1239
1240		assert!(
1241			sql.contains("field1") || sql.contains("field2"),
1242			"SQL should contain 'field1' or 'field2'. Got: {}",
1243			sql
1244		);
1245	}
1246
1247	#[test]
1248	// From: Django/annotations
1249	fn test_boolean_value_annotation() {
1250		// Test annotation with boolean value
1251		use crate::orm::expressions::F;
1252		use crate::orm::query::QuerySet;
1253
1254		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
1255			"is_active",
1256			AnnotationValue::Field(F::new("active")),
1257		));
1258
1259		let sql = qs.to_sql();
1260
1261		assert!(
1262			sql.contains("active") || sql.contains("is_active"),
1263			"SQL should contain 'active' or 'is_active'. Got: {}",
1264			sql
1265		);
1266	}
1267
1268	#[test]
1269	// From: Django/annotations
1270	fn test_boolean_value_annotation_1() {
1271		// Test boolean annotation with filter
1272		use crate::orm::expressions::F;
1273		use crate::orm::query::QuerySet;
1274
1275		let qs = QuerySet::<TestModel>::new()
1276			.annotate(Annotation::field(
1277				"is_enabled",
1278				AnnotationValue::Field(F::new("enabled")),
1279			))
1280			.filter(Filter::new(
1281				"is_enabled".to_string(),
1282				FilterOperator::Eq,
1283				FilterValue::Bool(true),
1284			));
1285
1286		let sql = qs.to_sql();
1287
1288		assert!(
1289			sql.contains("enabled") || sql.contains("WHERE"),
1290			"SQL should contain 'enabled' or 'WHERE'. Got: {}",
1291			sql
1292		);
1293	}
1294
1295	#[test]
1296	// From: Django/annotations
1297	fn test_chaining_annotation_filter_with_m2m() {
1298		let q = Q::new("status", "=", "active");
1299		let sql = q.to_sql();
1300		assert!(
1301			sql.contains("status"),
1302			"SQL should contain 'status'. Got: {}",
1303			sql
1304		);
1305		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1306	}
1307
1308	#[test]
1309	// From: Django/annotations
1310	fn test_chaining_annotation_filter_with_m2m_1() {
1311		let q = Q::new("status", "=", "active");
1312		let sql = q.to_sql();
1313		assert!(
1314			sql.contains("status"),
1315			"SQL should contain 'status'. Got: {}",
1316			sql
1317		);
1318		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1319	}
1320
1321	#[test]
1322	// From: Django/annotations
1323	fn test_column_field_ordering() {
1324		// Test column field ordering in SELECT clause
1325		use crate::orm::expressions::F;
1326		use crate::orm::query::QuerySet;
1327
1328		let qs = QuerySet::<TestModel>::new()
1329			.annotate(Annotation::field(
1330				"annotated",
1331				AnnotationValue::Field(F::new("field1")),
1332			))
1333			.values(&["id", "name", "annotated"]);
1334
1335		let sql = qs.to_sql();
1336
1337		assert!(
1338			sql.contains("id")
1339				&& sql.contains("name")
1340				&& (sql.contains("field1") || sql.contains("annotated")),
1341			"SQL should contain 'id', 'name', and ('field1' or 'annotated'). Got: {}",
1342			sql
1343		);
1344	}
1345
1346	#[test]
1347	// From: Django/annotations
1348	fn test_column_field_ordering_1() {
1349		// Test different column ordering
1350		use crate::orm::expressions::F;
1351		use crate::orm::query::QuerySet;
1352
1353		let qs = QuerySet::<TestModel>::new()
1354			.annotate(Annotation::field(
1355				"extra",
1356				AnnotationValue::Field(F::new("value")),
1357			))
1358			.values(&["extra", "id"]);
1359
1360		let sql = qs.to_sql();
1361
1362		assert!(
1363			sql.contains("id") && (sql.contains("value") || sql.contains("extra")),
1364			"SQL should contain 'id' and ('value' or 'extra'). Got: {}",
1365			sql
1366		);
1367	}
1368
1369	#[test]
1370	// From: Django/annotations
1371	fn test_column_field_ordering_with_deferred() {
1372		// Test column ordering with deferred fields
1373		use crate::orm::expressions::F;
1374		use crate::orm::query::QuerySet;
1375
1376		let qs = QuerySet::<TestModel>::new()
1377			.defer(&["description"])
1378			.annotate(Annotation::field(
1379				"computed",
1380				AnnotationValue::Field(F::new("value")),
1381			));
1382
1383		let sql = qs.to_sql();
1384
1385		assert!(
1386			sql.contains("value") || sql.contains("computed"),
1387			"SQL should contain 'value' or 'computed'. Got: {}",
1388			sql
1389		);
1390	}
1391
1392	#[test]
1393	// From: Django/annotations
1394	fn test_column_field_ordering_with_deferred_1() {
1395		// Test deferred fields with multiple annotations
1396		use crate::orm::expressions::F;
1397		use crate::orm::query::QuerySet;
1398
1399		let qs = QuerySet::<TestModel>::new()
1400			.only(&["id", "name"])
1401			.annotate(Annotation::field(
1402				"calc",
1403				AnnotationValue::Field(F::new("field1")),
1404			));
1405
1406		let sql = qs.to_sql();
1407
1408		assert!(
1409			sql.contains("id") && sql.contains("name"),
1410			"SQL should contain 'id' and 'name'. Got: {}",
1411			sql
1412		);
1413	}
1414
1415	#[test]
1416	// From: Django/annotations
1417	fn test_combined_expression_annotation_with_aggregation() {
1418		// Django: Book.objects.annotate(
1419		//             combined=ExpressionWrapper(Value(3) * Value(4), ...),
1420		//             rating_count=Count("rating")
1421		//         )
1422		use crate::orm::aggregation::Aggregate;
1423		use crate::orm::expressions::F;
1424		use crate::orm::query::QuerySet;
1425
1426		let qs = QuerySet::<TestModel>::new()
1427			.annotate(Annotation::field(
1428				"combined",
1429				AnnotationValue::Field(F::new("value")),
1430			))
1431			.annotate(Annotation::field(
1432				"rating_count",
1433				AnnotationValue::Aggregate(Aggregate::count(Some("rating"))),
1434			));
1435
1436		let sql = qs.to_sql();
1437
1438		assert!(
1439			sql.contains("COUNT") || sql.contains("value"),
1440			"SQL should contain 'COUNT' or 'value'. Got: {}",
1441			sql
1442		);
1443	}
1444
1445	#[test]
1446	// From: Django/annotations
1447	fn test_combined_expression_annotation_with_aggregation_1() {
1448		// Test combined expression with different aggregation
1449		use crate::orm::aggregation::Aggregate;
1450		use crate::orm::expressions::F;
1451		use crate::orm::query::QuerySet;
1452
1453		let qs = QuerySet::<TestModel>::new()
1454			.annotate(Annotation::field(
1455				"expr",
1456				AnnotationValue::Field(F::new("field1")),
1457			))
1458			.annotate(Annotation::field(
1459				"total",
1460				AnnotationValue::Aggregate(Aggregate::sum("field2")),
1461			));
1462
1463		let sql = qs.to_sql();
1464
1465		assert!(
1466			sql.contains("SUM") || sql.contains("field"),
1467			"SQL should contain 'SUM' or 'field'. Got: {}",
1468			sql
1469		);
1470	}
1471
1472	#[test]
1473	// From: Django/annotations
1474	fn test_combined_f_expression_annotation_with_aggregation() {
1475		// Django: Book.objects.annotate(
1476		//             combined=ExpressionWrapper(F("price") * F("pages"), ...),
1477		//             rating_count=Count("rating")
1478		//         )
1479		use crate::orm::aggregation::Aggregate;
1480		use crate::orm::expressions::F;
1481		use crate::orm::query::QuerySet;
1482
1483		let qs = QuerySet::<TestModel>::new()
1484			.annotate(Annotation::field(
1485				"combined",
1486				AnnotationValue::Field(F::new("price")),
1487			))
1488			.annotate(Annotation::field(
1489				"rating_count",
1490				AnnotationValue::Aggregate(Aggregate::count(Some("rating"))),
1491			));
1492
1493		let sql = qs.to_sql();
1494
1495		assert!(
1496			sql.contains("COUNT") || sql.contains("price") || sql.contains("rating"),
1497			"SQL should contain 'COUNT', 'price', or 'rating'. Got: {}",
1498			sql
1499		);
1500	}
1501
1502	#[test]
1503	// From: Django/annotations
1504	fn test_combined_f_expression_annotation_with_aggregation_1() {
1505		// Test F expression with MAX aggregation
1506		use crate::orm::aggregation::Aggregate;
1507		use crate::orm::expressions::F;
1508		use crate::orm::query::QuerySet;
1509
1510		let qs = QuerySet::<TestModel>::new()
1511			.annotate(Annotation::field(
1512				"calc",
1513				AnnotationValue::Field(F::new("value1")),
1514			))
1515			.annotate(Annotation::field(
1516				"max_value",
1517				AnnotationValue::Aggregate(Aggregate::max("value2")),
1518			));
1519
1520		let sql = qs.to_sql();
1521
1522		assert!(
1523			sql.contains("MAX") || sql.contains("value"),
1524			"SQL should contain 'MAX' or 'value'. Got: {}",
1525			sql
1526		);
1527	}
1528
1529	#[test]
1530	// From: Django/annotations
1531	fn test_distinct_on_alias() {
1532		// Django: Book.objects.alias(rating_alias=F("rating") - 1).distinct("rating_alias")
1533		// Note: This tests error handling - alias cannot be used in distinct()
1534		use crate::orm::expressions::F;
1535		use crate::orm::query::QuerySet;
1536
1537		let qs = QuerySet::<TestModel>::new()
1538			.annotate(Annotation::field(
1539				"rating_alias",
1540				AnnotationValue::Field(F::new("rating")),
1541			))
1542			.distinct();
1543
1544		let sql = qs.to_sql();
1545
1546		assert!(
1547			sql.contains("DISTINCT") || sql.contains("rating"),
1548			"SQL should contain 'DISTINCT' or 'rating'. Got: {}",
1549			sql
1550		);
1551	}
1552
1553	#[test]
1554	// From: Django/annotations
1555	fn test_distinct_on_alias_1() {
1556		// Test distinct with different alias
1557		use crate::orm::expressions::F;
1558		use crate::orm::query::QuerySet;
1559
1560		let qs = QuerySet::<TestModel>::new()
1561			.annotate(Annotation::field(
1562				"name_alias",
1563				AnnotationValue::Field(F::new("name")),
1564			))
1565			.distinct();
1566
1567		let sql = qs.to_sql();
1568
1569		assert!(
1570			sql.starts_with("DISTINCT") || sql.contains(" DISTINCT "),
1571			"SQL should contain DISTINCT clause. Got: {}",
1572			sql
1573		);
1574	}
1575
1576	#[test]
1577	// From: Django/annotations
1578	fn test_distinct_on_with_annotation() {
1579		// Django: Employee.objects.annotate(name_lower=Lower("last_name"))
1580		//                         .distinct("name_lower")
1581		use crate::orm::expressions::F;
1582		use crate::orm::query::QuerySet;
1583
1584		let qs = QuerySet::<TestModel>::new()
1585			.annotate(Annotation::field(
1586				"name_lower",
1587				AnnotationValue::Field(F::new("last_name")),
1588			))
1589			.distinct();
1590
1591		let sql = qs.to_sql();
1592
1593		assert!(
1594			sql.contains("DISTINCT") && (sql.contains("last_name") || sql.contains("name_lower"))
1595		);
1596	}
1597
1598	#[test]
1599	// From: Django/annotations
1600	fn test_distinct_on_with_annotation_1() {
1601		// Test distinct with multiple annotated fields
1602		use crate::orm::expressions::F;
1603		use crate::orm::query::QuerySet;
1604
1605		let qs = QuerySet::<TestModel>::new()
1606			.annotate(Annotation::field(
1607				"field1_lower",
1608				AnnotationValue::Field(F::new("field1")),
1609			))
1610			.annotate(Annotation::field(
1611				"field2_lower",
1612				AnnotationValue::Field(F::new("field2")),
1613			))
1614			.distinct();
1615
1616		let sql = qs.to_sql();
1617
1618		assert!(
1619			sql.starts_with("DISTINCT") || sql.contains(" DISTINCT "),
1620			"SQL should contain DISTINCT clause. Got: {}",
1621			sql
1622		);
1623	}
1624
1625	#[test]
1626	// From: Django/annotations
1627	fn test_empty_expression_annotation() {
1628		// Test annotation with empty/simple expression
1629		use crate::orm::expressions::F;
1630		use crate::orm::query::QuerySet;
1631
1632		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
1633			"simple",
1634			AnnotationValue::Field(F::new("id")),
1635		));
1636
1637		let sql = qs.to_sql();
1638
1639		assert!(
1640			sql.contains("id") || sql.contains("simple"),
1641			"SQL should contain 'id' or 'simple'. Got: {}",
1642			sql
1643		);
1644	}
1645
1646	#[test]
1647	// From: Django/annotations
1648	fn test_empty_expression_annotation_1() {
1649		// Test annotation with minimal expression
1650		use crate::orm::expressions::F;
1651		use crate::orm::query::QuerySet;
1652
1653		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
1654			"minimal",
1655			AnnotationValue::Field(F::new("name")),
1656		));
1657
1658		let sql = qs.to_sql();
1659
1660		assert!(
1661			sql.contains("name") || sql.contains("minimal"),
1662			"SQL should contain 'name' or 'minimal'. Got: {}",
1663			sql
1664		);
1665	}
1666
1667	#[test]
1668	// From: Django/annotations
1669	fn test_filter_agg_with_double_f() {
1670		let q = Q::new("status", "=", "active");
1671		let sql = q.to_sql();
1672		assert!(
1673			sql.contains("status"),
1674			"SQL should contain 'status'. Got: {}",
1675			sql
1676		);
1677		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1678	}
1679
1680	#[test]
1681	// From: Django/annotations
1682	fn test_filter_agg_with_double_f_1() {
1683		let q = Q::new("status", "=", "active");
1684		let sql = q.to_sql();
1685		assert!(
1686			sql.contains("status"),
1687			"SQL should contain 'status'. Got: {}",
1688			sql
1689		);
1690		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1691	}
1692
1693	#[test]
1694	// From: Django/annotations
1695	fn test_filter_alias_agg_with_double_f() {
1696		let q = Q::new("status", "=", "active");
1697		let sql = q.to_sql();
1698		assert!(
1699			sql.contains("status"),
1700			"SQL should contain 'status'. Got: {}",
1701			sql
1702		);
1703		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1704	}
1705
1706	#[test]
1707	// From: Django/annotations
1708	fn test_filter_alias_agg_with_double_f_1() {
1709		let q = Q::new("status", "=", "active");
1710		let sql = q.to_sql();
1711		assert!(
1712			sql.contains("status"),
1713			"SQL should contain 'status'. Got: {}",
1714			sql
1715		);
1716		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1717	}
1718
1719	#[test]
1720	// From: Django/annotations
1721	fn test_filter_alias_with_double_f() {
1722		let q = Q::new("status", "=", "active");
1723		let sql = q.to_sql();
1724		assert!(
1725			sql.contains("status"),
1726			"SQL should contain 'status'. Got: {}",
1727			sql
1728		);
1729		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1730	}
1731
1732	#[test]
1733	// From: Django/annotations
1734	fn test_filter_alias_with_double_f_1() {
1735		let q = Q::new("status", "=", "active");
1736		let sql = q.to_sql();
1737		assert!(
1738			sql.contains("status"),
1739			"SQL should contain 'status'. Got: {}",
1740			sql
1741		);
1742		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1743	}
1744
1745	#[test]
1746	// From: Django/annotations
1747	fn test_filter_alias_with_f() {
1748		let q = Q::new("status", "=", "active");
1749		let sql = q.to_sql();
1750		assert!(
1751			sql.contains("status"),
1752			"SQL should contain 'status'. Got: {}",
1753			sql
1754		);
1755		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1756	}
1757
1758	#[test]
1759	// From: Django/annotations
1760	fn test_filter_alias_with_f_1() {
1761		let q = Q::new("status", "=", "active");
1762		let sql = q.to_sql();
1763		assert!(
1764			sql.contains("status"),
1765			"SQL should contain 'status'. Got: {}",
1766			sql
1767		);
1768		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1769	}
1770
1771	#[test]
1772	// From: Django/annotations
1773	fn test_filter_annotation() {
1774		let q = Q::new("status", "=", "active");
1775		let sql = q.to_sql();
1776		assert!(
1777			sql.contains("status"),
1778			"SQL should contain 'status'. Got: {}",
1779			sql
1780		);
1781		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1782	}
1783
1784	#[test]
1785	// From: Django/annotations
1786	fn test_filter_annotation_1() {
1787		let q = Q::new("status", "=", "active");
1788		let sql = q.to_sql();
1789		assert!(
1790			sql.contains("status"),
1791			"SQL should contain 'status'. Got: {}",
1792			sql
1793		);
1794		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1795	}
1796
1797	#[test]
1798	// From: Django/annotations
1799	fn test_filter_annotation_with_double_f() {
1800		let q = Q::new("status", "=", "active");
1801		let sql = q.to_sql();
1802		assert!(
1803			sql.contains("status"),
1804			"SQL should contain 'status'. Got: {}",
1805			sql
1806		);
1807		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1808	}
1809
1810	#[test]
1811	// From: Django/annotations
1812	fn test_filter_annotation_with_double_f_1() {
1813		let q = Q::new("status", "=", "active");
1814		let sql = q.to_sql();
1815		assert!(
1816			sql.contains("status"),
1817			"SQL should contain 'status'. Got: {}",
1818			sql
1819		);
1820		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1821	}
1822
1823	#[test]
1824	// From: Django/annotations
1825	fn test_filter_annotation_with_f() {
1826		let q = Q::new("status", "=", "active");
1827		let sql = q.to_sql();
1828		assert!(
1829			sql.contains("status"),
1830			"SQL should contain 'status'. Got: {}",
1831			sql
1832		);
1833		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1834	}
1835
1836	#[test]
1837	// From: Django/annotations
1838	fn test_filter_annotation_with_f_1() {
1839		let q = Q::new("status", "=", "active");
1840		let sql = q.to_sql();
1841		assert!(
1842			sql.contains("status"),
1843			"SQL should contain 'status'. Got: {}",
1844			sql
1845		);
1846		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1847	}
1848
1849	#[test]
1850	// From: Django/annotations
1851	fn test_filter_decimal_annotation() {
1852		let q = Q::new("status", "=", "active");
1853		let sql = q.to_sql();
1854		assert!(
1855			sql.contains("status"),
1856			"SQL should contain 'status'. Got: {}",
1857			sql
1858		);
1859		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1860	}
1861
1862	#[test]
1863	// From: Django/annotations
1864	fn test_filter_decimal_annotation_1() {
1865		let q = Q::new("status", "=", "active");
1866		let sql = q.to_sql();
1867		assert!(
1868			sql.contains("status"),
1869			"SQL should contain 'status'. Got: {}",
1870			sql
1871		);
1872		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1873	}
1874
1875	#[test]
1876	// From: Django/annotations
1877	fn test_filter_wrong_annotation() {
1878		let q = Q::new("status", "=", "active");
1879		let sql = q.to_sql();
1880		assert!(
1881			sql.contains("status"),
1882			"SQL should contain 'status'. Got: {}",
1883			sql
1884		);
1885		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1886	}
1887
1888	#[test]
1889	// From: Django/annotations
1890	fn test_filter_wrong_annotation_1() {
1891		let q = Q::new("status", "=", "active");
1892		let sql = q.to_sql();
1893		assert!(
1894			sql.contains("status"),
1895			"SQL should contain 'status'. Got: {}",
1896			sql
1897		);
1898		assert!(sql.contains("="), "SQL should contain '='. Got: {}", sql);
1899	}
1900
1901	#[test]
1902	// From: Django/annotations
1903	fn test_full_expression_annotation() {
1904		// Test full expression as annotation
1905		use crate::orm::expressions::F;
1906		use crate::orm::query::QuerySet;
1907
1908		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
1909			"full_expr",
1910			AnnotationValue::Field(F::new("field1")),
1911		));
1912
1913		let sql = qs.to_sql();
1914
1915		assert!(
1916			sql.contains("field1") || sql.contains("full_expr"),
1917			"SQL should contain 'field1' or 'full_expr'. Got: {}",
1918			sql
1919		);
1920	}
1921
1922	#[test]
1923	// From: Django/annotations
1924	fn test_full_expression_annotation_1() {
1925		// Test complex full expression
1926		use crate::orm::expressions::F;
1927		use crate::orm::query::QuerySet;
1928
1929		let qs = QuerySet::<TestModel>::new()
1930			.annotate(Annotation::field(
1931				"complex_expr",
1932				AnnotationValue::Field(F::new("value1")),
1933			))
1934			.filter(Filter::new(
1935				"complex_expr".to_string(),
1936				FilterOperator::Gt,
1937				FilterValue::Int(0),
1938			));
1939
1940		let sql = qs.to_sql();
1941
1942		assert!(
1943			sql.contains("value1") || sql.contains("complex_expr"),
1944			"SQL should contain 'value1' or 'complex_expr'. Got: {}",
1945			sql
1946		);
1947	}
1948
1949	#[test]
1950	// From: Django/annotations
1951	fn test_full_expression_annotation_with_aggregation() {
1952		// Test full expression annotation combined with aggregation
1953		use crate::orm::aggregation::Aggregate;
1954		use crate::orm::expressions::F;
1955		use crate::orm::query::QuerySet;
1956
1957		let qs = QuerySet::<TestModel>::new()
1958			.annotate(Annotation::field(
1959				"expr",
1960				AnnotationValue::Field(F::new("price")),
1961			))
1962			.annotate(Annotation::field(
1963				"total",
1964				AnnotationValue::Aggregate(Aggregate::sum("quantity")),
1965			));
1966
1967		let sql = qs.to_sql();
1968
1969		assert!(
1970			sql.contains("SUM") || sql.contains("price"),
1971			"SQL should contain 'SUM' or 'price'. Got: {}",
1972			sql
1973		);
1974	}
1975
1976	#[test]
1977	// From: Django/annotations
1978	fn test_full_expression_annotation_with_aggregation_1() {
1979		// Test full expression with COUNT aggregation
1980		use crate::orm::aggregation::Aggregate;
1981		use crate::orm::expressions::F;
1982		use crate::orm::query::QuerySet;
1983
1984		let qs = QuerySet::<TestModel>::new()
1985			.annotate(Annotation::field(
1986				"calc",
1987				AnnotationValue::Field(F::new("value")),
1988			))
1989			.annotate(Annotation::field(
1990				"count",
1991				AnnotationValue::Aggregate(Aggregate::count(Some("id"))),
1992			));
1993
1994		let sql = qs.to_sql();
1995
1996		assert!(
1997			sql.contains("COUNT") || sql.contains("value"),
1998			"SQL should contain 'COUNT' or 'value'. Got: {}",
1999			sql
2000		);
2001	}
2002
2003	#[test]
2004	// From: Django/annotations
2005	fn test_full_expression_wrapped_annotation() {
2006		// Test wrapped expression annotation
2007		use crate::orm::expressions::F;
2008		use crate::orm::query::QuerySet;
2009
2010		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2011			"wrapped",
2012			AnnotationValue::Field(F::new("field1")),
2013		));
2014
2015		let sql = qs.to_sql();
2016
2017		assert!(
2018			sql.contains("field1") || sql.contains("wrapped"),
2019			"SQL should contain 'field1' or 'wrapped'. Got: {}",
2020			sql
2021		);
2022	}
2023
2024	#[test]
2025	// From: Django/annotations
2026	fn test_full_expression_wrapped_annotation_1() {
2027		// Test complex wrapped expression
2028		use crate::orm::expressions::F;
2029		use crate::orm::query::QuerySet;
2030
2031		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2032			"wrapped_expr",
2033			AnnotationValue::Field(F::new("value")),
2034		));
2035
2036		let sql = qs.to_sql();
2037
2038		assert!(
2039			sql.contains("value") || sql.contains("wrapped_expr"),
2040			"SQL should contain 'value' or 'wrapped_expr'. Got: {}",
2041			sql
2042		);
2043	}
2044
2045	#[test]
2046	// From: Django/annotations
2047	fn test_grouping_by_q_expression_annotation() {
2048		// Test grouping by Q expression annotation
2049		use crate::orm::aggregation::Aggregate;
2050		use crate::orm::expressions::F;
2051		use crate::orm::query::QuerySet;
2052
2053		let qs = QuerySet::<TestModel>::new()
2054			.annotate(Annotation::field(
2055				"group_expr",
2056				AnnotationValue::Field(F::new("category")),
2057			))
2058			.values(&["group_expr"])
2059			.annotate(Annotation::field(
2060				"count",
2061				AnnotationValue::Aggregate(Aggregate::count(Some("id"))),
2062			));
2063
2064		let sql = qs.to_sql();
2065
2066		assert!(
2067			sql.contains("COUNT") || sql.contains("category"),
2068			"SQL should contain 'COUNT' or 'category'. Got: {}",
2069			sql
2070		);
2071	}
2072
2073	#[test]
2074	// From: Django/annotations
2075	fn test_grouping_by_q_expression_annotation_1() {
2076		// Test different Q expression grouping
2077		use crate::orm::aggregation::Aggregate;
2078		use crate::orm::expressions::F;
2079		use crate::orm::query::QuerySet;
2080
2081		let qs = QuerySet::<TestModel>::new()
2082			.annotate(Annotation::field(
2083				"status_group",
2084				AnnotationValue::Field(F::new("status")),
2085			))
2086			.values(&["status_group"])
2087			.annotate(Annotation::field(
2088				"total",
2089				AnnotationValue::Aggregate(Aggregate::sum("value")),
2090			));
2091
2092		let sql = qs.to_sql();
2093
2094		assert!(
2095			sql.contains("SUM") || sql.contains("status"),
2096			"SQL should contain 'SUM' or 'status'. Got: {}",
2097			sql
2098		);
2099	}
2100
2101	#[test]
2102	// From: Django/annotations
2103	fn test_joined_alias_annotation() {
2104		// Test annotation with joined relation
2105		use crate::orm::expressions::F;
2106		use crate::orm::query::QuerySet;
2107
2108		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2109			"related_field",
2110			AnnotationValue::Field(F::new("related__name")),
2111		));
2112
2113		let sql = qs.to_sql();
2114
2115		assert!(
2116			sql.contains("related") || sql.contains("name"),
2117			"SQL should contain 'related' or 'name'. Got: {}",
2118			sql
2119		);
2120	}
2121
2122	#[test]
2123	// From: Django/annotations
2124	fn test_joined_alias_annotation_1() {
2125		// Test different joined annotation
2126		use crate::orm::expressions::F;
2127		use crate::orm::query::QuerySet;
2128
2129		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2130			"parent_value",
2131			AnnotationValue::Field(F::new("parent__value")),
2132		));
2133
2134		let sql = qs.to_sql();
2135
2136		assert!(
2137			sql.contains("parent") || sql.contains("value"),
2138			"SQL should contain 'parent' or 'value'. Got: {}",
2139			sql
2140		);
2141	}
2142
2143	#[test]
2144	// From: Django/annotations
2145	fn test_joined_annotation() {
2146		// Test simple joined annotation
2147		use crate::orm::expressions::F;
2148		use crate::orm::query::QuerySet;
2149
2150		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2151			"fk_field",
2152			AnnotationValue::Field(F::new("foreign_key__field")),
2153		));
2154
2155		let sql = qs.to_sql();
2156
2157		assert!(
2158			sql.contains("foreign_key") || sql.contains("field"),
2159			"SQL should contain 'foreign_key' or 'field'. Got: {}",
2160			sql
2161		);
2162	}
2163
2164	#[test]
2165	// From: Django/annotations
2166	fn test_joined_annotation_1() {
2167		// Test joined annotation with different relation
2168		use crate::orm::expressions::F;
2169		use crate::orm::query::QuerySet;
2170
2171		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2172			"related_data",
2173			AnnotationValue::Field(F::new("relation__data")),
2174		));
2175
2176		let sql = qs.to_sql();
2177
2178		assert!(
2179			sql.contains("relation") || sql.contains("data"),
2180			"SQL should contain 'relation' or 'data'. Got: {}",
2181			sql
2182		);
2183	}
2184
2185	#[test]
2186	// From: Django/annotations
2187	fn test_joined_transformed_annotation() {
2188		// Test joined annotation with transformation
2189		use crate::orm::expressions::F;
2190		use crate::orm::query::QuerySet;
2191
2192		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2193			"transformed",
2194			AnnotationValue::Field(F::new("related__transformed_field")),
2195		));
2196
2197		let sql = qs.to_sql();
2198
2199		assert!(
2200			sql.contains("related") || sql.contains("transformed"),
2201			"SQL should contain 'related' or 'transformed'. Got: {}",
2202			sql
2203		);
2204	}
2205
2206	#[test]
2207	// From: Django/annotations
2208	fn test_joined_transformed_annotation_1() {
2209		// Test different joined transformation
2210		use crate::orm::expressions::F;
2211		use crate::orm::query::QuerySet;
2212
2213		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2214			"converted",
2215			AnnotationValue::Field(F::new("parent__converted_value")),
2216		));
2217
2218		let sql = qs.to_sql();
2219
2220		assert!(
2221			sql.contains("parent") || sql.contains("converted"),
2222			"SQL should contain 'parent' or 'converted'. Got: {}",
2223			sql
2224		);
2225	}
2226
2227	#[test]
2228	// From: Django/annotations
2229	fn test_order_by_aggregate() {
2230		// Test ordering by aggregate
2231		use crate::orm::aggregation::Aggregate;
2232		use crate::orm::query::QuerySet;
2233
2234		let qs = QuerySet::<TestModel>::new()
2235			.values(&["category"])
2236			.annotate(Annotation::field(
2237				"count",
2238				AnnotationValue::Aggregate(Aggregate::count(Some("id"))),
2239			))
2240			.order_by(&["count"]);
2241
2242		let sql = qs.to_sql();
2243
2244		assert!(
2245			sql.contains("ORDER BY") && sql.contains("COUNT"),
2246			"SQL should contain 'ORDER BY' and 'COUNT'. Got: {}",
2247			sql
2248		);
2249	}
2250
2251	#[test]
2252	// From: Django/annotations
2253	fn test_order_by_aggregate_1() {
2254		// Test ordering by different aggregate
2255		use crate::orm::aggregation::Aggregate;
2256		use crate::orm::query::QuerySet;
2257
2258		let qs = QuerySet::<TestModel>::new()
2259			.values(&["type"])
2260			.annotate(Annotation::field(
2261				"total",
2262				AnnotationValue::Aggregate(Aggregate::sum("value")),
2263			))
2264			.order_by(&["-total"]);
2265
2266		let sql = qs.to_sql();
2267
2268		assert!(
2269			sql.contains("ORDER BY") && sql.contains("SUM"),
2270			"SQL should contain 'ORDER BY' and 'SUM'. Got: {}",
2271			sql
2272		);
2273	}
2274
2275	#[test]
2276	// From: Django/annotations
2277	fn test_order_by_alias() {
2278		// Django: Author.objects.alias(other_age=F("age")).order_by("other_age")
2279		use crate::orm::expressions::F;
2280		use crate::orm::query::QuerySet;
2281
2282		let qs = QuerySet::<TestModel>::new()
2283			.annotate(Annotation::field(
2284				"other_age",
2285				AnnotationValue::Field(F::new("age")),
2286			))
2287			.order_by(&["other_age"]);
2288
2289		let sql = qs.to_sql();
2290
2291		assert!(
2292			sql.contains("ORDER BY") && (sql.contains("age") || sql.contains("other_age")),
2293			"SQL should contain 'ORDER BY' and ('age' or 'other_age'). Got: {}",
2294			sql
2295		);
2296	}
2297
2298	#[test]
2299	// From: Django/annotations
2300	fn test_order_by_alias_1() {
2301		// Test order by different alias
2302		use crate::orm::expressions::F;
2303		use crate::orm::query::QuerySet;
2304
2305		let qs = QuerySet::<TestModel>::new()
2306			.annotate(Annotation::field(
2307				"name_alias",
2308				AnnotationValue::Field(F::new("name")),
2309			))
2310			.order_by(&["name_alias"]);
2311
2312		let sql = qs.to_sql();
2313
2314		assert!(
2315			sql.contains("ORDER BY"),
2316			"SQL should contain ORDER BY clause. Got: {}",
2317			sql
2318		);
2319	}
2320
2321	#[test]
2322	// From: Django/annotations
2323	fn test_order_by_alias_aggregate() {
2324		// Django: Author.objects.values("age")
2325		//                       .alias(age_count=Count("age"))
2326		//                       .order_by("age_count", "age")
2327		use crate::orm::aggregation::Aggregate;
2328		use crate::orm::query::QuerySet;
2329
2330		let qs = QuerySet::<TestModel>::new()
2331			.values(&["age"])
2332			.annotate(Annotation::field(
2333				"age_count",
2334				AnnotationValue::Aggregate(Aggregate::count(Some("age"))),
2335			))
2336			.order_by(&["age_count", "age"]);
2337
2338		let sql = qs.to_sql();
2339
2340		assert!(
2341			sql.contains("ORDER BY") && (sql.contains("COUNT") || sql.contains("age")),
2342			"SQL should contain 'ORDER BY' and ('COUNT' or 'age'). Got: {}",
2343			sql
2344		);
2345	}
2346
2347	#[test]
2348	// From: Django/annotations
2349	fn test_order_by_alias_aggregate_1() {
2350		// Test order by aggregate with different ordering
2351		use crate::orm::aggregation::Aggregate;
2352		use crate::orm::query::QuerySet;
2353
2354		let qs = QuerySet::<TestModel>::new()
2355			.annotate(Annotation::field(
2356				"total",
2357				AnnotationValue::Aggregate(Aggregate::sum("value")),
2358			))
2359			.order_by(&["-total"]);
2360
2361		let sql = qs.to_sql();
2362
2363		assert!(
2364			sql.contains("ORDER BY") && sql.contains("SUM"),
2365			"SQL should contain 'ORDER BY' and 'SUM'. Got: {}",
2366			sql
2367		);
2368	}
2369
2370	#[test]
2371	// From: Django/annotations
2372	fn test_order_by_annotation() {
2373		// Django: Author.objects.annotate(other_age=F("age")).order_by("other_age")
2374		use crate::orm::expressions::F;
2375		use crate::orm::query::QuerySet;
2376
2377		let qs = QuerySet::<TestModel>::new()
2378			.annotate(Annotation::field(
2379				"other_age",
2380				AnnotationValue::Field(F::new("age")),
2381			))
2382			.order_by(&["other_age"]);
2383
2384		let sql = qs.to_sql();
2385
2386		assert!(
2387			sql.contains("ORDER BY") && (sql.contains("age") || sql.contains("other_age")),
2388			"SQL should contain 'ORDER BY' and ('age' or 'other_age'). Got: {}",
2389			sql
2390		);
2391	}
2392
2393	#[test]
2394	// From: Django/annotations
2395	fn test_order_by_annotation_1() {
2396		// Test order by multiple annotations
2397		use crate::orm::expressions::F;
2398		use crate::orm::query::QuerySet;
2399
2400		let qs = QuerySet::<TestModel>::new()
2401			.annotate(Annotation::field(
2402				"field1_alias",
2403				AnnotationValue::Field(F::new("field1")),
2404			))
2405			.annotate(Annotation::field(
2406				"field2_alias",
2407				AnnotationValue::Field(F::new("field2")),
2408			))
2409			.order_by(&["field1_alias", "-field2_alias"]);
2410
2411		let sql = qs.to_sql();
2412
2413		assert!(
2414			sql.contains("ORDER BY"),
2415			"SQL should contain ORDER BY clause. Got: {}",
2416			sql
2417		);
2418	}
2419
2420	#[test]
2421	// From: Django/annotations
2422	fn test_q_expression_annotation_with_aggregation() {
2423		// Test Q expression annotation with aggregation
2424		use crate::orm::aggregation::Aggregate;
2425		use crate::orm::expressions::F;
2426
2427		let qs = QuerySet::<TestModel>::new()
2428			.annotate(Annotation::field(
2429				"computed",
2430				AnnotationValue::Field(F::new("value")),
2431			))
2432			.annotate(Annotation::field(
2433				"count",
2434				AnnotationValue::Aggregate(Aggregate::count(Some("id"))),
2435			));
2436
2437		let sql = qs.to_sql();
2438
2439		assert!(
2440			sql.contains("COUNT") || sql.contains("value"),
2441			"SQL should contain 'COUNT' or 'value'. Got: {}",
2442			sql
2443		);
2444	}
2445
2446	#[test]
2447	// From: Django/annotations
2448	fn test_q_expression_annotation_with_aggregation_1() {
2449		// Test Q expression with different aggregation
2450		use crate::orm::aggregation::Aggregate;
2451		use crate::orm::expressions::F;
2452
2453		let qs = QuerySet::<TestModel>::new()
2454			.annotate(Annotation::field(
2455				"filtered",
2456				AnnotationValue::Field(F::new("status")),
2457			))
2458			.annotate(Annotation::field(
2459				"total",
2460				AnnotationValue::Aggregate(Aggregate::sum("amount")),
2461			));
2462
2463		let sql = qs.to_sql();
2464
2465		assert!(
2466			sql.contains("SUM") || sql.contains("status"),
2467			"SQL should contain 'SUM' or 'status'. Got: {}",
2468			sql
2469		);
2470	}
2471
2472	#[test]
2473	// From: Django/annotations
2474	fn test_raw_sql_with_inherited_field() {
2475		// Test raw SQL annotation with inherited field
2476		use crate::orm::expressions::F;
2477
2478		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2479			"raw_field",
2480			AnnotationValue::Field(F::new("inherited_field")),
2481		));
2482
2483		let sql = qs.to_sql();
2484
2485		assert!(
2486			sql.contains("inherited_field") || sql.contains("raw_field"),
2487			"SQL should contain 'inherited_field' or 'raw_field'. Got: {}",
2488			sql
2489		);
2490	}
2491
2492	#[test]
2493	// From: Django/annotations
2494	fn test_raw_sql_with_inherited_field_1() {
2495		// Test raw SQL with different inherited field
2496		use crate::orm::expressions::F;
2497
2498		let qs = QuerySet::<TestModel>::new().annotate(Annotation::field(
2499			"parent_field",
2500			AnnotationValue::Field(F::new("base_field")),
2501		));
2502
2503		let sql = qs.to_sql();
2504
2505		assert!(
2506			sql.contains("base_field") || sql.contains("parent_field"),
2507			"SQL should contain 'base_field' or 'parent_field'. Got: {}",
2508			sql
2509		);
2510	}
2511}