oxidite_db/
relations.rs

1use crate::{Database, Model, Result};
2use std::marker::PhantomData;
3
4/// Represents a one-to-many relationship
5pub struct HasMany<P, C> {
6    parent_id: i64,
7    foreign_key: String,
8    _phantom: PhantomData<(P, C)>,
9}
10
11impl<P, C> HasMany<P, C>
12where
13    P: Model,
14    C: Model,
15{
16    pub fn new(parent_id: i64, foreign_key: impl Into<String>) -> Self {
17        Self {
18            parent_id,
19            foreign_key: foreign_key.into(),
20            _phantom: PhantomData,
21        }
22    }
23
24    /// Fetch all related records
25    pub async fn get(&self, db: &impl Database) -> Result<Vec<C>> {
26        let query = format!(
27            "SELECT * FROM {} WHERE {} = {}",
28            C::table_name(),
29            self.foreign_key,
30            self.parent_id
31        );
32        let rows = db.query(&query).await?;
33        
34        let mut models = Vec::new();
35        for row in rows {
36            models.push(C::from_row(&row)?);
37        }
38        Ok(models)
39    }
40}
41
42/// Represents a one-to-one relationship (owned)
43pub struct HasOne<P, C> {
44    parent_id: i64,
45    foreign_key: String,
46    _phantom: PhantomData<(P, C)>,
47}
48
49impl<P, C> HasOne<P, C>
50where
51    P: Model,
52    C: Model,
53{
54    pub fn new(parent_id: i64, foreign_key: impl Into<String>) -> Self {
55        Self {
56            parent_id,
57            foreign_key: foreign_key.into(),
58            _phantom: PhantomData,
59        }
60    }
61
62    /// Fetch the related record
63    pub async fn get(&self, db: &impl Database) -> Result<Option<C>> {
64        let query = format!(
65            "SELECT * FROM {} WHERE {} = {}",
66            C::table_name(),
67            self.foreign_key,
68            self.parent_id
69        );
70        let row = db.query_one(&query).await?;
71        
72        match row {
73            Some(row) => Ok(Some(C::from_row(&row)?)),
74            None => Ok(None),
75        }
76    }
77}
78
79/// Represents a belongs-to relationship (inverse of HasMany/HasOne)
80pub struct BelongsTo<C, P> {
81    foreign_key_value: i64,
82    _phantom: PhantomData<(C, P)>,
83}
84
85impl<C, P> BelongsTo<C, P>
86where
87    C: Model,
88    P: Model,
89{
90    pub fn new(foreign_key_value: i64) -> Self {
91        Self {
92            foreign_key_value,
93            _phantom: PhantomData,
94        }
95    }
96
97    /// Fetch the parent record
98    pub async fn get(&self, db: &impl Database) -> Result<Option<P>> {
99        P::find(db, self.foreign_key_value).await
100    }
101}