edgedb_composable_query/
args.rs

1use crate::prim::EdgedbPrim;
2use crate::EdgedbValue;
3use crate::Result;
4use edgedb_protocol::query_arg::QueryArgs;
5use edgedb_protocol::value::Value;
6
7/// A tuple of query arguments, currently each must be [`EdgedbPrim`].
8pub trait EdgedbQueryArgs {
9    type EdgedbArgsType: QueryArgs;
10
11    fn to_query_args(self) -> Result<Self::EdgedbArgsType>;
12}
13
14impl EdgedbQueryArgs for () {
15    type EdgedbArgsType = ();
16
17    fn to_query_args(self) -> Result<Self::EdgedbArgsType> {
18        Ok(self)
19    }
20}
21
22macro_rules! ignore_first {
23    ($a:ident, $b:ident) => {
24        $b
25    };
26}
27
28macro_rules! impl_tuple {
29    ( $count:expr, ($($name:ident,)+), ($($small_name:ident,)+) ) => (
30
31        impl<$($name:EdgedbPrim),+> EdgedbQueryArgs for ($($name,)+) {
32            type EdgedbArgsType = ($(ignore_first!($name, Value),)+);
33
34            fn to_query_args(self) -> Result<Self::EdgedbArgsType> {
35                let ($($small_name,)+) = self;
36
37                Ok(($($small_name.to_edgedb_val()?,)+))
38            }
39        }
40
41    )
42}
43
44impl_tuple! {1, (T0,), (t0,)}
45impl_tuple! {2, (T0, T1,), (t0, t1,)}
46impl_tuple! {3, (T0, T1, T2,), (t0, t1, t2,)}
47impl_tuple! {4, (T0, T1, T2, T3,), (t0, t1, t2, t3,)}
48impl_tuple! {5, (T0, T1, T2, T3, T4,), (t0, t1, t2, t3, t4,)}
49impl_tuple! {6, (T0, T1, T2, T3, T4, T5,), (t0, t1, t2, t3, t4, t5,)}
50
51#[cfg(test)]
52mod test {
53    use serde_json::json;
54
55    use crate::{prim::EdgedbJson, query, value::EdgedbSetValue, EdgedbObject};
56
57    #[derive(Debug, PartialEq)]
58    struct ExamplImplStruct {
59        a: String,
60        b: Option<String>,
61    }
62
63    impl EdgedbObject for ExamplImplStruct {
64        fn from_edgedb_object(
65            shape: edgedb_protocol::codec::ObjectShape,
66            mut fields: Vec<Option<edgedb_protocol::value::Value>>,
67        ) -> anyhow::Result<Self> {
68            let mut a = None;
69            let mut b = None;
70
71            for (i, s) in shape.elements.iter().enumerate() {
72                match s.name.as_str() {
73                    "a" => {
74                        a = fields[i]
75                            .take()
76                            .map(EdgedbSetValue::from_edgedb_set_value)
77                            .transpose()?;
78                    }
79                    "b" => {
80                        b = fields[i]
81                            .take()
82                            .map(EdgedbSetValue::from_edgedb_set_value)
83                            .transpose()?;
84                    }
85                    _ => {}
86                }
87            }
88
89            Ok(Self {
90                a: EdgedbSetValue::interpret_possibly_missing_required_value(a)?,
91                b: EdgedbSetValue::interpret_possibly_missing_required_value(b)?,
92            })
93        }
94
95        // fn to_edgedb_object(
96        //     &self,
97        // ) -> anyhow::Result<(
98        //     edgedb_protocol::codec::ObjectShape,
99        //     Vec<Option<edgedb_protocol::value::Value>>,
100        // )> {
101        //     todo!()
102        // }
103    }
104
105    #[tokio::test]
106    async fn some_queries() -> anyhow::Result<()> {
107        let conn = edgedb_tokio::create_client().await?;
108
109        assert_eq!(
110            query::<ExamplImplStruct, _>(
111                &conn,
112                "select { a := <str>$0, b := <str><int32>$1 }",
113                ("hi".to_owned(), 3)
114            )
115            .await?,
116            ExamplImplStruct {
117                a: "hi".to_string(),
118                b: Some("3".to_string())
119            }
120        );
121
122        assert_eq!(
123            query::<ExamplImplStruct, _>(
124                &conn,
125                "select { a := <str>(<json>$0)['a'], b := <str><int32>(<json>$0)['b'] }",
126                (EdgedbJson(json!({"a": "hello", "b": 3})),)
127            )
128            .await?,
129            ExamplImplStruct {
130                a: "hello".to_string(),
131                b: Some("3".to_string())
132            }
133        );
134
135        Ok(())
136    }
137}