Skip to main content

gatelogue_types/
util.rs

1use rusqlite::{Connection, Params, Row};
2
3use crate::error::Result;
4
5pub type ID = u32;
6
7#[macro_export]
8#[doc(hidden)]
9macro_rules! _get_column {
10    ($table_name:literal, $column_name:ident, $ColTy:ty) => {
11        pub fn $column_name(self, gd: &$crate::GD) -> $crate::error::Result<$ColTy> {
12            #[expect(clippy::allow_attributes)]
13            #[allow(unused_imports)]
14            use $crate::node::Node;
15            gd.0.query_one(
16                concat!(
17                    "SELECT \"",
18                    stringify!($column_name),
19                    "\" FROM ",
20                    $table_name,
21                    " WHERE i = ?"
22                ),
23                (self.i(),),
24                |a| a.get(0),
25            )
26            .map_err(|e| {
27                if e == rusqlite::Error::QueryReturnedNoRows {
28                    $crate::error::Error::NoNodeOfType(self.i(), self.ty())
29                } else {
30                    e.into()
31                }
32            })
33        }
34    };
35    ($table_name:literal, $fn_name:ident, $column_name:literal, $ColTy:ty) => {
36        pub fn $fn_name(self, gd: &$crate::GD) -> $crate::error::Result<$ColTy> {
37            #[expect(clippy::allow_attributes)]
38            #[allow(unused_imports)]
39            use $crate::node::Node;
40            gd.0.query_one(
41                concat!(
42                    "SELECT \"",
43                    $column_name,
44                    "\" FROM ",
45                    $table_name,
46                    " WHERE i = ?"
47                ),
48                (self.i(),),
49                |a| a.get(0),
50            )
51            .map_err(|e| {
52                if e == rusqlite::Error::QueryReturnedNoRows {
53                    $crate::error::Error::NoNodeOfType(self.i(), self.ty())
54                } else {
55                    e.into()
56                }
57            })
58        }
59    };
60}
61#[macro_export]
62#[doc(hidden)]
63macro_rules! _get_set {
64    ($table_name:literal, $fn_name:ident, $column_name:literal, $ColTy:ty) => {
65        pub fn $fn_name(self, gd: &$crate::GD) -> $crate::error::Result<Vec<$ColTy>> {
66            #[expect(clippy::allow_attributes)]
67            #[allow(unused_imports)]
68            use $crate::node::Node;
69            match gd
70                .0
71                .prepare_cached(concat!(
72                    "SELECT DISTINCT \"",
73                    $column_name,
74                    "\" FROM ",
75                    $table_name,
76                    " WHERE i = ?"
77                ))?
78                .query_and_then((self.i(),), |a| a.get(0).map_err(Into::into))
79            {
80                Ok(a) => Ok(a.collect::<$crate::error::Result<Vec<_>>>()?),
81                Err(e) => Err(e.into()),
82            }
83        }
84    };
85}
86
87#[macro_export]
88#[doc(hidden)]
89macro_rules! _get_derived_vec {
90    ($fn_name:ident, $RetTy:ty, $key:literal) => {
91        pub fn $fn_name(self, gd: &$crate::GD) -> $crate::error::Result<Vec<$RetTy>> {
92            use $crate::util::ConnectionExt;
93            gd.0.query_and_then_get_vec(include_str!($key), (self.0,), |row| Ok(row.get(0)?))
94        }
95    };
96}
97
98#[macro_export]
99#[doc(hidden)]
100macro_rules! _from_sql_for_enum {
101    ($Ty:ty) => {
102        impl rusqlite::types::FromSql for $Ty {
103            fn column_result(
104                value: rusqlite::types::ValueRef<'_>,
105            ) -> rusqlite::types::FromSqlResult<Self> {
106                use std::str::FromStr;
107                Self::from_str(value.as_str()?)
108                    .map_err(|e| rusqlite::types::FromSqlError::Other(e.into()))
109            }
110        }
111    };
112}
113
114pub trait ConnectionExt {
115    fn query_and_then_get_vec<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<Vec<T>>
116    where
117        P: Params,
118        F: FnMut(&Row<'_>) -> Result<T>;
119}
120impl ConnectionExt for Connection {
121    fn query_and_then_get_vec<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<Vec<T>>
122    where
123        P: Params,
124        F: FnMut(&Row<'_>) -> Result<T>,
125    {
126        match self.prepare(sql)?.query_and_then(params, f) {
127            Ok(a) => Ok(a.collect::<Result<Vec<_>>>()?),
128            Err(e) => Err(e.into()),
129        }
130    }
131}