dojo_orm/
model.rs

1use crate::pagination::{Cursor, Row};
2use crate::types::ToSql;
3use anyhow::Result;
4use async_graphql::Enum;
5use chrono::NaiveDateTime;
6use postgres_types::{accepts, to_sql_checked};
7use serde::{Deserialize, Serialize};
8use std::fmt::Display;
9use strum::{Display, EnumString};
10use uuid::Uuid;
11
12macro_rules! impl_value {
13    ($ty: ty, $variant: ident) => {
14        impl From<$ty> for Value {
15            fn from(value: $ty) -> Self {
16                Value::$variant(value)
17            }
18        }
19
20        impl From<&$ty> for Value {
21            fn from(value: &$ty) -> Self {
22                Value::$variant(value.clone())
23            }
24        }
25
26        impl From<Option<$ty>> for Value {
27            fn from(_: Option<$ty>) -> Self {
28                Value::Null
29            }
30        }
31    };
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
35pub enum Value {
36    Uuid(Uuid),
37    Int32(i32),
38    Int64(i64),
39    String(String),
40    NaiveDateTime(NaiveDateTime),
41    Null,
42}
43
44impl_value!(Uuid, Uuid);
45impl_value!(i32, Int32);
46impl_value!(i64, Int64);
47impl_value!(String, String);
48impl_value!(NaiveDateTime, NaiveDateTime);
49
50impl ToSql for Value {
51    fn to_sql(
52        &self,
53        ty: &crate::types::Type,
54        w: &mut bytes::BytesMut,
55    ) -> std::result::Result<crate::types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
56        match self {
57            Value::Uuid(t) => t.to_sql(ty, w),
58            Value::Int32(t) => t.to_sql(ty, w),
59            Value::Int64(t) => t.to_sql(ty, w),
60            Value::String(t) => t.to_sql(ty, w),
61            Value::NaiveDateTime(t) => t.to_sql(ty, w),
62            Value::Null => Ok(crate::types::IsNull::Yes),
63        }
64    }
65
66    accepts!(UUID, INT4, INT8, TEXT, TIMESTAMP);
67    to_sql_checked!();
68}
69
70pub trait Model {
71    const NAME: &'static str;
72    const COLUMNS: &'static [&'static str];
73    fn params(&self) -> Vec<&(dyn ToSql + Sync)>;
74    fn from_row(row: tokio_postgres::Row) -> Result<Self>
75    where
76        Self: Sized;
77
78    fn get_value(&self, column: &str) -> Option<Value>;
79    fn sort_keys() -> Vec<String>;
80    fn cursor(&self) -> Cursor {
81        let mut values = vec![];
82        for key in Self::sort_keys() {
83            if let Some(value) = self.get_value(key.as_str()) {
84                values.push(Row::new(key, value));
85            }
86        }
87
88        Cursor::new(values)
89    }
90}
91
92pub trait UpdateModel {
93    const COLUMNS: &'static [&'static str];
94    fn columns(&self) -> Vec<&'static str>;
95    fn params(&self) -> Vec<&(dyn ToSql + Sync)>;
96}