1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Subquery / Exists / OuterRef builders (issue #5).
//!
//! The fifth slice of the ORM Expression DSL epic. Three Django-shape
//! primitives that turn a [`SelectQuery`] into something embeddable
//! inside a larger queryset.
//!
//! [`SelectQuery`]: crate::core::SelectQuery
//!
//! ```ignore
//! use rustango::core::subquery::{exists, not_exists, in_subquery, outer_ref};
//! use rustango::core::{Column as _, F};
//!
//! // EXISTS — "authors who have at least one book".
//! let with_books = Book::objects()
//! .where_(Book::author_id.eq_expr(outer_ref("id")))
//! .compile()?;
//! let authors = Author::objects()
//! .where_expr(exists(with_books))
//! .fetch(&pool).await?;
//!
//! // NOT EXISTS — "authors with no books".
//! let no_books = Book::objects()
//! .where_(Book::author_id.eq_expr(outer_ref("id")))
//! .compile()?;
//! let empty = Author::objects()
//! .where_expr(not_exists(no_books))
//! .fetch(&pool).await?;
//!
//! // IN (SELECT …) — "posts in any of the public categories".
//! let public_cat_ids = Category::objects()
//! .where_(Category::is_public.eq(true))
//! .compile()?;
//! let visible = Post::objects()
//! .where_expr(in_subquery("category_id", public_cat_ids))
//! .fetch(&pool).await?;
//! ```
//!
//! ## How OuterRef resolves
//!
//! [`outer_ref("col")`][outer_ref] returns an [`Expr::OuterRef`] that
//! the SQL writer resolves against the immediately enclosing query at
//! emit time. Concretely:
//!
//! ```text
//! SELECT … FROM "author" WHERE EXISTS (
//! SELECT … FROM "book" WHERE "book"."author_id" = "author"."id"
//! ^^^^^^^^
//! OuterRef
//! )
//! ```
//!
//! The writer threads a scope stack through emission — every `EXISTS`,
//! `NOT EXISTS`, `IN (SELECT …)`, and scalar [`subquery`] pushes a
//! frame, and `outer_ref("col")` reads the immediate parent. Multi-
//! level correlation works the same way (parent of parent of …).
//!
//! ## Compile-time validation lives on the inner queryset
//!
//! These builders take an already-compiled [`SelectQuery`], so any
//! column-name typo or schema mismatch surfaces at the inner
//! `queryset.compile()` call — not when the outer query is finally
//! executed. Build the subquery first, propagate `?`, then embed.
use Expr;
use ;
/// `EXISTS (subquery)` — true when the subquery returns at least one
/// row. Mirrors Django's [`Exists`] expression and is by far the most
/// common subquery shape in ORM code.
///
/// [`Exists`]: https://docs.djangoproject.com/en/6.0/ref/models/expressions/#django.db.models.Exists
/// `NOT EXISTS (subquery)` — true when the subquery returns no rows.
/// Django's `~Exists(…)` shorthand. The canonical "find rows in A
/// with no related row in B" pattern.
/// `<column> IN (subquery)` — the standard subquery-membership shape.
/// Useful when the inner query needs joins or aggregation that can't
/// be expressed as a flat [`crate::core::Op::In`] list literal.
///
/// `column` is the outer column to compare; `subquery` should select
/// a single column whose values are checked against `column`.
/// `<column> NOT IN (subquery)` — inverse of [`in_subquery`].
/// Scalar subquery — `(SELECT … FROM …)`. Embeddable as an `Expr`
/// anywhere `set_expr` / `eq_expr` / a CASE THEN slot expects a value.
/// Caller is responsible for shaping the inner queryset (`.limit(1)`,
/// projection narrowing, etc.) so the result is one column × one row;
/// otherwise the database errors at runtime.
/// `OuterRef("col")` — reference a column from the enclosing query
/// inside a correlated subquery. Equivalent to Django's
/// [`OuterRef('col')`]. Only resolves correctly when emitted from
/// inside a subquery wrapper ([`exists`], [`not_exists`],
/// [`in_subquery`], [`subquery`]); the writer raises
/// [`crate::sql::SqlError::OuterRefOutsideSubquery`] if it shows up
/// outside one.
///
/// `column` is a column name on the outer model — the writer
/// qualifies it as `"<outer_table>"."<col>"` at emission time, so the
/// generated SQL stays unambiguous even with name collisions across
/// inner and outer tables.
///
/// [`OuterRef('col')`]: https://docs.djangoproject.com/en/6.0/ref/models/expressions/#django.db.models.OuterRef