rws_server/model/
relation.rs1use std::marker::PhantomData;
8
9use super::pool::DbPool;
10use super::repository::{live_condition, placeholder};
11use super::{DbError, Model, Value};
12
13#[derive(Debug, Clone)]
24pub struct HasMany<T: Model> {
25 owner_pk: Value,
26 fk_col: &'static str,
27 _phantom: PhantomData<T>,
28}
29
30impl<T: Model> HasMany<T> {
31 pub fn new(owner_pk: Value, fk_col: &'static str) -> Self {
32 HasMany { owner_pk, fk_col, _phantom: PhantomData }
33 }
34
35 pub async fn load(&self, pool: &DbPool) -> Result<Vec<T>, DbError> {
37 let sql = format!(
38 "SELECT * FROM {} WHERE {} = {}{}",
39 T::table_name(), self.fk_col, placeholder(pool.backend(), 1), and_live::<T>(),
40 );
41 let rows = pool.query_rows(&sql, &[self.owner_pk.clone()]).await?;
42 rows.iter().map(|r| T::from_row(r)).collect()
43 }
44}
45
46#[derive(Debug, Clone)]
52pub struct HasOne<O: Model> {
53 owner_pk: Value,
54 fk_col: &'static str,
55 _phantom: PhantomData<O>,
56}
57
58impl<O: Model> HasOne<O> {
59 pub fn new(owner_pk: Value, fk_col: &'static str) -> Self {
60 HasOne { owner_pk, fk_col, _phantom: PhantomData }
61 }
62
63 pub async fn load(&self, pool: &DbPool) -> Result<Option<O>, DbError> {
65 let sql = format!(
66 "SELECT * FROM {} WHERE {} = {}{} LIMIT 1",
67 O::table_name(), self.fk_col, placeholder(pool.backend(), 1), and_live::<O>(),
68 );
69 let rows = pool.query_rows(&sql, &[self.owner_pk.clone()]).await?;
70 match rows.into_iter().next() {
71 Some(row) => Ok(Some(O::from_row(&row)?)),
72 None => Ok(None),
73 }
74 }
75}
76
77#[derive(Debug, Clone)]
83pub struct BelongsTo<O: Model> {
84 fk_value: Value,
85 _phantom: PhantomData<O>,
86}
87
88impl<O: Model> BelongsTo<O> {
89 pub fn new(fk_value: Value) -> Self {
90 BelongsTo { fk_value, _phantom: PhantomData }
91 }
92
93 pub async fn load(&self, pool: &DbPool) -> Result<Option<O>, DbError> {
95 let sql = format!(
96 "SELECT * FROM {} WHERE {} = {}{} LIMIT 1",
97 O::table_name(), O::primary_key_name(), placeholder(pool.backend(), 1), and_live::<O>(),
98 );
99 let rows = pool.query_rows(&sql, &[self.fk_value.clone()]).await?;
100 match rows.into_iter().next() {
101 Some(row) => Ok(Some(O::from_row(&row)?)),
102 None => Ok(None),
103 }
104 }
105}
106
107fn and_live<T: Model>() -> String {
108 live_condition::<T>().map(|c| format!(" AND {c}")).unwrap_or_default()
109}