gel_protocol/
value_opt.rs1use std::collections::HashMap;
2
3use gel_errors::{ClientEncodingError, Error, ErrorKind};
4
5use crate::codec::{ObjectShape, ShapeElement};
6use crate::descriptors::Descriptor;
7use crate::query_arg::{Encoder, QueryArgs};
8use crate::value::Value;
9
10#[derive(Clone, Debug, PartialEq)]
15pub struct ValueOpt(Option<Value>);
16
17impl<V: Into<Value>> From<V> for ValueOpt {
18 fn from(value: V) -> Self {
19 ValueOpt(Some(value.into()))
20 }
21}
22impl<V: Into<Value>> From<Option<V>> for ValueOpt
23where
24 Value: From<V>,
25{
26 fn from(value: Option<V>) -> Self {
27 ValueOpt(value.map(Value::from))
28 }
29}
30impl<V: Into<Value>> From<Vec<V>> for ValueOpt
31where
32 Value: From<V>,
33{
34 fn from(value: Vec<V>) -> Self {
35 ValueOpt(Some(Value::Array(
36 value.into_iter().map(Value::from).collect(),
37 )))
38 }
39}
40impl<V: Into<Value>> From<Option<Vec<V>>> for ValueOpt
41where
42 Value: From<V>,
43{
44 fn from(value: Option<Vec<V>>) -> Self {
45 let mapped = value.map(|value| Value::Array(value.into_iter().map(Value::from).collect()));
46 ValueOpt(mapped)
47 }
48}
49impl From<ValueOpt> for Option<Value> {
50 fn from(value: ValueOpt) -> Self {
51 value.0
52 }
53}
54
55impl QueryArgs for HashMap<&str, ValueOpt> {
56 fn encode(&self, encoder: &mut Encoder) -> Result<(), Error> {
57 if self.is_empty() && encoder.ctx.root_pos.is_none() {
58 return Ok(());
59 }
60
61 let root_pos = encoder.ctx.root_pos.ok_or_else(|| {
62 ClientEncodingError::with_message(format!(
63 "provided {} named arguments, but no arguments were expected by the server",
64 self.len()
65 ))
66 })?;
67
68 let Descriptor::ObjectShape(target_shape) = encoder.ctx.get(root_pos)? else {
69 return Err(ClientEncodingError::with_message(
70 "query didn't expect named arguments",
71 ));
72 };
73
74 let mut shape_elements: Vec<ShapeElement> = Vec::new();
75 let mut fields: Vec<Option<Value>> = Vec::new();
76
77 for param_descriptor in target_shape.elements.iter() {
78 let value = self.get(param_descriptor.name.as_str());
79
80 let Some(value) = value else {
81 return Err(ClientEncodingError::with_message(format!(
82 "argument for ${} missing",
83 param_descriptor.name
84 )));
85 };
86
87 shape_elements.push(ShapeElement::from(param_descriptor));
88 fields.push(value.0.clone());
89 }
90
91 Value::Object {
92 shape: ObjectShape::new(shape_elements),
93 fields,
94 }
95 .encode(encoder)
96 }
97}
98
99#[macro_export]
114macro_rules! named_args {
115 ($($key:expr => $value:expr,)+) => { $crate::named_args!($($key => $value),+) };
116 ($($key:expr => $value:expr),*) => {
117 {
118 const CAP: usize = <[()]>::len(&[$({ stringify!($key); }),*]);
119 let mut map = ::std::collections::HashMap::<&str, $crate::value_opt::ValueOpt>::with_capacity(CAP);
120 $(
121 map.insert($key, $crate::value_opt::ValueOpt::from($value));
122 )*
123 map
124 }
125 };
126}