1use crate::entity::{IEntityType, IFromRow, ILazyInit};
24use crate::error::{EFError, EFResult};
25use crate::lazy::{load_collection_lazy, load_scalar_lazy, LazyContext, MAX_LAZY_DEPTH};
26use std::marker::PhantomData;
27use std::sync::Arc;
28
29pub struct BelongsTo<T> {
38 inner: Option<Box<T>>,
39 lazy_ctx: Option<Arc<dyn LazyContext>>,
40 loaded: bool,
41 _phantom: PhantomData<T>,
42}
43
44impl<T> BelongsTo<T> {
45 pub fn new() -> Self {
46 Self {
47 inner: None,
48 lazy_ctx: None,
49 loaded: false,
50 _phantom: PhantomData,
51 }
52 }
53
54 pub fn with(entity: T) -> Self {
55 Self {
56 inner: Some(Box::new(entity)),
57 lazy_ctx: None,
58 loaded: true,
59 _phantom: PhantomData,
60 }
61 }
62
63 pub fn get(&self) -> Option<&T> {
64 self.inner.as_deref()
65 }
66
67 pub fn get_mut(&mut self) -> Option<&mut T> {
68 self.inner.as_deref_mut()
69 }
70
71 pub fn is_loaded(&self) -> bool {
74 self.loaded
75 }
76
77 pub fn set_lazy_context(&mut self, ctx: Arc<dyn LazyContext>) {
82 self.lazy_ctx = Some(ctx);
83 }
84
85 pub async fn load(&mut self) -> EFResult<()>
94 where
95 T: IFromRow + IEntityType + ILazyInit,
96 {
97 if self.loaded {
98 return Ok(());
99 }
100 let Some(ctx) = self.lazy_ctx.clone() else {
101 return Ok(());
103 };
104 if ctx.depth() >= MAX_LAZY_DEPTH {
105 return Err(EFError::other("lazy loading recursion limit exceeded"));
106 }
107 let maybe_entity = load_scalar_lazy::<T>(ctx.as_ref()).await?;
108 if let Some(mut entity) = maybe_entity {
109 let provider = ctx.provider().clone();
111 let filter_map = ctx.filter_map().map(|m| Arc::new(m.clone()));
112 entity.attach_lazy_contexts(provider, filter_map, ctx.depth() + 1);
113 self.inner = Some(Box::new(entity));
114 }
115 self.loaded = true;
116 Ok(())
117 }
118}
119
120impl<T> Default for BelongsTo<T> {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125
126impl<T> Clone for BelongsTo<T> {
127 fn clone(&self) -> Self {
128 Self {
129 inner: None, lazy_ctx: None,
131 loaded: false,
132 _phantom: PhantomData,
133 }
134 }
135}
136
137impl<T> std::fmt::Debug for BelongsTo<T> {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 f.debug_struct("BelongsTo")
140 .field("loaded", &self.loaded)
141 .finish()
142 }
143}
144
145pub struct HasMany<T, Join = ()> {
154 items: Vec<T>,
155 lazy_ctx: Option<Arc<dyn LazyContext>>,
156 loaded: bool,
157 _phantom: PhantomData<(T, Join)>,
158}
159
160impl<T, Join> HasMany<T, Join> {
161 pub fn new() -> Self {
162 Self {
163 items: Vec::new(),
164 lazy_ctx: None,
165 loaded: false,
166 _phantom: PhantomData,
167 }
168 }
169
170 pub fn with(items: Vec<T>) -> Self {
171 Self {
172 items,
173 lazy_ctx: None,
174 loaded: true,
175 _phantom: PhantomData,
176 }
177 }
178
179 pub fn items(&self) -> &[T] {
180 &self.items
181 }
182
183 pub fn items_mut(&mut self) -> &mut Vec<T> {
184 &mut self.items
185 }
186
187 pub fn add(&mut self, item: T) {
188 self.items.push(item);
189 }
190
191 pub fn remove(&mut self, index: usize) -> Option<T> {
192 if index < self.items.len() {
193 Some(self.items.remove(index))
194 } else {
195 None
196 }
197 }
198
199 pub fn len(&self) -> usize {
200 self.items.len()
201 }
202
203 pub fn is_empty(&self) -> bool {
204 self.items.is_empty()
205 }
206
207 pub fn is_loaded(&self) -> bool {
210 self.loaded
211 }
212
213 pub fn set_lazy_context(&mut self, ctx: Arc<dyn LazyContext>) {
218 self.lazy_ctx = Some(ctx);
219 }
220
221 pub async fn load(&mut self) -> EFResult<()>
229 where
230 T: IFromRow + IEntityType + ILazyInit,
231 Join: 'static,
232 {
233 if self.loaded {
234 return Ok(());
235 }
236 let Some(ctx) = self.lazy_ctx.clone() else {
237 return Ok(());
239 };
240 if ctx.depth() >= MAX_LAZY_DEPTH {
241 return Err(EFError::other("lazy loading recursion limit exceeded"));
242 }
243 let mut entities = load_collection_lazy::<T>(ctx.as_ref()).await?;
244 let provider = ctx.provider().clone();
246 let filter_map = ctx.filter_map().map(|m| Arc::new(m.clone()));
247 let depth = ctx.depth() + 1;
248 for entity in &mut entities {
249 let p = provider.clone();
251 let fm = filter_map.clone();
252 entity.attach_lazy_contexts(p, fm, depth);
253 }
254 self.items = entities;
255 self.loaded = true;
256 Ok(())
257 }
258}
259
260impl<T, Join> Default for HasMany<T, Join> {
261 fn default() -> Self {
262 Self::new()
263 }
264}
265
266impl<T, Join> Clone for HasMany<T, Join> {
267 fn clone(&self) -> Self {
268 Self {
269 items: Vec::new(), lazy_ctx: None,
271 loaded: false,
272 _phantom: PhantomData,
273 }
274 }
275}
276
277impl<T, Join> std::fmt::Debug for HasMany<T, Join> {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 f.debug_struct("HasMany")
280 .field("loaded", &self.loaded)
281 .field("len", &self.items.len())
282 .finish()
283 }
284}
285
286pub type Through<Join> = Join;
288
289pub struct HasOne<T> {
296 inner: Option<Box<T>>,
297 lazy_ctx: Option<Arc<dyn LazyContext>>,
298 loaded: bool,
299 _phantom: PhantomData<T>,
300}
301
302impl<T> HasOne<T> {
303 pub fn new() -> Self {
304 Self {
305 inner: None,
306 lazy_ctx: None,
307 loaded: false,
308 _phantom: PhantomData,
309 }
310 }
311
312 pub fn with(entity: T) -> Self {
313 Self {
314 inner: Some(Box::new(entity)),
315 lazy_ctx: None,
316 loaded: true,
317 _phantom: PhantomData,
318 }
319 }
320
321 pub fn get(&self) -> Option<&T> {
322 self.inner.as_deref()
323 }
324
325 pub fn get_mut(&mut self) -> Option<&mut T> {
326 self.inner.as_deref_mut()
327 }
328
329 pub fn is_loaded(&self) -> bool {
331 self.loaded
332 }
333
334 pub fn set_lazy_context(&mut self, ctx: Arc<dyn LazyContext>) {
336 self.lazy_ctx = Some(ctx);
337 }
338
339 pub async fn load(&mut self) -> EFResult<()>
341 where
342 T: IFromRow + IEntityType + ILazyInit,
343 {
344 if self.loaded {
345 return Ok(());
346 }
347 let Some(ctx) = self.lazy_ctx.clone() else {
348 return Ok(());
349 };
350 if ctx.depth() >= MAX_LAZY_DEPTH {
351 return Err(EFError::other("lazy loading recursion limit exceeded"));
352 }
353 let maybe_entity = load_scalar_lazy::<T>(ctx.as_ref()).await?;
354 if let Some(mut entity) = maybe_entity {
355 let provider = ctx.provider().clone();
356 let filter_map = ctx.filter_map().map(|m| Arc::new(m.clone()));
357 entity.attach_lazy_contexts(provider, filter_map, ctx.depth() + 1);
358 self.inner = Some(Box::new(entity));
359 }
360 self.loaded = true;
361 Ok(())
362 }
363}
364
365impl<T> Default for HasOne<T> {
366 fn default() -> Self {
367 Self::new()
368 }
369}
370
371impl<T> Clone for HasOne<T> {
372 fn clone(&self) -> Self {
373 Self {
374 inner: None,
375 lazy_ctx: None,
376 loaded: false,
377 _phantom: PhantomData,
378 }
379 }
380}
381
382impl<T> std::fmt::Debug for HasOne<T> {
383 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
384 f.debug_struct("HasOne")
385 .field("loaded", &self.loaded)
386 .finish()
387 }
388}
389
390#[derive(Debug, Clone, Copy, PartialEq, Eq)]
397pub enum DeleteBehavior {
398 Cascade,
399 Restrict,
400 SetNull,
401 NoAction,
402}