diff --git a/lib/src/dbs/iterator.rs b/lib/src/dbs/iterator.rs index 9c8acc86..fdf16a08 100644 --- a/lib/src/dbs/iterator.rs +++ b/lib/src/dbs/iterator.rs @@ -14,6 +14,7 @@ use crate::sql::table::Table; use crate::sql::thing::Thing; use crate::sql::value::Value; use async_recursion::async_recursion; +use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeMap; use std::mem; @@ -219,36 +220,31 @@ impl Iterator { let vals = Value::from(vals); // Loop over each group clause for field in fields.other() { - // Process it if it is a normal field - if let Field::Alone(v) = field { - match v { + // Process the field + if let Field::Single { + expr, + alias, + } = field + { + let idiom = alias + .as_ref() + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(expr.to_idiom())); + match expr { Value::Function(f) if f.is_aggregate() => { - let x = vals - .all() - .get(ctx, opt, txn, None, v.to_idiom().as_ref()) - .await?; + let x = + vals.all().get(ctx, opt, txn, None, idiom.as_ref()).await?; let x = f.aggregate(x).compute(ctx, opt, txn, None).await?; - obj.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?; + obj.set(ctx, opt, txn, idiom.as_ref(), x).await?; } _ => { let x = vals.first(); - let x = v.compute(ctx, opt, txn, Some(&x)).await?; - obj.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?; - } - } - } - // Process it if it is a aliased field - if let Field::Alias(v, i) = field { - match v { - Value::Function(f) if f.is_aggregate() => { - let x = vals.all().get(ctx, opt, txn, None, i).await?; - let x = f.aggregate(x).compute(ctx, opt, txn, None).await?; - obj.set(ctx, opt, txn, i, x).await?; - } - _ => { - let x = vals.first(); - let x = i.compute(ctx, opt, txn, Some(&x)).await?; - obj.set(ctx, opt, txn, i, x).await?; + let x = if let Some(alias) = alias { + alias.compute(ctx, opt, txn, Some(&x)).await? + } else { + expr.compute(ctx, opt, txn, Some(&x)).await? + }; + obj.set(ctx, opt, txn, idiom.as_ref(), x).await?; } } } diff --git a/lib/src/doc/table.rs b/lib/src/doc/table.rs index 40dc7394..b8a9a1fa 100644 --- a/lib/src/doc/table.rs +++ b/lib/src/doc/table.rs @@ -261,67 +261,40 @@ impl<'a> Document<'a> { }; // for field in exp.other() { - // Process it if it is a normal field - if let Field::Alone(v) = field { - match v { + // Process the field + if let Field::Single { + expr, + alias, + } = field + { + let idiom = alias.clone().unwrap_or_else(|| expr.to_idiom()); + match expr { Value::Function(f) if f.is_rolling() => match f.name() { "count" => { let val = f.compute(ctx, opt, txn, doc).await?; - self.chg(&mut ops, &act, v.to_idiom(), val); + self.chg(&mut ops, &act, idiom, val); } "math::sum" => { let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.chg(&mut ops, &act, v.to_idiom(), val); + self.chg(&mut ops, &act, idiom, val); } "math::min" => { let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.min(&mut ops, &act, v.to_idiom(), val); + self.min(&mut ops, &act, idiom, val); } "math::max" => { let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.max(&mut ops, &act, v.to_idiom(), val); + self.max(&mut ops, &act, idiom, val); } "math::mean" => { let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.mean(&mut ops, &act, v.to_idiom(), val); + self.mean(&mut ops, &act, idiom, val); } _ => unreachable!(), }, _ => { - let val = v.compute(ctx, opt, txn, doc).await?; - self.set(&mut ops, v.to_idiom(), val); - } - } - } - // Process it if it is a aliased field - if let Field::Alias(v, i) = field { - match v { - Value::Function(f) if f.is_rolling() => match f.name() { - "count" => { - let val = f.compute(ctx, opt, txn, doc).await?; - self.chg(&mut ops, &act, i.to_owned(), val); - } - "math::sum" => { - let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.chg(&mut ops, &act, i.to_owned(), val); - } - "math::min" => { - let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.min(&mut ops, &act, i.to_owned(), val); - } - "math::max" => { - let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.max(&mut ops, &act, i.to_owned(), val); - } - "math::mean" => { - let val = f.args()[0].compute(ctx, opt, txn, doc).await?; - self.mean(&mut ops, &act, i.to_owned(), val); - } - _ => unreachable!(), - }, - _ => { - let val = v.compute(ctx, opt, txn, doc).await?; - self.set(&mut ops, i.to_owned(), val); + let val = expr.compute(ctx, opt, txn, doc).await?; + self.set(&mut ops, idiom, val); } } } diff --git a/lib/src/sql/field.rs b/lib/src/sql/field.rs index 88062c02..d97a5d01 100644 --- a/lib/src/sql/field.rs +++ b/lib/src/sql/field.rs @@ -14,6 +14,7 @@ use nom::branch::alt; use nom::bytes::complete::tag_no_case; use nom::multi::separated_list1; use serde::{Deserialize, Serialize}; +use std::borrow::Cow; use std::fmt::{self, Display, Formatter, Write}; use std::ops::Deref; @@ -91,122 +92,79 @@ impl Fields { for v in self.other() { match v { Field::All => (), - Field::Alone(v) => match v { - // This expression is a grouped aggregate function - Value::Function(f) if group && f.is_aggregate() => { - let x = match f.args().len() { - // If no function arguments, then compute the result - 0 => f.compute(ctx, opt, txn, Some(doc)).await?, - // If arguments, then pass the first value through - _ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?, - }; - // Check if this is a single VALUE field expression - match self.single().is_some() { - false => out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?, - true => out = x, - } - } - // This expression is a multi-output graph traversal - Value::Idiom(v) if v.is_multi_yield() => { - // Store the different output yields here - let mut res: Vec<(&[Part], Value)> = Vec::new(); - // Split the expression by each output alias - for v in v.split_inclusive(Idiom::split_multi_yield) { - // Use the last fetched value for each fetch - let x = match res.last() { - Some((_, r)) => r, - None => doc, + Field::Single { + expr, + alias, + } => { + let idiom = alias + .as_ref() + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(expr.to_idiom())); + match expr { + // This expression is a grouped aggregate function + Value::Function(f) if group && f.is_aggregate() => { + let x = match f.args().len() { + // If no function arguments, then compute the result + 0 => f.compute(ctx, opt, txn, Some(doc)).await?, + // If arguments, then pass the first value through + _ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?, }; - // Continue fetching the next idiom part - let x = x - .get(ctx, opt, txn, Some(doc), v) - .await? - .compute(ctx, opt, txn, Some(doc)) - .await? - .flatten(); - // Add the result to the temporary store - res.push((v, x)); - } - // Assign each fetched yield to the output - for (p, x) in res { - match p.last().unwrap().alias() { - // This is an alias expression part - Some(a) => out.set(ctx, opt, txn, a, x).await?, - // This is the end of the expression - None => out.set(ctx, opt, txn, v, x).await?, + // Check if this is a single VALUE field expression + match self.single().is_some() { + false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?, + true => out = x, } } - } - // This expression is a normal field expression - _ => { - let x = v.compute(ctx, opt, txn, Some(doc)).await?; - // Check if this is a single VALUE field expression - match self.single().is_some() { - false => out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?, - true => out = x, - } - } - }, - Field::Alias(v, i) => match v { - // This expression is a grouped aggregate function - Value::Function(f) if group && f.is_aggregate() => { - let x = match f.args().len() { - // If no function arguments, then compute the result - 0 => f.compute(ctx, opt, txn, Some(doc)).await?, - // If arguments, then pass the first value through - _ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?, - }; - // Check if this is a single VALUE field expression - match self.single().is_some() { - false => out.set(ctx, opt, txn, i, x).await?, - true => out = x, - } - } - // This expression is a multi-output graph traversal - Value::Idiom(v) if v.is_multi_yield() => { - // Store the different output yields here - let mut res: Vec<(&[Part], Value)> = Vec::new(); - // Split the expression by each output alias - for v in v.split_inclusive(Idiom::split_multi_yield) { - // Use the last fetched value for each fetch - let x = match res.last() { - Some((_, r)) => r, - None => doc, - }; - // Continue fetching the next idiom part - let x = x - .get(ctx, opt, txn, Some(doc), v) - .await? - .compute(ctx, opt, txn, Some(doc)) - .await? - .flatten(); - // Add the result to the temporary store - res.push((v, x)); - } - // Assign each fetched yield to the output - for (p, x) in res { - match p.last().unwrap().alias() { - // This is an alias expression part - Some(a) => { - let v = x.clone(); - out.set(ctx, opt, txn, a, x).await?; - out.set(ctx, opt, txn, i, v).await?; + // This expression is a multi-output graph traversal + Value::Idiom(v) if v.is_multi_yield() => { + // Store the different output yields here + let mut res: Vec<(&[Part], Value)> = Vec::new(); + // Split the expression by each output alias + for v in v.split_inclusive(Idiom::split_multi_yield) { + // Use the last fetched value for each fetch + let x = match res.last() { + Some((_, r)) => r, + None => doc, + }; + // Continue fetching the next idiom part + let x = x + .get(ctx, opt, txn, Some(doc), v) + .await? + .compute(ctx, opt, txn, Some(doc)) + .await? + .flatten(); + // Add the result to the temporary store + res.push((v, x)); + } + // Assign each fetched yield to the output + for (p, x) in res { + match p.last().unwrap().alias() { + // This is an alias expression part + Some(a) => { + if let Some(i) = alias { + out.set(ctx, opt, txn, i, x.clone()).await?; + } + out.set(ctx, opt, txn, a, x).await?; + } + // This is the end of the expression + None => { + out.set(ctx, opt, txn, alias.as_ref().unwrap_or(v), x) + .await? + } } - // This is the end of the expression - None => out.set(ctx, opt, txn, i, x).await?, + } + } + // This expression is a normal field expression + _ => { + let x = expr.compute(ctx, opt, txn, Some(doc)).await?; + // Check if this is a single VALUE field expression + match self.single().is_some() { + false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?, + true => out = x, } } } - // This expression is a normal field expression - _ => { - let x = v.compute(ctx, opt, txn, Some(doc)).await?; - // Check if this is a single VALUE field expression - match self.single().is_some() { - false => out.set(ctx, opt, txn, i, x).await?, - true => out = x, - } - } - }, + } } } Ok(out) @@ -230,25 +188,35 @@ fn field_many(i: &str) -> IResult<&str, Fields> { Ok((i, Fields(v, false))) } -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] +#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] pub enum Field { + /// The `*` in `SELECT * FROM ...` + #[default] All, - Alone(Value), - Alias(Value, Idiom), -} - -impl Default for Field { - fn default() -> Self { - Self::All - } + /// The 'rating' in `SELECT rating FROM ...` + Single { + expr: Value, + /// The `quality` in `SELECT rating AS quality FROM ...` + alias: Option, + }, } impl Display for Field { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::All => f.write_char('*'), - Self::Alone(e) => Display::fmt(e, f), - Self::Alias(e, a) => write!(f, "{e} AS {a}"), + Self::Single { + expr, + alias, + } => { + Display::fmt(expr, f)?; + if let Some(alias) = alias { + f.write_str(" AS ")?; + Display::fmt(alias, f) + } else { + Ok(()) + } + } } } } @@ -263,17 +231,29 @@ pub fn all(i: &str) -> IResult<&str, Field> { } pub fn alone(i: &str) -> IResult<&str, Field> { - let (i, f) = value(i)?; - Ok((i, Field::Alone(f))) + let (i, expr) = value(i)?; + Ok(( + i, + Field::Single { + expr, + alias: None, + }, + )) } pub fn alias(i: &str) -> IResult<&str, Field> { - let (i, f) = value(i)?; + let (i, expr) = value(i)?; let (i, _) = shouldbespace(i)?; let (i, _) = tag_no_case("AS")(i)?; let (i, _) = shouldbespace(i)?; - let (i, a) = idiom(i)?; - Ok((i, Field::Alias(f, a))) + let (i, alias) = idiom(i)?; + Ok(( + i, + Field::Single { + expr, + alias: Some(alias), + }, + )) } #[cfg(test)] diff --git a/lib/src/sql/special.rs b/lib/src/sql/special.rs index 5e57752b..713c8d8c 100644 --- a/lib/src/sql/special.rs +++ b/lib/src/sql/special.rs @@ -4,43 +4,51 @@ use crate::sql::group::Groups; use crate::sql::order::Orders; use crate::sql::split::Splits; use crate::sql::value::Value; +use crate::sql::Idiom; use nom::Err; use nom::Err::Failure; +/// Check to see whether the expression is in the SELECT clause +fn contains_idiom(fields: &Fields, idiom: &Idiom) -> bool { + fields.iter().any(|field| { + match field { + // There is a SELECT * expression, so presume everything is ok + Field::All => true, + // Check each field + Field::Single { + expr, + alias, + } => { + if let Some(i) = alias { + // This field is aliased, so check the alias name + i.as_ref() == idiom.as_ref() + } else { + // This field is not aliased, so check the field value + match expr { + // Use raw idiom (TODO: should this use `simplify`?) + Value::Idiom(i) => i.as_ref() == idiom.as_ref(), + // Check the expression + v => v.to_idiom().as_ref() == idiom.as_ref(), + } + } + } + } + }) +} + pub fn check_split_on_fields<'a>( i: &'a str, fields: &Fields, splits: &Option, ) -> Result<(), Err>> { - // Check to see if a ORDER BY clause has been defined + // Check to see if a SPLIT ON clause has been defined if let Some(splits) = splits { // Loop over each of the expressions in the SPLIT ON clause - 'outer: for split in splits.iter() { - // Loop over each of the expressions in the SELECT clause - for field in fields.iter() { - // Check to see whether the expression is in the SELECT clause - match field { - // There is a SELECT * expression, so presume everything is ok - Field::All => break 'outer, - // This field is aliased, so check the alias name - Field::Alias(_, i) if i.as_ref() == split.as_ref() => continue 'outer, - // This field is not aliased, so check the field value - Field::Alone(v) => { - match v { - // If the expression in the SELECT clause is a field, check if it exists in the SPLIT ON clause - Value::Idiom(i) if i.as_ref() == split.as_ref() => continue 'outer, - // Otherwise check if the expression itself exists in the SPLIT ON clause - v if v.to_idiom().as_ref() == split.as_ref() => continue 'outer, - // If not, then this query should fail - _ => (), - } - } - // If not, then this query should fail - _ => (), - } + for split in splits.iter() { + if !contains_idiom(fields, &split.0) { + // If the expression isn't specified in the SELECT clause, then error + return Err(Failure(Error::Split(i, split.to_string()))); } - // If the expression isn't specified in the SELECT clause, then error - return Err(Failure(Error::Split(i, split.to_string()))); } } // This query is ok to run @@ -55,32 +63,11 @@ pub fn check_order_by_fields<'a>( // Check to see if a ORDER BY clause has been defined if let Some(orders) = orders { // Loop over each of the expressions in the ORDER BY clause - 'outer: for order in orders.iter() { - // Loop over each of the expressions in the SELECT clause - for field in fields.iter() { - // Check to see whether the expression is in the SELECT clause - match field { - // There is a SELECT * expression, so presume everything is ok - Field::All => break 'outer, - // This field is aliased, so check the alias name - Field::Alias(_, i) if i.as_ref() == order.as_ref() => continue 'outer, - // This field is not aliased, so check the field value - Field::Alone(v) => { - match v { - // If the expression in the SELECT clause is a field, check if it exists in the ORDER BY clause - Value::Idiom(i) if i.as_ref() == order.as_ref() => continue 'outer, - // Otherwise check if the expression itself exists in the ORDER BY clause - v if v.to_idiom().as_ref() == order.as_ref() => continue 'outer, - // If not, then this query should fail - _ => (), - } - } - // If not, then this query should fail - _ => (), - } + for order in orders.iter() { + if !contains_idiom(fields, &*order) { + // If the expression isn't specified in the SELECT clause, then error + return Err(Failure(Error::Order(i, order.to_string()))); } - // If the expression isn't specified in the SELECT clause, then error - return Err(Failure(Error::Order(i, order.to_string()))); } } // This query is ok to run @@ -95,54 +82,43 @@ pub fn check_group_by_fields<'a>( // Check to see if a GROUP BY clause has been defined if let Some(groups) = groups { // Loop over each of the expressions in the GROUP BY clause - 'outer: for group in groups.iter() { - // Loop over each of the expressions in the SELECT clause - for field in fields.iter() { - // Check to see whether the expression is in the SELECT clause - match field { - // This field is aliased, so check the alias name - Field::Alias(_, i) if i.as_ref() == group.as_ref() => continue 'outer, - // This field is not aliased, so check the field value - Field::Alone(v) => { - match v { - // If the expression in the SELECT clause is a field, check if it exists in the GROUP BY clause - Value::Idiom(i) if i.as_ref() == group.as_ref() => continue 'outer, - // Otherwise check if the expression itself exists in the GROUP BY clause - v if v.to_idiom().as_ref() == group.as_ref() => continue 'outer, - // If not, then this query should fail - _ => (), - } - } - // If not, then this query should fail - _ => (), - } + for group in groups.iter() { + if !contains_idiom(fields, &group.0) { + // If the expression isn't specified in the SELECT clause, then error + return Err(Failure(Error::Group(i, group.to_string()))); } - // If the expression isn't specified in the SELECT clause, then error - return Err(Failure(Error::Group(i, group.to_string()))); } // Check if this is a GROUP ALL clause or a GROUP BY clause - if groups.len() > 0 { + if !groups.is_empty() { // Loop over each of the expressions in the SELECT clause 'outer: for field in fields.iter() { // Loop over each of the expressions in the GROUP BY clause for group in groups.iter() { - // Check to see whether the expression is in the SELECT clause + // Check to see whether the expression is in the GROUP BY clause or is an aggregate match field { - // This field is aliased, so check the alias name - Field::Alias(_, i) if i.as_ref() == group.as_ref() => continue 'outer, - // Otherwise, check the type of the field value - Field::Alias(v, _) | Field::Alone(v) => match v { - // If the expression in the SELECT clause is a field, check to see if it exists in the GROUP BY - Value::Idiom(i) if i == &group.0 => continue 'outer, - // If the expression in the SELECT clause is a function, check to see if it is an aggregate function - Value::Function(f) if f.is_aggregate() => continue 'outer, - // Otherwise check if the expression itself exists in the GROUP BY clause - v if v.to_idiom() == group.0 => continue 'outer, - // Check if this is a static value which can be used in the GROUP BY clause - v if v.is_static() => continue 'outer, - // If not, then this query should fail - _ => (), - }, + Field::Single { + expr, + alias, + } => { + if alias.as_ref().map(|i| i.as_ref() == group.as_ref()).unwrap_or(false) + { + // This field is aliased, and the alias name matched + continue 'outer; + } else { + match expr { + // If the expression in the SELECT clause is a field, check to see if it exists in the GROUP BY + Value::Idiom(i) if i == &group.0 => continue 'outer, + // If the expression in the SELECT clause is a function, check to see if it is an aggregate function + Value::Function(f) if f.is_aggregate() => continue 'outer, + // Otherwise check if the expression itself exists in the GROUP BY clause + v if v.to_idiom() == group.0 => continue 'outer, + // Check if this is a static value which can be used in the GROUP BY clause + v if v.is_static() => continue 'outer, + // If not, then this query should fail + _ => (), + } + } + } _ => (), } } diff --git a/lib/src/sql/statements/select.rs b/lib/src/sql/statements/select.rs index f3c42184..81aea04a 100644 --- a/lib/src/sql/statements/select.rs +++ b/lib/src/sql/statements/select.rs @@ -50,8 +50,10 @@ impl SelectStatement { pub(crate) fn writeable(&self) -> bool { if self.expr.iter().any(|v| match v { Field::All => false, - Field::Alone(v) => v.writeable(), - Field::Alias(v, _) => v.writeable(), + Field::Single { + expr, + .. + } => expr.writeable(), }) { return true; } diff --git a/lib/src/sql/value/serde/ser/field/mod.rs b/lib/src/sql/value/serde/ser/field/mod.rs index 3fc60069..2b8972b2 100644 --- a/lib/src/sql/value/serde/ser/field/mod.rs +++ b/lib/src/sql/value/serde/ser/field/mod.rs @@ -19,10 +19,10 @@ impl ser::Serializer for Serializer { type SerializeSeq = Impossible; type SerializeTuple = Impossible; type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = SerializeValueIdiomTuple; + type SerializeTupleVariant = Impossible; type SerializeMap = Impossible; type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; + type SerializeStructVariant = SerializeValueIdiomTuple; const EXPECTED: &'static str = "an enum `Field`"; @@ -39,77 +39,89 @@ impl ser::Serializer for Serializer { } } - #[inline] - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - match variant { - "Alone" => Ok(Field::Alone(value.serialize(ser::value::Serializer.wrap())?)), - variant => { - Err(Error::custom(format!("unexpected newtype variant `{name}::{variant}`"))) - } - } - } - - fn serialize_tuple_variant( + fn serialize_struct_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { match variant { - "Alias" => Ok(SerializeValueIdiomTuple::default()), - variant => Err(Error::custom(format!("unexpected tuple variant `{name}::{variant}`"))), + "Single" => Ok(SerializeValueIdiomTuple::default()), + variant => Err(Error::custom(format!("unexpected struct variant `{name}::{variant}`"))), } } } #[derive(Default)] pub(super) struct SerializeValueIdiomTuple { - index: usize, value: Option, - idiom: Option, + idiom: Option>, } -impl serde::ser::SerializeTupleVariant for SerializeValueIdiomTuple { +impl serde::ser::SerializeStructVariant for SerializeValueIdiomTuple { type Ok = Field; type Error = Error; - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: Serialize + ?Sized, { - match self.index { - 0 => { + match key { + "expr" => { self.value = Some(value.serialize(ser::value::Serializer.wrap())?); } - 1 => { - self.idiom = Some(Idiom(value.serialize(ser::part::vec::Serializer.wrap())?)); + "alias" => { + self.idiom = Some(value.serialize(SerializeOptionIdiom.wrap())?); } - index => { - return Err(Error::custom(format!("unexpected `Field::Alias` index `{index}`"))); + key => { + return Err(Error::custom(format!("unexpected `Field::Single` field `{key}`"))); } } - self.index += 1; Ok(()) } fn end(self) -> Result { match (self.value, self.idiom) { - (Some(value), Some(idiom)) => Ok(Field::Alias(value, idiom)), - _ => Err(Error::custom("`Field::Alias` missing required value(s)")), + (Some(expr), Some(alias)) => Ok(Field::Single { + expr, + alias, + }), + _ => Err(Error::custom("`Field::Single` missing required value(s)")), } } } +#[derive(Default)] +struct SerializeOptionIdiom; + +impl ser::Serializer for SerializeOptionIdiom { + type Ok = Option; + type Error = Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + const EXPECTED: &'static str = "an enum `Option`"; + + fn serialize_none(self) -> Result { + Ok(None) + } + + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize, + { + let idiom = Idiom(value.serialize(ser::part::vec::Serializer.wrap())?); + Ok(Some(idiom)) + } +} + #[cfg(test)] mod tests { use super::*; @@ -124,14 +136,20 @@ mod tests { #[test] fn alone() { - let field = Field::Alone(Default::default()); + let field = Field::Single { + expr: Default::default(), + alias: None, + }; let serialized = field.serialize(Serializer.wrap()).unwrap(); assert_eq!(field, serialized); } #[test] fn alias() { - let field = Field::Alias(Default::default(), Default::default()); + let field = Field::Single { + expr: Default::default(), + alias: Some(Default::default()), + }; let serialized = field.serialize(Serializer.wrap()).unwrap(); assert_eq!(field, serialized); } diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index 70f39611..d4742922 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -2225,6 +2225,7 @@ impl Value { Value::None => true, Value::Null => true, Value::Bool(_) => true, + Value::Bytes(_) => true, Value::Uuid(_) => true, Value::Number(_) => true, Value::Strand(_) => true,