Improve type casting support (#2083)
Co-authored-by: Finn Bear <finnbearlabs@gmail.com>
This commit is contained in:
parent
1bcf57ecc9
commit
f5f10d508f
20 changed files with 1166 additions and 412 deletions
|
@ -292,7 +292,7 @@ pub(crate) fn router(
|
|||
if let Some(response) = option {
|
||||
trace!(target: LOG, "{response:?}");
|
||||
if let Some(Ok(id)) =
|
||||
response.id.map(Value::convert_to_i64)
|
||||
response.id.map(Value::coerce_to_i64)
|
||||
{
|
||||
if let Some((method, sender)) = routes.remove(&id) {
|
||||
let _res = sender
|
||||
|
|
|
@ -265,7 +265,7 @@ pub(crate) fn router(
|
|||
Ok(option) => {
|
||||
if let Some(response) = option {
|
||||
trace!(target: LOG, "{response:?}");
|
||||
if let Some(Ok(id)) = response.id.map(Value::convert_to_i64) {
|
||||
if let Some(Ok(id)) = response.id.map(Value::coerce_to_i64) {
|
||||
if let Some((method, sender)) = routes.remove(&id) {
|
||||
let _ = sender
|
||||
.into_send_async(DbResponse::from((
|
||||
|
|
|
@ -377,6 +377,7 @@ fn into_json(value: Value, simplify: bool) -> JsonValue {
|
|||
},
|
||||
false => json!(constant),
|
||||
},
|
||||
Value::Cast(cast) => json!(cast),
|
||||
Value::Function(function) => json!(function),
|
||||
Value::Subquery(subquery) => json!(subquery),
|
||||
Value::Expression(expression) => json!(expression),
|
||||
|
|
|
@ -34,9 +34,9 @@ impl<'a> Document<'a> {
|
|||
// Check for a TYPE clause
|
||||
if let Some(kind) = &fd.kind {
|
||||
if !val.is_none() {
|
||||
val = val.convert_to(kind).map_err(|e| match e {
|
||||
val = val.coerce_to(kind).map_err(|e| match e {
|
||||
// There was a conversion error
|
||||
Error::ConvertTo {
|
||||
Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
} => Error::FieldCheck {
|
||||
|
@ -63,9 +63,9 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
// Check for a TYPE clause
|
||||
if let Some(kind) = &fd.kind {
|
||||
val = val.convert_to(kind).map_err(|e| match e {
|
||||
val = val.coerce_to(kind).map_err(|e| match e {
|
||||
// There was a conversion error
|
||||
Error::ConvertTo {
|
||||
Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
} => Error::FieldCheck {
|
||||
|
|
|
@ -361,13 +361,27 @@ pub enum Error {
|
|||
value: String,
|
||||
},
|
||||
|
||||
/// The requested function does not exist
|
||||
#[error("Expected a {into} but failed to convert {from} into a {into}")]
|
||||
/// Unable to coerce to a value to another value
|
||||
#[error("Expected a {into} but found {from}")]
|
||||
CoerceTo {
|
||||
from: Value,
|
||||
into: Cow<'static, str>,
|
||||
},
|
||||
|
||||
/// Unable to convert a value to another value
|
||||
#[error("Expected a {into} but cannot convert {from} into a {into}")]
|
||||
ConvertTo {
|
||||
from: Value,
|
||||
into: Cow<'static, str>,
|
||||
},
|
||||
|
||||
/// Unable to coerce to a value to another value
|
||||
#[error("Expected a {kind} but the array had {size} items")]
|
||||
LengthInvalid {
|
||||
kind: Cow<'static, str>,
|
||||
size: usize,
|
||||
},
|
||||
|
||||
/// Cannot perform addition
|
||||
#[error("Cannot perform addition with '{0}' and '{1}'")]
|
||||
TryAdd(String, String),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::{Array, Bytes, Datetime, Duration, Number, Strand, Thing};
|
||||
use crate::sql::{Array, Bytes, Datetime, Duration, Kind, Number, Strand, Thing};
|
||||
|
||||
/// Implemented by types that are commonly used, in a certain way, as arguments.
|
||||
pub trait FromArg: Sized {
|
||||
|
@ -15,85 +15,85 @@ impl FromArg for Value {
|
|||
|
||||
impl FromArg for String {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_string()
|
||||
arg.coerce_to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Strand {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_strand()
|
||||
arg.coerce_to_strand()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Number {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_number()
|
||||
arg.coerce_to_number()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Datetime {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_datetime()
|
||||
arg.coerce_to_datetime()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Duration {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_duration()
|
||||
arg.coerce_to_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Thing {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_record()
|
||||
arg.coerce_to_record()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Array {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_array()
|
||||
arg.coerce_to_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Bytes {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_bytes()
|
||||
arg.coerce_to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for i64 {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_i64()
|
||||
arg.coerce_to_i64()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for u64 {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_u64()
|
||||
arg.coerce_to_u64()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for f64 {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_f64()
|
||||
arg.coerce_to_f64()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for isize {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.convert_to_i64()? as isize)
|
||||
Ok(arg.coerce_to_i64()? as isize)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for usize {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.convert_to_u64()? as usize)
|
||||
Ok(arg.coerce_to_u64()? as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Vec<Number> {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
arg.convert_to_array()?.into_iter().map(Value::convert_to_number).collect()
|
||||
arg.coerce_to_array_type(&Kind::Number)?.into_iter().map(Value::try_into).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[cfg(any(feature = "kv-tikv", feature = "kv-rocksdb", feature = "kv-fdb"))]
|
||||
#[cfg(any(feature = "kv-tikv", feature = "kv-rocksdb", feature = "kv-speedb", feature = "kv-fdb"))]
|
||||
pub(crate) mod transaction {
|
||||
use crate::dbs::{Response, Session};
|
||||
use crate::kvs::ds::Inner;
|
||||
|
|
89
lib/src/sql/cast.rs
Normal file
89
lib/src/sql/cast.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::kind::{kind, Kind};
|
||||
use crate::sql::value::{single, Value};
|
||||
use async_recursion::async_recursion;
|
||||
use nom::character::complete::char;
|
||||
use nom::sequence::delimited;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[serde(rename = "$surrealdb::private::sql::Cast")]
|
||||
pub struct Cast(pub Kind, pub Value);
|
||||
|
||||
impl PartialOrd for Cast {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Cast {
|
||||
/// Convert cast to a field name
|
||||
pub fn to_idiom(&self) -> Idiom {
|
||||
self.1.to_idiom()
|
||||
}
|
||||
}
|
||||
|
||||
impl Cast {
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&'async_recursion Value>,
|
||||
) -> Result<Value, Error> {
|
||||
// Prevent long cast chains
|
||||
let opt = &opt.dive(1)?;
|
||||
// Compute the value to be cast and convert it
|
||||
self.1.compute(ctx, opt, txn, doc).await?.convert_to(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Cast {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "<{}> {}", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cast(i: &str) -> IResult<&str, Cast> {
|
||||
let (i, k) = delimited(char('<'), kind, char('>'))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = single(i)?;
|
||||
Ok((i, Cast(k, v)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cast_int() {
|
||||
let sql = "<int>1.2345";
|
||||
let res = cast(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("<int> 1.2345", format!("{}", out));
|
||||
assert_eq!(out, Cast(Kind::Int, 1.2345.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cast_string() {
|
||||
let sql = "<string>1.2345";
|
||||
let res = cast(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("<string> 1.2345", format!("{}", out));
|
||||
assert_eq!(out, Cast(Kind::String, 1.2345.into()));
|
||||
}
|
||||
}
|
|
@ -9,9 +9,8 @@ use crate::sql::common::{closeparentheses, commas, openparentheses};
|
|||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::kind::{kind, Kind};
|
||||
use crate::sql::script::{script as func, Script};
|
||||
use crate::sql::value::{single, value, Value};
|
||||
use crate::sql::value::{value, Value};
|
||||
use async_recursion::async_recursion;
|
||||
use futures::future::try_join_all;
|
||||
use nom::branch::alt;
|
||||
|
@ -21,7 +20,6 @@ use nom::character::complete::char;
|
|||
use nom::combinator::recognize;
|
||||
use nom::multi::separated_list0;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::sequence::delimited;
|
||||
use nom::sequence::preceded;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
|
@ -32,7 +30,6 @@ pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Function";
|
|||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[serde(rename = "$surrealdb::private::sql::Function")]
|
||||
pub enum Function {
|
||||
Cast(Kind, Value),
|
||||
Normal(String, Vec<Value>),
|
||||
Custom(String, Vec<Value>),
|
||||
Script(Script, Vec<Value>),
|
||||
|
@ -69,7 +66,6 @@ impl Function {
|
|||
Self::Script(_, _) => "function".to_string().into(),
|
||||
Self::Normal(f, _) => f.to_owned().into(),
|
||||
Self::Custom(f, _) => format!("fn::{f}").into(),
|
||||
Self::Cast(_, v) => v.to_idiom(),
|
||||
}
|
||||
}
|
||||
/// Convert this function to an aggregate
|
||||
|
@ -149,12 +145,6 @@ impl Function {
|
|||
let opt = &opt.futures(true);
|
||||
// Process the function type
|
||||
match self {
|
||||
Self::Cast(k, x) => {
|
||||
// Compute the value to be cast
|
||||
let a = x.compute(ctx, opt, txn, doc).await?;
|
||||
// Run the cast function
|
||||
a.convert_to(k)
|
||||
}
|
||||
Self::Normal(s, x) => {
|
||||
// Compute the function arguments
|
||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
||||
|
@ -187,7 +177,7 @@ impl Function {
|
|||
let mut ctx = Context::new(ctx);
|
||||
// Process the function arguments
|
||||
for (val, (name, kind)) in a.into_iter().zip(val.args) {
|
||||
ctx.add_value(name.to_raw(), val.convert_to(&kind)?);
|
||||
ctx.add_value(name.to_raw(), val.coerce_to(&kind)?);
|
||||
}
|
||||
// Run the custom function
|
||||
val.block.compute(&ctx, opt, txn, doc).await
|
||||
|
@ -215,7 +205,6 @@ impl Function {
|
|||
impl fmt::Display for Function {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Cast(k, e) => write!(f, "<{k}> {e}"),
|
||||
Self::Normal(s, e) => write!(f, "{s}({})", Fmt::comma_separated(e)),
|
||||
Self::Custom(s, e) => write!(f, "fn::{s}({})", Fmt::comma_separated(e)),
|
||||
Self::Script(s, e) => write!(f, "function({}) {{{s}}}", Fmt::comma_separated(e)),
|
||||
|
@ -224,7 +213,7 @@ impl fmt::Display for Function {
|
|||
}
|
||||
|
||||
pub fn function(i: &str) -> IResult<&str, Function> {
|
||||
alt((normal, custom, script, cast))(i)
|
||||
alt((normal, custom, script))(i)
|
||||
}
|
||||
|
||||
pub fn normal(i: &str) -> IResult<&str, Function> {
|
||||
|
@ -259,13 +248,6 @@ fn script(i: &str) -> IResult<&str, Function> {
|
|||
Ok((i, Function::Script(v, a)))
|
||||
}
|
||||
|
||||
fn cast(i: &str) -> IResult<&str, Function> {
|
||||
let (i, k) = delimited(char('<'), kind, char('>'))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = single(i)?;
|
||||
Ok((i, Function::Cast(k, v)))
|
||||
}
|
||||
|
||||
pub(crate) fn function_names(i: &str) -> IResult<&str, &str> {
|
||||
recognize(alt((
|
||||
preceded(tag("array::"), function_array),
|
||||
|
@ -598,26 +580,6 @@ mod tests {
|
|||
assert_eq!(out, Function::Normal(String::from("is::numeric"), vec![Value::Null]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_casting_number() {
|
||||
let sql = "<int>1.2345";
|
||||
let res = function(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("<int> 1.2345", format!("{}", out));
|
||||
assert_eq!(out, Function::Cast(Kind::Int, 1.2345.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_casting_string() {
|
||||
let sql = "<string>1.2345";
|
||||
let res = function(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("<string> 1.2345", format!("{}", out));
|
||||
assert_eq!(out, Function::Cast(Kind::String, 1.2345.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_script_expression() {
|
||||
let sql = "function() { return this.tags.filter(t => { return t.length > 3; }); }";
|
||||
|
|
|
@ -49,6 +49,13 @@ impl Kind {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&Kind> for Box<Kind> {
|
||||
#[inline]
|
||||
fn from(v: &Kind) -> Self {
|
||||
Box::new(v.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Kind {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
|
|
@ -5,6 +5,7 @@ pub(crate) mod array;
|
|||
pub(crate) mod base;
|
||||
pub(crate) mod block;
|
||||
pub(crate) mod bytes;
|
||||
pub(crate) mod cast;
|
||||
pub(crate) mod comment;
|
||||
pub(crate) mod common;
|
||||
pub(crate) mod cond;
|
||||
|
@ -78,6 +79,7 @@ pub use self::array::Array;
|
|||
pub use self::base::Base;
|
||||
pub use self::block::Block;
|
||||
pub use self::bytes::Bytes;
|
||||
pub use self::cast::Cast;
|
||||
pub use self::cond::Cond;
|
||||
pub use self::data::Data;
|
||||
pub use self::datetime::Datetime;
|
||||
|
|
85
lib/src/sql/value/serde/ser/cast/mod.rs
Normal file
85
lib/src/sql/value/serde/ser/cast/mod.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::value::serde::ser;
|
||||
use crate::sql::Cast;
|
||||
use crate::sql::Kind;
|
||||
use crate::sql::Value;
|
||||
use ser::Serializer as _;
|
||||
use serde::ser::Error as _;
|
||||
use serde::ser::Impossible;
|
||||
use serde::ser::Serialize;
|
||||
|
||||
pub(super) struct Serializer;
|
||||
|
||||
impl ser::Serializer for Serializer {
|
||||
type Ok = Cast;
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = Impossible<Cast, Error>;
|
||||
type SerializeTuple = Impossible<Cast, Error>;
|
||||
type SerializeTupleStruct = SerializeCast;
|
||||
type SerializeTupleVariant = Impossible<Cast, Error>;
|
||||
type SerializeMap = Impossible<Cast, Error>;
|
||||
type SerializeStruct = Impossible<Cast, Error>;
|
||||
type SerializeStructVariant = Impossible<Cast, Error>;
|
||||
|
||||
const EXPECTED: &'static str = "an struct `Cast`";
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Error> {
|
||||
Ok(SerializeCast::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct SerializeCast {
|
||||
index: usize,
|
||||
kind: Option<Kind>,
|
||||
value: Option<Value>,
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeTupleStruct for SerializeCast {
|
||||
type Ok = Cast;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize + ?Sized,
|
||||
{
|
||||
match self.index {
|
||||
0 => {
|
||||
self.kind = Some(value.serialize(ser::kind::Serializer.wrap())?);
|
||||
}
|
||||
1 => {
|
||||
self.value = Some(value.serialize(ser::value::Serializer.wrap())?);
|
||||
}
|
||||
index => {
|
||||
return Err(Error::custom(format!("unexpected `Cast` index `{index}`")));
|
||||
}
|
||||
}
|
||||
self.index += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
match (self.kind, self.value) {
|
||||
(Some(kind), Some(value)) => Ok(Cast(kind, value)),
|
||||
_ => Err(Error::custom("`Cast` missing required value(s)")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde::Serialize;
|
||||
|
||||
#[test]
|
||||
fn cast() {
|
||||
let cast = Cast(Default::default(), Default::default());
|
||||
let serialized = cast.serialize(Serializer.wrap()).unwrap();
|
||||
assert_eq!(cast, serialized);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::value::serde::ser;
|
||||
use crate::sql::Function;
|
||||
use crate::sql::Kind;
|
||||
use crate::sql::Script;
|
||||
use crate::sql::Value;
|
||||
use ser::Serializer as _;
|
||||
|
@ -33,7 +32,6 @@ impl ser::Serializer for Serializer {
|
|||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
let inner = match variant {
|
||||
"Cast" => Inner::Cast(None, None),
|
||||
"Normal" => Inner::Normal(None, None),
|
||||
"Custom" => Inner::Custom(None, None),
|
||||
"Script" => Inner::Script(None, None),
|
||||
|
@ -54,7 +52,6 @@ pub(super) struct SerializeFunction {
|
|||
}
|
||||
|
||||
enum Inner {
|
||||
Cast(Option<Kind>, Option<Value>),
|
||||
Normal(Option<String>, Option<Vec<Value>>),
|
||||
Custom(Option<String>, Option<Vec<Value>>),
|
||||
Script(Option<Script>, Option<Vec<Value>>),
|
||||
|
@ -75,12 +72,6 @@ impl serde::ser::SerializeTupleVariant for SerializeFunction {
|
|||
(0, Inner::Script(ref mut var, _)) => {
|
||||
*var = Some(Script(value.serialize(ser::string::Serializer.wrap())?));
|
||||
}
|
||||
(0, Inner::Cast(ref mut var, _)) => {
|
||||
*var = Some(value.serialize(ser::kind::Serializer.wrap())?);
|
||||
}
|
||||
(1, Inner::Cast(_, ref mut var)) => {
|
||||
*var = Some(value.serialize(ser::value::Serializer.wrap())?);
|
||||
}
|
||||
(
|
||||
1,
|
||||
Inner::Normal(_, ref mut var)
|
||||
|
@ -91,7 +82,6 @@ impl serde::ser::SerializeTupleVariant for SerializeFunction {
|
|||
}
|
||||
(index, inner) => {
|
||||
let variant = match inner {
|
||||
Inner::Cast(..) => "Cast",
|
||||
Inner::Normal(..) => "Normal",
|
||||
Inner::Custom(..) => "Custom",
|
||||
Inner::Script(..) => "Script",
|
||||
|
@ -107,7 +97,6 @@ impl serde::ser::SerializeTupleVariant for SerializeFunction {
|
|||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
match self.inner {
|
||||
Inner::Cast(Some(one), Some(two)) => Ok(Function::Cast(one, two)),
|
||||
Inner::Normal(Some(one), Some(two)) => Ok(Function::Normal(one, two)),
|
||||
Inner::Custom(Some(one), Some(two)) => Ok(Function::Custom(one, two)),
|
||||
Inner::Script(Some(one), Some(two)) => Ok(Function::Script(one, two)),
|
||||
|
@ -121,13 +110,6 @@ mod tests {
|
|||
use super::*;
|
||||
use serde::Serialize;
|
||||
|
||||
#[test]
|
||||
fn cast() {
|
||||
let function = Function::Cast(Default::default(), Default::default());
|
||||
let serialized = function.serialize(Serializer.wrap()).unwrap();
|
||||
assert_eq!(function, serialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normal() {
|
||||
let function = Function::Normal(Default::default(), vec![Default::default()]);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod block;
|
||||
mod cast;
|
||||
mod cond;
|
||||
mod constant;
|
||||
mod data;
|
||||
|
|
|
@ -807,7 +807,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn function() {
|
||||
let function = Box::new(Function::Cast(Default::default(), Default::default()));
|
||||
let function = Box::new(Function::Normal(Default::default(), Default::default()));
|
||||
let value = to_value(&function).unwrap();
|
||||
let expected = Value::Function(function);
|
||||
assert_eq!(value, expected);
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::sql::array::Uniq;
|
|||
use crate::sql::array::{array, Array};
|
||||
use crate::sql::block::{block, Block};
|
||||
use crate::sql::bytes::Bytes;
|
||||
use crate::sql::cast::{cast, Cast};
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::constant::{constant, Constant};
|
||||
|
@ -141,6 +142,7 @@ pub enum Value {
|
|||
Table(Table),
|
||||
Model(Model),
|
||||
Regex(Regex),
|
||||
Cast(Box<Cast>),
|
||||
Block(Box<Block>),
|
||||
Range(Box<Range>),
|
||||
Edges(Box<Edges>),
|
||||
|
@ -287,6 +289,12 @@ impl From<Future> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Cast> for Value {
|
||||
fn from(v: Cast) -> Self {
|
||||
Value::Cast(Box::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Function> for Value {
|
||||
fn from(v: Function) -> Self {
|
||||
Value::Function(Box::new(v))
|
||||
|
@ -670,7 +678,7 @@ impl TryFrom<Value> for bool {
|
|||
type Error = Error;
|
||||
fn try_from(value: Value) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Value::Bool(boolean) => Ok(boolean),
|
||||
Value::Bool(v) => Ok(v),
|
||||
_ => Err(Error::TryFrom(value.to_string(), "bool")),
|
||||
}
|
||||
}
|
||||
|
@ -716,6 +724,16 @@ impl TryFrom<Value> for Vec<Value> {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Value> for Number {
|
||||
type Error = Error;
|
||||
fn try_from(value: Value) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Value::Number(x) => Ok(x),
|
||||
_ => Err(Error::TryFrom(value.to_string(), "Number")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Value> for Object {
|
||||
type Error = Error;
|
||||
fn try_from(value: Value) -> Result<Self, Self::Error> {
|
||||
|
@ -787,7 +805,7 @@ impl Value {
|
|||
/// Check if this Value is truthy
|
||||
pub fn is_truthy(&self) -> bool {
|
||||
match self {
|
||||
Value::Bool(boolean) => *boolean,
|
||||
Value::Bool(v) => *v,
|
||||
Value::Uuid(_) => true,
|
||||
Value::Thing(_) => true,
|
||||
Value::Geometry(_) => true,
|
||||
|
@ -1042,7 +1060,564 @@ impl Value {
|
|||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Simple conversion of value
|
||||
// Simple output of value type
|
||||
// -----------------------------------
|
||||
|
||||
/// Treat a string as a table name
|
||||
pub fn kindof(&self) -> &'static str {
|
||||
match self {
|
||||
Self::None => "none",
|
||||
Self::Null => "null",
|
||||
Self::Bool(_) => "bool",
|
||||
Self::Uuid(_) => "uuid",
|
||||
Self::Array(_) => "array",
|
||||
Self::Object(_) => "object",
|
||||
Self::Strand(_) => "string",
|
||||
Self::Duration(_) => "duration",
|
||||
Self::Datetime(_) => "datetime",
|
||||
Self::Number(Number::Int(_)) => "int",
|
||||
Self::Number(Number::Float(_)) => "float",
|
||||
Self::Number(Number::Decimal(_)) => "decimal",
|
||||
Self::Geometry(Geometry::Point(_)) => "geometry<point>",
|
||||
Self::Geometry(Geometry::Line(_)) => "geometry<line>",
|
||||
Self::Geometry(Geometry::Polygon(_)) => "geometry<polygon>",
|
||||
Self::Geometry(Geometry::MultiPoint(_)) => "geometry<multipoint>",
|
||||
Self::Geometry(Geometry::MultiLine(_)) => "geometry<multiline>",
|
||||
Self::Geometry(Geometry::MultiPolygon(_)) => "geometry<multipolygon>",
|
||||
Self::Geometry(Geometry::Collection(_)) => "geometry<collection>",
|
||||
Self::Bytes(_) => "bytes",
|
||||
_ => "incorrect type",
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Simple type coercion of values
|
||||
// -----------------------------------
|
||||
|
||||
/// Try to coerce this value to the specified `Kind`
|
||||
pub(crate) fn coerce_to(self, kind: &Kind) -> Result<Value, Error> {
|
||||
// Attempt to convert to the desired type
|
||||
let res = match kind {
|
||||
Kind::Any => Ok(self),
|
||||
Kind::Bool => self.coerce_to_bool().map(Value::from),
|
||||
Kind::Int => self.coerce_to_int().map(Value::from),
|
||||
Kind::Float => self.coerce_to_float().map(Value::from),
|
||||
Kind::Decimal => self.coerce_to_decimal().map(Value::from),
|
||||
Kind::Number => self.coerce_to_number().map(Value::from),
|
||||
Kind::String => self.coerce_to_strand().map(Value::from),
|
||||
Kind::Datetime => self.coerce_to_datetime().map(Value::from),
|
||||
Kind::Duration => self.coerce_to_duration().map(Value::from),
|
||||
Kind::Object => self.coerce_to_object().map(Value::from),
|
||||
Kind::Point => self.coerce_to_point().map(Value::from),
|
||||
Kind::Bytes => self.coerce_to_bytes().map(Value::from),
|
||||
Kind::Uuid => self.coerce_to_uuid().map(Value::from),
|
||||
Kind::Set(t, l) => match l {
|
||||
Some(l) => self.coerce_to_set_type_len(t, l).map(Value::from),
|
||||
None => self.coerce_to_set_type(t).map(Value::from),
|
||||
},
|
||||
Kind::Array(t, l) => match l {
|
||||
Some(l) => self.coerce_to_array_type_len(t, l).map(Value::from),
|
||||
None => self.coerce_to_array_type(t).map(Value::from),
|
||||
},
|
||||
Kind::Record(t) => match t.is_empty() {
|
||||
true => self.coerce_to_record().map(Value::from),
|
||||
false => self.coerce_to_record_type(t).map(Value::from),
|
||||
},
|
||||
Kind::Geometry(t) => match t.is_empty() {
|
||||
true => self.coerce_to_geometry().map(Value::from),
|
||||
false => self.coerce_to_geometry_type(t).map(Value::from),
|
||||
},
|
||||
Kind::Option(k) => match self {
|
||||
Self::None => Ok(Self::None),
|
||||
Self::Null => Ok(Self::None),
|
||||
v => v.coerce_to(k),
|
||||
},
|
||||
Kind::Either(k) => {
|
||||
let mut val = self;
|
||||
for k in k {
|
||||
match val.coerce_to(k) {
|
||||
Err(Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
}) => val = from,
|
||||
Err(e) => return Err(e),
|
||||
Ok(v) => return Ok(v),
|
||||
}
|
||||
}
|
||||
Err(Error::CoerceTo {
|
||||
from: val,
|
||||
into: kind.to_string().into(),
|
||||
})
|
||||
}
|
||||
};
|
||||
// Check for any conversion errors
|
||||
match res {
|
||||
// There was a conversion error
|
||||
Err(Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
}) => Err(Error::CoerceTo {
|
||||
from,
|
||||
into: kind.to_string().into(),
|
||||
}),
|
||||
// There was a different error
|
||||
Err(e) => Err(e),
|
||||
// Everything converted ok
|
||||
Ok(v) => Ok(v),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `i64`
|
||||
pub(crate) fn coerce_to_i64(self) -> Result<i64, Error> {
|
||||
match self {
|
||||
// Allow any int number
|
||||
Value::Number(Number::Int(v)) => Ok(v),
|
||||
// Attempt to convert an float number
|
||||
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(v as i64),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_i64() {
|
||||
// The Decimal can be represented as an i64
|
||||
Some(v) => Ok(v),
|
||||
// The Decimal is out of bounds
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "i64".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "i64".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `u64`
|
||||
pub(crate) fn coerce_to_u64(self) -> Result<u64, Error> {
|
||||
match self {
|
||||
// Allow any int number
|
||||
Value::Number(Number::Int(v)) => Ok(v as u64),
|
||||
// Attempt to convert an float number
|
||||
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(v as u64),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_u64() {
|
||||
// The Decimal can be represented as an u64
|
||||
Some(v) => Ok(v),
|
||||
// The Decimal is out of bounds
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "u64".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "u64".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `f64`
|
||||
pub(crate) fn coerce_to_f64(self) -> Result<f64, Error> {
|
||||
match self {
|
||||
// Allow any float number
|
||||
Value::Number(Number::Float(v)) => Ok(v),
|
||||
// Attempt to convert an int number
|
||||
Value::Number(Number::Int(v)) => Ok(v as f64),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) => match v.to_f64() {
|
||||
// The Decimal can be represented as a f64
|
||||
Some(v) => Ok(v),
|
||||
// Ths Decimal loses precision
|
||||
None => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "f64".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "f64".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `bool`
|
||||
pub(crate) fn coerce_to_bool(self) -> Result<bool, Error> {
|
||||
match self {
|
||||
// Allow any boolean value
|
||||
Value::Bool(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "bool".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an integer `Number`
|
||||
pub(crate) fn coerce_to_int(self) -> Result<Number, Error> {
|
||||
match self {
|
||||
// Allow any int number
|
||||
Value::Number(v) if v.is_int() => Ok(v),
|
||||
// Attempt to convert an float number
|
||||
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(Number::Int(v as i64)),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_i64() {
|
||||
// The Decimal can be represented as an Int
|
||||
Some(v) => Ok(Number::Int(v)),
|
||||
// The Decimal is out of bounds
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "int".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "int".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a float `Number`
|
||||
pub(crate) fn coerce_to_float(self) -> Result<Number, Error> {
|
||||
match self {
|
||||
// Allow any float number
|
||||
Value::Number(v) if v.is_float() => Ok(v),
|
||||
// Attempt to convert an int number
|
||||
Value::Number(Number::Int(v)) => Ok(Number::Float(v as f64)),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) => match v.to_f64() {
|
||||
// The Decimal can be represented as a Float
|
||||
Some(v) => Ok(Number::Float(v)),
|
||||
// Ths BigDecimal loses precision
|
||||
None => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "float".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "float".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a decimal `Number`
|
||||
pub(crate) fn coerce_to_decimal(self) -> Result<Number, Error> {
|
||||
match self {
|
||||
// Allow any decimal number
|
||||
Value::Number(v) if v.is_decimal() => Ok(v),
|
||||
// Attempt to convert an int number
|
||||
Value::Number(Number::Int(ref v)) => match BigDecimal::from_i64(*v) {
|
||||
// The Int can be represented as a Decimal
|
||||
Some(v) => Ok(Number::Decimal(v)),
|
||||
// Ths Int does not convert to a Decimal
|
||||
None => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "decimal".into(),
|
||||
}),
|
||||
},
|
||||
// Attempt to convert an float number
|
||||
Value::Number(Number::Float(ref v)) => match BigDecimal::from_f64(*v) {
|
||||
// The Float can be represented as a Decimal
|
||||
Some(v) => Ok(Number::Decimal(v)),
|
||||
// Ths Float does not convert to a Decimal
|
||||
None => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "decimal".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "decimal".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `Number`
|
||||
pub(crate) fn coerce_to_number(self) -> Result<Number, Error> {
|
||||
match self {
|
||||
// Allow any number
|
||||
Value::Number(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "number".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `String`
|
||||
pub(crate) fn coerce_to_string(self) -> Result<String, Error> {
|
||||
match self {
|
||||
// Allow any uuid value
|
||||
Value::Uuid(v) => Ok(v.to_raw()),
|
||||
// Allow any datetime value
|
||||
Value::Datetime(v) => Ok(v.to_raw()),
|
||||
// Allow any string value
|
||||
Value::Strand(v) => Ok(v.as_string()),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "string".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `Strand`
|
||||
pub(crate) fn coerce_to_strand(self) -> Result<Strand, Error> {
|
||||
match self {
|
||||
// Allow any uuid value
|
||||
Value::Uuid(v) => Ok(v.to_raw().into()),
|
||||
// Allow any datetime value
|
||||
Value::Datetime(v) => Ok(v.to_raw().into()),
|
||||
// Allow any string value
|
||||
Value::Strand(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "string".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `Uuid`
|
||||
pub(crate) fn coerce_to_uuid(self) -> Result<Uuid, Error> {
|
||||
match self {
|
||||
// Uuids are allowed
|
||||
Value::Uuid(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "uuid".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `Datetime`
|
||||
pub(crate) fn coerce_to_datetime(self) -> Result<Datetime, Error> {
|
||||
match self {
|
||||
// Datetimes are allowed
|
||||
Value::Datetime(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "datetime".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `Duration`
|
||||
pub(crate) fn coerce_to_duration(self) -> Result<Duration, Error> {
|
||||
match self {
|
||||
// Durations are allowed
|
||||
Value::Duration(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "duration".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `Bytes`
|
||||
pub(crate) fn coerce_to_bytes(self) -> Result<Bytes, Error> {
|
||||
match self {
|
||||
// Bytes are allowed
|
||||
Value::Bytes(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "bytes".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Object`
|
||||
pub(crate) fn coerce_to_object(self) -> Result<Object, Error> {
|
||||
match self {
|
||||
// Objects are allowed
|
||||
Value::Object(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "object".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Array`
|
||||
pub(crate) fn coerce_to_array(self) -> Result<Array, Error> {
|
||||
match self {
|
||||
// Arrays are allowed
|
||||
Value::Array(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "array".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Geometry` point
|
||||
pub(crate) fn coerce_to_point(self) -> Result<Geometry, Error> {
|
||||
match self {
|
||||
// Geometry points are allowed
|
||||
Value::Geometry(Geometry::Point(v)) => Ok(v.into()),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "point".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a Record or `Thing`
|
||||
pub(crate) fn coerce_to_record(self) -> Result<Thing, Error> {
|
||||
match self {
|
||||
// Records are allowed
|
||||
Value::Thing(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "record".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Geometry` type
|
||||
pub(crate) fn coerce_to_geometry(self) -> Result<Geometry, Error> {
|
||||
match self {
|
||||
// Geometries are allowed
|
||||
Value::Geometry(v) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "geometry".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a Record of a certain type
|
||||
pub(crate) fn coerce_to_record_type(self, val: &[Table]) -> Result<Thing, Error> {
|
||||
match self {
|
||||
// Records are allowed if correct type
|
||||
Value::Thing(v) if self.is_record_type(val) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "record".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to a `Geometry` of a certain type
|
||||
pub(crate) fn coerce_to_geometry_type(self, val: &[String]) -> Result<Geometry, Error> {
|
||||
match self {
|
||||
// Geometries are allowed if correct type
|
||||
Value::Geometry(v) if self.is_geometry_type(val) => Ok(v),
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::CoerceTo {
|
||||
from: self,
|
||||
into: "geometry".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Array` of a certain type
|
||||
pub(crate) fn coerce_to_array_type(self, kind: &Kind) -> Result<Array, Error> {
|
||||
self.coerce_to_array()?
|
||||
.into_iter()
|
||||
.map(|value| value.coerce_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
} => Error::CoerceTo {
|
||||
from,
|
||||
into: format!("array<{kind}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Array` of a certain type, and length
|
||||
pub(crate) fn coerce_to_array_type_len(self, kind: &Kind, len: &u64) -> Result<Array, Error> {
|
||||
self.coerce_to_array()?
|
||||
.into_iter()
|
||||
.map(|value| value.coerce_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
} => Error::CoerceTo {
|
||||
from,
|
||||
into: format!("array<{kind}, {len}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
.and_then(|v| match v.len() {
|
||||
v if v > *len as usize => Err(Error::LengthInvalid {
|
||||
kind: format!("array<{kind}, {len}>").into(),
|
||||
size: v,
|
||||
}),
|
||||
_ => Ok(v),
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Array` of a certain type, unique values
|
||||
pub(crate) fn coerce_to_set_type(self, kind: &Kind) -> Result<Array, Error> {
|
||||
self.coerce_to_array()?
|
||||
.uniq()
|
||||
.into_iter()
|
||||
.map(|value| value.coerce_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
} => Error::CoerceTo {
|
||||
from,
|
||||
into: format!("set<{kind}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to coerce this value to an `Array` of a certain type, unique values, and length
|
||||
pub(crate) fn coerce_to_set_type_len(self, kind: &Kind, len: &u64) -> Result<Array, Error> {
|
||||
self.coerce_to_array()?
|
||||
.uniq()
|
||||
.into_iter()
|
||||
.map(|value| value.coerce_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::CoerceTo {
|
||||
from,
|
||||
..
|
||||
} => Error::CoerceTo {
|
||||
from,
|
||||
into: format!("set<{kind}, {len}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
.and_then(|v| match v.len() {
|
||||
v if v > *len as usize => Err(Error::LengthInvalid {
|
||||
kind: format!("set<{kind}, {len}>").into(),
|
||||
size: v,
|
||||
}),
|
||||
_ => Ok(v),
|
||||
})
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Advanced type conversion of values
|
||||
// -----------------------------------
|
||||
|
||||
/// Try to convert this value to the specified `Kind`
|
||||
|
@ -1062,8 +1637,14 @@ impl Value {
|
|||
Kind::Point => self.convert_to_point().map(Value::from),
|
||||
Kind::Bytes => self.convert_to_bytes().map(Value::from),
|
||||
Kind::Uuid => self.convert_to_uuid().map(Value::from),
|
||||
Kind::Set(t, l) => self.convert_to_set_type(t, l).map(Value::from),
|
||||
Kind::Array(t, l) => self.convert_to_array_type(t, l).map(Value::from),
|
||||
Kind::Set(t, l) => match l {
|
||||
Some(l) => self.convert_to_set_type_len(t, l).map(Value::from),
|
||||
None => self.convert_to_set_type(t).map(Value::from),
|
||||
},
|
||||
Kind::Array(t, l) => match l {
|
||||
Some(l) => self.convert_to_array_type_len(t, l).map(Value::from),
|
||||
None => self.convert_to_array_type(t).map(Value::from),
|
||||
},
|
||||
Kind::Record(t) => match t.is_empty() {
|
||||
true => self.convert_to_record().map(Value::from),
|
||||
false => self.convert_to_record_type(t).map(Value::from),
|
||||
|
@ -1112,116 +1693,11 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Try to convert this value to an `i64`
|
||||
pub(crate) fn convert_to_i64(self) -> Result<i64, Error> {
|
||||
match self {
|
||||
// Allow any int number
|
||||
Value::Number(Number::Int(v)) => Ok(v),
|
||||
// Attempt to convert an float number
|
||||
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(v as i64),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_i64() {
|
||||
// The Decimal can be represented as an i64
|
||||
Some(v) => Ok(v),
|
||||
// The Decimal is out of bounds
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "i64".into(),
|
||||
}),
|
||||
},
|
||||
// Attempt to convert a string value
|
||||
Value::Strand(ref v) => match v.parse::<i64>() {
|
||||
// The Strand can be represented as an i64
|
||||
Ok(v) => Ok(v),
|
||||
// Ths string is not a float
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "i64".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "i64".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to convert this value to an `u64`
|
||||
pub(crate) fn convert_to_u64(self) -> Result<u64, Error> {
|
||||
match self {
|
||||
// Allow any int number
|
||||
Value::Number(Number::Int(v)) => Ok(v as u64),
|
||||
// Attempt to convert an float number
|
||||
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(v as u64),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_u64() {
|
||||
// The Decimal can be represented as an u64
|
||||
Some(v) => Ok(v),
|
||||
// The Decimal is out of bounds
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "u64".into(),
|
||||
}),
|
||||
},
|
||||
// Attempt to convert a string value
|
||||
Value::Strand(ref v) => match v.parse::<u64>() {
|
||||
// The Strand can be represented as a Float
|
||||
Ok(v) => Ok(v),
|
||||
// Ths string is not a float
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "u64".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "u64".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to convert this value to an `f64`
|
||||
pub(crate) fn convert_to_f64(self) -> Result<f64, Error> {
|
||||
match self {
|
||||
// Allow any float number
|
||||
Value::Number(Number::Float(v)) => Ok(v),
|
||||
// Attempt to convert an int number
|
||||
Value::Number(Number::Int(v)) => Ok(v as f64),
|
||||
// Attempt to convert a decimal number
|
||||
Value::Number(Number::Decimal(ref v)) => match v.to_f64() {
|
||||
// The Decimal can be represented as a f64
|
||||
Some(v) => Ok(v),
|
||||
// Ths Decimal loses precision
|
||||
None => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "f64".into(),
|
||||
}),
|
||||
},
|
||||
// Attempt to convert a string value
|
||||
Value::Strand(ref v) => match v.parse::<f64>() {
|
||||
// The Strand can be represented as a f64
|
||||
Ok(v) => Ok(v),
|
||||
// Ths string is not a float
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "f64".into(),
|
||||
}),
|
||||
},
|
||||
// Anything else raises an error
|
||||
_ => Err(Error::ConvertTo {
|
||||
from: self,
|
||||
into: "f64".into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to convert this value to a `bool`
|
||||
pub(crate) fn convert_to_bool(self) -> Result<bool, Error> {
|
||||
match self {
|
||||
// Allow any boolean value
|
||||
Value::Bool(boolean) => Ok(boolean),
|
||||
Value::Bool(v) => Ok(v),
|
||||
// Attempt to convert a string value
|
||||
Value::Strand(ref v) => match v.parse::<bool>() {
|
||||
// The string can be represented as a Float
|
||||
|
@ -1613,54 +2089,92 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Try to convert this value to ab `Array` of a certain type and optional length
|
||||
pub(crate) fn convert_to_array_type(
|
||||
self,
|
||||
kind: &Kind,
|
||||
size: &Option<u64>,
|
||||
) -> Result<Array, Error> {
|
||||
match size {
|
||||
Some(l) => self
|
||||
.convert_to_array()?
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map(|mut v| {
|
||||
v.truncate(*l as usize);
|
||||
v
|
||||
}),
|
||||
None => self
|
||||
.convert_to_array()?
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>(),
|
||||
}
|
||||
/// Try to convert this value to ab `Array` of a certain type
|
||||
pub(crate) fn convert_to_array_type(self, kind: &Kind) -> Result<Array, Error> {
|
||||
self.convert_to_array()?
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::ConvertTo {
|
||||
from,
|
||||
..
|
||||
} => Error::ConvertTo {
|
||||
from,
|
||||
into: format!("array<{kind}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to convert this value to an `Array` of a certain type, unique values, and optional length
|
||||
pub(crate) fn convert_to_set_type(
|
||||
self,
|
||||
kind: &Kind,
|
||||
size: &Option<u64>,
|
||||
) -> Result<Array, Error> {
|
||||
match size {
|
||||
Some(l) => self
|
||||
.convert_to_array()?
|
||||
.uniq()
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map(|mut v| {
|
||||
v.truncate(*l as usize);
|
||||
v
|
||||
/// Try to convert this value to ab `Array` of a certain type and length
|
||||
pub(crate) fn convert_to_array_type_len(self, kind: &Kind, len: &u64) -> Result<Array, Error> {
|
||||
self.convert_to_array()?
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::ConvertTo {
|
||||
from,
|
||||
..
|
||||
} => Error::ConvertTo {
|
||||
from,
|
||||
into: format!("array<{kind}, {len}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
.and_then(|v| match v.len() {
|
||||
v if v > *len as usize => Err(Error::LengthInvalid {
|
||||
kind: format!("array<{kind}, {len}>").into(),
|
||||
size: v,
|
||||
}),
|
||||
None => self
|
||||
.convert_to_array()?
|
||||
.uniq()
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>(),
|
||||
}
|
||||
_ => Ok(v),
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to convert this value to an `Array` of a certain type, unique values
|
||||
pub(crate) fn convert_to_set_type(self, kind: &Kind) -> Result<Array, Error> {
|
||||
self.convert_to_array()?
|
||||
.uniq()
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::ConvertTo {
|
||||
from,
|
||||
..
|
||||
} => Error::ConvertTo {
|
||||
from,
|
||||
into: format!("set<{kind}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to convert this value to an `Array` of a certain type, unique values, and length
|
||||
pub(crate) fn convert_to_set_type_len(self, kind: &Kind, len: &u64) -> Result<Array, Error> {
|
||||
self.convert_to_array()?
|
||||
.uniq()
|
||||
.into_iter()
|
||||
.map(|value| value.convert_to(kind))
|
||||
.collect::<Result<Array, Error>>()
|
||||
.map_err(|e| match e {
|
||||
Error::ConvertTo {
|
||||
from,
|
||||
..
|
||||
} => Error::ConvertTo {
|
||||
from,
|
||||
into: format!("set<{kind}, {len}>").into(),
|
||||
},
|
||||
e => e,
|
||||
})
|
||||
.and_then(|v| match v.len() {
|
||||
v if v > *len as usize => Err(Error::LengthInvalid {
|
||||
kind: format!("set<{kind}, {len}>").into(),
|
||||
size: v,
|
||||
}),
|
||||
_ => Ok(v),
|
||||
})
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
|
@ -1734,7 +2248,7 @@ impl Value {
|
|||
match self {
|
||||
Value::None => other.is_none(),
|
||||
Value::Null => other.is_null(),
|
||||
Value::Bool(boolean) => *boolean,
|
||||
Value::Bool(v) => *v,
|
||||
Value::Uuid(v) => match other {
|
||||
Value::Uuid(w) => v == w,
|
||||
Value::Regex(w) => w.regex().is_match(v.to_raw().as_str()),
|
||||
|
@ -1922,30 +2436,31 @@ impl fmt::Display for Value {
|
|||
match self {
|
||||
Value::None => write!(f, "NONE"),
|
||||
Value::Null => write!(f, "NULL"),
|
||||
Value::Bool(v) => write!(f, "{v}"),
|
||||
Value::Number(v) => write!(f, "{v}"),
|
||||
Value::Strand(v) => write!(f, "{v}"),
|
||||
Value::Duration(v) => write!(f, "{v}"),
|
||||
Value::Datetime(v) => write!(f, "{v}"),
|
||||
Value::Uuid(v) => write!(f, "{v}"),
|
||||
Value::Array(v) => write!(f, "{v}"),
|
||||
Value::Object(v) => write!(f, "{v}"),
|
||||
Value::Block(v) => write!(f, "{v}"),
|
||||
Value::Bool(v) => write!(f, "{v}"),
|
||||
Value::Bytes(v) => write!(f, "{v}"),
|
||||
Value::Cast(v) => write!(f, "{v}"),
|
||||
Value::Constant(v) => write!(f, "{v}"),
|
||||
Value::Datetime(v) => write!(f, "{v}"),
|
||||
Value::Duration(v) => write!(f, "{v}"),
|
||||
Value::Edges(v) => write!(f, "{v}"),
|
||||
Value::Expression(v) => write!(f, "{v}"),
|
||||
Value::Function(v) => write!(f, "{v}"),
|
||||
Value::Future(v) => write!(f, "{v}"),
|
||||
Value::Geometry(v) => write!(f, "{v}"),
|
||||
Value::Param(v) => write!(f, "{v}"),
|
||||
Value::Idiom(v) => write!(f, "{v}"),
|
||||
Value::Model(v) => write!(f, "{v}"),
|
||||
Value::Number(v) => write!(f, "{v}"),
|
||||
Value::Object(v) => write!(f, "{v}"),
|
||||
Value::Param(v) => write!(f, "{v}"),
|
||||
Value::Range(v) => write!(f, "{v}"),
|
||||
Value::Regex(v) => write!(f, "{v}"),
|
||||
Value::Strand(v) => write!(f, "{v}"),
|
||||
Value::Subquery(v) => write!(f, "{v}"),
|
||||
Value::Table(v) => write!(f, "{v}"),
|
||||
Value::Thing(v) => write!(f, "{v}"),
|
||||
Value::Model(v) => write!(f, "{v}"),
|
||||
Value::Regex(v) => write!(f, "{v}"),
|
||||
Value::Block(v) => write!(f, "{v}"),
|
||||
Value::Range(v) => write!(f, "{v}"),
|
||||
Value::Edges(v) => write!(f, "{v}"),
|
||||
Value::Future(v) => write!(f, "{v}"),
|
||||
Value::Constant(v) => write!(f, "{v}"),
|
||||
Value::Function(v) => write!(f, "{v}"),
|
||||
Value::Subquery(v) => write!(f, "{v}"),
|
||||
Value::Expression(v) => write!(f, "{v}"),
|
||||
Value::Bytes(v) => write!(f, "{v}"),
|
||||
Value::Uuid(v) => write!(f, "{v}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1975,6 +2490,7 @@ impl Value {
|
|||
doc: Option<&'async_recursion Value>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Value::Cast(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Thing(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Block(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Range(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
|
@ -2125,9 +2641,10 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
|||
map(tag_no_case("NULL"), |_| Value::Null),
|
||||
map(tag_no_case("true"), |_| Value::Bool(true)),
|
||||
map(tag_no_case("false"), |_| Value::Bool(false)),
|
||||
map(idiom::multi, Value::from),
|
||||
)),
|
||||
alt((
|
||||
map(idiom::multi, Value::from),
|
||||
map(cast, Value::from),
|
||||
map(function, Value::from),
|
||||
map(subquery, Value::from),
|
||||
map(constant, Value::from),
|
||||
|
@ -2160,9 +2677,10 @@ pub fn select(i: &str) -> IResult<&str, Value> {
|
|||
map(tag_no_case("NULL"), |_| Value::Null),
|
||||
map(tag_no_case("true"), |_| Value::Bool(true)),
|
||||
map(tag_no_case("false"), |_| Value::Bool(false)),
|
||||
map(idiom::multi, Value::from),
|
||||
)),
|
||||
alt((
|
||||
map(idiom::multi, Value::from),
|
||||
map(cast, Value::from),
|
||||
map(function, Value::from),
|
||||
map(subquery, Value::from),
|
||||
map(constant, Value::from),
|
||||
|
|
|
@ -36,28 +36,45 @@ async fn field_definition_value_assert_failure() -> Result<(), Error> {
|
|||
assert!(tmp.is_ok());
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Found NONE for field `age`, with record `person:test`, but expected a number"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Found NONE for field `age`, with record `person:test`, but expected a number",
|
||||
|
||||
),
|
||||
"{}",
|
||||
tmp.unwrap_err().to_string()
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Found NONE for field `age`, with record `person:test`, but expected a number"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Found NONE for field `age`, with record `person:test`, but expected a number"
|
||||
),
|
||||
"{}",
|
||||
tmp.unwrap_err().to_string()
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Found NULL for field `age`, with record `person:test`, but expected a number"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Found NULL for field `age`, with record `person:test`, but expected a number"
|
||||
),
|
||||
"{}",
|
||||
tmp.unwrap_err().to_string()
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Found 0 for field `age`, with record `person:test`, but field must conform to: $value > 0"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Found 0 for field `age`, with record `person:test`, but field must conform to: $value > 0"
|
||||
),
|
||||
"{}",
|
||||
tmp.unwrap_err().to_string()
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
|
|
|
@ -28,10 +28,13 @@ async fn function_array_add() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::add(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::add(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2]");
|
||||
|
@ -65,10 +68,13 @@ async fn function_array_all() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::all(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::all(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::Bool(false);
|
||||
|
@ -94,10 +100,13 @@ async fn function_array_any() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::any(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::any(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::Bool(true);
|
||||
|
@ -123,10 +132,13 @@ async fn function_array_append() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::append(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::append(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,[2,3]]");
|
||||
|
@ -152,10 +164,13 @@ async fn function_array_combine() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::combine(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::combine(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[ [1,2], [1,3], [2,2], [2,3] ]");
|
||||
|
@ -181,10 +196,13 @@ async fn function_array_complement() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::complement(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::complement(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2]");
|
||||
|
@ -210,10 +228,13 @@ async fn function_array_concat() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::concat(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::concat(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,3,4,3,4,5,6]");
|
||||
|
@ -239,10 +260,13 @@ async fn function_array_difference() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::difference(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::difference(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,5,6]");
|
||||
assert_eq!(tmp, val);
|
||||
|
@ -267,10 +291,13 @@ async fn function_array_distinct() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::distinct(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::distinct(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,3,4]");
|
||||
|
@ -297,10 +324,13 @@ async fn function_array_flatten() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::flatten(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::flatten(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,3,4]");
|
||||
|
@ -330,10 +360,13 @@ async fn function_array_group() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::group(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::group(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,3,4,5,6]");
|
||||
|
@ -391,10 +424,13 @@ async fn function_array_intersect() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::intersect(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::intersect(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[3,4]");
|
||||
|
@ -452,10 +488,13 @@ async fn function_array_len() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::len(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::len(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::from(6);
|
||||
|
@ -481,10 +520,13 @@ async fn function_array_max() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::max(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::max(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("'text'");
|
||||
|
@ -510,10 +552,13 @@ async fn function_array_min() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::min(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::min(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("1");
|
||||
|
@ -539,10 +584,13 @@ async fn function_array_pop() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::pop(). Argument 1 was the wrong type. Expected a array but failed to convert 'some text' into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::pop(). Argument 1 was the wrong type. Expected a array but found 'some text'"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::from(4);
|
||||
|
@ -568,10 +616,13 @@ async fn function_array_prepend() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::prepend(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::prepend(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[[2,3],1,2]");
|
||||
|
@ -597,10 +648,13 @@ async fn function_array_push() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::push(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::push(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,[2,3]]");
|
||||
|
@ -658,10 +712,13 @@ async fn function_array_reverse() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::reverse(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::reverse(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[4,3,3,'text',2,1]");
|
||||
|
@ -691,10 +748,13 @@ async fn function_array_slice() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::slice(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::slice(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,'text',3,3,4]");
|
||||
|
@ -740,10 +800,13 @@ async fn function_array_sort() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::sort(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::sort(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,3,4,4,'text']");
|
||||
|
@ -785,10 +848,13 @@ async fn function_array_sort_asc() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::sort::asc(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::sort::asc(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,3,4,4,'text']");
|
||||
|
@ -814,10 +880,13 @@ async fn function_array_sort_desc() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::sort::desc(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::sort::desc(). Argument 1 was the wrong type. Expected a array but found 3"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("['text',4,4,3,2,1]");
|
||||
|
@ -843,10 +912,13 @@ async fn function_array_union() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function array::union(). Argument 1 was the wrong type. Expected a array but failed to convert 3 into a array"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function array::union(). Argument 1 was the wrong type. Expected a array but found 3",
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1,2,6,3,4,5]");
|
||||
|
@ -865,7 +937,7 @@ async fn function_bytes_len() -> Result<(), Error> {
|
|||
RETURN bytes::len(<bytes>"");
|
||||
RETURN bytes::len(true);
|
||||
RETURN bytes::len(<bytes>"π");
|
||||
RETURN bytes::len("ππ");
|
||||
RETURN bytes::len(<bytes>"ππ");
|
||||
"#;
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
|
@ -877,10 +949,13 @@ async fn function_bytes_len() -> Result<(), Error> {
|
|||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function bytes::len(). Argument 1 was the wrong type. Expected a bytes but failed to convert true into a bytes"
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function bytes::len(). Argument 1 was the wrong type. Expected a bytes but found true"
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("2");
|
||||
|
@ -1458,8 +1533,8 @@ async fn function_encoding_base64_decode() -> Result<(), Error> {
|
|||
#[tokio::test]
|
||||
async fn function_encoding_base64_encode() -> Result<(), Error> {
|
||||
let sql = r#"
|
||||
RETURN encoding::base64::encode("");
|
||||
RETURN encoding::base64::encode("hello");
|
||||
RETURN encoding::base64::encode(<bytes>"");
|
||||
RETURN encoding::base64::encode(<bytes>"hello");
|
||||
"#;
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
|
@ -1968,10 +2043,13 @@ async fn function_math_bottom() -> Result<(), Error> {
|
|||
assert_eq!(res.len(), 3);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function math::bottom(). The second argument must be an integer greater than 0."
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function math::bottom(). The second argument must be an integer greater than 0."
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[1]");
|
||||
|
@ -2019,10 +2097,13 @@ async fn function_math_fixed() -> Result<(), Error> {
|
|||
assert_eq!(res.len(), 3);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function math::fixed(). The second argument must be an integer greater than 0."
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function math::fixed(). The second argument must be an integer greater than 0."
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::from(101);
|
||||
|
@ -2479,10 +2560,13 @@ async fn function_math_top() -> Result<(), Error> {
|
|||
assert_eq!(res.len(), 3);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Incorrect arguments for function math::top(). The second argument must be an integer greater than 0."
|
||||
));
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Incorrect arguments for function math::top(). The second argument must be an integer greater than 0."
|
||||
),
|
||||
"{tmp:?}"
|
||||
);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse("[3]");
|
||||
|
|
|
@ -26,7 +26,7 @@ async fn strict_typing_inline() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Expected a int but failed to convert NONE into a int"
|
||||
Some(e) if e.to_string() == "Expected a int but cannot convert NONE into a int"
|
||||
));
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
|
@ -43,7 +43,7 @@ async fn strict_typing_inline() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Expected a bool | int but failed to convert NONE into a bool | int"
|
||||
Some(e) if e.to_string() == "Expected a bool | int but cannot convert NONE into a bool | int"
|
||||
));
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
|
@ -113,19 +113,11 @@ async fn strict_typing_inline() -> Result<(), Error> {
|
|||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"[
|
||||
{
|
||||
id: person:test,
|
||||
age: 18,
|
||||
enabled: true,
|
||||
name: 'Tobie Morgan Hitchcock',
|
||||
scores: [1.0, 1.0, 2.0, 2.0, 3.0],
|
||||
}
|
||||
]",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(matches!(
|
||||
tmp.err(),
|
||||
Some(e) if e.to_string() == "Expected a array<float, 5> but the array had 10 items"
|
||||
));
|
||||
//
|
||||
Ok(())
|
||||
}
|
||||
|
@ -138,9 +130,9 @@ async fn strict_typing_defined() -> Result<(), Error> {
|
|||
DEFINE FIELD name ON person TYPE string;
|
||||
DEFINE FIELD scores ON person TYPE set<float, 5>;
|
||||
UPDATE person:test SET age = NONE, enabled = NONE, name = NONE, scored = [1,1,2,2,3,3,4,4,5,5];
|
||||
UPDATE person:test SET age = '18', enabled = NONE, name = NONE, scored = [1,1,2,2,3,3,4,4,5,5];
|
||||
UPDATE person:test SET age = '18', enabled = true, name = NONE, scored = [1,1,2,2,3,3,4,4,5,5];
|
||||
UPDATE person:test SET age = '18', enabled = true, name = 'Tobie Morgan Hitchcock', scores = [1,1,2,2,3,3,4,4,5,5];
|
||||
UPDATE person:test SET age = 18, enabled = NONE, name = NONE, scored = [1,1,2,2,3,3,4,4,5,5];
|
||||
UPDATE person:test SET age = 18, enabled = true, name = NONE, scored = [1,1,2,2,3,3,4,4,5,5];
|
||||
UPDATE person:test SET age = 18, enabled = true, name = 'Tobie Morgan Hitchcock', scores = [1,1,2,2,3,3,4,4,5,5];
|
||||
";
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
|
|
|
@ -20,7 +20,7 @@ use std::collections::HashMap;
|
|||
use std::sync::Arc;
|
||||
use surrealdb::channel;
|
||||
use surrealdb::channel::Sender;
|
||||
use surrealdb::dbs::{Response, Session};
|
||||
use surrealdb::dbs::Session;
|
||||
use surrealdb::sql::Array;
|
||||
use surrealdb::sql::Object;
|
||||
use surrealdb::sql::Strand;
|
||||
|
|
Loading…
Reference in a new issue