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}