1use super::QuerySet;
19use crate::backend::Row;
20use crate::db::Db;
21use crate::error::{OrmError, QueryError};
22use crate::expr::{Expr, Field, FkSlot, Ident, RelHop, RelatedColumn, path_alias_of, pk_column};
23use crate::model::{FieldMeta, Model};
24use crate::persist::value_key;
25use crate::plan::SelectExpr;
26use crate::types::DbType;
27use crate::value::Value;
28use async_trait::async_trait;
29use std::any::Any;
30use std::collections::{HashMap, HashSet};
31use std::marker::PhantomData;
32use std::sync::Arc;
33
34type Loaded = Box<dyn Any + Send + Sync>;
35type Load = fn(&Row, &str) -> Result<Loaded, QueryError>;
36type Attach = Arc<dyn Fn(&mut dyn Any, Arc<dyn Any + Send + Sync>) + Send + Sync>;
37
38fn load<T: Model>(row: &Row, prefix: &str) -> Result<Loaded, QueryError> {
39 Ok(Box::new(T::from_row(row, prefix)?))
40}
41
42#[derive(Clone)]
44struct Step {
45 hop: RelHop,
46 fields: &'static [FieldMeta],
48 load: Load,
49 attach: Attach,
50}
51
52pub struct Relation<M, T> {
63 steps: Vec<Step>,
64 _marker: PhantomData<fn() -> (M, T)>,
65}
66
67impl<M, T> Clone for Relation<M, T> {
68 fn clone(&self) -> Self {
69 Self {
70 steps: self.steps.clone(),
71 _marker: PhantomData,
72 }
73 }
74}
75
76impl<M: Model, T: Model> Relation<M, T> {
77 pub fn new<S: FkSlot<T> + 'static>(field: Field<M, S>, slot: fn(&mut M) -> &mut S) -> Self {
81 let attach: Attach = Arc::new(move |parent, child| {
82 if let (Some(parent), Ok(child)) = (parent.downcast_mut::<M>(), child.downcast::<T>())
83 && let Some(fk) = slot(parent).fk()
84 {
85 fk.set_cached(child);
86 }
87 });
88 Self {
89 steps: vec![Step {
90 hop: RelHop {
91 fk_column: field.name().into(),
92 table: T::META.table.into(),
93 pk_column: pk_column::<T>(),
94 },
95 fields: T::META.fields,
96 load: load::<T>,
97 attach,
98 }],
99 _marker: PhantomData,
100 }
101 }
102
103 pub fn then<U: Model>(mut self, next: Relation<T, U>) -> Relation<M, U> {
106 self.steps.extend(next.steps);
107 Relation {
108 steps: self.steps,
109 _marker: PhantomData,
110 }
111 }
112}
113
114#[derive(Clone)]
116pub(super) struct RelNode {
117 step: Step,
118 alias: String,
119 children: Vec<RelNode>,
120}
121
122impl RelNode {
123 fn decode(&self, row: &Row) -> Result<Option<Loaded>, QueryError> {
126 let prefix = format!("{}__", self.alias);
127 let key = format!("{prefix}{}", self.step.hop.pk_column);
128 if row.get(&key).is_none_or(Value::is_null) {
129 return Ok(None);
130 }
131 let mut object = (self.step.load)(row, &prefix)?;
132 attach_all(&mut *object, &self.children, row)?;
133 Ok(Some(object))
134 }
135}
136
137pub(super) fn attach_all(
139 parent: &mut dyn Any,
140 nodes: &[RelNode],
141 row: &Row,
142) -> Result<(), QueryError> {
143 for node in nodes {
144 if let Some(object) = node.decode(row)? {
145 (node.step.attach)(parent, Arc::from(object));
146 }
147 }
148 Ok(())
149}
150
151fn insert_path(nodes: &mut Vec<RelNode>, steps: &[Step], path: &mut Vec<RelHop>) {
153 let Some((step, rest)) = steps.split_first() else {
154 return;
155 };
156 path.push(step.hop.clone());
157 let position = match nodes.iter().position(|n| n.step.hop == step.hop) {
158 Some(position) => position,
159 None => {
160 nodes.push(RelNode {
161 step: step.clone(),
162 alias: path_alias_of(path),
163 children: Vec::new(),
164 });
165 nodes.len() - 1
166 }
167 };
168 insert_path(&mut nodes[position].children, rest, path);
169 path.pop();
170}
171
172fn related_projection(nodes: &[RelNode], path: &mut Vec<RelHop>, out: &mut Vec<SelectExpr>) {
175 for node in nodes {
176 path.push(node.step.hop.clone());
177 for field in node.step.fields {
178 let column = RelatedColumn {
179 path: path.clone(),
180 column: field.column.into(),
181 };
182 let alias: Ident = column.output_name().into();
183 out.push(SelectExpr::new(Expr::Related(column), Some(alias)));
184 }
185 related_projection(&node.children, path, out);
186 path.pop();
187 }
188}
189
190impl<M: Model> QuerySet<M> {
191 #[must_use]
195 pub fn select_related<T: Model>(mut self, relation: Relation<M, T>) -> Self {
196 let mut earlier = Vec::new();
197 related_projection(&self.related, &mut Vec::new(), &mut earlier);
198 insert_path(&mut self.related, &relation.steps, &mut Vec::new());
199 let mut columns = Vec::new();
200 related_projection(&self.related, &mut Vec::new(), &mut columns);
201 self.with_plan(|mut plan| {
202 plan.projection
204 .retain(|s| !earlier.iter().any(|e| e.alias == s.alias));
205 if plan.projection.is_empty() {
206 plan.projection = super::model_projection::<M>();
207 }
208 plan.projection.extend(columns);
209 plan
210 })
211 }
212
213 #[must_use]
219 pub fn prefetch_related<T: Model>(mut self, prefetch: impl Into<Prefetch<M, T>>) -> Self {
220 let prefetch = prefetch.into();
221 if prefetch.relation.steps.len() != 1 {
222 return self.fail("prefetch_related supports single-hop relations only");
223 }
224 self.prefetches.push(Arc::new(prefetch));
225 self
226 }
227
228 pub(super) async fn run_prefetches(&self, models: &mut [M]) -> Result<(), OrmError> {
230 for prefetch in &self.prefetches {
231 prefetch.run(&self.db, models).await?;
232 }
233 Ok(())
234 }
235}
236
237pub struct Prefetch<M: Model, T: Model> {
240 relation: Relation<M, T>,
241 queryset: Option<QuerySet<T>>,
242}
243
244impl<M: Model, T: Model> Prefetch<M, T> {
245 pub fn new(relation: Relation<M, T>) -> Self {
247 Self {
248 relation,
249 queryset: None,
250 }
251 }
252
253 #[must_use]
258 pub fn queryset(mut self, queryset: QuerySet<T>) -> Self {
259 self.queryset = Some(queryset);
260 self
261 }
262}
263
264impl<M: Model, T: Model> From<Relation<M, T>> for Prefetch<M, T> {
265 fn from(relation: Relation<M, T>) -> Self {
266 Self::new(relation)
267 }
268}
269
270#[async_trait]
272pub(super) trait Prefetcher<M: Model>: Send + Sync {
273 async fn run(&self, db: &Db, models: &mut [M]) -> Result<(), OrmError>;
274}
275
276#[async_trait]
277impl<M: Model, T: Model> Prefetcher<M> for Prefetch<M, T> {
278 async fn run(&self, db: &Db, models: &mut [M]) -> Result<(), OrmError> {
279 let Some(step) = self.relation.steps.first() else {
280 return Ok(());
281 };
282 let column = step.hop.fk_column.as_ref();
283 let mut seen = HashSet::new();
284 let mut wanted = Vec::new();
285 let keys: Vec<Option<String>> = models
286 .iter()
287 .map(|model| {
288 let value = model
289 .to_values()
290 .into_iter()
291 .find(|(c, _)| *c == column)
292 .map(|(_, v)| v)
293 .filter(|v| !v.is_null())?;
294 let key = value_key(&value);
295 if seen.insert(key.clone()) {
296 wanted.push(value);
297 }
298 Some(key)
299 })
300 .collect();
301 if wanted.is_empty() {
302 return Ok(());
303 }
304 let base = self.queryset.clone().unwrap_or_else(|| T::objects(db));
305 base.ready()?;
306 if base.empty {
307 return Ok(());
308 }
309 let caps = base.db.capabilities();
310 let used = match base.db.read_parameter_count(base.plan())? {
311 Some(count) => count,
312 None if matches!(caps.kind, crate::BackendKind::MongoDb) => 0,
313 None => {
314 return Err(QueryError::InvalidPlan(
315 "prefetch requires compiled parameter counting".into(),
316 )
317 .into());
318 }
319 };
320 let chunk = caps
321 .max_params
322 .checked_sub(used)
323 .filter(|remaining| *remaining > 0)
324 .ok_or_else(|| QueryError::InvalidPlan("prefetch bind capacity exhausted".into()))?;
325 if wanted.len() > chunk && (base.plan.limit.is_some() || base.plan.offset.is_some()) {
326 return Err(
327 QueryError::InvalidPlan("sliced prefetch cannot span bind batches".into()).into(),
328 );
329 }
330 let mut loaded: HashMap<String, Arc<T>> = HashMap::new();
331 for wanted in wanted.chunks(chunk) {
332 let pk = Expr::col(step.hop.pk_column.clone());
333 let predicate = pk.is_in(wanted.iter().cloned());
334 for target in base.clone().filter(predicate).all().await? {
335 loaded.insert(value_key(&target.pk().to_value()), Arc::new(target));
336 }
337 }
338 for (model, key) in models.iter_mut().zip(&keys) {
339 let target = key.as_ref().and_then(|key| loaded.get(key));
340 if let Some(target) = target {
341 (step.attach)(model, Arc::<T>::clone(target));
342 }
343 }
344 Ok(())
345 }
346}