diff --git a/core/Cargo.toml b/core/Cargo.toml index 8963762c..1c5b8916 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -41,7 +41,7 @@ kv-surrealkv = ["dep:surrealkv", "tokio/time"] scripting = ["dep:js"] http = ["dep:reqwest"] ml = ["dep:surrealml-core1", "dep:ndarray"] -jwks = ["dep:reqwest", "sql2"] +jwks = ["dep:reqwest"] arbitrary = [ "dep:arbitrary", "dep:regex-syntax", @@ -50,7 +50,6 @@ arbitrary = [ "uuid/arbitrary", ] experimental-parser = ["dep:phf", "dep:unicase"] -sql2 = [] # Private features kv-fdb = ["tokio/time"] diff --git a/core/src/doc/field.rs b/core/src/doc/field.rs index bf2adfc8..de336f84 100644 --- a/core/src/doc/field.rs +++ b/core/src/doc/field.rs @@ -32,7 +32,6 @@ impl<'a> Document<'a> { // Get the input value let inp = inp.pick(&k); // Check for READONLY clause - #[cfg(feature = "sql2")] if fd.readonly && !self.is_new() && val != old { return Err(Error::FieldReadonly { field: fd.name.clone(), @@ -80,11 +79,7 @@ impl<'a> Document<'a> { // Check for a VALUE clause if let Some(expr) = &fd.value { // Only run value clause for mutable and new fields - #[cfg(feature = "sql2")] - let readonly = fd.readonly; - #[cfg(not(feature = "sql2"))] - let readonly = false; - if !readonly || self.is_new() { + if !fd.readonly || self.is_new() { // Configure the context let mut ctx = Context::new(ctx); ctx.add_value("input", &inp); diff --git a/core/src/err/mod.rs b/core/src/err/mod.rs index a21c10d9..153c4b78 100644 --- a/core/src/err/mod.rs +++ b/core/src/err/mod.rs @@ -321,7 +321,6 @@ pub enum Error { /// The requested event does not exist #[error("The event '{value}' does not exist")] - #[cfg(feature = "sql2")] EvNotFound { value: String, }, @@ -334,7 +333,6 @@ pub enum Error { /// The requested field does not exist #[error("The field '{value}' does not exist")] - #[cfg(feature = "sql2")] FdNotFound { value: String, }, @@ -796,112 +794,96 @@ pub enum Error { /// The requested analyzer already exists #[error("The analyzer '{value}' already exists")] - #[cfg(feature = "sql2")] AzAlreadyExists { value: String, }, /// The requested database already exists #[error("The database '{value}' already exists")] - #[cfg(feature = "sql2")] DbAlreadyExists { value: String, }, /// The requested event already exists #[error("The event '{value}' already exists")] - #[cfg(feature = "sql2")] EvAlreadyExists { value: String, }, /// The requested field already exists #[error("The field '{value}' already exists")] - #[cfg(feature = "sql2")] FdAlreadyExists { value: String, }, /// The requested function already exists #[error("The function 'fn::{value}' already exists")] - #[cfg(feature = "sql2")] FcAlreadyExists { value: String, }, /// The requested index already exists #[error("The index '{value}' already exists")] - #[cfg(feature = "sql2")] IxAlreadyExists { value: String, }, /// The requested model already exists #[error("The model '{value}' already exists")] - #[cfg(feature = "sql2")] MlAlreadyExists { value: String, }, /// The requested namespace already exists #[error("The namespace '{value}' already exists")] - #[cfg(feature = "sql2")] NsAlreadyExists { value: String, }, /// The requested param already exists #[error("The param '${value}' already exists")] - #[cfg(feature = "sql2")] PaAlreadyExists { value: String, }, /// The requested scope already exists #[error("The scope '{value}' already exists")] - #[cfg(feature = "sql2")] ScAlreadyExists { value: String, }, /// The requested table already exists #[error("The table '{value}' already exists")] - #[cfg(feature = "sql2")] TbAlreadyExists { value: String, }, /// The requested namespace token already exists #[error("The namespace token '{value}' already exists")] - #[cfg(feature = "sql2")] NtAlreadyExists { value: String, }, /// The requested database token already exists #[error("The database token '{value}' already exists")] - #[cfg(feature = "sql2")] DtAlreadyExists { value: String, }, /// The requested scope token already exists #[error("The scope token '{value}' already exists")] - #[cfg(feature = "sql2")] StAlreadyExists { value: String, }, /// The requested user already exists #[error("The user '{value}' already exists")] - #[cfg(feature = "sql2")] UserRootAlreadyExists { value: String, }, /// The requested namespace user already exists #[error("The user '{value}' already exists in the namespace '{ns}'")] - #[cfg(feature = "sql2")] UserNsAlreadyExists { value: String, ns: String, @@ -909,7 +891,6 @@ pub enum Error { /// The requested database user already exists #[error("The user '{value}' already exists in the database '{db}'")] - #[cfg(feature = "sql2")] UserDbAlreadyExists { value: String, ns: String, diff --git a/core/src/fnc/operate.rs b/core/src/fnc/operate.rs index 4169b252..c8efece4 100644 --- a/core/src/fnc/operate.rs +++ b/core/src/fnc/operate.rs @@ -3,7 +3,6 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::idx::planner::executor::QueryExecutor; -#[cfg(feature = "sql2")] use crate::sql::value::TryRem; use crate::sql::value::{TryAdd, TryDiv, TryMul, TryNeg, TryPow, TrySub, Value}; use crate::sql::{Expression, Thing}; @@ -60,7 +59,6 @@ pub fn div(a: Value, b: Value) -> Result { a.try_div(b) } -#[cfg(feature = "sql2")] pub fn rem(a: Value, b: Value) -> Result { a.try_rem(b) } diff --git a/core/src/iam/verify.rs b/core/src/iam/verify.rs index f7bfd5e2..5ca9e53a 100644 --- a/core/src/iam/verify.rs +++ b/core/src/iam/verify.rs @@ -19,11 +19,7 @@ async fn config( de_code: String, _token_header: Header, ) -> Result<(DecodingKey, Validation), Error> { - #[cfg(feature = "sql2")] - let is_jwks = de_kind == Algorithm::Jwks; - #[cfg(not(feature = "sql2"))] - let is_jwks = false; - if is_jwks { + if de_kind == Algorithm::Jwks { #[cfg(not(feature = "jwks"))] { warn!("Failed to verify a token defined as JWKS when the feature is not enabled"); @@ -95,7 +91,6 @@ fn config_alg(algo: Algorithm, code: String) -> Result<(DecodingKey, Validation) DecodingKey::from_rsa_pem(code.as_ref())?, Validation::new(jsonwebtoken::Algorithm::RS512), )), - #[cfg(feature = "sql2")] Algorithm::Jwks => Err(Error::InvalidAuth), // We should never get here } } diff --git a/core/src/idx/ft/analyzer/mod.rs b/core/src/idx/ft/analyzer/mod.rs index e4eb95f7..24f223ee 100644 --- a/core/src/idx/ft/analyzer/mod.rs +++ b/core/src/idx/ft/analyzer/mod.rs @@ -9,7 +9,6 @@ use crate::idx::ft::terms::{TermId, Terms}; use crate::sql::statements::DefineAnalyzerStatement; use crate::sql::tokenizer::Tokenizer as SqlTokenizer; use crate::sql::Value; -#[cfg(feature = "sql2")] use crate::sql::{Function, Strand}; use async_recursion::async_recursion; use filter::Filter; @@ -20,7 +19,6 @@ mod filter; mod tokenizer; pub(crate) struct Analyzer { - #[cfg(feature = "sql2")] function: Option, tokenizers: Option>, filters: Option>, @@ -29,7 +27,6 @@ pub(crate) struct Analyzer { impl From for Analyzer { fn from(az: DefineAnalyzerStatement) -> Self { Self { - #[cfg(feature = "sql2")] function: az.function.map(|i| i.0), tokenizers: az.tokenizers, filters: Filter::from(az.filters), @@ -198,7 +195,6 @@ impl Analyzer { txn: &Transaction, mut input: String, ) -> Result { - #[cfg(feature = "sql2")] if let Some(function_name) = self.function.clone() { let fns = Function::Custom(function_name.clone(), vec![Value::Strand(Strand(input))]); let val = fns.compute(ctx, opt, txn, None).await?; diff --git a/core/src/kvs/tests/tb.rs b/core/src/kvs/tests/tb.rs index 5402b164..3f87cd59 100644 --- a/core/src/kvs/tests/tb.rs +++ b/core/src/kvs/tests/tb.rs @@ -70,7 +70,6 @@ async fn table_definitions_can_be_deleted() { permissions: Default::default(), changefeed: None, comment: None, - #[cfg(feature = "sql2")] if_not_exists: false, }; tx.set(&key, &value).await.unwrap(); diff --git a/core/src/kvs/tx.rs b/core/src/kvs/tx.rs index b81a7963..b1ec943c 100644 --- a/core/src/kvs/tx.rs +++ b/core/src/kvs/tx.rs @@ -1939,7 +1939,6 @@ impl Transaction { } /// Retrieve a specific function definition from a database. - #[cfg(feature = "sql2")] pub async fn get_db_function( &mut self, ns: &str, @@ -1954,7 +1953,6 @@ impl Transaction { } /// Retrieve a specific function definition from a database. - #[cfg(feature = "sql2")] pub async fn get_db_param( &mut self, ns: &str, @@ -2044,7 +2042,6 @@ impl Transaction { } /// Retrieve an event for a table. - #[cfg(feature = "sql2")] pub async fn get_tb_event( &mut self, ns: &str, @@ -2062,7 +2059,6 @@ impl Transaction { } /// Retrieve an event for a table. - #[cfg(feature = "sql2")] pub async fn get_tb_field( &mut self, ns: &str, @@ -2080,7 +2076,6 @@ impl Transaction { } /// Retrieve an event for a table. - #[cfg(feature = "sql2")] pub async fn get_tb_index( &mut self, ns: &str, diff --git a/core/src/sql/v2/algorithm.rs b/core/src/sql/algorithm.rs similarity index 100% rename from core/src/sql/v2/algorithm.rs rename to core/src/sql/algorithm.rs diff --git a/core/src/sql/v1/arbitrary.rs b/core/src/sql/arbitrary.rs similarity index 100% rename from core/src/sql/v1/arbitrary.rs rename to core/src/sql/arbitrary.rs diff --git a/core/src/sql/v2/array.rs b/core/src/sql/array.rs similarity index 99% rename from core/src/sql/v2/array.rs rename to core/src/sql/array.rs index 8af1befa..36f48237 100644 --- a/core/src/sql/v2/array.rs +++ b/core/src/sql/array.rs @@ -289,7 +289,7 @@ impl Complement for Array { // ------------------------------ -#[cfg_attr(feature = "sql2", allow(dead_code))] +#[allow(dead_code)] pub(crate) trait Concat { fn concat(self, other: T) -> T; } diff --git a/core/src/sql/v1/base.rs b/core/src/sql/base.rs similarity index 100% rename from core/src/sql/v1/base.rs rename to core/src/sql/base.rs diff --git a/core/src/sql/v1/block.rs b/core/src/sql/block.rs similarity index 100% rename from core/src/sql/v1/block.rs rename to core/src/sql/block.rs diff --git a/core/src/sql/v1/bytes.rs b/core/src/sql/bytes.rs similarity index 100% rename from core/src/sql/v1/bytes.rs rename to core/src/sql/bytes.rs diff --git a/core/src/sql/v1/cast.rs b/core/src/sql/cast.rs similarity index 100% rename from core/src/sql/v1/cast.rs rename to core/src/sql/cast.rs diff --git a/core/src/sql/v2/change_feed_include.rs b/core/src/sql/change_feed_include.rs similarity index 100% rename from core/src/sql/v2/change_feed_include.rs rename to core/src/sql/change_feed_include.rs diff --git a/core/src/sql/v2/changefeed.rs b/core/src/sql/changefeed.rs similarity index 100% rename from core/src/sql/v2/changefeed.rs rename to core/src/sql/changefeed.rs diff --git a/core/src/sql/v1/cond.rs b/core/src/sql/cond.rs similarity index 100% rename from core/src/sql/v1/cond.rs rename to core/src/sql/cond.rs diff --git a/core/src/sql/v1/constant.rs b/core/src/sql/constant.rs similarity index 100% rename from core/src/sql/v1/constant.rs rename to core/src/sql/constant.rs diff --git a/core/src/sql/v1/data.rs b/core/src/sql/data.rs similarity index 100% rename from core/src/sql/v1/data.rs rename to core/src/sql/data.rs diff --git a/core/src/sql/v1/datetime.rs b/core/src/sql/datetime.rs similarity index 100% rename from core/src/sql/v1/datetime.rs rename to core/src/sql/datetime.rs diff --git a/core/src/sql/v1/dir.rs b/core/src/sql/dir.rs similarity index 100% rename from core/src/sql/v1/dir.rs rename to core/src/sql/dir.rs diff --git a/core/src/sql/v1/duration.rs b/core/src/sql/duration.rs similarity index 100% rename from core/src/sql/v1/duration.rs rename to core/src/sql/duration.rs diff --git a/core/src/sql/v1/edges.rs b/core/src/sql/edges.rs similarity index 100% rename from core/src/sql/v1/edges.rs rename to core/src/sql/edges.rs diff --git a/core/src/sql/v1/ending.rs b/core/src/sql/ending.rs similarity index 100% rename from core/src/sql/v1/ending.rs rename to core/src/sql/ending.rs diff --git a/core/src/sql/v2/escape.rs b/core/src/sql/escape.rs similarity index 100% rename from core/src/sql/v2/escape.rs rename to core/src/sql/escape.rs diff --git a/core/src/sql/v1/explain.rs b/core/src/sql/explain.rs similarity index 100% rename from core/src/sql/v1/explain.rs rename to core/src/sql/explain.rs diff --git a/core/src/sql/v2/expression.rs b/core/src/sql/expression.rs similarity index 100% rename from core/src/sql/v2/expression.rs rename to core/src/sql/expression.rs diff --git a/core/src/sql/v1/fetch.rs b/core/src/sql/fetch.rs similarity index 100% rename from core/src/sql/v1/fetch.rs rename to core/src/sql/fetch.rs diff --git a/core/src/sql/v1/field.rs b/core/src/sql/field.rs similarity index 100% rename from core/src/sql/v1/field.rs rename to core/src/sql/field.rs diff --git a/core/src/sql/v1/filter.rs b/core/src/sql/filter.rs similarity index 100% rename from core/src/sql/v1/filter.rs rename to core/src/sql/filter.rs diff --git a/core/src/sql/v2/fmt.rs b/core/src/sql/fmt.rs similarity index 100% rename from core/src/sql/v2/fmt.rs rename to core/src/sql/fmt.rs diff --git a/core/src/sql/v1/function.rs b/core/src/sql/function.rs similarity index 100% rename from core/src/sql/v1/function.rs rename to core/src/sql/function.rs diff --git a/core/src/sql/v1/future.rs b/core/src/sql/future.rs similarity index 100% rename from core/src/sql/v1/future.rs rename to core/src/sql/future.rs diff --git a/core/src/sql/v1/geometry.rs b/core/src/sql/geometry.rs similarity index 100% rename from core/src/sql/v1/geometry.rs rename to core/src/sql/geometry.rs diff --git a/core/src/sql/v1/graph.rs b/core/src/sql/graph.rs similarity index 100% rename from core/src/sql/v1/graph.rs rename to core/src/sql/graph.rs diff --git a/core/src/sql/v1/group.rs b/core/src/sql/group.rs similarity index 100% rename from core/src/sql/v1/group.rs rename to core/src/sql/group.rs diff --git a/core/src/sql/v1/id.rs b/core/src/sql/id.rs similarity index 100% rename from core/src/sql/v1/id.rs rename to core/src/sql/id.rs diff --git a/core/src/sql/v1/ident.rs b/core/src/sql/ident.rs similarity index 100% rename from core/src/sql/v1/ident.rs rename to core/src/sql/ident.rs diff --git a/core/src/sql/v1/idiom.rs b/core/src/sql/idiom.rs similarity index 100% rename from core/src/sql/v1/idiom.rs rename to core/src/sql/idiom.rs diff --git a/core/src/sql/v1/index.rs b/core/src/sql/index.rs similarity index 100% rename from core/src/sql/v1/index.rs rename to core/src/sql/index.rs diff --git a/core/src/sql/v1/kind.rs b/core/src/sql/kind.rs similarity index 100% rename from core/src/sql/v1/kind.rs rename to core/src/sql/kind.rs diff --git a/core/src/sql/v1/language.rs b/core/src/sql/language.rs similarity index 100% rename from core/src/sql/v1/language.rs rename to core/src/sql/language.rs diff --git a/core/src/sql/v1/limit.rs b/core/src/sql/limit.rs similarity index 100% rename from core/src/sql/v1/limit.rs rename to core/src/sql/limit.rs diff --git a/core/src/sql/v1/mock.rs b/core/src/sql/mock.rs similarity index 100% rename from core/src/sql/v1/mock.rs rename to core/src/sql/mock.rs diff --git a/core/src/sql/mod.rs b/core/src/sql/mod.rs index d10f6214..776345c4 100644 --- a/core/src/sql/mod.rs +++ b/core/src/sql/mod.rs @@ -1,9 +1,155 @@ -#[cfg(not(feature = "sql2"))] -mod v1; -#[cfg(not(feature = "sql2"))] -pub use v1::*; +//! The full type definitions for the SurrealQL query language -#[cfg(feature = "sql2")] -mod v2; -#[cfg(feature = "sql2")] -pub use v2::*; +pub(crate) mod algorithm; +#[cfg(feature = "arbitrary")] +pub(crate) mod arbitrary; +pub(crate) mod array; +pub(crate) mod base; +pub(crate) mod block; +pub(crate) mod bytes; +pub(crate) mod cast; +pub(crate) mod change_feed_include; +pub(crate) mod changefeed; +pub(crate) mod cond; +pub(crate) mod constant; +pub(crate) mod data; +pub(crate) mod datetime; +pub(crate) mod dir; +pub(crate) mod duration; +pub(crate) mod edges; +pub(crate) mod escape; +pub(crate) mod explain; +pub(crate) mod expression; +pub(crate) mod fetch; +pub(crate) mod field; +pub(crate) mod filter; +pub(crate) mod fmt; +pub(crate) mod function; +pub(crate) mod future; +pub(crate) mod geometry; +pub(crate) mod graph; +pub(crate) mod group; +pub(crate) mod id; +pub(crate) mod ident; +pub(crate) mod idiom; +pub(crate) mod kind; +pub(crate) mod language; +pub(crate) mod limit; +pub(crate) mod mock; +pub(crate) mod model; +pub(crate) mod number; +pub(crate) mod object; +pub(crate) mod operation; +pub(crate) mod operator; +pub(crate) mod order; +pub(crate) mod output; +pub(crate) mod param; +pub(crate) mod part; +pub(crate) mod paths; +pub(crate) mod permission; +pub(crate) mod query; +pub(crate) mod range; +pub(crate) mod regex; +pub(crate) mod scoring; +pub(crate) mod script; +pub(crate) mod split; +pub(crate) mod start; +pub(crate) mod statement; +pub(crate) mod strand; +pub(crate) mod subquery; +pub(crate) mod table; +pub(crate) mod thing; +pub(crate) mod timeout; +pub(crate) mod tokenizer; +pub(crate) mod uuid; +pub(crate) mod value; +pub(crate) mod version; +pub(crate) mod view; +pub(crate) mod with; + +#[doc(hidden)] +pub mod index; + +pub mod serde; +pub mod statements; + +pub use self::algorithm::Algorithm; +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::changefeed::ChangeFeed; +pub use self::cond::Cond; +pub use self::constant::Constant; +pub use self::data::Data; +pub use self::datetime::Datetime; +pub use self::dir::Dir; +pub use self::duration::Duration; +pub use self::edges::Edges; +pub use self::explain::Explain; +pub use self::expression::Expression; +pub use self::fetch::Fetch; +pub use self::fetch::Fetchs; +pub use self::field::Field; +pub use self::field::Fields; +pub use self::function::Function; +pub use self::future::Future; +pub use self::geometry::Geometry; +pub use self::graph::Graph; +pub use self::group::Group; +pub use self::group::Groups; +pub use self::id::Id; +pub use self::ident::Ident; +pub use self::idiom::Idiom; +pub use self::idiom::Idioms; +pub use self::index::Index; +pub use self::kind::Kind; +pub use self::limit::Limit; +pub use self::mock::Mock; +pub use self::model::Model; +pub use self::number::Number; +pub use self::object::Object; +pub use self::operation::Operation; +pub use self::operator::Operator; +pub use self::order::Order; +pub use self::order::Orders; +pub use self::output::Output; +pub use self::param::Param; +pub use self::part::Part; +pub use self::permission::Permission; +pub use self::permission::Permissions; +pub use self::query::Query; +pub use self::range::Range; +pub use self::regex::Regex; +pub use self::scoring::Scoring; +pub use self::script::Script; +pub use self::split::Split; +pub use self::split::Splits; +pub use self::start::Start; +pub use self::statement::Statement; +pub use self::statement::Statements; +pub use self::strand::Strand; +pub use self::subquery::Subquery; +pub use self::table::Table; +pub use self::table::Tables; +pub use self::thing::Thing; +pub use self::timeout::Timeout; +pub use self::tokenizer::Tokenizer; +pub use self::uuid::Uuid; +pub use self::value::serde::to_value; +#[doc(hidden)] +pub use self::value::serde::{from_value, FromValueError}; +pub use self::value::Value; +pub use self::value::Values; +pub use self::version::Version; +pub use self::view::View; +pub use self::with::With; + +// module reexporting parsing function to prevent a breaking change. +#[doc(hidden)] +mod parser { + pub use crate::syn::*; +} + +pub use self::parser::{idiom, json, parse, subquery, thing, value}; diff --git a/core/src/sql/v1/model.rs b/core/src/sql/model.rs similarity index 100% rename from core/src/sql/v1/model.rs rename to core/src/sql/model.rs diff --git a/core/src/sql/v1/number.rs b/core/src/sql/number.rs similarity index 100% rename from core/src/sql/v1/number.rs rename to core/src/sql/number.rs diff --git a/core/src/sql/v1/object.rs b/core/src/sql/object.rs similarity index 100% rename from core/src/sql/v1/object.rs rename to core/src/sql/object.rs diff --git a/core/src/sql/v1/operation.rs b/core/src/sql/operation.rs similarity index 100% rename from core/src/sql/v1/operation.rs rename to core/src/sql/operation.rs diff --git a/core/src/sql/v2/operator.rs b/core/src/sql/operator.rs similarity index 100% rename from core/src/sql/v2/operator.rs rename to core/src/sql/operator.rs diff --git a/core/src/sql/v1/order.rs b/core/src/sql/order.rs similarity index 100% rename from core/src/sql/v1/order.rs rename to core/src/sql/order.rs diff --git a/core/src/sql/v1/output.rs b/core/src/sql/output.rs similarity index 100% rename from core/src/sql/v1/output.rs rename to core/src/sql/output.rs diff --git a/core/src/sql/v1/param.rs b/core/src/sql/param.rs similarity index 100% rename from core/src/sql/v1/param.rs rename to core/src/sql/param.rs diff --git a/core/src/sql/v1/part.rs b/core/src/sql/part.rs similarity index 100% rename from core/src/sql/v1/part.rs rename to core/src/sql/part.rs diff --git a/core/src/sql/v1/paths.rs b/core/src/sql/paths.rs similarity index 100% rename from core/src/sql/v1/paths.rs rename to core/src/sql/paths.rs diff --git a/core/src/sql/v1/permission.rs b/core/src/sql/permission.rs similarity index 100% rename from core/src/sql/v1/permission.rs rename to core/src/sql/permission.rs diff --git a/core/src/sql/v1/query.rs b/core/src/sql/query.rs similarity index 100% rename from core/src/sql/v1/query.rs rename to core/src/sql/query.rs diff --git a/core/src/sql/v1/range.rs b/core/src/sql/range.rs similarity index 100% rename from core/src/sql/v1/range.rs rename to core/src/sql/range.rs diff --git a/core/src/sql/v2/regex.rs b/core/src/sql/regex.rs similarity index 100% rename from core/src/sql/v2/regex.rs rename to core/src/sql/regex.rs diff --git a/core/src/sql/v1/scoring.rs b/core/src/sql/scoring.rs similarity index 100% rename from core/src/sql/v1/scoring.rs rename to core/src/sql/scoring.rs diff --git a/core/src/sql/v1/script.rs b/core/src/sql/script.rs similarity index 100% rename from core/src/sql/v1/script.rs rename to core/src/sql/script.rs diff --git a/core/src/sql/v2/serde.rs b/core/src/sql/serde.rs similarity index 100% rename from core/src/sql/v2/serde.rs rename to core/src/sql/serde.rs diff --git a/core/src/sql/v1/split.rs b/core/src/sql/split.rs similarity index 100% rename from core/src/sql/v1/split.rs rename to core/src/sql/split.rs diff --git a/core/src/sql/v1/start.rs b/core/src/sql/start.rs similarity index 100% rename from core/src/sql/v1/start.rs rename to core/src/sql/start.rs diff --git a/core/src/sql/v1/statement.rs b/core/src/sql/statement.rs similarity index 100% rename from core/src/sql/v1/statement.rs rename to core/src/sql/statement.rs diff --git a/core/src/sql/v1/statements/analyze.rs b/core/src/sql/statements/analyze.rs similarity index 100% rename from core/src/sql/v1/statements/analyze.rs rename to core/src/sql/statements/analyze.rs diff --git a/core/src/sql/v1/statements/begin.rs b/core/src/sql/statements/begin.rs similarity index 100% rename from core/src/sql/v1/statements/begin.rs rename to core/src/sql/statements/begin.rs diff --git a/core/src/sql/v1/statements/break.rs b/core/src/sql/statements/break.rs similarity index 100% rename from core/src/sql/v1/statements/break.rs rename to core/src/sql/statements/break.rs diff --git a/core/src/sql/v1/statements/cancel.rs b/core/src/sql/statements/cancel.rs similarity index 100% rename from core/src/sql/v1/statements/cancel.rs rename to core/src/sql/statements/cancel.rs diff --git a/core/src/sql/v1/statements/commit.rs b/core/src/sql/statements/commit.rs similarity index 100% rename from core/src/sql/v1/statements/commit.rs rename to core/src/sql/statements/commit.rs diff --git a/core/src/sql/v1/statements/continue.rs b/core/src/sql/statements/continue.rs similarity index 100% rename from core/src/sql/v1/statements/continue.rs rename to core/src/sql/statements/continue.rs diff --git a/core/src/sql/v1/statements/create.rs b/core/src/sql/statements/create.rs similarity index 100% rename from core/src/sql/v1/statements/create.rs rename to core/src/sql/statements/create.rs diff --git a/core/src/sql/v2/statements/define/analyzer.rs b/core/src/sql/statements/define/analyzer.rs similarity index 100% rename from core/src/sql/v2/statements/define/analyzer.rs rename to core/src/sql/statements/define/analyzer.rs diff --git a/core/src/sql/v2/statements/define/database.rs b/core/src/sql/statements/define/database.rs similarity index 100% rename from core/src/sql/v2/statements/define/database.rs rename to core/src/sql/statements/define/database.rs diff --git a/core/src/sql/v2/statements/define/event.rs b/core/src/sql/statements/define/event.rs similarity index 100% rename from core/src/sql/v2/statements/define/event.rs rename to core/src/sql/statements/define/event.rs diff --git a/core/src/sql/v2/statements/define/field.rs b/core/src/sql/statements/define/field.rs similarity index 100% rename from core/src/sql/v2/statements/define/field.rs rename to core/src/sql/statements/define/field.rs diff --git a/core/src/sql/v2/statements/define/function.rs b/core/src/sql/statements/define/function.rs similarity index 100% rename from core/src/sql/v2/statements/define/function.rs rename to core/src/sql/statements/define/function.rs diff --git a/core/src/sql/v2/statements/define/index.rs b/core/src/sql/statements/define/index.rs similarity index 100% rename from core/src/sql/v2/statements/define/index.rs rename to core/src/sql/statements/define/index.rs diff --git a/core/src/sql/v2/statements/define/mod.rs b/core/src/sql/statements/define/mod.rs similarity index 100% rename from core/src/sql/v2/statements/define/mod.rs rename to core/src/sql/statements/define/mod.rs diff --git a/core/src/sql/v2/statements/define/model.rs b/core/src/sql/statements/define/model.rs similarity index 100% rename from core/src/sql/v2/statements/define/model.rs rename to core/src/sql/statements/define/model.rs diff --git a/core/src/sql/v2/statements/define/namespace.rs b/core/src/sql/statements/define/namespace.rs similarity index 100% rename from core/src/sql/v2/statements/define/namespace.rs rename to core/src/sql/statements/define/namespace.rs diff --git a/core/src/sql/v2/statements/define/param.rs b/core/src/sql/statements/define/param.rs similarity index 100% rename from core/src/sql/v2/statements/define/param.rs rename to core/src/sql/statements/define/param.rs diff --git a/core/src/sql/v2/statements/define/scope.rs b/core/src/sql/statements/define/scope.rs similarity index 100% rename from core/src/sql/v2/statements/define/scope.rs rename to core/src/sql/statements/define/scope.rs diff --git a/core/src/sql/v2/statements/define/table.rs b/core/src/sql/statements/define/table.rs similarity index 100% rename from core/src/sql/v2/statements/define/table.rs rename to core/src/sql/statements/define/table.rs diff --git a/core/src/sql/v2/statements/define/token.rs b/core/src/sql/statements/define/token.rs similarity index 100% rename from core/src/sql/v2/statements/define/token.rs rename to core/src/sql/statements/define/token.rs diff --git a/core/src/sql/v2/statements/define/user.rs b/core/src/sql/statements/define/user.rs similarity index 100% rename from core/src/sql/v2/statements/define/user.rs rename to core/src/sql/statements/define/user.rs diff --git a/core/src/sql/v1/statements/delete.rs b/core/src/sql/statements/delete.rs similarity index 100% rename from core/src/sql/v1/statements/delete.rs rename to core/src/sql/statements/delete.rs diff --git a/core/src/sql/v1/statements/foreach.rs b/core/src/sql/statements/foreach.rs similarity index 100% rename from core/src/sql/v1/statements/foreach.rs rename to core/src/sql/statements/foreach.rs diff --git a/core/src/sql/v1/statements/ifelse.rs b/core/src/sql/statements/ifelse.rs similarity index 100% rename from core/src/sql/v1/statements/ifelse.rs rename to core/src/sql/statements/ifelse.rs diff --git a/core/src/sql/v1/statements/info.rs b/core/src/sql/statements/info.rs similarity index 100% rename from core/src/sql/v1/statements/info.rs rename to core/src/sql/statements/info.rs diff --git a/core/src/sql/v1/statements/insert.rs b/core/src/sql/statements/insert.rs similarity index 100% rename from core/src/sql/v1/statements/insert.rs rename to core/src/sql/statements/insert.rs diff --git a/core/src/sql/v2/statements/kill.rs b/core/src/sql/statements/kill.rs similarity index 98% rename from core/src/sql/v2/statements/kill.rs rename to core/src/sql/statements/kill.rs index 2ad9bf93..651c641f 100644 --- a/core/src/sql/v2/statements/kill.rs +++ b/core/src/sql/statements/kill.rs @@ -124,7 +124,6 @@ impl fmt::Display for KillStatement { } #[cfg(test)] -#[cfg(feature = "sql2")] mod test { use std::str::FromStr; @@ -134,7 +133,7 @@ mod test { use crate::kvs::lq_structs::{KillEntry, TrackedResult}; use crate::kvs::{Datastore, LockType, TransactionType}; use crate::sql::statements::KillStatement; - use crate::sql::v2::uuid::Uuid; + use crate::sql::uuid::Uuid; #[test_log::test(tokio::test)] async fn kill_handles_uuid_event_registration() { @@ -151,7 +150,7 @@ mod test { .with_db(Some("database".into())) .with_ns(Some("namespace".into())); let ds = Datastore::new("memory").await.unwrap(); - let mut tx = + let tx = ds.transaction(TransactionType::Write, LockType::Optimistic).await.unwrap().enclose(); res.compute(&ctx, &opt, &tx, None).await.unwrap(); diff --git a/core/src/sql/v2/statements/live.rs b/core/src/sql/statements/live.rs similarity index 100% rename from core/src/sql/v2/statements/live.rs rename to core/src/sql/statements/live.rs diff --git a/core/src/sql/v1/statements/mod.rs b/core/src/sql/statements/mod.rs similarity index 100% rename from core/src/sql/v1/statements/mod.rs rename to core/src/sql/statements/mod.rs diff --git a/core/src/sql/v1/statements/option.rs b/core/src/sql/statements/option.rs similarity index 100% rename from core/src/sql/v1/statements/option.rs rename to core/src/sql/statements/option.rs diff --git a/core/src/sql/v1/statements/output.rs b/core/src/sql/statements/output.rs similarity index 100% rename from core/src/sql/v1/statements/output.rs rename to core/src/sql/statements/output.rs diff --git a/core/src/sql/v1/statements/relate.rs b/core/src/sql/statements/relate.rs similarity index 100% rename from core/src/sql/v1/statements/relate.rs rename to core/src/sql/statements/relate.rs diff --git a/core/src/sql/v2/statements/remove/analyzer.rs b/core/src/sql/statements/remove/analyzer.rs similarity index 100% rename from core/src/sql/v2/statements/remove/analyzer.rs rename to core/src/sql/statements/remove/analyzer.rs diff --git a/core/src/sql/v2/statements/remove/database.rs b/core/src/sql/statements/remove/database.rs similarity index 100% rename from core/src/sql/v2/statements/remove/database.rs rename to core/src/sql/statements/remove/database.rs diff --git a/core/src/sql/v2/statements/remove/event.rs b/core/src/sql/statements/remove/event.rs similarity index 100% rename from core/src/sql/v2/statements/remove/event.rs rename to core/src/sql/statements/remove/event.rs diff --git a/core/src/sql/v2/statements/remove/field.rs b/core/src/sql/statements/remove/field.rs similarity index 100% rename from core/src/sql/v2/statements/remove/field.rs rename to core/src/sql/statements/remove/field.rs diff --git a/core/src/sql/v2/statements/remove/function.rs b/core/src/sql/statements/remove/function.rs similarity index 100% rename from core/src/sql/v2/statements/remove/function.rs rename to core/src/sql/statements/remove/function.rs diff --git a/core/src/sql/v2/statements/remove/index.rs b/core/src/sql/statements/remove/index.rs similarity index 100% rename from core/src/sql/v2/statements/remove/index.rs rename to core/src/sql/statements/remove/index.rs diff --git a/core/src/sql/v1/statements/remove/mod.rs b/core/src/sql/statements/remove/mod.rs similarity index 100% rename from core/src/sql/v1/statements/remove/mod.rs rename to core/src/sql/statements/remove/mod.rs diff --git a/core/src/sql/v2/statements/remove/model.rs b/core/src/sql/statements/remove/model.rs similarity index 100% rename from core/src/sql/v2/statements/remove/model.rs rename to core/src/sql/statements/remove/model.rs diff --git a/core/src/sql/v2/statements/remove/namespace.rs b/core/src/sql/statements/remove/namespace.rs similarity index 100% rename from core/src/sql/v2/statements/remove/namespace.rs rename to core/src/sql/statements/remove/namespace.rs diff --git a/core/src/sql/v2/statements/remove/param.rs b/core/src/sql/statements/remove/param.rs similarity index 100% rename from core/src/sql/v2/statements/remove/param.rs rename to core/src/sql/statements/remove/param.rs diff --git a/core/src/sql/v2/statements/remove/scope.rs b/core/src/sql/statements/remove/scope.rs similarity index 100% rename from core/src/sql/v2/statements/remove/scope.rs rename to core/src/sql/statements/remove/scope.rs diff --git a/core/src/sql/v2/statements/remove/table.rs b/core/src/sql/statements/remove/table.rs similarity index 100% rename from core/src/sql/v2/statements/remove/table.rs rename to core/src/sql/statements/remove/table.rs diff --git a/core/src/sql/v2/statements/remove/token.rs b/core/src/sql/statements/remove/token.rs similarity index 100% rename from core/src/sql/v2/statements/remove/token.rs rename to core/src/sql/statements/remove/token.rs diff --git a/core/src/sql/v2/statements/remove/user.rs b/core/src/sql/statements/remove/user.rs similarity index 100% rename from core/src/sql/v2/statements/remove/user.rs rename to core/src/sql/statements/remove/user.rs diff --git a/core/src/sql/v1/statements/select.rs b/core/src/sql/statements/select.rs similarity index 100% rename from core/src/sql/v1/statements/select.rs rename to core/src/sql/statements/select.rs diff --git a/core/src/sql/v1/statements/set.rs b/core/src/sql/statements/set.rs similarity index 100% rename from core/src/sql/v1/statements/set.rs rename to core/src/sql/statements/set.rs diff --git a/core/src/sql/v2/statements/show.rs b/core/src/sql/statements/show.rs similarity index 100% rename from core/src/sql/v2/statements/show.rs rename to core/src/sql/statements/show.rs diff --git a/core/src/sql/v1/statements/sleep.rs b/core/src/sql/statements/sleep.rs similarity index 100% rename from core/src/sql/v1/statements/sleep.rs rename to core/src/sql/statements/sleep.rs diff --git a/core/src/sql/v1/statements/throw.rs b/core/src/sql/statements/throw.rs similarity index 100% rename from core/src/sql/v1/statements/throw.rs rename to core/src/sql/statements/throw.rs diff --git a/core/src/sql/v1/statements/update.rs b/core/src/sql/statements/update.rs similarity index 100% rename from core/src/sql/v1/statements/update.rs rename to core/src/sql/statements/update.rs diff --git a/core/src/sql/v1/statements/use.rs b/core/src/sql/statements/use.rs similarity index 100% rename from core/src/sql/v1/statements/use.rs rename to core/src/sql/statements/use.rs diff --git a/core/src/sql/v1/strand.rs b/core/src/sql/strand.rs similarity index 100% rename from core/src/sql/v1/strand.rs rename to core/src/sql/strand.rs diff --git a/core/src/sql/v1/subquery.rs b/core/src/sql/subquery.rs similarity index 100% rename from core/src/sql/v1/subquery.rs rename to core/src/sql/subquery.rs diff --git a/core/src/sql/v1/table.rs b/core/src/sql/table.rs similarity index 100% rename from core/src/sql/v1/table.rs rename to core/src/sql/table.rs diff --git a/core/src/sql/v1/thing.rs b/core/src/sql/thing.rs similarity index 100% rename from core/src/sql/v1/thing.rs rename to core/src/sql/thing.rs diff --git a/core/src/sql/v1/timeout.rs b/core/src/sql/timeout.rs similarity index 100% rename from core/src/sql/v1/timeout.rs rename to core/src/sql/timeout.rs diff --git a/core/src/sql/v1/tokenizer.rs b/core/src/sql/tokenizer.rs similarity index 100% rename from core/src/sql/v1/tokenizer.rs rename to core/src/sql/tokenizer.rs diff --git a/core/src/sql/v1/uuid.rs b/core/src/sql/uuid.rs similarity index 100% rename from core/src/sql/v1/uuid.rs rename to core/src/sql/uuid.rs diff --git a/core/src/sql/v1/algorithm.rs b/core/src/sql/v1/algorithm.rs deleted file mode 100644 index 91e0bbd6..00000000 --- a/core/src/sql/v1/algorithm.rs +++ /dev/null @@ -1,48 +0,0 @@ -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Algorithm { - EdDSA, - Es256, - Es384, - Es512, - Hs256, - Hs384, - Hs512, - Ps256, - Ps384, - Ps512, - Rs256, - Rs384, - Rs512, -} - -impl Default for Algorithm { - fn default() -> Self { - Self::Hs512 - } -} - -impl fmt::Display for Algorithm { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Self::EdDSA => "EDDSA", - Self::Es256 => "ES256", - Self::Es384 => "ES384", - Self::Es512 => "ES512", - Self::Hs256 => "HS256", - Self::Hs384 => "HS384", - Self::Hs512 => "HS512", - Self::Ps256 => "PS256", - Self::Ps384 => "PS384", - Self::Ps512 => "PS512", - Self::Rs256 => "RS256", - Self::Rs384 => "RS384", - Self::Rs512 => "RS512", - }) - } -} diff --git a/core/src/sql/v1/array.rs b/core/src/sql/v1/array.rs deleted file mode 100644 index 51146dc3..00000000 --- a/core/src/sql/v1/array.rs +++ /dev/null @@ -1,482 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{ - fmt::{pretty_indent, Fmt, Pretty}, - Number, Operation, Value, -}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::collections::HashSet; -use std::fmt::{self, Display, Formatter, Write}; -use std::ops; -use std::ops::Deref; -use std::ops::DerefMut; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Array"; - -#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Array")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Array(pub Vec); - -impl From for Array { - fn from(v: Value) -> Self { - vec![v].into() - } -} - -impl From> for Array { - fn from(v: Vec) -> Self { - Self(v) - } -} - -impl From> for Array { - fn from(v: Vec) -> Self { - Self(v.into_iter().map(Value::from).collect()) - } -} - -impl From> for Array { - fn from(v: Vec) -> Self { - Self(v.into_iter().map(Value::from).collect()) - } -} - -impl From> for Array { - fn from(v: Vec<&str>) -> Self { - Self(v.into_iter().map(Value::from).collect()) - } -} - -impl From> for Array { - fn from(v: Vec) -> Self { - Self(v.into_iter().map(Value::from).collect()) - } -} - -impl From> for Array { - fn from(v: Vec) -> Self { - Self(v.into_iter().map(Value::from).collect()) - } -} - -impl From> for Array { - fn from(v: Vec) -> Self { - Self(v.into_iter().map(Value::from).collect()) - } -} - -impl From> for Array { - fn from(v: Vec) -> Self { - Self(v.into_iter().map(Value::from).collect()) - } -} - -impl From for Vec { - fn from(s: Array) -> Self { - s.0 - } -} - -impl FromIterator for Array { - fn from_iter>(iter: I) -> Self { - Array(iter.into_iter().collect()) - } -} - -impl Deref for Array { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Array { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl IntoIterator for Array { - type Item = Value; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Array { - // Create a new empty array - pub fn new() -> Self { - Self::default() - } - // Create a new array with capacity - pub fn with_capacity(len: usize) -> Self { - Self(Vec::with_capacity(len)) - } - // Get the length of the array - pub fn len(&self) -> usize { - self.0.len() - } - // Check if there array is empty - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl Array { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - let mut x = Self::with_capacity(self.len()); - for v in self.iter() { - match v.compute(ctx, opt, txn, doc).await { - Ok(v) => x.push(v), - Err(e) => return Err(e), - }; - } - Ok(Value::Array(x)) - } - - pub(crate) fn is_all_none_or_null(&self) -> bool { - self.0.iter().all(|v| v.is_none_or_null()) - } - - pub(crate) fn is_static(&self) -> bool { - self.iter().all(Value::is_static) - } -} - -impl Display for Array { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let mut f = Pretty::from(f); - f.write_char('[')?; - if !self.is_empty() { - let indent = pretty_indent(); - write!(f, "{}", Fmt::pretty_comma_separated(self.as_slice()))?; - drop(indent); - } - f.write_char(']') - } -} - -// ------------------------------ - -impl ops::Add for Array { - type Output = Self; - fn add(mut self, other: Value) -> Self { - self.0.push(other); - self - } -} - -impl ops::Add for Array { - type Output = Self; - fn add(mut self, mut other: Self) -> Self { - self.0.append(&mut other.0); - self - } -} - -// ------------------------------ - -impl ops::Sub for Array { - type Output = Self; - fn sub(mut self, other: Value) -> Self { - if let Some(p) = self.0.iter().position(|x| *x == other) { - self.0.remove(p); - } - self - } -} - -impl ops::Sub for Array { - type Output = Self; - fn sub(mut self, other: Self) -> Self { - for v in other.0 { - if let Some(p) = self.0.iter().position(|x| *x == v) { - self.0.remove(p); - } - } - self - } -} - -// ------------------------------ - -pub trait Abolish { - fn abolish(&mut self, f: F) - where - F: FnMut(usize) -> bool; -} - -impl Abolish for Vec { - fn abolish(&mut self, mut f: F) - where - F: FnMut(usize) -> bool, - { - let mut i = 0; - // FIXME: use drain_filter once stabilized (https://github.com/rust-lang/rust/issues/43244) - // to avoid negation of the predicate return value. - self.retain(|_| { - let retain = !f(i); - i += 1; - retain - }); - } -} - -// ------------------------------ - -pub(crate) trait Clump { - fn clump(self, clump_size: usize) -> T; -} - -impl Clump for Array { - fn clump(self, clump_size: usize) -> Array { - self.0 - .chunks(clump_size) - .map::(|chunk| chunk.to_vec().into()) - .collect::>() - .into() - } -} - -// ------------------------------ - -pub(crate) trait Combine { - fn combine(self, other: T) -> T; -} - -impl Combine for Array { - fn combine(self, other: Self) -> Array { - let mut out = Self::with_capacity(self.len().saturating_mul(other.len())); - for a in self.iter() { - for b in other.iter() { - out.push(vec![a.clone(), b.clone()].into()); - } - } - out - } -} - -// ------------------------------ - -pub(crate) trait Complement { - fn complement(self, other: T) -> T; -} - -impl Complement for Array { - fn complement(self, other: Self) -> Array { - let mut out = Array::new(); - for v in self.into_iter() { - if !other.contains(&v) { - out.push(v) - } - } - out - } -} - -// ------------------------------ - -pub(crate) trait Concat { - fn concat(self, other: T) -> T; -} - -impl Concat for Array { - fn concat(mut self, mut other: Array) -> Array { - self.append(&mut other); - self - } -} - -// ------------------------------ - -pub(crate) trait Difference { - fn difference(self, other: T) -> T; -} - -impl Difference for Array { - fn difference(self, mut other: Array) -> Array { - let mut out = Array::new(); - for v in self.into_iter() { - if let Some(pos) = other.iter().position(|w| v == *w) { - other.remove(pos); - } else { - out.push(v); - } - } - out.append(&mut other); - out - } -} - -// ------------------------------ - -pub(crate) trait Flatten { - fn flatten(self) -> T; -} - -impl Flatten for Array { - fn flatten(self) -> Array { - let mut out = Array::new(); - for v in self.into_iter() { - match v { - Value::Array(mut a) => out.append(&mut a), - _ => out.push(v), - } - } - out - } -} - -// ------------------------------ - -pub(crate) trait Intersect { - fn intersect(self, other: T) -> T; -} - -impl Intersect for Array { - fn intersect(self, mut other: Self) -> Self { - let mut out = Self::new(); - for v in self.0.into_iter() { - if let Some(pos) = other.iter().position(|w| v == *w) { - other.remove(pos); - out.push(v); - } - } - out - } -} - -// ------------------------------ - -// Documented with the assumption that it is just for arrays. -pub(crate) trait Matches { - /// Returns an array complimenting the original where each value is true or false - /// depending on whether it is == to the compared value. - /// - /// Admittedly, this is most often going to be used in `count(array::matches($arr, $val))` - /// to count the number of times an element appears in an array but it's nice to have - /// this in addition. - fn matches(self, compare_val: Value) -> T; -} - -impl Matches for Array { - fn matches(self, compare_val: Value) -> Array { - self.iter().map(|arr_val| (arr_val == &compare_val).into()).collect::>().into() - } -} - -// ------------------------------ - -// Documented with the assumption that it is just for arrays. -pub(crate) trait Transpose { - /// Stacks arrays on top of each other. This can serve as 2d array transposition. - /// - /// The input array can contain regular values which are treated as arrays with - /// a single element. - /// - /// It's best to think of the function as creating a layered structure of the arrays - /// rather than transposing them when the input is not a 2d array. See the examples - /// for what happense when the input arrays are not all the same size. - /// - /// Here's a diagram: - /// [0, 1, 2, 3], [4, 5, 6] - /// -> - /// [0 | 1 | 2 | 3] - /// [4 | 5 | 6 ] - /// ^ ^ ^ ^ - /// [0, 4] [1, 5] [2, 6] [3] - /// - /// # Examples - /// - /// ```ignore - /// fn array(sql: &str) -> Array { - /// unimplemented!(); - /// } - /// - /// // Example of `transpose` doing what it says on the tin. - /// assert_eq!(array("[[0, 1], [2, 3]]").transpose(), array("[[0, 2], [1, 3]]")); - /// // `transpose` can be thought of layering arrays on top of each other so when - /// // one array runs out, it stops appearing in the output. - /// assert_eq!(array("[[0, 1], [2]]").transpose(), array("[[0, 2], [1]]")); - /// assert_eq!(array("[0, 1, 2]").transpose(), array("[[0, 1, 2]]")); - /// ``` - fn transpose(self) -> T; -} - -impl Transpose for Array { - fn transpose(self) -> Array { - if self.is_empty() { - return self; - } - // I'm sure there's a way more efficient way to do this that I don't know about. - // The new array will be at *least* this large so we can start there; - let mut transposed_vec = Vec::::with_capacity(self.len()); - let mut iters = self - .iter() - .map(|v| { - if let Value::Array(arr) = v { - Box::new(arr.iter().cloned()) as Box> - } else { - Box::new(std::iter::once(v).cloned()) - as Box> - } - }) - .collect::>(); - // We know there is at least one element in the array therefore iters is not empty. - // This is safe. - let longest_length = iters.iter().map(|i| i.len()).max().unwrap(); - for _ in 0..longest_length { - transposed_vec - .push(iters.iter_mut().filter_map(|i| i.next()).collect::>().into()); - } - transposed_vec.into() - } -} - -// ------------------------------ - -pub(crate) trait Union { - fn union(self, other: T) -> T; -} - -impl Union for Array { - fn union(mut self, mut other: Self) -> Array { - self.append(&mut other); - self.uniq() - } -} - -// ------------------------------ - -pub(crate) trait Uniq { - fn uniq(self) -> T; -} - -impl Uniq for Array { - fn uniq(mut self) -> Array { - let mut set: HashSet<&Value> = HashSet::new(); - let mut to_remove: Vec = Vec::new(); - for (i, item) in self.iter().enumerate() { - if !set.insert(item) { - to_remove.push(i); - } - } - for i in to_remove.iter().rev() { - self.remove(*i); - } - self - } -} diff --git a/core/src/sql/v1/change_feed_include.rs b/core/src/sql/v1/change_feed_include.rs deleted file mode 100644 index 79b100de..00000000 --- a/core/src/sql/v1/change_feed_include.rs +++ /dev/null @@ -1,25 +0,0 @@ -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -/// ChangeFeedInclude statements are an appendix -pub enum ChangeFeedInclude { - Original, -} - -impl Default for crate::sql::change_feed_include::ChangeFeedInclude { - fn default() -> Self { - Self::Original - } -} - -impl fmt::Display for crate::sql::change_feed_include::ChangeFeedInclude { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Self::Original => "Original", - }) - } -} diff --git a/core/src/sql/v1/changefeed.rs b/core/src/sql/v1/changefeed.rs deleted file mode 100644 index a34b0f65..00000000 --- a/core/src/sql/v1/changefeed.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::sql::duration::Duration; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::str; -use std::time; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 2)] -pub struct ChangeFeed { - pub expiry: time::Duration, - #[revision(start = 2)] - pub store_original: bool, -} - -impl Display for ChangeFeed { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "CHANGEFEED {}", Duration(self.expiry))?; - if self.store_original { - write!(f, " INCLUDE ORIGINAL")?; - }; - Ok(()) - } -} - -impl Default for ChangeFeed { - fn default() -> Self { - Self { - expiry: time::Duration::from_secs(0), - store_original: false, - } - } -} diff --git a/core/src/sql/v1/escape.rs b/core/src/sql/v1/escape.rs deleted file mode 100644 index 59f17afa..00000000 --- a/core/src/sql/v1/escape.rs +++ /dev/null @@ -1,167 +0,0 @@ -use std::borrow::Cow; - -const SINGLE: char = '\''; - -const BRACKETL: char = '⟨'; -const BRACKETR: char = '⟩'; -const BRACKET_ESC: &str = r"\⟩"; - -const DOUBLE: char = '"'; -const DOUBLE_ESC: &str = r#"\""#; - -const BACKTICK: char = '`'; -const BACKTICK_ESC: &str = r"\`"; - -/// Quotes a string with single or double quotes: -/// - cat -> 'cat' -/// - cat's -> "cat's" -/// - cat's "toy" -> "cat's \"toy\"" -/// -/// Escapes / as // -#[inline] -pub fn quote_str(s: &str) -> String { - // Rough approximation of capacity, which may be exceeded - // if things must be escaped. - let mut ret = String::with_capacity(2 + s.len()); - - fn escape_into(into: &mut String, s: &str, escape_double: bool) { - // Based on internals of str::replace - let mut last_end = 0; - for (start, part) in s.match_indices(|c| c == '\\' || (c == DOUBLE && escape_double)) { - into.push_str(&s[last_end..start]); - into.push_str(if part == "\\" { - "\\\\" - } else { - DOUBLE_ESC - }); - last_end = start + part.len(); - } - into.push_str(&s[last_end..s.len()]); - } - - let quote = if s.contains(SINGLE) { - DOUBLE - } else { - SINGLE - }; - - ret.push(quote); - escape_into(&mut ret, s, quote == DOUBLE); - ret.push(quote); - ret -} - -#[inline] -pub fn quote_plain_str(s: &str) -> String { - #[cfg(not(feature = "experimental-parser"))] - { - if crate::syn::thing(s).is_ok() { - let mut ret = quote_str(s); - ret.insert(0, 's'); - return ret; - } - - let mut ret = quote_str(s); - // HACK: We need to prefix strands which look like records, uuids, or datetimes with an `s` - // otherwise the strands will parsed as a different type when parsed again. - // This is not required for the new parser. - // Because this only required for the old parse we just reference the partial parsers - // directly to avoid having to create a common interface between the old and new parser. - if crate::syn::v1::literal::uuid(&ret).is_ok() - || crate::syn::v1::literal::datetime(&ret).is_ok() - || crate::syn::thing(&ret).is_ok() - { - ret.insert(0, 's'); - } - ret - } - - #[cfg(feature = "experimental-parser")] - quote_str(s) -} - -#[inline] -/// Escapes a key if necessary -pub fn escape_key(s: &str) -> Cow<'_, str> { - escape_normal(s, DOUBLE, DOUBLE, DOUBLE_ESC) -} - -#[inline] -/// Escapes an id if necessary -pub fn escape_rid(s: &str) -> Cow<'_, str> { - #[cfg(feature = "experimental-parser")] - if let Some(x) = escape_reserved_keyword(s) { - return Cow::Owned(x); - } - escape_numeric(s, BRACKETL, BRACKETR, BRACKET_ESC) -} - -#[inline] -/// Escapes an ident if necessary -pub fn escape_ident(s: &str) -> Cow<'_, str> { - #[cfg(feature = "experimental-parser")] - if let Some(x) = escape_reserved_keyword(s) { - return Cow::Owned(x); - } - escape_numeric(s, BACKTICK, BACKTICK, BACKTICK_ESC) -} - -#[inline] -pub fn escape_normal<'a>(s: &'a str, l: char, r: char, e: &str) -> Cow<'a, str> { - // Loop over each character - for x in s.bytes() { - // Check if character is allowed - if !(x.is_ascii_alphanumeric() || x == b'_') { - return Cow::Owned(format!("{l}{}{r}", s.replace(r, e))); - } - } - // Output the value - Cow::Borrowed(s) -} - -#[cfg(not(feature = "experimental-parser"))] -#[inline] -pub fn escape_numeric<'a>(s: &'a str, l: char, r: char, e: &str) -> Cow<'a, str> { - // Presume this is numeric - let mut numeric = true; - // Loop over each character - for x in s.bytes() { - // Check if character is allowed - if !(x.is_ascii_alphanumeric() || x == b'_') { - return Cow::Owned(format!("{l}{}{r}", s.replace(r, e))); - } - // Check if character is non-numeric - if !x.is_ascii_digit() { - numeric = false; - } - } - // Output the id value - match numeric { - // This is numeric so escape it - true => Cow::Owned(format!("{l}{}{r}", s.replace(r, e))), - // No need to escape the value - _ => Cow::Borrowed(s), - } -} - -#[cfg(feature = "experimental-parser")] -pub fn escape_reserved_keyword(s: &str) -> Option { - crate::syn::v2::could_be_reserved_keyword(s).then(|| format!("`{}`", s)) -} - -#[cfg(feature = "experimental-parser")] -#[inline] -pub fn escape_numeric<'a>(s: &'a str, l: char, r: char, e: &str) -> Cow<'a, str> { - // Loop over each character - for (idx, x) in s.bytes().enumerate() { - // the first character is not allowed to be a digit. - if idx == 0 && x.is_ascii_digit() { - return Cow::Owned(format!("{l}{}{r}", s.replace(r, e))); - } - // Check if character is allowed - if !(x.is_ascii_alphanumeric() || x == b'_') { - return Cow::Owned(format!("{l}{}{r}", s.replace(r, e))); - } - } - Cow::Borrowed(s) -} diff --git a/core/src/sql/v1/expression.rs b/core/src/sql/v1/expression.rs deleted file mode 100644 index e4842c96..00000000 --- a/core/src/sql/v1/expression.rs +++ /dev/null @@ -1,207 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::fnc; -use crate::sql::operator::Operator; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::str; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Expression"; - -/// Binary expressions. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Expression")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Expression { - Unary { - o: Operator, - v: Value, - }, - Binary { - l: Value, - o: Operator, - r: Value, - }, -} - -impl Default for Expression { - fn default() -> Expression { - Expression::Binary { - l: Value::Null, - o: Operator::default(), - r: Value::Null, - } - } -} - -impl Expression { - /// Create a new binary expression - #[doc(hidden)] - pub fn new(l: Value, o: Operator, r: Value) -> Self { - Self::Binary { - l, - o, - r, - } - } -} - -impl Expression { - pub(crate) fn writeable(&self) -> bool { - match self { - Self::Unary { - v, - .. - } => v.writeable(), - Self::Binary { - l, - r, - .. - } => l.writeable() || r.writeable(), - } - } - - pub(crate) fn is_static(&self) -> bool { - match self { - Self::Unary { - v, - .. - } => v.is_static(), - Self::Binary { - l, - r, - .. - } => l.is_static() && r.is_static(), - } - } - - /// Returns the operator - pub(crate) fn operator(&self) -> &Operator { - match self { - Expression::Unary { - o, - .. - } => o, - Expression::Binary { - o, - .. - } => o, - } - } - - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - let (l, o, r) = match self { - Self::Unary { - o, - v, - } => { - let operand = v.compute(ctx, opt, txn, doc).await?; - return match o { - Operator::Neg => fnc::operate::neg(operand), - // TODO: Check if it is a number? - Operator::Add => Ok(operand), - Operator::Not => fnc::operate::not(operand), - op => unreachable!("{op:?} is not a unary op"), - }; - } - Self::Binary { - l, - o, - r, - } => (l, o, r), - }; - - let l = l.compute(ctx, opt, txn, doc).await?; - match o { - Operator::Or => { - if l.is_truthy() { - return Ok(l); - } - } - Operator::And => { - if !l.is_truthy() { - return Ok(l); - } - } - Operator::Tco => { - if l.is_truthy() { - return Ok(l); - } - } - Operator::Nco => { - if l.is_some() { - return Ok(l); - } - } - _ => {} // Continue - } - let r = r.compute(ctx, opt, txn, doc).await?; - match o { - Operator::Or => fnc::operate::or(l, r), - Operator::And => fnc::operate::and(l, r), - Operator::Tco => fnc::operate::tco(l, r), - Operator::Nco => fnc::operate::nco(l, r), - Operator::Add => fnc::operate::add(l, r), - Operator::Sub => fnc::operate::sub(l, r), - Operator::Mul => fnc::operate::mul(l, r), - Operator::Div => fnc::operate::div(l, r), - Operator::Pow => fnc::operate::pow(l, r), - Operator::Equal => fnc::operate::equal(&l, &r), - Operator::Exact => fnc::operate::exact(&l, &r), - Operator::NotEqual => fnc::operate::not_equal(&l, &r), - Operator::AllEqual => fnc::operate::all_equal(&l, &r), - Operator::AnyEqual => fnc::operate::any_equal(&l, &r), - Operator::Like => fnc::operate::like(&l, &r), - Operator::NotLike => fnc::operate::not_like(&l, &r), - Operator::AllLike => fnc::operate::all_like(&l, &r), - Operator::AnyLike => fnc::operate::any_like(&l, &r), - Operator::LessThan => fnc::operate::less_than(&l, &r), - Operator::LessThanOrEqual => fnc::operate::less_than_or_equal(&l, &r), - Operator::MoreThan => fnc::operate::more_than(&l, &r), - Operator::MoreThanOrEqual => fnc::operate::more_than_or_equal(&l, &r), - Operator::Contain => fnc::operate::contain(&l, &r), - Operator::NotContain => fnc::operate::not_contain(&l, &r), - Operator::ContainAll => fnc::operate::contain_all(&l, &r), - Operator::ContainAny => fnc::operate::contain_any(&l, &r), - Operator::ContainNone => fnc::operate::contain_none(&l, &r), - Operator::Inside => fnc::operate::inside(&l, &r), - Operator::NotInside => fnc::operate::not_inside(&l, &r), - Operator::AllInside => fnc::operate::inside_all(&l, &r), - Operator::AnyInside => fnc::operate::inside_any(&l, &r), - Operator::NoneInside => fnc::operate::inside_none(&l, &r), - Operator::Outside => fnc::operate::outside(&l, &r), - Operator::Intersects => fnc::operate::intersects(&l, &r), - Operator::Matches(_) => fnc::operate::matches(ctx, txn, doc, self).await, - Operator::Knn(_, _) => fnc::operate::knn(ctx, opt, txn, doc, self).await, - _ => unreachable!(), - } - } -} - -impl fmt::Display for Expression { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Unary { - o, - v, - } => write!(f, "{o}{v}"), - Self::Binary { - l, - o, - r, - } => write!(f, "{l} {o} {r}"), - } - } -} diff --git a/core/src/sql/v1/fmt.rs b/core/src/sql/v1/fmt.rs deleted file mode 100644 index c70c49e2..00000000 --- a/core/src/sql/v1/fmt.rs +++ /dev/null @@ -1,313 +0,0 @@ -use std::cell::Cell; -use std::fmt::{self, Display, Formatter, Write}; -use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; - -/// Implements fmt::Display by calling formatter on contents. -pub(crate) struct Fmt { - contents: Cell>, - formatter: F, -} - -impl fmt::Result> Fmt { - pub(crate) fn new(t: T, formatter: F) -> Self { - Self { - contents: Cell::new(Some(t)), - formatter, - } - } -} - -impl fmt::Result> Display for Fmt { - /// fmt is single-use only. - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let contents = self.contents.replace(None).expect("only call Fmt::fmt once"); - (self.formatter)(contents, f) - } -} - -impl, T: Display> Fmt fmt::Result> { - /// Formats values with a comma and a space separating them. - pub(crate) fn comma_separated(into_iter: I) -> Self { - Self::new(into_iter, fmt_comma_separated) - } - - /// Formats values with a verbar and a space separating them. - pub(crate) fn verbar_separated(into_iter: I) -> Self { - Self::new(into_iter, fmt_verbar_separated) - } - - /// Formats values with a comma and a space separating them or, if pretty printing is in - /// effect, a comma, a newline, and indentation. - pub(crate) fn pretty_comma_separated(into_iter: I) -> Self { - Self::new(into_iter, fmt_pretty_comma_separated) - } - - /// Formats values with a new line separating them. - pub(crate) fn one_line_separated(into_iter: I) -> Self { - Self::new(into_iter, fmt_one_line_separated) - } - - /// Formats values with a new line separating them. - pub(crate) fn two_line_separated(into_iter: I) -> Self { - Self::new(into_iter, fmt_two_line_separated) - } -} - -fn fmt_comma_separated>( - into_iter: I, - f: &mut Formatter, -) -> fmt::Result { - for (i, v) in into_iter.into_iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - Display::fmt(&v, f)?; - } - Ok(()) -} - -fn fmt_verbar_separated>( - into_iter: I, - f: &mut Formatter, -) -> fmt::Result { - for (i, v) in into_iter.into_iter().enumerate() { - if i > 0 { - f.write_str(" | ")?; - } - Display::fmt(&v, f)?; - } - Ok(()) -} - -fn fmt_pretty_comma_separated>( - into_iter: I, - f: &mut Formatter, -) -> fmt::Result { - for (i, v) in into_iter.into_iter().enumerate() { - if i > 0 { - if is_pretty() { - f.write_char(',')?; - pretty_sequence_item(); - } else { - f.write_str(", ")?; - } - } - Display::fmt(&v, f)?; - } - Ok(()) -} - -fn fmt_one_line_separated>( - into_iter: I, - f: &mut Formatter, -) -> fmt::Result { - for (i, v) in into_iter.into_iter().enumerate() { - if i > 0 { - if is_pretty() { - pretty_sequence_item(); - } else { - f.write_char('\n')?; - } - } - Display::fmt(&v, f)?; - } - Ok(()) -} - -fn fmt_two_line_separated>( - into_iter: I, - f: &mut Formatter, -) -> fmt::Result { - for (i, v) in into_iter.into_iter().enumerate() { - if i > 0 { - if is_pretty() { - f.write_char('\n')?; - pretty_sequence_item(); - } else { - f.write_char('\n')?; - f.write_char('\n')?; - } - } - Display::fmt(&v, f)?; - } - Ok(()) -} - -/// Creates a formatting function that joins iterators with an arbitrary separator. -pub fn fmt_separated_by>( - separator: impl Display, -) -> impl Fn(I, &mut Formatter) -> fmt::Result { - move |into_iter: I, f: &mut Formatter| { - for (i, v) in into_iter.into_iter().enumerate() { - if i > 0 { - Display::fmt(&separator, f)?; - } - Display::fmt(&v, f)?; - } - Ok(()) - } -} - -thread_local! { - // Avoid `RefCell`/`UnsafeCell` by using atomic types. Access is synchronized due to - // `thread_local!` so all accesses can use `Ordering::Relaxed`. - - /// Whether pretty-printing. - static PRETTY: AtomicBool = const { AtomicBool::new(false) }; - /// The current level of indentation, in units of tabs. - static INDENT: AtomicU32 = const { AtomicU32::new(0) }; - /// Whether the next formatting action should be preceded by a newline and indentation. - static NEW_LINE: AtomicBool = const{ AtomicBool::new(false) }; -} - -/// An adapter that, if enabled, adds pretty print formatting. -pub(crate) struct Pretty { - inner: W, - /// This is the active pretty printer, responsible for injecting formatting. - active: bool, -} - -impl Pretty { - #[allow(unused)] - pub fn new(inner: W) -> Self { - Self::conditional(inner, true) - } - - pub fn conditional(inner: W, enable: bool) -> Self { - let pretty_started_here = enable - && PRETTY.with(|pretty| { - // Evaluates to true if PRETTY was false and is now true. - pretty.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed).is_ok() - }); - if pretty_started_here { - // Clean slate. - NEW_LINE.with(|new_line| new_line.store(false, Ordering::Relaxed)); - INDENT.with(|indent| indent.store(0, Ordering::Relaxed)); - } - Self { - inner, - // Don't want multiple active pretty printers, although they wouldn't necessarily misbehave. - active: pretty_started_here, - } - } -} - -impl<'a, 'b> From<&'a mut Formatter<'b>> for Pretty<&'a mut Formatter<'b>> { - fn from(f: &'a mut Formatter<'b>) -> Self { - Self::conditional(f, f.alternate()) - } -} - -impl Drop for Pretty { - fn drop(&mut self) { - if self.active { - PRETTY.with(|pretty| { - debug_assert!(pretty.load(Ordering::Relaxed), "pretty status changed unexpectedly"); - pretty.store(false, Ordering::Relaxed); - }); - } - } -} - -/// Returns whether pretty printing is in effect. -pub(crate) fn is_pretty() -> bool { - PRETTY.with(|pretty| pretty.load(Ordering::Relaxed)) -} - -/// If pretty printing is in effect, increments the indentation level (until the return value -/// is dropped). -#[must_use = "hold for the span of the indent, then drop"] -pub(crate) fn pretty_indent() -> PrettyGuard { - PrettyGuard::new(1) -} - -/// Marks the end of an item in the sequence, after which indentation will follow if pretty printing -/// is in effect. -pub(crate) fn pretty_sequence_item() { - // List items need a new line, but no additional indentation. - NEW_LINE.with(|new_line| new_line.store(true, Ordering::Relaxed)); -} - -/// When dropped, applies the opposite increment to the current indentation level. -pub(crate) struct PrettyGuard { - increment: i8, -} - -impl PrettyGuard { - fn new(increment: i8) -> Self { - Self::raw(increment); - PrettyGuard { - increment, - } - } - - fn raw(increment: i8) { - INDENT.with(|indent| { - // Equivalent to `indent += increment` if signed numbers could be added to unsigned - // numbers in stable, atomic Rust. - if increment >= 0 { - indent.fetch_add(increment as u32, Ordering::Relaxed); - } else { - indent.fetch_sub(increment.unsigned_abs() as u32, Ordering::Relaxed); - } - }); - NEW_LINE.with(|new_line| new_line.store(true, Ordering::Relaxed)); - } -} - -impl Drop for PrettyGuard { - fn drop(&mut self) { - Self::raw(-self.increment) - } -} - -impl std::fmt::Write for Pretty { - fn write_str(&mut self, s: &str) -> std::fmt::Result { - if self.active && NEW_LINE.with(|new_line| new_line.swap(false, Ordering::Relaxed)) { - // Newline. - self.inner.write_char('\n')?; - for _ in 0..INDENT.with(|indent| indent.load(Ordering::Relaxed)) { - // One level of indentation. - self.inner.write_char('\t')?; - } - } - // What we were asked to write. - self.inner.write_str(s) - } -} - -#[cfg(test)] -mod tests { - use crate::syn::{parse, value}; - - #[test] - fn pretty_query() { - let query = parse("SELECT * FROM {foo: [1, 2, 3]};").unwrap(); - assert_eq!(format!("{}", query), "SELECT * FROM { foo: [1, 2, 3] };"); - assert_eq!( - format!("{:#}", query), - "SELECT * FROM {\n\tfoo: [\n\t\t1,\n\t\t2,\n\t\t3\n\t]\n};" - ); - } - - #[test] - fn pretty_define_query() { - let query = parse("DEFINE TABLE test SCHEMAFULL PERMISSIONS FOR create, update, delete NONE FOR select WHERE public = true;").unwrap(); - assert_eq!(format!("{}", query), "DEFINE TABLE test SCHEMAFULL PERMISSIONS FOR select WHERE public = true, FOR create, update, delete NONE;"); - assert_eq!(format!("{:#}", query), "DEFINE TABLE test SCHEMAFULL\n\tPERMISSIONS\n\t\tFOR select\n\t\t\tWHERE public = true\n\t\tFOR create, update, delete NONE\n;"); - } - - #[test] - fn pretty_value() { - let value = value("{foo: [1, 2, 3]}").unwrap(); - assert_eq!(format!("{}", value), "{ foo: [1, 2, 3] }"); - assert_eq!(format!("{:#}", value), "{\n\tfoo: [\n\t\t1,\n\t\t2,\n\t\t3\n\t]\n}"); - } - - #[test] - fn pretty_array() { - let array = value("[1, 2, 3]").unwrap(); - assert_eq!(format!("{}", array), "[1, 2, 3]"); - assert_eq!(format!("{:#}", array), "[\n\t1,\n\t2,\n\t3\n]"); - } -} diff --git a/core/src/sql/v1/mod.rs b/core/src/sql/v1/mod.rs deleted file mode 100644 index 3bf987f2..00000000 --- a/core/src/sql/v1/mod.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! The full type definitions for the SurrealQL query language - -pub(crate) mod algorithm; -#[cfg(feature = "arbitrary")] -pub(crate) mod arbitrary; -pub(crate) mod array; -pub(crate) mod base; -pub(crate) mod block; -pub(crate) mod bytes; -pub(crate) mod cast; -pub(crate) mod change_feed_include; -pub(crate) mod changefeed; -pub(crate) mod cond; -pub(crate) mod constant; -pub(crate) mod data; -pub(crate) mod datetime; -pub(crate) mod dir; -pub(crate) mod duration; -pub(crate) mod edges; -pub(crate) mod escape; -pub(crate) mod explain; -pub(crate) mod expression; -pub(crate) mod fetch; -pub(crate) mod field; -pub(crate) mod filter; -pub(crate) mod fmt; -pub(crate) mod function; -pub(crate) mod future; -pub(crate) mod geometry; -pub(crate) mod graph; -pub(crate) mod group; -pub(crate) mod id; -pub(crate) mod ident; -pub(crate) mod idiom; -pub(crate) mod kind; -pub(crate) mod language; -pub(crate) mod limit; -pub(crate) mod mock; -pub(crate) mod model; -pub(crate) mod number; -pub(crate) mod object; -pub(crate) mod operation; -pub(crate) mod operator; -pub(crate) mod order; -pub(crate) mod output; -pub(crate) mod param; -pub(crate) mod part; -pub(crate) mod paths; -pub(crate) mod permission; -pub(crate) mod query; -pub(crate) mod range; -pub(crate) mod regex; -pub(crate) mod scoring; -pub(crate) mod script; -pub(crate) mod split; -pub(crate) mod start; -pub(crate) mod statement; -pub(crate) mod strand; -pub(crate) mod subquery; -pub(crate) mod table; -pub(crate) mod thing; -pub(crate) mod timeout; -pub(crate) mod tokenizer; -pub(crate) mod uuid; -pub(crate) mod value; -pub(crate) mod version; -pub(crate) mod view; -pub(crate) mod with; - -#[doc(hidden)] -pub mod index; - -pub mod serde; -pub mod statements; - -pub use self::algorithm::Algorithm; -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::changefeed::ChangeFeed; -pub use self::cond::Cond; -pub use self::constant::Constant; -pub use self::data::Data; -pub use self::datetime::Datetime; -pub use self::dir::Dir; -pub use self::duration::Duration; -pub use self::edges::Edges; -pub use self::explain::Explain; -pub use self::expression::Expression; -pub use self::fetch::Fetch; -pub use self::fetch::Fetchs; -pub use self::field::Field; -pub use self::field::Fields; -pub use self::function::Function; -pub use self::future::Future; -pub use self::geometry::Geometry; -pub use self::graph::Graph; -pub use self::group::Group; -pub use self::group::Groups; -pub use self::id::Id; -pub use self::ident::Ident; -pub use self::idiom::Idiom; -pub use self::idiom::Idioms; -pub use self::index::Index; -pub use self::kind::Kind; -pub use self::limit::Limit; -pub use self::mock::Mock; -pub use self::model::Model; -pub use self::number::Number; -pub use self::object::Object; -pub use self::operation::Operation; -pub use self::operator::Operator; -pub use self::order::Order; -pub use self::order::Orders; -pub use self::output::Output; -pub use self::param::Param; -pub use self::part::Part; -pub use self::permission::Permission; -pub use self::permission::Permissions; -pub use self::query::Query; -pub use self::range::Range; -pub use self::regex::Regex; -pub use self::scoring::Scoring; -pub use self::script::Script; -pub use self::split::Split; -pub use self::split::Splits; -pub use self::start::Start; -pub use self::statement::Statement; -pub use self::statement::Statements; -pub use self::strand::Strand; -pub use self::subquery::Subquery; -pub use self::table::Table; -pub use self::table::Tables; -pub use self::thing::Thing; -pub use self::timeout::Timeout; -pub use self::tokenizer::Tokenizer; -pub use self::uuid::Uuid; -pub use self::value::serde::to_value; -#[doc(hidden)] -pub use self::value::serde::{from_value, FromValueError}; -pub use self::value::Value; -pub use self::value::Values; -pub use self::version::Version; -pub use self::view::View; -pub use self::with::With; - -// module reexporting parsing function to prevent a breaking change. -#[doc(hidden)] -mod parser { - pub use crate::syn::*; -} - -pub use self::parser::{idiom, json, parse, subquery, thing, value}; - -#[deprecated(since = "1.2.0")] -pub use self::parser::error::ParseError; diff --git a/core/src/sql/v1/operator.rs b/core/src/sql/v1/operator.rs deleted file mode 100644 index 6c4cc61f..00000000 --- a/core/src/sql/v1/operator.rs +++ /dev/null @@ -1,146 +0,0 @@ -use crate::idx::ft::MatchRef; -use crate::sql::index::Distance; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fmt::Write; - -/// Binary operators. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Operator { - // - Neg, // - - Not, // ! - // - Or, // || - And, // && - Tco, // ?: Ternary conditional operator - Nco, // ?? Null coalescing operator - // - Add, // + - Sub, // - - Mul, // * - Div, // / - Pow, // ** - Inc, // += - Dec, // -= - Ext, // +?= - // - Equal, // = - Exact, // == - NotEqual, // != - AllEqual, // *= - AnyEqual, // ?= - // - Like, // ~ - NotLike, // !~ - AllLike, // *~ - AnyLike, // ?~ - Matches(Option), // @{ref}@ - // - LessThan, // < - LessThanOrEqual, // <= - MoreThan, // > - MoreThanOrEqual, // >= - // - Contain, // ∋ - NotContain, // ∌ - ContainAll, // ⊇ - ContainAny, // ⊃ - ContainNone, // ⊅ - Inside, // ∈ - NotInside, // ∉ - AllInside, // ⊆ - AnyInside, // ⊂ - NoneInside, // ⊄ - // - Outside, - Intersects, - // - Knn(u32, Option), // <{k}[,{dist}]> -} - -impl Default for Operator { - fn default() -> Self { - Self::Equal - } -} - -impl Operator { - #[inline] - pub fn precedence(&self) -> u8 { - match self { - Self::Or => 1, - Self::And => 2, - Self::Tco => 3, - Self::Nco => 4, - Self::Sub => 6, - Self::Add => 7, - Self::Mul => 8, - Self::Div => 9, - _ => 5, - } - } -} - -impl fmt::Display for Operator { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Neg => f.write_str("-"), - Self::Not => f.write_str("!"), - Self::Or => f.write_str("OR"), - Self::And => f.write_str("AND"), - Self::Tco => f.write_str("?:"), - Self::Nco => f.write_str("??"), - Self::Add => f.write_str("+"), - Self::Sub => f.write_char('-'), - Self::Mul => f.write_char('*'), - Self::Div => f.write_char('/'), - Self::Pow => f.write_str("**"), - Self::Inc => f.write_str("+="), - Self::Dec => f.write_str("-="), - Self::Ext => f.write_str("+?="), - Self::Equal => f.write_char('='), - Self::Exact => f.write_str("=="), - Self::NotEqual => f.write_str("!="), - Self::AllEqual => f.write_str("*="), - Self::AnyEqual => f.write_str("?="), - Self::Like => f.write_char('~'), - Self::NotLike => f.write_str("!~"), - Self::AllLike => f.write_str("*~"), - Self::AnyLike => f.write_str("?~"), - Self::LessThan => f.write_char('<'), - Self::LessThanOrEqual => f.write_str("<="), - Self::MoreThan => f.write_char('>'), - Self::MoreThanOrEqual => f.write_str(">="), - Self::Contain => f.write_str("CONTAINS"), - Self::NotContain => f.write_str("CONTAINSNOT"), - Self::ContainAll => f.write_str("CONTAINSALL"), - Self::ContainAny => f.write_str("CONTAINSANY"), - Self::ContainNone => f.write_str("CONTAINSNONE"), - Self::Inside => f.write_str("INSIDE"), - Self::NotInside => f.write_str("NOTINSIDE"), - Self::AllInside => f.write_str("ALLINSIDE"), - Self::AnyInside => f.write_str("ANYINSIDE"), - Self::NoneInside => f.write_str("NONEINSIDE"), - Self::Outside => f.write_str("OUTSIDE"), - Self::Intersects => f.write_str("INTERSECTS"), - Self::Matches(reference) => { - if let Some(r) = reference { - write!(f, "@{r}@") - } else { - f.write_str("@@") - } - } - Self::Knn(k, dist) => { - if let Some(d) = dist { - write!(f, "<{k},{d}>") - } else { - write!(f, "<{k}>") - } - } - } - } -} diff --git a/core/src/sql/v1/regex.rs b/core/src/sql/v1/regex.rs deleted file mode 100644 index efbd175c..00000000 --- a/core/src/sql/v1/regex.rs +++ /dev/null @@ -1,150 +0,0 @@ -use once_cell::sync::Lazy; -use quick_cache::sync::Cache; -use quick_cache::GuardResult; -use revision::revisioned; -use serde::{ - de::{self, Visitor}, - Deserialize, Deserializer, Serialize, Serializer, -}; -use std::cmp::Ordering; -use std::fmt::Debug; -use std::fmt::{self, Display, Formatter}; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; -use std::{env, str}; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Regex"; - -#[derive(Clone)] -#[revisioned(revision = 1)] -pub struct Regex(pub regex::Regex); - -impl Regex { - // Deref would expose `regex::Regex::as_str` which wouldn't have the '/' delimiters. - pub fn regex(&self) -> ®ex::Regex { - &self.0 - } -} - -fn regex_new(str: &str) -> Result { - static REGEX_CACHE: Lazy> = Lazy::new(|| { - let cache_size: usize = env::var("SURREAL_REGEX_CACHE_SIZE") - .map_or(1000, |v| v.parse().unwrap_or(1000)) - .max(10); // The minimum cache size is 10 - Cache::new(cache_size) - }); - match REGEX_CACHE.get_value_or_guard(str, None) { - GuardResult::Value(v) => Ok(v), - GuardResult::Guard(g) => { - let re = regex::Regex::new(str)?; - g.insert(re.clone()).ok(); - Ok(re) - } - GuardResult::Timeout => { - warn!("Regex cache timeout"); - regex::Regex::new(str) - } - } -} - -impl FromStr for Regex { - type Err = ::Err; - - fn from_str(s: &str) -> Result { - if s.contains('\0') { - Err(regex::Error::Syntax("regex contained NUL byte".to_owned())) - } else { - regex_new(&s.replace("\\/", "/")).map(Self) - } - } -} - -impl PartialEq for Regex { - fn eq(&self, other: &Self) -> bool { - self.0.as_str().eq(other.0.as_str()) - } -} - -impl Eq for Regex {} - -impl Ord for Regex { - fn cmp(&self, other: &Self) -> Ordering { - self.0.as_str().cmp(other.0.as_str()) - } -} - -impl PartialOrd for Regex { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Hash for Regex { - fn hash(&self, state: &mut H) { - self.0.as_str().hash(state); - } -} - -impl Debug for Regex { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - -impl Display for Regex { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "/{}/", &self.0) - } -} - -impl Serialize for Regex { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_newtype_struct(TOKEN, self.0.as_str()) - } -} - -impl<'de> Deserialize<'de> for Regex { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct RegexNewtypeVisitor; - - impl<'de> Visitor<'de> for RegexNewtypeVisitor { - type Value = Regex; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a regex newtype") - } - - fn visit_newtype_struct(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct RegexVisitor; - - impl<'de> Visitor<'de> for RegexVisitor { - type Value = Regex; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a regex str") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - Regex::from_str(value).map_err(|_| de::Error::custom("invalid regex")) - } - } - - deserializer.deserialize_str(RegexVisitor) - } - } - - deserializer.deserialize_newtype_struct(TOKEN, RegexNewtypeVisitor) - } -} diff --git a/core/src/sql/v1/serde.rs b/core/src/sql/v1/serde.rs deleted file mode 100644 index 0c03b407..00000000 --- a/core/src/sql/v1/serde.rs +++ /dev/null @@ -1,28 +0,0 @@ -use bincode::Options; -use bincode::Result; -use serde::{Deserialize, Serialize}; - -pub fn serialize(value: &T) -> Result> -where - T: Serialize + ?Sized, -{ - bincode::options() - .with_no_limit() - .with_little_endian() - .with_varint_encoding() - .reject_trailing_bytes() - .serialize(value) -} - -pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result -where - T: Deserialize<'a>, -{ - bincode::options() - .with_no_limit() - .with_little_endian() - .with_varint_encoding() - // Ignore extra fields so we can pull out the ID only from responses that fail to deserialise - .allow_trailing_bytes() - .deserialize(bytes) -} diff --git a/core/src/sql/v1/statements/define/analyzer.rs b/core/src/sql/v1/statements/define/analyzer.rs deleted file mode 100644 index 1071832a..00000000 --- a/core/src/sql/v1/statements/define/analyzer.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{filter::Filter, tokenizer::Tokenizer, Base, Ident, Strand, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineAnalyzerStatement { - pub name: Ident, - pub tokenizers: Option>, - pub filters: Option>, - pub comment: Option, -} - -impl DefineAnalyzerStatement { - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Analyzer, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::database::az::new(opt.ns(), opt.db(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.set(key, self).await?; - // Release the transaction - drop(run); // Do we really need this? - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineAnalyzerStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE ANALYZER {}", self.name)?; - if let Some(v) = &self.tokenizers { - let tokens: Vec = v.iter().map(|f| f.to_string()).collect(); - write!(f, " TOKENIZERS {}", tokens.join(","))?; - } - if let Some(v) = &self.filters { - let tokens: Vec = v.iter().map(|f| f.to_string()).collect(); - write!(f, " FILTERS {}", tokens.join(","))?; - } - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/database.rs b/core/src/sql/v1/statements/define/database.rs deleted file mode 100644 index cc86469f..00000000 --- a/core/src/sql/v1/statements/define/database.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{changefeed::ChangeFeed, Base, Ident, Strand, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineDatabaseStatement { - pub id: Option, - pub name: Ident, - pub comment: Option, - pub changefeed: Option, -} - -impl DefineDatabaseStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Database, &Base::Ns)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::namespace::db::new(opt.ns(), &self.name); - let ns = run.add_ns(opt.ns(), opt.strict).await?; - // Store the db - if self.id.is_none() && ns.id.is_some() { - let mut db = self.clone(); - db.id = Some(run.get_next_db_id(ns.id.unwrap()).await?); - // Store the db - run.set(key, db).await?; - } else { - // Store the db - run.set(key, self).await?; - } - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineDatabaseStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE DATABASE {}", self.name)?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - if let Some(ref v) = self.changefeed { - write!(f, " {v}")?; - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/event.rs b/core/src/sql/v1/statements/define/event.rs deleted file mode 100644 index abb3213a..00000000 --- a/core/src/sql/v1/statements/define/event.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Strand, Value, Values}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineEventStatement { - pub name: Ident, - pub what: Ident, - pub when: Value, - pub then: Values, - pub comment: Option, -} - -impl DefineEventStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Event, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::table::ev::new(opt.ns(), opt.db(), &self.what, &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?; - run.set(key, self).await?; - // Clear the cache - let key = crate::key::table::ev::prefix(opt.ns(), opt.db(), &self.what); - run.clr(key).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineEventStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "DEFINE EVENT {} ON {} WHEN {} THEN {}", - self.name, self.what, self.when, self.then - )?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/field.rs b/core/src/sql/v1/statements/define/field.rs deleted file mode 100644 index a094d3ae..00000000 --- a/core/src/sql/v1/statements/define/field.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::Part; -use crate::sql::{ - fmt::is_pretty, fmt::pretty_indent, Base, Ident, Idiom, Kind, Permissions, Strand, Value, -}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Write}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineFieldStatement { - pub name: Idiom, - pub what: Ident, - pub flex: bool, - pub kind: Option, - pub value: Option, - pub assert: Option, - pub default: Option, - pub permissions: Permissions, - pub comment: Option, -} - -impl DefineFieldStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let fd = self.name.to_string(); - let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?; - - // Process possible recursive_definitions. - if let Some(mut cur_kind) = self.kind.as_ref().and_then(|x| x.inner_kind()) { - let mut name = self.name.clone(); - // find existing field definitions. - let fields = run.all_tb_fields(opt.ns(), opt.db(), &self.what).await.ok(); - loop { - let new_kind = cur_kind.inner_kind(); - name.0.push(Part::All); - - let fd = name.to_string(); - let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - - // merge the new definition with possible existing definitions. - let statement = if let Some(existing) = - fields.as_ref().and_then(|x| x.iter().find(|x| x.name == name)) - { - DefineFieldStatement { - kind: Some(cur_kind), - ..existing.clone() - } - } else { - DefineFieldStatement { - name: name.clone(), - what: self.what.clone(), - flex: self.flex, - kind: Some(cur_kind), - ..Default::default() - } - }; - - run.set(key, statement).await?; - - if let Some(new_kind) = new_kind { - cur_kind = new_kind; - } else { - break; - } - } - } - - run.set(key, self).await?; - // Clear the cache - let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what); - run.clr(key).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineFieldStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE FIELD {} ON {}", self.name, self.what)?; - if self.flex { - write!(f, " FLEXIBLE")? - } - if let Some(ref v) = self.kind { - write!(f, " TYPE {v}")? - } - if let Some(ref v) = self.default { - write!(f, " DEFAULT {v}")? - } - if let Some(ref v) = self.value { - write!(f, " VALUE {v}")? - } - if let Some(ref v) = self.assert { - write!(f, " ASSERT {v}")? - } - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - let _indent = if is_pretty() { - Some(pretty_indent()) - } else { - f.write_char(' ')?; - None - }; - write!(f, "{}", self.permissions)?; - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/function.rs b/core/src/sql/v1/statements/define/function.rs deleted file mode 100644 index dd06df9b..00000000 --- a/core/src/sql/v1/statements/define/function.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{ - fmt::{is_pretty, pretty_indent}, - Base, Block, Ident, Kind, Permission, Strand, Value, -}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Write}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineFunctionStatement { - pub name: Ident, - pub args: Vec<(Ident, Kind)>, - pub block: Block, - pub comment: Option, - pub permissions: Permission, -} - -impl DefineFunctionStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::database::fc::new(opt.ns(), opt.db(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } -} - -impl fmt::Display for DefineFunctionStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE FUNCTION fn::{}(", self.name.0)?; - for (i, (name, kind)) in self.args.iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - write!(f, "${name}: {kind}")?; - } - f.write_str(") ")?; - Display::fmt(&self.block, f)?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - let _indent = if is_pretty() { - Some(pretty_indent()) - } else { - f.write_char(' ')?; - None - }; - write!(f, "PERMISSIONS {}", self.permissions)?; - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/index.rs b/core/src/sql/v1/statements/define/index.rs deleted file mode 100644 index 4985bd0f..00000000 --- a/core/src/sql/v1/statements/define/index.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{statements::UpdateStatement, Base, Ident, Idioms, Index, Strand, Value, Values}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineIndexStatement { - pub name: Ident, - pub what: Ident, - pub cols: Idioms, - pub index: Index, - pub comment: Option, -} - -impl DefineIndexStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::table::ix::new(opt.ns(), opt.db(), &self.what, &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?; - run.set(key, self).await?; - // Remove the index data - let key = crate::key::index::all::new(opt.ns(), opt.db(), &self.what, &self.name); - run.delp(key, u32::MAX).await?; - // Clear the cache - let key = crate::key::table::ix::prefix(opt.ns(), opt.db(), &self.what); - run.clr(key).await?; - // Release the transaction - drop(run); - // Force queries to run - let opt = &opt.new_with_force(true); - // Don't process field queries - let opt = &opt.new_with_fields(false); - // Don't process event queries - let opt = &opt.new_with_events(false); - // Don't process table queries - let opt = &opt.new_with_tables(false); - // Update the index data - let stm = UpdateStatement { - what: Values(vec![Value::Table(self.what.clone().into())]), - ..UpdateStatement::default() - }; - stm.compute(ctx, opt, txn, doc).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineIndexStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE INDEX {} ON {} FIELDS {}", self.name, self.what, self.cols)?; - if Index::Idx != self.index { - write!(f, " {}", self.index)?; - } - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/mod.rs b/core/src/sql/v1/statements/define/mod.rs deleted file mode 100644 index da737e6c..00000000 --- a/core/src/sql/v1/statements/define/mod.rs +++ /dev/null @@ -1,125 +0,0 @@ -mod analyzer; -mod database; -mod event; -mod field; -mod function; -mod index; -mod model; -mod namespace; -mod param; -mod scope; -mod table; -mod token; -mod user; - -pub use analyzer::DefineAnalyzerStatement; -pub use database::DefineDatabaseStatement; -pub use event::DefineEventStatement; -pub use field::DefineFieldStatement; -pub use function::DefineFunctionStatement; -pub use index::DefineIndexStatement; -pub use model::DefineModelStatement; -pub use namespace::DefineNamespaceStatement; -pub use param::DefineParamStatement; -pub use scope::DefineScopeStatement; -pub use table::DefineTableStatement; -pub use token::DefineTokenStatement; -pub use user::DefineUserStatement; - -use crate::ctx::Context; -use crate::dbs::Options; -use crate::dbs::Transaction; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::value::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum DefineStatement { - Namespace(DefineNamespaceStatement), - Database(DefineDatabaseStatement), - Function(DefineFunctionStatement), - Analyzer(DefineAnalyzerStatement), - Token(DefineTokenStatement), - Scope(DefineScopeStatement), - Param(DefineParamStatement), - Table(DefineTableStatement), - Event(DefineEventStatement), - Field(DefineFieldStatement), - Index(DefineIndexStatement), - User(DefineUserStatement), - Model(DefineModelStatement), -} - -impl DefineStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - true - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self { - Self::Namespace(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Database(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Function(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Token(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Scope(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Param(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Table(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::User(ref v) => v.compute(ctx, opt, txn, doc).await, - Self::Model(ref v) => v.compute(ctx, opt, txn, doc).await, - } - } -} - -impl Display for DefineStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Namespace(v) => Display::fmt(v, f), - Self::Database(v) => Display::fmt(v, f), - Self::Function(v) => Display::fmt(v, f), - Self::User(v) => Display::fmt(v, f), - Self::Token(v) => Display::fmt(v, f), - Self::Scope(v) => Display::fmt(v, f), - Self::Param(v) => Display::fmt(v, f), - Self::Table(v) => Display::fmt(v, f), - Self::Event(v) => Display::fmt(v, f), - Self::Field(v) => Display::fmt(v, f), - Self::Index(v) => Display::fmt(v, f), - Self::Analyzer(v) => Display::fmt(v, f), - Self::Model(v) => Display::fmt(v, f), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::Ident; - - #[test] - fn check_define_serialize() { - let stm = DefineStatement::Namespace(DefineNamespaceStatement { - name: Ident::from("test"), - ..Default::default() - }); - let enc: Vec = stm.into(); - assert_eq!(11, enc.len()); - } -} diff --git a/core/src/sql/v1/statements/define/model.rs b/core/src/sql/v1/statements/define/model.rs deleted file mode 100644 index 8122d282..00000000 --- a/core/src/sql/v1/statements/define/model.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{ - fmt::{is_pretty, pretty_indent}, - Base, Ident, Permission, Strand, Value, -}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Write}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineModelStatement { - pub hash: String, - pub name: Ident, - pub version: String, - pub comment: Option, - pub permissions: Permission, -} - -impl fmt::Display for DefineModelStatement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DEFINE MODEL ml::{}<{}>", self.name, self.version)?; - if let Some(comment) = self.comment.as_ref() { - write!(f, " COMMENT {}", comment)?; - } - let _indent = if is_pretty() { - Some(pretty_indent()) - } else { - f.write_char(' ')?; - None - }; - write!(f, "PERMISSIONS {}", self.permissions)?; - Ok(()) - } -} - -impl DefineModelStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Model, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::database::ml::new(opt.ns(), opt.db(), &self.name, &self.version); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.set(key, self).await?; - // Store the model file - // TODO - // Ok all good - Ok(Value::None) - } -} diff --git a/core/src/sql/v1/statements/define/namespace.rs b/core/src/sql/v1/statements/define/namespace.rs deleted file mode 100644 index e2db1a25..00000000 --- a/core/src/sql/v1/statements/define/namespace.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Strand, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineNamespaceStatement { - pub id: Option, - pub name: Ident, - pub comment: Option, -} - -impl DefineNamespaceStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?; - // Process the statement - let key = crate::key::root::ns::new(&self.name); - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Set the id - if self.id.is_none() { - let mut ns = self.clone(); - ns.id = Some(run.get_next_ns_id().await?); - run.set(key, ns).await?; - } else { - run.set(key, self).await?; - } - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineNamespaceStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE NAMESPACE {}", self.name)?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/param.rs b/core/src/sql/v1/statements/define/param.rs deleted file mode 100644 index f2be9707..00000000 --- a/core/src/sql/v1/statements/define/param.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::fmt::{is_pretty, pretty_indent}; -use crate::sql::{Base, Ident, Permission, Strand, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Write}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineParamStatement { - pub name: Ident, - pub value: Value, - pub comment: Option, - pub permissions: Permission, -} - -impl DefineParamStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Compute the param - let val = DefineParamStatement { - value: self.value.compute(ctx, opt, txn, doc).await?, - ..self.clone() - }; - // Process the statement - let key = crate::key::database::pa::new(opt.ns(), opt.db(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.set(key, val).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineParamStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE PARAM ${} VALUE {}", self.name, self.value)?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - let _indent = if is_pretty() { - Some(pretty_indent()) - } else { - f.write_char(' ')?; - None - }; - write!(f, "PERMISSIONS {}", self.permissions)?; - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/scope.rs b/core/src/sql/v1/statements/define/scope.rs deleted file mode 100644 index 19d3d68c..00000000 --- a/core/src/sql/v1/statements/define/scope.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Duration, Ident, Strand, Value}; -use derive::Store; -use rand::distributions::Alphanumeric; -use rand::Rng; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineScopeStatement { - pub name: Ident, - pub code: String, - pub session: Option, - pub signup: Option, - pub signin: Option, - pub comment: Option, -} - -impl DefineScopeStatement { - pub fn random_code() -> String { - rand::thread_rng().sample_iter(&Alphanumeric).take(128).map(char::from).collect::() - } -} - -impl DefineScopeStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Scope, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::database::sc::new(opt.ns(), opt.db(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineScopeStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE SCOPE {}", self.name)?; - if let Some(ref v) = self.session { - write!(f, " SESSION {v}")? - } - if let Some(ref v) = self.signup { - write!(f, " SIGNUP {v}")? - } - if let Some(ref v) = self.signin { - write!(f, " SIGNIN {v}")? - } - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/table.rs b/core/src/sql/v1/statements/define/table.rs deleted file mode 100644 index f73c3f6a..00000000 --- a/core/src/sql/v1/statements/define/table.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{ - changefeed::ChangeFeed, - fmt::{is_pretty, pretty_indent}, - statements::UpdateStatement, - Base, Ident, Permissions, Strand, Value, Values, View, -}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Write}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineTableStatement { - pub id: Option, - pub name: Ident, - pub drop: bool, - pub full: bool, - pub view: Option, - pub permissions: Permissions, - pub changefeed: Option, - pub comment: Option, -} - -impl DefineTableStatement { - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name); - let ns = run.add_ns(opt.ns(), opt.strict).await?; - let db = run.add_db(opt.ns(), opt.db(), opt.strict).await?; - let dt = if self.id.is_none() && ns.id.is_some() && db.id.is_some() { - let mut tb = self.clone(); - tb.id = Some(run.get_next_tb_id(ns.id.unwrap(), db.id.unwrap()).await?); - run.set(key, &tb).await?; - tb - } else { - run.set(key, self).await?; - self.to_owned() - }; - // Check if table is a view - if let Some(view) = &self.view { - // Remove the table data - let key = crate::key::table::all::new(opt.ns(), opt.db(), &self.name); - run.delp(key, u32::MAX).await?; - // Process each foreign table - for v in view.what.0.iter() { - // Save the view config - let key = crate::key::table::ft::new(opt.ns(), opt.db(), v, &self.name); - run.set(key, self).await?; - // Clear the cache - let key = crate::key::table::ft::prefix(opt.ns(), opt.db(), v); - run.clr(key).await?; - } - // Release the transaction - drop(run); - // Force queries to run - let opt = &opt.new_with_force(true); - // Don't process field queries - let opt = &opt.new_with_fields(false); - // Don't process event queries - let opt = &opt.new_with_events(false); - // Don't process index queries - let opt = &opt.new_with_indexes(false); - // Process each foreign table - for v in view.what.0.iter() { - // Process the view data - let stm = UpdateStatement { - what: Values(vec![Value::Table(v.clone())]), - ..UpdateStatement::default() - }; - stm.compute(ctx, opt, txn, doc).await?; - } - } else if dt.changefeed.is_some() { - run.record_table_change(opt.ns(), opt.db(), self.name.0.as_str(), &dt); - } - // Ok all good - Ok(Value::None) - } -} - -impl Display for DefineTableStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE TABLE {}", self.name)?; - if self.drop { - f.write_str(" DROP")?; - } - f.write_str(if self.full { - " SCHEMAFULL" - } else { - " SCHEMALESS" - })?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - if let Some(ref v) = self.view { - write!(f, " {v}")? - } - if let Some(ref v) = self.changefeed { - write!(f, " {v}")?; - } - let _indent = if is_pretty() { - Some(pretty_indent()) - } else { - f.write_char(' ')?; - None - }; - write!(f, "{}", self.permissions)?; - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/token.rs b/core/src/sql/v1/statements/define/token.rs deleted file mode 100644 index cd870b52..00000000 --- a/core/src/sql/v1/statements/define/token.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{escape::quote_str, Algorithm, Base, Ident, Strand, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineTokenStatement { - pub name: Ident, - pub base: Base, - pub kind: Algorithm, - pub code: String, - pub comment: Option, -} - -impl DefineTokenStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?; - - match &self.base { - Base::Ns => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::namespace::tk::new(opt.ns(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } - Base::Db => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::database::tk::new(opt.ns(), opt.db(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } - Base::Sc(sc) => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::scope::tk::new(opt.ns(), opt.db(), sc, &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.add_sc(opt.ns(), opt.db(), sc, opt.strict).await?; - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } - // Other levels are not supported - _ => Err(Error::InvalidLevel(self.base.to_string())), - } - } -} - -impl Display for DefineTokenStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "DEFINE TOKEN {} ON {} TYPE {} VALUE {}", - self.name, - self.base, - self.kind, - quote_str(&self.code) - )?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/define/user.rs b/core/src/sql/v1/statements/define/user.rs deleted file mode 100644 index a466e5df..00000000 --- a/core/src/sql/v1/statements/define/user.rs +++ /dev/null @@ -1,146 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{escape::quote_str, fmt::Fmt, Base, Ident, Strand, Value}; -use argon2::{ - password_hash::{PasswordHasher, SaltString}, - Argon2, -}; -use derive::Store; -use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct DefineUserStatement { - pub name: Ident, - pub base: Base, - pub hash: String, - pub code: String, - pub roles: Vec, - pub comment: Option, -} - -impl From<(Base, &str, &str)> for DefineUserStatement { - fn from((base, user, pass): (Base, &str, &str)) -> Self { - DefineUserStatement { - base, - name: user.into(), - hash: Argon2::default() - .hash_password(pass.as_ref(), &SaltString::generate(&mut OsRng)) - .unwrap() - .to_string(), - code: rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(128) - .map(char::from) - .collect::(), - roles: vec!["owner".into()], - comment: None, - } - } -} - -impl DefineUserStatement { - pub(crate) fn from_parsed_values(name: Ident, base: Base, roles: Vec) -> Self { - DefineUserStatement { - name, - base, - roles, // New users get the viewer role by default - code: rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(128) - .map(char::from) - .collect::(), - ..Default::default() - } - } - - pub(crate) fn set_password(&mut self, password: &str) { - self.hash = Argon2::default() - .hash_password(password.as_bytes(), &SaltString::generate(&mut OsRng)) - .unwrap() - .to_string() - } - - pub(crate) fn set_passhash(&mut self, passhash: String) { - self.hash = passhash; - } - - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?; - - match self.base { - Base::Root => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::root::us::new(&self.name); - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } - Base::Ns => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::namespace::us::new(opt.ns(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } - Base::Db => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name); - run.add_ns(opt.ns(), opt.strict).await?; - run.add_db(opt.ns(), opt.db(), opt.strict).await?; - run.set(key, self).await?; - // Ok all good - Ok(Value::None) - } - // Other levels are not supported - _ => Err(Error::InvalidLevel(self.base.to_string())), - } - } -} - -impl Display for DefineUserStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "DEFINE USER {} ON {} PASSHASH {} ROLES {}", - self.name, - self.base, - quote_str(&self.hash), - Fmt::comma_separated( - &self.roles.iter().map(|r| r.to_string().to_uppercase()).collect::>() - ) - )?; - if let Some(ref v) = self.comment { - write!(f, " COMMENT {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/kill.rs b/core/src/sql/v1/statements/kill.rs deleted file mode 100644 index be028ccc..00000000 --- a/core/src/sql/v1/statements/kill.rs +++ /dev/null @@ -1,157 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::fflags::FFLAGS; -use crate::kvs::lq_structs::{KillEntry, TrackedResult}; -use crate::sql::Uuid; -use crate::sql::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct KillStatement { - // Uuid of Live Query - // or Param resolving to Uuid of Live Query - pub id: Value, -} - -impl KillStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Is realtime enabled? - opt.realtime()?; - // Valid options? - opt.valid_for_db()?; - // Resolve live query id - let live_query_id = match &self.id { - Value::Uuid(id) => *id, - Value::Param(param) => match param.compute(ctx, opt, txn, None).await? { - Value::Uuid(id) => id, - Value::Strand(id) => match uuid::Uuid::try_parse(&id) { - Ok(id) => Uuid(id), - _ => { - return Err(Error::KillStatement { - value: self.id.to_string(), - }) - } - }, - _ => { - return Err(Error::KillStatement { - value: self.id.to_string(), - }) - } - }, - _ => { - return Err(Error::KillStatement { - value: self.id.to_string(), - }) - } - }; - // Claim transaction - let mut run = txn.lock().await; - if FFLAGS.change_feed_live_queries.enabled() { - run.pre_commit_register_async_event(TrackedResult::KillQuery(KillEntry { - live_id: live_query_id, - ns: opt.ns().to_string(), - db: opt.db().to_string(), - }))?; - } else { - // Fetch the live query key - let key = crate::key::node::lq::new(opt.id()?, live_query_id.0, opt.ns(), opt.db()); - // Fetch the live query key if it exists - match run.get(key).await? { - Some(val) => match std::str::from_utf8(&val) { - Ok(tb) => { - // Delete the node live query - let key = crate::key::node::lq::new( - opt.id()?, - live_query_id.0, - opt.ns(), - opt.db(), - ); - run.del(key).await?; - // Delete the table live query - let key = - crate::key::table::lq::new(opt.ns(), opt.db(), tb, live_query_id.0); - run.del(key).await?; - } - _ => { - return Err(Error::KillStatement { - value: self.id.to_string(), - }) - } - }, - None => { - return Err(Error::KillStatement { - value: self.id.to_string(), - }) - } - } - // Return the query id - } - Ok(Value::None) - } -} - -impl fmt::Display for KillStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "KILL {}", self.id) - } -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - - use crate::ctx::Context; - use crate::dbs::Options; - use crate::fflags::FFLAGS; - use crate::kvs::lq_structs::{KillEntry, TrackedResult}; - use crate::kvs::{Datastore, LockType, TransactionType}; - use crate::sql::v1::statements::KillStatement; - use crate::sql::Uuid; - - #[test_log::test(tokio::test)] - async fn kill_handles_uuid_event_registration() { - if !FFLAGS.change_feed_live_queries.enabled() { - return; - } - let res = KillStatement { - id: Uuid::from_str("889757b3-2040-4da3-9ad6-47fe65bd2fb6").unwrap().into(), - }; - let ctx = Context::default(); - let opt = Options::new() - .with_id(uuid::Uuid::from_str("55a85e9c-7cd1-49cb-a8f7-41124d8fdaf8").unwrap()) - .with_live(true) - .with_db(Some("database".into())) - .with_ns(Some("namespace".into())); - let ds = Datastore::new("memory").await.unwrap(); - let mut tx = - ds.transaction(TransactionType::Write, LockType::Optimistic).await.unwrap().enclose(); - res.compute(&ctx, &opt, &tx, None).await.unwrap(); - - let mut tx = tx.lock().await; - tx.commit().await.unwrap(); - - // Validate sent - assert_eq!( - tx.consume_pending_live_queries(), - vec![TrackedResult::KillQuery(KillEntry { - live_id: Uuid::from_str("889757b3-2040-4da3-9ad6-47fe65bd2fb6").unwrap(), - ns: "namespace".to_string(), - db: "database".to_string(), - })] - ); - } -} diff --git a/core/src/sql/v1/statements/live.rs b/core/src/sql/v1/statements/live.rs deleted file mode 100644 index d4f01f28..00000000 --- a/core/src/sql/v1/statements/live.rs +++ /dev/null @@ -1,142 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::fflags::FFLAGS; -use crate::iam::Auth; -use crate::sql::{Cond, Fetchs, Fields, Uuid, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 2)] -pub struct LiveStatement { - pub id: Uuid, - pub node: Uuid, - pub expr: Fields, - pub what: Value, - pub cond: Option, - pub fetch: Option, - // When a live query is marked for archiving, this will - // be set to the node ID that archived the query. This - // is an internal property, set by the database runtime. - // This is optional, and os only set when archived. - pub(crate) archived: Option, - // When a live query is created, we must also store the - // authenticated session of the user who made the query, - // so we can chack it later when sending notifications. - // This is optional as it is only set by the database - // runtime when storing the live query to storage. - #[revision(start = 2)] - pub(crate) session: Option, - // When a live query is created, we must also store the - // authenticated session of the user who made the query, - // so we can chack it later when sending notifications. - // This is optional as it is only set by the database - // runtime when storing the live query to storage. - pub(crate) auth: Option, -} - -impl LiveStatement { - #[doc(hidden)] - pub fn new(expr: Fields) -> Self { - LiveStatement { - id: Uuid::new_v4(), - node: Uuid::new_v4(), - expr, - ..Default::default() - } - } - - /// Creates a live statement from parts that can be set during a query. - pub(crate) fn from_source_parts( - expr: Fields, - what: Value, - cond: Option, - fetch: Option, - ) -> Self { - LiveStatement { - id: Uuid::new_v4(), - node: Uuid::new_v4(), - expr, - what, - cond, - fetch, - ..Default::default() - } - } - - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Is realtime enabled? - opt.realtime()?; - // Valid options? - opt.valid_for_db()?; - // Get the Node ID - let nid = opt.id()?; - // Check that auth has been set - let mut stm = LiveStatement { - // Use the current session authentication - // for when we store the LIVE Statement - session: ctx.value("session").cloned(), - // Use the current session authentication - // for when we store the LIVE Statement - auth: Some(opt.auth.as_ref().clone()), - // Clone the rest of the original fields - // from the LIVE statement to the new one - ..self.clone() - }; - let id = stm.id.0; - // Claim transaction - let mut run = txn.lock().await; - // Process the live query table - match stm.what.compute(ctx, opt, txn, doc).await? { - Value::Table(tb) => { - if FFLAGS.change_feed_live_queries.enabled() { - // We no longer need to write, as LQs are only computed locally from CF - return Ok(id.into()); - } - // Store the current Node ID - stm.node = nid.into(); - // Insert the node live query - run.putc_ndlq(nid, id, opt.ns(), opt.db(), tb.as_str(), None).await?; - // Insert the table live query - run.putc_tblq(opt.ns(), opt.db(), &tb, stm, None).await?; - } - v => { - return Err(Error::LiveStatement { - value: v.to_string(), - }) - } - }; - // Return the query id - Ok(id.into()) - } - - pub(crate) fn archive(mut self, node_id: Uuid) -> LiveStatement { - self.archived = Some(node_id); - self - } -} - -impl fmt::Display for LiveStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LIVE SELECT {} FROM {}", self.expr, self.what)?; - if let Some(ref v) = self.cond { - write!(f, " {v}")? - } - if let Some(ref v) = self.fetch { - write!(f, " {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v1/statements/remove/analyzer.rs b/core/src/sql/v1/statements/remove/analyzer.rs deleted file mode 100644 index b32c7e15..00000000 --- a/core/src/sql/v1/statements/remove/analyzer.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct RemoveAnalyzerStatement { - pub name: Ident, -} - -impl RemoveAnalyzerStatement { - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Analyzer, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::database::az::new(opt.ns(), opt.db(), &self.name); - run.del(key).await?; - // TODO Check that the analyzer is not used in any schema - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveAnalyzerStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE ANALYZER {}", self.name) - } -} diff --git a/core/src/sql/v1/statements/remove/database.rs b/core/src/sql/v1/statements/remove/database.rs deleted file mode 100644 index 5dbd3e1d..00000000 --- a/core/src/sql/v1/statements/remove/database.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct RemoveDatabaseStatement { - pub name: Ident, -} - -impl RemoveDatabaseStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Database, &Base::Ns)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::namespace::db::new(opt.ns(), &self.name); - run.del(key).await?; - // Delete the resource data - let key = crate::key::database::all::new(opt.ns(), &self.name); - run.delp(key, u32::MAX).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveDatabaseStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE DATABASE {}", self.name) - } -} diff --git a/core/src/sql/v1/statements/remove/event.rs b/core/src/sql/v1/statements/remove/event.rs deleted file mode 100644 index 30d7d121..00000000 --- a/core/src/sql/v1/statements/remove/event.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct RemoveEventStatement { - pub name: Ident, - pub what: Ident, -} - -impl RemoveEventStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Event, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::table::ev::new(opt.ns(), opt.db(), &self.what, &self.name); - run.del(key).await?; - // Clear the cache - let key = crate::key::table::ev::prefix(opt.ns(), opt.db(), &self.what); - run.clr(key).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveEventStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE EVENT {} ON {}", self.name, self.what) - } -} diff --git a/core/src/sql/v1/statements/remove/field.rs b/core/src/sql/v1/statements/remove/field.rs deleted file mode 100644 index 51f3f2dc..00000000 --- a/core/src/sql/v1/statements/remove/field.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Idiom, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct RemoveFieldStatement { - pub name: Idiom, - pub what: Ident, -} - -impl RemoveFieldStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let fd = self.name.to_string(); - let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd); - run.del(key).await?; - // Clear the cache - let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what); - run.clr(key).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveFieldStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE FIELD {} ON {}", self.name, self.what) - } -} diff --git a/core/src/sql/v1/statements/remove/function.rs b/core/src/sql/v1/statements/remove/function.rs deleted file mode 100644 index d35037d9..00000000 --- a/core/src/sql/v1/statements/remove/function.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct RemoveFunctionStatement { - pub name: Ident, -} - -impl RemoveFunctionStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::database::fc::new(opt.ns(), opt.db(), &self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveFunctionStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Bypass ident display since we don't want backticks arround the ident. - write!(f, "REMOVE FUNCTION fn::{}", self.name.0) - } -} diff --git a/core/src/sql/v1/statements/remove/index.rs b/core/src/sql/v1/statements/remove/index.rs deleted file mode 100644 index 06da30c3..00000000 --- a/core/src/sql/v1/statements/remove/index.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct RemoveIndexStatement { - pub name: Ident, - pub what: Ident, -} - -impl RemoveIndexStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the index store cache - ctx.get_index_stores().index_removed(opt, &mut run, &self.what, &self.name).await?; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::table::ix::new(opt.ns(), opt.db(), &self.what, &self.name); - run.del(key).await?; - // Remove the index data - let key = crate::key::index::all::new(opt.ns(), opt.db(), &self.what, &self.name); - run.delp(key, u32::MAX).await?; - // Clear the cache - let key = crate::key::table::ix::prefix(opt.ns(), opt.db(), &self.what); - run.clr(key).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveIndexStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE INDEX {} ON {}", self.name, self.what) - } -} diff --git a/core/src/sql/v1/statements/remove/model.rs b/core/src/sql/v1/statements/remove/model.rs deleted file mode 100644 index dfec396e..00000000 --- a/core/src/sql/v1/statements/remove/model.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct RemoveModelStatement { - pub name: Ident, - pub version: String, -} - -impl RemoveModelStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Model, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::database::ml::new(opt.ns(), opt.db(), &self.name, &self.version); - run.del(key).await?; - // Remove the model file - // TODO - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveModelStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Bypass ident display since we don't want backticks arround the ident. - write!(f, "REMOVE MODEL ml::{}<{}>", self.name.0, self.version) - } -} diff --git a/core/src/sql/v1/statements/remove/namespace.rs b/core/src/sql/v1/statements/remove/namespace.rs deleted file mode 100644 index 51559eb1..00000000 --- a/core/src/sql/v1/statements/remove/namespace.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct RemoveNamespaceStatement { - pub name: Ident, -} - -impl RemoveNamespaceStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?; - // Claim transaction - let mut run = txn.lock().await; - ctx.get_index_stores().namespace_removed(opt, &mut run).await?; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::root::ns::new(&self.name); - run.del(key).await?; - // Delete the resource data - let key = crate::key::namespace::all::new(&self.name); - run.delp(key, u32::MAX).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveNamespaceStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE NAMESPACE {}", self.name) - } -} diff --git a/core/src/sql/v1/statements/remove/param.rs b/core/src/sql/v1/statements/remove/param.rs deleted file mode 100644 index 53da35fa..00000000 --- a/core/src/sql/v1/statements/remove/param.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct RemoveParamStatement { - pub name: Ident, -} - -impl RemoveParamStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::database::pa::new(opt.ns(), opt.db(), &self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveParamStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE PARAM ${}", self.name) - } -} diff --git a/core/src/sql/v1/statements/remove/scope.rs b/core/src/sql/v1/statements/remove/scope.rs deleted file mode 100644 index 290ad9ea..00000000 --- a/core/src/sql/v1/statements/remove/scope.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct RemoveScopeStatement { - pub name: Ident, -} - -impl RemoveScopeStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Scope, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::database::sc::new(opt.ns(), opt.db(), &self.name); - run.del(key).await?; - // Remove the resource data - let key = crate::key::scope::all::new(opt.ns(), opt.db(), &self.name); - run.delp(key, u32::MAX).await?; - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveScopeStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE SCOPE {}", self.name) - } -} diff --git a/core/src/sql/v1/statements/remove/table.rs b/core/src/sql/v1/statements/remove/table.rs deleted file mode 100644 index f956caba..00000000 --- a/core/src/sql/v1/statements/remove/table.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::Options; -use crate::dbs::Transaction; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct RemoveTableStatement { - pub name: Ident, -} - -impl RemoveTableStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Remove the index stores - ctx.get_index_stores().table_removed(opt, &mut run, &self.name).await?; - // Clear the cache - run.clear_cache(); - // Get the defined table - let tb = run.get_tb(opt.ns(), opt.db(), &self.name).await?; - // Delete the definition - let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name); - run.del(key).await?; - // Remove the resource data - let key = crate::key::table::all::new(opt.ns(), opt.db(), &self.name); - run.delp(key, u32::MAX).await?; - // Check if this is a foreign table - if let Some(view) = &tb.view { - // Process each foreign table - for v in view.what.0.iter() { - // Save the view config - let key = crate::key::table::ft::new(opt.ns(), opt.db(), v, &self.name); - run.del(key).await?; - } - } - // Ok all good - Ok(Value::None) - } -} - -impl Display for RemoveTableStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE TABLE {}", self.name) - } -} diff --git a/core/src/sql/v1/statements/remove/token.rs b/core/src/sql/v1/statements/remove/token.rs deleted file mode 100644 index 9b689f95..00000000 --- a/core/src/sql/v1/statements/remove/token.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct RemoveTokenStatement { - pub name: Ident, - pub base: Base, -} - -impl RemoveTokenStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?; - - match &self.base { - Base::Ns => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::namespace::tk::new(opt.ns(), &self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } - Base::Db => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::database::tk::new(opt.ns(), opt.db(), &self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } - Base::Sc(sc) => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::scope::tk::new(opt.ns(), opt.db(), sc, &self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } - _ => Err(Error::InvalidLevel(self.base.to_string())), - } - } -} - -impl Display for RemoveTokenStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE TOKEN {} ON {}", self.name, self.base) - } -} diff --git a/core/src/sql/v1/statements/remove/user.rs b/core/src/sql/v1/statements/remove/user.rs deleted file mode 100644 index 5248d59f..00000000 --- a/core/src/sql/v1/statements/remove/user.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct RemoveUserStatement { - pub name: Ident, - pub base: Base, -} - -impl RemoveUserStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?; - - match self.base { - Base::Root => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Process the statement - let key = crate::key::root::us::new(&self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } - Base::Ns => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::namespace::us::new(opt.ns(), &self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } - Base::Db => { - // Claim transaction - let mut run = txn.lock().await; - // Clear the cache - run.clear_cache(); - // Delete the definition - let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name); - run.del(key).await?; - // Ok all good - Ok(Value::None) - } - _ => Err(Error::InvalidLevel(self.base.to_string())), - } - } -} - -impl Display for RemoveUserStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "REMOVE USER {} ON {}", self.name, self.base) - } -} diff --git a/core/src/sql/v1/statements/show.rs b/core/src/sql/v1/statements/show.rs deleted file mode 100644 index 7020dc1a..00000000 --- a/core/src/sql/v1/statements/show.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Datetime, Table, Value}; -use crate::vs::{conv, Versionstamp}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum ShowSince { - Timestamp(Datetime), - Versionstamp(u64), -} - -impl ShowSince { - pub fn versionstamp(vs: &Versionstamp) -> ShowSince { - ShowSince::Versionstamp(conv::versionstamp_to_u64(vs)) - } - - pub fn as_versionstamp(&self) -> Option { - match self { - ShowSince::Timestamp(_) => None, - ShowSince::Versionstamp(v) => Some(conv::u64_to_versionstamp(*v)), - } - } -} - -// ShowStatement is used to show changes in a table or database via -// the SHOW CHANGES statement. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct ShowStatement { - pub table: Option, - pub since: ShowSince, - pub limit: Option, -} - -impl ShowStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Selected DB? - opt.is_allowed(Action::View, ResourceKind::Table, &Base::Db)?; - // Clone transaction - let txn = txn.clone(); - // Claim transaction - let mut run = txn.lock().await; - // Process the show query - let tb = self.table.as_deref(); - let r = crate::cf::read( - &mut run, - opt.ns(), - opt.db(), - tb.map(|x| x.as_str()), - self.since.clone(), - self.limit, - ) - .await?; - // Return the changes - let mut a = Vec::::new(); - for r in r.into_iter() { - let v: Value = r.into_value(); - a.push(v); - } - let v: Value = Value::Array(crate::sql::array::Array(a)); - Ok(v) - } -} - -impl fmt::Display for ShowStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "SHOW CHANGES FOR")?; - match self.table { - Some(ref v) => write!(f, " TABLE {}", v)?, - None => write!(f, " DATABASE")?, - } - match self.since { - ShowSince::Timestamp(ref v) => write!(f, " SINCE {}", v)?, - ShowSince::Versionstamp(ref v) => write!(f, " SINCE {}", v)?, - } - if let Some(ref v) = self.limit { - write!(f, " LIMIT {}", v)? - } - Ok(()) - } -} - -#[cfg(test)] -mod test { - use crate::sql::Datetime; - - #[test] - fn timestamps_are_not_versionstamps() { - // given - let sql_dt = Datetime::try_from("2020-01-01T00:00:00Z").unwrap(); - - // when - let since = super::ShowSince::Timestamp(sql_dt); - - // then - assert_eq!(since.as_versionstamp(), None); - } - - #[test] - fn versionstamp_can_be_converted() { - // given - let versionstamp = crate::vs::conv::u64_to_versionstamp(1234567890); - let since = super::ShowSince::Versionstamp(1234567890); - - // when - let converted = since.as_versionstamp().unwrap(); - - // then - assert_eq!(converted, versionstamp); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/analyzer.rs b/core/src/sql/v1/value/serde/ser/statement/define/analyzer.rs deleted file mode 100644 index a0823440..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/analyzer.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::err::Error; -use crate::sql::filter::Filter; -use crate::sql::statements::DefineAnalyzerStatement; -use crate::sql::tokenizer::Tokenizer; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Strand; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineAnalyzerStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineAnalyzerStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineAnalyzerStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineAnalyzerStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineAnalyzerStatement { - name: Ident, - tokenizers: Option>, - filters: Option>, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineAnalyzerStatement { - type Ok = DefineAnalyzerStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "tokenizers" => { - self.tokenizers = value.serialize(ser::tokenizer::vec::opt::Serializer.wrap())?; - } - "filters" => { - self.filters = value.serialize(ser::filter::vec::opt::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineAnalyzerStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineAnalyzerStatement { - name: self.name, - tokenizers: self.tokenizers, - filters: self.filters, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineAnalyzerStatement::default(); - let value: DefineAnalyzerStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/database.rs b/core/src/sql/v1/value/serde/ser/statement/define/database.rs deleted file mode 100644 index 2daf9355..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/database.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::err::Error; -use crate::sql::changefeed::ChangeFeed; -use crate::sql::statements::DefineDatabaseStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Strand; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineDatabaseStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineDatabaseStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineDatabaseStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineDatabaseStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineDatabaseStatement { - name: Ident, - changefeed: Option, - id: Option, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineDatabaseStatement { - type Ok = DefineDatabaseStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "changefeed" => { - self.changefeed = value.serialize(ser::changefeed::opt::Serializer.wrap())?; - } - "id" => { - self.id = value.serialize(ser::primitive::u32::opt::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineDatabaseStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineDatabaseStatement { - name: self.name, - changefeed: self.changefeed, - id: self.id, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineDatabaseStatement::default(); - let value: DefineDatabaseStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/event.rs b/core/src/sql/v1/value/serde/ser/statement/define/event.rs deleted file mode 100644 index 19e5c949..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/event.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineEventStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Strand; -use crate::sql::Value; -use crate::sql::Values; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineEventStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineEventStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineEventStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineEventStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineEventStatement { - name: Ident, - what: Ident, - when: Value, - then: Values, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineEventStatement { - type Ok = DefineEventStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "what" => { - self.what = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "when" => { - self.when = value.serialize(ser::value::Serializer.wrap())?; - } - "then" => { - self.then = Values(value.serialize(ser::value::vec::Serializer.wrap())?); - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineEventStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineEventStatement { - name: self.name, - what: self.what, - when: self.when, - then: self.then, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineEventStatement::default(); - let value: DefineEventStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/field.rs b/core/src/sql/v1/value/serde/ser/statement/define/field.rs deleted file mode 100644 index 04901c79..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/field.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineFieldStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Idiom; -use crate::sql::Kind; -use crate::sql::Permissions; -use crate::sql::Strand; -use crate::sql::Value; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineFieldStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineFieldStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineFieldStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineFieldStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineFieldStatement { - name: Idiom, - what: Ident, - flex: bool, - kind: Option, - value: Option, - assert: Option, - default: Option, - permissions: Permissions, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineFieldStatement { - type Ok = DefineFieldStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Idiom(value.serialize(ser::part::vec::Serializer.wrap())?); - } - "what" => { - self.what = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "flex" => { - self.flex = value.serialize(ser::primitive::bool::Serializer.wrap())?; - } - "kind" => { - self.kind = value.serialize(ser::kind::opt::Serializer.wrap())?; - } - "value" => { - self.value = value.serialize(ser::value::opt::Serializer.wrap())?; - } - "assert" => { - self.assert = value.serialize(ser::value::opt::Serializer.wrap())?; - } - "default" => { - self.default = value.serialize(ser::value::opt::Serializer.wrap())?; - } - "permissions" => { - self.permissions = value.serialize(ser::permissions::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineFieldStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineFieldStatement { - name: self.name, - what: self.what, - flex: self.flex, - kind: self.kind, - value: self.value, - assert: self.assert, - default: self.default, - permissions: self.permissions, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineFieldStatement::default(); - let value: DefineFieldStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/function.rs b/core/src/sql/v1/value/serde/ser/statement/define/function.rs deleted file mode 100644 index b9a3686a..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/function.rs +++ /dev/null @@ -1,202 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineFunctionStatement; -use crate::sql::value::serde::ser; -use crate::sql::Block; -use crate::sql::Ident; -use crate::sql::Kind; -use crate::sql::Permission; -use crate::sql::Strand; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineFunctionStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineFunctionStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineFunctionStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineFunctionStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineFunctionStatement { - name: Ident, - args: Vec<(Ident, Kind)>, - block: Block, - comment: Option, - permissions: Permission, -} - -impl serde::ser::SerializeStruct for SerializeDefineFunctionStatement { - type Ok = DefineFunctionStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "args" => { - self.args = value.serialize(IdentKindVecSerializer.wrap())?; - } - "block" => { - self.block = Block(value.serialize(ser::block::entry::vec::Serializer.wrap())?); - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - "permissions" => { - self.permissions = value.serialize(ser::permission::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineFunctionStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineFunctionStatement { - name: self.name, - args: self.args, - block: self.block, - comment: self.comment, - permissions: self.permissions, - }) - } -} - -type IdentKindTuple = (Ident, Kind); - -struct IdentKindVecSerializer; - -impl ser::Serializer for IdentKindVecSerializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeIdentKindVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "a `Vec<(Ident, Kind)>`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeIdentKindVec(Vec::with_capacity(len.unwrap_or_default()))) - } -} - -struct SerializeIdentKindVec(Vec); - -impl serde::ser::SerializeSeq for SerializeIdentKindVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(value.serialize(IdentKindTupleSerializer.wrap())?); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -struct IdentKindTupleSerializer; - -impl ser::Serializer for IdentKindTupleSerializer { - type Ok = IdentKindTuple; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = SerializeIdentKindTuple; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "an `(Ident, Kind)`"; - - fn serialize_tuple(self, _len: usize) -> Result { - Ok(SerializeIdentKindTuple::default()) - } -} - -#[derive(Default)] -struct SerializeIdentKindTuple { - index: usize, - tuple: IdentKindTuple, -} - -impl serde::ser::SerializeTuple for SerializeIdentKindTuple { - type Ok = IdentKindTuple; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - match self.index { - 0 => { - self.tuple.0 = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - 1 => { - self.tuple.1 = value.serialize(ser::kind::Serializer.wrap())?; - } - index => { - return Err(Error::custom(format!( - "unexpected tuple index `{index}` for `(Ident, Kind)`" - ))); - } - } - self.index += 1; - Ok(()) - } - - fn end(self) -> Result { - Ok(self.tuple) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineFunctionStatement::default(); - let value: DefineFunctionStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/index.rs b/core/src/sql/v1/value/serde/ser/statement/define/index.rs deleted file mode 100644 index 0934a794..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/index.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::err::Error; -use crate::sql::index::Index; -use crate::sql::statements::DefineIndexStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Idioms; -use crate::sql::Strand; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineIndexStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineIndexStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineIndexStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineIndexStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineIndexStatement { - name: Ident, - what: Ident, - cols: Idioms, - index: Index, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineIndexStatement { - type Ok = DefineIndexStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "what" => { - self.what = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "cols" => { - self.cols = Idioms(value.serialize(ser::idiom::vec::Serializer.wrap())?); - } - "index" => { - self.index = value.serialize(ser::index::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineIndexStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineIndexStatement { - name: self.name, - what: self.what, - cols: self.cols, - index: self.index, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineIndexStatement::default(); - let value: DefineIndexStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/namespace.rs b/core/src/sql/v1/value/serde/ser/statement/define/namespace.rs deleted file mode 100644 index a3d5e032..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/namespace.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineNamespaceStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Strand; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineNamespaceStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineNamespaceStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineNamespaceStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineNamespaceStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineNamespaceStatement { - name: Ident, - id: Option, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineNamespaceStatement { - type Ok = DefineNamespaceStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "id" => { - self.id = value.serialize(ser::primitive::u32::opt::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineNamespaceStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineNamespaceStatement { - name: self.name, - id: self.id, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineNamespaceStatement::default(); - let value: DefineNamespaceStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/param.rs b/core/src/sql/v1/value/serde/ser/statement/define/param.rs deleted file mode 100644 index 2e101084..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/param.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineParamStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Permission; -use crate::sql::Strand; -use crate::sql::Value; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineParamStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineParamStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineParamStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineParamStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineParamStatement { - name: Ident, - value: Value, - comment: Option, - permissions: Permission, -} - -impl serde::ser::SerializeStruct for SerializeDefineParamStatement { - type Ok = DefineParamStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "value" => { - self.value = value.serialize(ser::value::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - "permissions" => { - self.permissions = value.serialize(ser::permission::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineParamStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineParamStatement { - name: self.name, - value: self.value, - comment: self.comment, - permissions: self.permissions, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineParamStatement::default(); - let value: DefineParamStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/scope.rs b/core/src/sql/v1/value/serde/ser/statement/define/scope.rs deleted file mode 100644 index 6aa2a2d0..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/scope.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineScopeStatement; -use crate::sql::value::serde::ser; -use crate::sql::Duration; -use crate::sql::Ident; -use crate::sql::Strand; -use crate::sql::Value; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineScopeStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineScopeStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineScopeStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineScopeStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineScopeStatement { - name: Ident, - code: String, - session: Option, - signup: Option, - signin: Option, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineScopeStatement { - type Ok = DefineScopeStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "code" => { - self.code = value.serialize(ser::string::Serializer.wrap())?; - } - "session" => { - self.session = - value.serialize(ser::duration::opt::Serializer.wrap())?.map(Into::into); - } - "signup" => { - self.signup = value.serialize(ser::value::opt::Serializer.wrap())?; - } - "signin" => { - self.signin = value.serialize(ser::value::opt::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineScopeStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineScopeStatement { - name: self.name, - code: self.code, - session: self.session, - signup: self.signup, - signin: self.signin, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineScopeStatement::default(); - let value: DefineScopeStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/table.rs b/core/src/sql/v1/value/serde/ser/statement/define/table.rs deleted file mode 100644 index 379caf2d..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/table.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::err::Error; -use crate::sql::changefeed::ChangeFeed; -use crate::sql::statements::DefineTableStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Permissions; -use crate::sql::Strand; -use crate::sql::View; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineTableStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineTableStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineTableStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineTableStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineTableStatement { - name: Ident, - drop: bool, - full: bool, - id: Option, - view: Option, - permissions: Permissions, - changefeed: Option, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineTableStatement { - type Ok = DefineTableStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "drop" => { - self.drop = value.serialize(ser::primitive::bool::Serializer.wrap())?; - } - "full" => { - self.full = value.serialize(ser::primitive::bool::Serializer.wrap())?; - } - "id" => { - self.id = value.serialize(ser::primitive::u32::opt::Serializer.wrap())?; - } - "view" => { - self.view = value.serialize(ser::view::opt::Serializer.wrap())?; - } - "permissions" => { - self.permissions = value.serialize(ser::permissions::Serializer.wrap())?; - } - "changefeed" => { - self.changefeed = value.serialize(ser::changefeed::opt::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineTableStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineTableStatement { - name: self.name, - drop: self.drop, - full: self.full, - id: self.id, - view: self.view, - permissions: self.permissions, - changefeed: self.changefeed, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineTableStatement::default(); - let value: DefineTableStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/token.rs b/core/src/sql/v1/value/serde/ser/statement/define/token.rs deleted file mode 100644 index fe5989b6..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/token.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineTokenStatement; -use crate::sql::value::serde::ser; -use crate::sql::Algorithm; -use crate::sql::Base; -use crate::sql::Ident; -use crate::sql::Strand; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineTokenStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineTokenStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineTokenStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineTokenStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineTokenStatement { - name: Ident, - base: Base, - kind: Algorithm, - code: String, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineTokenStatement { - type Ok = DefineTokenStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "base" => { - self.base = value.serialize(ser::base::Serializer.wrap())?; - } - "kind" => { - self.kind = value.serialize(ser::algorithm::Serializer.wrap())?; - } - "code" => { - self.code = value.serialize(ser::string::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineTokenStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineTokenStatement { - name: self.name, - base: self.base, - kind: self.kind, - code: self.code, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineTokenStatement::default(); - let value: DefineTokenStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/define/user.rs b/core/src/sql/v1/value/serde/ser/statement/define/user.rs deleted file mode 100644 index 9d85feaa..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/define/user.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::DefineUserStatement; -use crate::sql::value::serde::ser; -use crate::sql::Base; -use crate::sql::Ident; -use crate::sql::Strand; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DefineUserStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDefineUserStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `DefineUserStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDefineUserStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeDefineUserStatement { - name: Ident, - base: Base, - hash: String, - code: String, - roles: Vec, - comment: Option, -} - -impl serde::ser::SerializeStruct for SerializeDefineUserStatement { - type Ok = DefineUserStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "base" => { - self.base = value.serialize(ser::base::Serializer.wrap())?; - } - "hash" => { - self.hash = value.serialize(ser::string::Serializer.wrap())?; - } - "code" => { - self.code = value.serialize(ser::string::Serializer.wrap())?; - } - "roles" => { - self.roles = value.serialize(ser::ident::vec::Serializer.wrap())?; - } - "comment" => { - self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `DefineUserStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(DefineUserStatement { - name: self.name, - base: self.base, - hash: self.hash, - code: self.code, - roles: self.roles, - comment: self.comment, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = DefineUserStatement::default(); - let value: DefineUserStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/analyzer.rs b/core/src/sql/v1/value/serde/ser/statement/remove/analyzer.rs deleted file mode 100644 index c78ce590..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/analyzer.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::remove::RemoveAnalyzerStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveAnalyzerStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveAnalyzerStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveAnalyzerStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveAnalyzerStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveAnalyzerStatement { - name: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement { - type Ok = RemoveAnalyzerStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveAnalyzerStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveAnalyzerStatement { - name: self.name, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveAnalyzerStatement::default(); - let value: RemoveAnalyzerStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/database.rs b/core/src/sql/v1/value/serde/ser/statement/remove/database.rs deleted file mode 100644 index 98b7b153..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/database.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveDatabaseStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveDatabaseStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveDatabaseStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveDatabaseStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveDatabaseStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveDatabaseStatement { - name: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveDatabaseStatement { - type Ok = RemoveDatabaseStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveDatabaseStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveDatabaseStatement { - name: self.name, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveDatabaseStatement::default(); - let value: RemoveDatabaseStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/event.rs b/core/src/sql/v1/value/serde/ser/statement/remove/event.rs deleted file mode 100644 index 33bf77f5..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/event.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveEventStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveEventStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveEventStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveEventStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveEventStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveEventStatement { - name: Ident, - what: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveEventStatement { - type Ok = RemoveEventStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "what" => { - self.what = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveEventStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveEventStatement { - name: self.name, - what: self.what, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveEventStatement::default(); - let value: RemoveEventStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/field.rs b/core/src/sql/v1/value/serde/ser/statement/remove/field.rs deleted file mode 100644 index 78ca4e57..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/field.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveFieldStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use crate::sql::Idiom; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveFieldStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveFieldStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveFieldStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveFieldStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveFieldStatement { - name: Idiom, - what: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveFieldStatement { - type Ok = RemoveFieldStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Idiom(value.serialize(ser::part::vec::Serializer.wrap())?); - } - "what" => { - self.what = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveFieldStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveFieldStatement { - name: self.name, - what: self.what, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveFieldStatement::default(); - let value: RemoveFieldStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/function.rs b/core/src/sql/v1/value/serde/ser/statement/remove/function.rs deleted file mode 100644 index a608fe6d..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/function.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveFunctionStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveFunctionStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveFunctionStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveFunctionStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveFunctionStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveFunctionStatement { - name: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveFunctionStatement { - type Ok = RemoveFunctionStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveFunctionStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveFunctionStatement { - name: self.name, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveFunctionStatement::default(); - let value: RemoveFunctionStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/index.rs b/core/src/sql/v1/value/serde/ser/statement/remove/index.rs deleted file mode 100644 index 950045f0..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/index.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveIndexStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveIndexStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveIndexStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveIndexStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveIndexStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveIndexStatement { - name: Ident, - what: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveIndexStatement { - type Ok = RemoveIndexStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "what" => { - self.what = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveIndexStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveIndexStatement { - name: self.name, - what: self.what, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveIndexStatement::default(); - let value: RemoveIndexStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/namespace.rs b/core/src/sql/v1/value/serde/ser/statement/remove/namespace.rs deleted file mode 100644 index 77659b3f..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/namespace.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveNamespaceStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveNamespaceStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveNamespaceStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveNamespaceStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveNamespaceStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveNamespaceStatement { - name: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveNamespaceStatement { - type Ok = RemoveNamespaceStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveNamespaceStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveNamespaceStatement { - name: self.name, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveNamespaceStatement::default(); - let value: RemoveNamespaceStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/param.rs b/core/src/sql/v1/value/serde/ser/statement/remove/param.rs deleted file mode 100644 index a0b99800..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/param.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveParamStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveParamStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveParamStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveParamStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveParamStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveParamStatement { - name: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveParamStatement { - type Ok = RemoveParamStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveParamStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveParamStatement { - name: self.name, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveParamStatement::default(); - let value: RemoveParamStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/scope.rs b/core/src/sql/v1/value/serde/ser/statement/remove/scope.rs deleted file mode 100644 index 54eb1b93..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/scope.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveScopeStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveScopeStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveScopeStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveScopeStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveScopeStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveScopeStatement { - name: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveScopeStatement { - type Ok = RemoveScopeStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveScopeStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveScopeStatement { - name: self.name, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveScopeStatement::default(); - let value: RemoveScopeStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/table.rs b/core/src/sql/v1/value/serde/ser/statement/remove/table.rs deleted file mode 100644 index 68ccc066..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/table.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveTableStatement; -use crate::sql::value::serde::ser; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveTableStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveTableStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveTableStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveTableStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveTableStatement { - name: Ident, -} - -impl serde::ser::SerializeStruct for SerializeRemoveTableStatement { - type Ok = RemoveTableStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveTableStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveTableStatement { - name: self.name, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveTableStatement::default(); - let value: RemoveTableStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/token.rs b/core/src/sql/v1/value/serde/ser/statement/remove/token.rs deleted file mode 100644 index cd558205..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/token.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveTokenStatement; -use crate::sql::value::serde::ser; -use crate::sql::Base; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveTokenStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveTokenStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveTokenStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveTokenStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveTokenStatement { - name: Ident, - base: Base, -} - -impl serde::ser::SerializeStruct for SerializeRemoveTokenStatement { - type Ok = RemoveTokenStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "base" => { - self.base = value.serialize(ser::base::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveTokenStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveTokenStatement { - name: self.name, - base: self.base, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveTokenStatement::default(); - let value: RemoveTokenStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/serde/ser/statement/remove/user.rs b/core/src/sql/v1/value/serde/ser/statement/remove/user.rs deleted file mode 100644 index b60af58b..00000000 --- a/core/src/sql/v1/value/serde/ser/statement/remove/user.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::err::Error; -use crate::sql::statements::RemoveUserStatement; -use crate::sql::value::serde::ser; -use crate::sql::Base; -use crate::sql::Ident; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = RemoveUserStatement; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeRemoveUserStatement; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `RemoveUserStatement`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeRemoveUserStatement::default()) - } -} - -#[derive(Default)] -pub struct SerializeRemoveUserStatement { - name: Ident, - base: Base, -} - -impl serde::ser::SerializeStruct for SerializeRemoveUserStatement { - type Ok = RemoveUserStatement; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "name" => { - self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); - } - "base" => { - self.base = value.serialize(ser::base::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!( - "unexpected field `RemoveUserStatement::{key}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(RemoveUserStatement { - name: self.name, - base: self.base, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = RemoveUserStatement::default(); - let value: RemoveUserStatement = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v1/value/value.rs b/core/src/sql/v1/value/value.rs deleted file mode 100644 index 2f685346..00000000 --- a/core/src/sql/v1/value/value.rs +++ /dev/null @@ -1,2915 +0,0 @@ -#![allow(clippy::derive_ord_xor_partial_ord)] - -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::fnc::util::string::fuzzy::Fuzzy; -use crate::sql::{ - array::Uniq, - fmt::{Fmt, Pretty}, - id::{Gen, Id}, - model::Model, - Array, Block, Bytes, Cast, Constant, Datetime, Duration, Edges, Expression, Function, Future, - Geometry, Idiom, Kind, Mock, Number, Object, Operation, Param, Part, Query, Range, Regex, - Strand, Subquery, Table, Thing, Uuid, -}; -use async_recursion::async_recursion; -use chrono::{DateTime, Utc}; -use derive::Store; -use geo::Point; -use revision::revisioned; -use rust_decimal::prelude::*; -use serde::{Deserialize, Serialize}; -use serde_json::Value as Json; -use std::cmp::Ordering; -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::fmt::{self, Display, Formatter, Write}; -use std::ops::Deref; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Value"; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Values(pub Vec); - -impl Deref for Values { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Values { - type Item = Value; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Display for Values { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&Fmt::comma_separated(&self.0), f) - } -} - -#[derive(Clone, Debug, Default, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[serde(rename = "$surrealdb::private::sql::Value")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Value { - // These value types are simple values which - // can be used in query responses sent to - // the client. They typically do not need to - // be computed, unless an un-computed value - // is present inside an Array or Object type. - // These types can also be used within indexes - // and sort according to their order below. - #[default] - None, - Null, - Bool(bool), - Number(Number), - Strand(Strand), - Duration(Duration), - Datetime(Datetime), - Uuid(Uuid), - Array(Array), - Object(Object), - Geometry(Geometry), - Bytes(Bytes), - Thing(Thing), - // These Value types are un-computed values - // and are not used in query responses sent - // to the client. These types need to be - // computed, in order to convert them into - // one of the simple types listed above. - // These types are first computed into a - // simple type before being used in indexes. - Param(Param), - Idiom(Idiom), - Table(Table), - Mock(Mock), - Regex(Regex), - Cast(Box), - Block(Box), - Range(Box), - Edges(Box), - Future(Box), - Constant(Constant), - Function(Box), - Subquery(Box), - Expression(Box), - Query(Query), - Model(Box), - // Add new variants here -} - -impl Eq for Value {} - -impl Ord for Value { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap_or(Ordering::Equal) - } -} - -impl From for Value { - #[inline] - fn from(v: bool) -> Self { - Value::Bool(v) - } -} - -impl From for Value { - fn from(v: Uuid) -> Self { - Value::Uuid(v) - } -} - -impl From for Value { - fn from(v: Param) -> Self { - Value::Param(v) - } -} - -impl From for Value { - fn from(v: Idiom) -> Self { - Value::Idiom(v) - } -} - -impl From for Value { - fn from(v: Mock) -> Self { - Value::Mock(v) - } -} - -impl From
for Value { - fn from(v: Table) -> Self { - Value::Table(v) - } -} - -impl From for Value { - fn from(v: Thing) -> Self { - Value::Thing(v) - } -} - -impl From for Value { - fn from(v: Regex) -> Self { - Value::Regex(v) - } -} - -impl From for Value { - fn from(v: Bytes) -> Self { - Value::Bytes(v) - } -} - -impl From for Value { - fn from(v: Array) -> Self { - Value::Array(v) - } -} - -impl From for Value { - fn from(v: Object) -> Self { - Value::Object(v) - } -} - -impl From for Value { - fn from(v: Number) -> Self { - Value::Number(v) - } -} - -impl From for Value { - fn from(v: Strand) -> Self { - Value::Strand(v) - } -} - -impl From for Value { - fn from(v: Geometry) -> Self { - Value::Geometry(v) - } -} - -impl From for Value { - fn from(v: Datetime) -> Self { - Value::Datetime(v) - } -} - -impl From for Value { - fn from(v: Duration) -> Self { - Value::Duration(v) - } -} - -impl From for Value { - fn from(v: Constant) -> Self { - Value::Constant(v) - } -} - -impl From for Value { - fn from(v: Block) -> Self { - Value::Block(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Range) -> Self { - Value::Range(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Edges) -> Self { - Value::Edges(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Future) -> Self { - Value::Future(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Cast) -> Self { - Value::Cast(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Function) -> Self { - Value::Function(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Model) -> Self { - Value::Model(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Subquery) -> Self { - Value::Subquery(Box::new(v)) - } -} - -impl From for Value { - fn from(v: Expression) -> Self { - Value::Expression(Box::new(v)) - } -} - -impl From> for Value { - fn from(v: Box) -> Self { - Value::Edges(v) - } -} - -impl From for Value { - fn from(v: i8) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: i16) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: i32) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: i64) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: i128) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: isize) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: u8) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: u16) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: u32) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: u64) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: u128) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: usize) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: f32) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: f64) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: Decimal) -> Self { - Value::Number(Number::from(v)) - } -} - -impl From for Value { - fn from(v: String) -> Self { - Self::Strand(Strand::from(v)) - } -} - -impl From<&str> for Value { - fn from(v: &str) -> Self { - Self::Strand(Strand::from(v)) - } -} - -impl From> for Value { - fn from(v: DateTime) -> Self { - Value::Datetime(Datetime::from(v)) - } -} - -impl From<(f64, f64)> for Value { - fn from(v: (f64, f64)) -> Self { - Value::Geometry(Geometry::from(v)) - } -} - -impl From<[f64; 2]> for Value { - fn from(v: [f64; 2]) -> Self { - Value::Geometry(Geometry::from(v)) - } -} - -impl From> for Value { - fn from(v: Point) -> Self { - Value::Geometry(Geometry::from(v)) - } -} - -impl From for Value { - fn from(v: Operation) -> Self { - Value::Object(Object::from(v)) - } -} - -impl From for Value { - fn from(v: uuid::Uuid) -> Self { - Value::Uuid(Uuid(v)) - } -} - -impl From> for Value { - fn from(v: Vec<&str>) -> Self { - Value::Array(Array::from(v)) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Value::Array(Array::from(v)) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Value::Array(Array::from(v)) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Value::Array(Array::from(v)) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Value::Array(Array::from(v)) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Value::Array(Array::from(v)) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Value::Array(Array::from(v)) - } -} - -impl From> for Value { - fn from(v: HashMap<&str, Value>) -> Self { - Value::Object(Object::from(v)) - } -} - -impl From> for Value { - fn from(v: HashMap) -> Self { - Value::Object(Object::from(v)) - } -} - -impl From> for Value { - fn from(v: BTreeMap) -> Self { - Value::Object(Object::from(v)) - } -} - -impl From> for Value { - fn from(v: BTreeMap<&str, Value>) -> Self { - Value::Object(Object::from(v)) - } -} - -impl From> for Value { - fn from(v: Option) -> Self { - match v { - Some(v) => v, - None => Value::None, - } - } -} - -impl From> for Value { - fn from(v: Option) -> Self { - match v { - Some(v) => Value::from(v), - None => Value::None, - } - } -} - -impl From> for Value { - fn from(v: Option) -> Self { - match v { - Some(v) => Value::from(v), - None => Value::None, - } - } -} - -impl From for Value { - fn from(v: Id) -> Self { - match v { - Id::Number(v) => v.into(), - Id::String(v) => v.into(), - Id::Array(v) => v.into(), - Id::Object(v) => v.into(), - Id::Generate(v) => match v { - Gen::Rand => Id::rand().into(), - Gen::Ulid => Id::ulid().into(), - Gen::Uuid => Id::uuid().into(), - }, - } - } -} - -impl From for Value { - fn from(q: Query) -> Self { - Value::Query(q) - } -} - -impl TryFrom for i8 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "i8")), - } - } -} - -impl TryFrom for i16 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "i16")), - } - } -} - -impl TryFrom for i32 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "i32")), - } - } -} - -impl TryFrom for i64 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "i64")), - } - } -} - -impl TryFrom for i128 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "i128")), - } - } -} - -impl TryFrom for u8 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "u8")), - } - } -} - -impl TryFrom for u16 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "u16")), - } - } -} - -impl TryFrom for u32 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "u32")), - } - } -} - -impl TryFrom for u64 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "u64")), - } - } -} - -impl TryFrom for u128 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "u128")), - } - } -} - -impl TryFrom for f32 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "f32")), - } - } -} - -impl TryFrom for f64 { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "f64")), - } - } -} - -impl TryFrom for Decimal { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => x.try_into(), - _ => Err(Error::TryFrom(value.to_string(), "Decimal")), - } - } -} - -impl TryFrom for String { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Strand(x) => Ok(x.into()), - _ => Err(Error::TryFrom(value.to_string(), "String")), - } - } -} - -impl TryFrom for bool { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Bool(v) => Ok(v), - _ => Err(Error::TryFrom(value.to_string(), "bool")), - } - } -} - -impl TryFrom for std::time::Duration { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Duration(x) => Ok(x.into()), - _ => Err(Error::TryFrom(value.to_string(), "time::Duration")), - } - } -} - -impl TryFrom for DateTime { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Datetime(x) => Ok(x.into()), - _ => Err(Error::TryFrom(value.to_string(), "chrono::DateTime")), - } - } -} - -impl TryFrom for uuid::Uuid { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Uuid(x) => Ok(x.into()), - _ => Err(Error::TryFrom(value.to_string(), "uuid::Uuid")), - } - } -} - -impl TryFrom for Vec { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Array(x) => Ok(x.into()), - _ => Err(Error::TryFrom(value.to_string(), "Vec")), - } - } -} - -impl TryFrom for Number { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Number(x) => Ok(x), - _ => Err(Error::TryFrom(value.to_string(), "Number")), - } - } -} - -impl TryFrom<&Value> for Number { - type Error = Error; - fn try_from(value: &Value) -> Result { - match value { - Value::Number(x) => Ok(x.clone()), - _ => Err(Error::TryFrom(value.to_string(), "Number")), - } - } -} - -impl TryFrom for Datetime { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Datetime(x) => Ok(x), - _ => Err(Error::TryFrom(value.to_string(), "Datetime")), - } - } -} - -impl TryFrom for Object { - type Error = Error; - fn try_from(value: Value) -> Result { - match value { - Value::Object(x) => Ok(x), - _ => Err(Error::TryFrom(value.to_string(), "Object")), - } - } -} - -impl FromIterator for Value { - fn from_iter>(iter: I) -> Self { - Value::Array(Array(iter.into_iter().collect())) - } -} - -impl FromIterator<(String, Value)> for Value { - fn from_iter>(iter: I) -> Self { - Value::Object(Object(iter.into_iter().collect())) - } -} - -impl Value { - // ----------------------------------- - // Initial record value - // ----------------------------------- - - /// Create an empty Object Value - pub fn base() -> Self { - Value::Object(Object::default()) - } - - // ----------------------------------- - // Builtin types - // ----------------------------------- - - /// Convert this Value to a Result - pub fn ok(self) -> Result { - Ok(self) - } - - /// Convert this Value to an Option - pub fn some(self) -> Option { - match self { - Value::None => None, - val => Some(val), - } - } - - // ----------------------------------- - // Simple value detection - // ----------------------------------- - - /// Check if this Value is NONE or NULL - pub fn is_none_or_null(&self) -> bool { - matches!(self, Value::None | Value::Null) - } - - /// Check if this Value is NONE - pub fn is_none(&self) -> bool { - matches!(self, Value::None) - } - - /// Check if this Value is NULL - pub fn is_null(&self) -> bool { - matches!(self, Value::Null) - } - - /// Check if this Value not NONE or NULL - pub fn is_some(&self) -> bool { - !self.is_none() && !self.is_null() - } - - /// Check if this Value is a boolean value - pub fn is_bool(&self) -> bool { - matches!(self, Value::Bool(_)) - } - - /// Check if this Value is TRUE or 'true' - pub fn is_true(&self) -> bool { - matches!(self, Value::Bool(true)) - } - - /// Check if this Value is FALSE or 'false' - pub fn is_false(&self) -> bool { - matches!(self, Value::Bool(false)) - } - - /// Check if this Value is truthy - pub fn is_truthy(&self) -> bool { - match self { - Value::Bool(v) => *v, - Value::Uuid(_) => true, - Value::Thing(_) => true, - Value::Geometry(_) => true, - Value::Array(v) => !v.is_empty(), - Value::Object(v) => !v.is_empty(), - Value::Strand(v) => !v.is_empty() && !v.eq_ignore_ascii_case("false"), - Value::Number(v) => v.is_truthy(), - Value::Duration(v) => v.as_nanos() > 0, - Value::Datetime(v) => v.timestamp() > 0, - _ => false, - } - } - - /// Check if this Value is a UUID - pub fn is_uuid(&self) -> bool { - matches!(self, Value::Uuid(_)) - } - - /// Check if this Value is a Thing - pub fn is_thing(&self) -> bool { - matches!(self, Value::Thing(_)) - } - - /// Check if this Value is a Mock - pub fn is_mock(&self) -> bool { - matches!(self, Value::Mock(_)) - } - - /// Check if this Value is a Param - pub fn is_param(&self) -> bool { - matches!(self, Value::Param(_)) - } - - /// Check if this Value is a Range - pub fn is_range(&self) -> bool { - matches!(self, Value::Range(_)) - } - - /// Check if this Value is a Table - pub fn is_table(&self) -> bool { - matches!(self, Value::Table(_)) - } - - /// Check if this Value is a Strand - pub fn is_strand(&self) -> bool { - matches!(self, Value::Strand(_)) - } - - /// Check if this Value is a Query - pub fn is_query(&self) -> bool { - matches!(self, Value::Query(_)) - } - - /// Check if this Value is a float Number - pub fn is_bytes(&self) -> bool { - matches!(self, Value::Bytes(_)) - } - - /// Check if this Value is an Array - pub fn is_array(&self) -> bool { - matches!(self, Value::Array(_)) - } - - /// Check if this Value is an Object - pub fn is_object(&self) -> bool { - matches!(self, Value::Object(_)) - } - - /// Check if this Value is a Number - pub fn is_number(&self) -> bool { - matches!(self, Value::Number(_)) - } - - /// Check if this Value is a Datetime - pub fn is_datetime(&self) -> bool { - matches!(self, Value::Datetime(_)) - } - - /// Check if this Value is a Duration - pub fn is_duration(&self) -> bool { - matches!(self, Value::Duration(_)) - } - - /// Check if this Value is a Thing - pub fn is_record(&self) -> bool { - matches!(self, Value::Thing(_)) - } - - /// Check if this Value is a Thing, and belongs to a certain table - pub fn is_record_of_table(&self, table: String) -> bool { - match self { - Value::Thing(Thing { - tb, - .. - }) => *tb == table, - _ => false, - } - } - - /// Check if this Value is a Geometry - pub fn is_geometry(&self) -> bool { - matches!(self, Value::Geometry(_)) - } - - /// Check if this Value is an int Number - pub fn is_int(&self) -> bool { - matches!(self, Value::Number(Number::Int(_))) - } - - /// Check if this Value is a float Number - pub fn is_float(&self) -> bool { - matches!(self, Value::Number(Number::Float(_))) - } - - /// Check if this Value is a decimal Number - pub fn is_decimal(&self) -> bool { - matches!(self, Value::Number(Number::Decimal(_))) - } - - /// Check if this Value is a Number but is a NAN - pub fn is_nan(&self) -> bool { - matches!(self, Value::Number(v) if v.is_nan()) - } - - /// Check if this Value is a Number and is an integer - pub fn is_integer(&self) -> bool { - matches!(self, Value::Number(v) if v.is_integer()) - } - - /// Check if this Value is a Number and is positive - pub fn is_positive(&self) -> bool { - matches!(self, Value::Number(v) if v.is_positive()) - } - - /// Check if this Value is a Number and is negative - pub fn is_negative(&self) -> bool { - matches!(self, Value::Number(v) if v.is_negative()) - } - - /// Check if this Value is a Number and is zero or positive - pub fn is_zero_or_positive(&self) -> bool { - matches!(self, Value::Number(v) if v.is_zero_or_positive()) - } - - /// Check if this Value is a Number and is zero or negative - pub fn is_zero_or_negative(&self) -> bool { - matches!(self, Value::Number(v) if v.is_zero_or_negative()) - } - - /// Check if this Value is a Thing of a specific type - pub fn is_record_type(&self, types: &[Table]) -> bool { - match self { - Value::Thing(v) => types.is_empty() || types.iter().any(|tb| tb.0 == v.tb), - _ => false, - } - } - - /// Check if this Value is a Geometry of a specific type - pub fn is_geometry_type(&self, types: &[String]) -> bool { - match self { - Value::Geometry(Geometry::Point(_)) => { - types.iter().any(|t| matches!(t.as_str(), "feature" | "point")) - } - Value::Geometry(Geometry::Line(_)) => { - types.iter().any(|t| matches!(t.as_str(), "feature" | "line")) - } - Value::Geometry(Geometry::Polygon(_)) => { - types.iter().any(|t| matches!(t.as_str(), "feature" | "polygon")) - } - Value::Geometry(Geometry::MultiPoint(_)) => { - types.iter().any(|t| matches!(t.as_str(), "feature" | "multipoint")) - } - Value::Geometry(Geometry::MultiLine(_)) => { - types.iter().any(|t| matches!(t.as_str(), "feature" | "multiline")) - } - Value::Geometry(Geometry::MultiPolygon(_)) => { - types.iter().any(|t| matches!(t.as_str(), "feature" | "multipolygon")) - } - Value::Geometry(Geometry::Collection(_)) => { - types.iter().any(|t| matches!(t.as_str(), "feature" | "collection")) - } - _ => false, - } - } - - // ----------------------------------- - // Simple conversion of value - // ----------------------------------- - - /// Convert this Value into a String - pub fn as_string(self) -> String { - match self { - Value::Strand(v) => v.0, - Value::Uuid(v) => v.to_raw(), - Value::Datetime(v) => v.to_raw(), - _ => self.to_string(), - } - } - - /// Converts this Value into an unquoted String - pub fn as_raw_string(self) -> String { - match self { - Value::Strand(v) => v.0, - Value::Uuid(v) => v.to_raw(), - Value::Datetime(v) => v.to_raw(), - _ => self.to_string(), - } - } - - // ----------------------------------- - // Expensive conversion of value - // ----------------------------------- - - /// Converts this Value into an unquoted String - pub fn to_raw_string(&self) -> String { - match self { - Value::Strand(v) => v.0.to_owned(), - Value::Uuid(v) => v.to_raw(), - Value::Datetime(v) => v.to_raw(), - _ => self.to_string(), - } - } - - /// Converts this Value into a field name - pub fn to_idiom(&self) -> Idiom { - match self { - Value::Idiom(v) => v.simplify(), - Value::Param(v) => v.to_raw().into(), - Value::Strand(v) => v.0.to_string().into(), - Value::Datetime(v) => v.0.to_string().into(), - Value::Future(_) => "future".to_string().into(), - Value::Function(v) => v.to_idiom(), - _ => self.to_string().into(), - } - } - - /// Returns if this value can be the start of a idiom production. - pub fn can_start_idiom(&self) -> bool { - match self { - Value::Function(x) => !x.is_script(), - Value::Model(_) - | Value::Subquery(_) - | Value::Constant(_) - | Value::Datetime(_) - | Value::Duration(_) - | Value::Uuid(_) - | Value::Number(_) - | Value::Object(_) - | Value::Array(_) - | Value::Param(_) - | Value::Edges(_) - | Value::Thing(_) - | Value::Table(_) => true, - _ => false, - } - } - - /// Try to convert this Value into a set of JSONPatch operations - pub fn to_operations(&self) -> Result, Error> { - match self { - Value::Array(v) => v - .iter() - .map(|v| match v { - Value::Object(v) => v.to_operation(), - _ => Err(Error::InvalidPatch { - message: String::from("Operation must be an object"), - }), - }) - .collect::, Error>>(), - _ => Err(Error::InvalidPatch { - message: String::from("Operations must be an array"), - }), - } - } - - /// Converts a `surrealdb::sq::Value` into a `serde_json::Value` - /// - /// This converts certain types like `Thing` into their simpler formats - /// instead of the format used internally by SurrealDB. - pub fn into_json(self) -> Json { - self.into() - } - - // ----------------------------------- - // Simple conversion of values - // ----------------------------------- - - /// Treat a string as a table name - pub fn could_be_table(self) -> Value { - match self { - Value::Strand(v) => Value::Table(v.0.into()), - _ => self, - } - } - - // ----------------------------------- - // 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", - Self::Geometry(Geometry::Line(_)) => "geometry", - Self::Geometry(Geometry::Polygon(_)) => "geometry", - Self::Geometry(Geometry::MultiPoint(_)) => "geometry", - Self::Geometry(Geometry::MultiLine(_)) => "geometry", - Self::Geometry(Geometry::MultiPolygon(_)) => "geometry", - Self::Geometry(Geometry::Collection(_)) => "geometry", - 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 { - // Attempt to convert to the desired type - let res = match kind { - Kind::Any => Ok(self), - Kind::Null => self.coerce_to_null(), - 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), - 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(), - }) - } - }; - // Check for any conversion errors - match res { - // There was a conversion error - Err(Error::CoerceTo { - from, - .. - }) => Err(Error::CoerceTo { - from, - into: kind.to_string(), - }), - // There was a different error - Err(e) => Err(e), - // Everything converted ok - Ok(v) => Ok(v), - } - } - - /// Try to coerce this value to an `i64` - #[doc(hidden)] - pub fn coerce_to_i64(self) -> Result { - 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(v)) if v.is_integer() => match v.try_into() { - // The Decimal can be represented as an i64 - Ok(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 { - 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(v)) if v.is_integer() => match v.try_into() { - // The Decimal can be represented as an u64 - Ok(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 { - 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(v)) => match v.try_into() { - // The Decimal can be represented as a f64 - Ok(v) => Ok(v), - // This Decimal loses precision - _ => 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 `null` - pub(crate) fn coerce_to_null(self) -> Result { - match self { - // Allow any null value - Value::Null => Ok(Value::Null), - // Anything else raises an error - _ => Err(Error::CoerceTo { - from: self, - into: "null".into(), - }), - } - } - - /// Try to coerce this value to a `bool` - pub(crate) fn coerce_to_bool(self) -> Result { - 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 { - 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(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 { - 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)), - // This 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 { - 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(v)) => match Decimal::from_i64(v) { - // The Int can be represented as a Decimal - Some(v) => Ok(Number::Decimal(v)), - // This 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(v)) => match Decimal::from_f64(v) { - // The Float can be represented as a Decimal - Some(v) => Ok(Number::Decimal(v)), - // This 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 { - 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 `Regex` - pub(crate) fn coerce_to_regex(self) -> Result { - match self { - // Allow any Regex value - Value::Regex(v) => Ok(v), - // Allow any string value - Value::Strand(v) => Ok(v.as_str().parse()?), - // Anything else raises an error - _ => Err(Error::CoerceTo { - from: self, - into: "regex".into(), - }), - } - } - - /// Try to coerce this value to a `String` - pub(crate) fn coerce_to_string(self) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - self.coerce_to_array()? - .into_iter() - .map(|value| value.coerce_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::CoerceTo { - from, - .. - } => Error::CoerceTo { - from, - into: format!("array<{kind}>"), - }, - 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 { - self.coerce_to_array()? - .into_iter() - .map(|value| value.coerce_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::CoerceTo { - from, - .. - } => Error::CoerceTo { - from, - into: format!("array<{kind}, {len}>"), - }, - e => e, - }) - .and_then(|v| match v.len() { - v if v > *len as usize => Err(Error::LengthInvalid { - kind: format!("array<{kind}, {len}>"), - 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 { - self.coerce_to_array()? - .uniq() - .into_iter() - .map(|value| value.coerce_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::CoerceTo { - from, - .. - } => Error::CoerceTo { - from, - into: format!("set<{kind}>"), - }, - 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 { - self.coerce_to_array()? - .uniq() - .into_iter() - .map(|value| value.coerce_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::CoerceTo { - from, - .. - } => Error::CoerceTo { - from, - into: format!("set<{kind}, {len}>"), - }, - e => e, - }) - .and_then(|v| match v.len() { - v if v > *len as usize => Err(Error::LengthInvalid { - kind: format!("set<{kind}, {len}>"), - size: v, - }), - _ => Ok(v), - }) - } - - // ----------------------------------- - // Advanced type conversion of values - // ----------------------------------- - - /// Try to convert this value to the specified `Kind` - pub(crate) fn convert_to(self, kind: &Kind) -> Result { - // Attempt to convert to the desired type - let res = match kind { - Kind::Any => Ok(self), - Kind::Null => self.convert_to_null(), - Kind::Bool => self.convert_to_bool().map(Value::from), - Kind::Int => self.convert_to_int().map(Value::from), - Kind::Float => self.convert_to_float().map(Value::from), - Kind::Decimal => self.convert_to_decimal().map(Value::from), - Kind::Number => self.convert_to_number().map(Value::from), - Kind::String => self.convert_to_strand().map(Value::from), - Kind::Datetime => self.convert_to_datetime().map(Value::from), - Kind::Duration => self.convert_to_duration().map(Value::from), - Kind::Object => self.convert_to_object().map(Value::from), - 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) => 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), - }, - Kind::Geometry(t) => match t.is_empty() { - true => self.convert_to_geometry().map(Value::from), - false => self.convert_to_geometry_type(t).map(Value::from), - }, - Kind::Option(k) => match self { - Self::None => Ok(Self::None), - v => v.convert_to(k), - }, - Kind::Either(k) => { - let mut val = self; - for k in k { - match val.convert_to(k) { - Err(Error::ConvertTo { - from, - .. - }) => val = from, - Err(e) => return Err(e), - Ok(v) => return Ok(v), - } - } - Err(Error::ConvertTo { - from: val, - into: kind.to_string(), - }) - } - }; - // Check for any conversion errors - match res { - // There was a conversion error - Err(Error::ConvertTo { - from, - .. - }) => Err(Error::ConvertTo { - from, - into: kind.to_string(), - }), - // There was a different error - Err(e) => Err(e), - // Everything converted ok - Ok(v) => Ok(v), - } - } - - /// Try to convert this value to a `null` - pub(crate) fn convert_to_null(self) -> Result { - match self { - // Allow any boolean value - Value::Null => Ok(Value::Null), - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "null".into(), - }), - } - } - - /// Try to convert this value to a `bool` - pub(crate) fn convert_to_bool(self) -> Result { - match self { - // Allow any boolean value - Value::Bool(v) => Ok(v), - // Attempt to convert a string value - Value::Strand(ref v) => match v.parse::() { - // The string can be represented as a Float - Ok(v) => Ok(v), - // This string is not a float - _ => Err(Error::ConvertTo { - from: self, - into: "bool".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "bool".into(), - }), - } - } - - /// Try to convert this value to an integer `Number` - pub(crate) fn convert_to_int(self) -> Result { - 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(v)) if v.is_integer() => match v.try_into() { - // The Decimal can be represented as an Int - Ok(v) => Ok(Number::Int(v)), - // The Decimal is out of bounds - _ => Err(Error::ConvertTo { - from: self, - into: "int".into(), - }), - }, - // Attempt to convert a string value - Value::Strand(ref v) => match v.parse::() { - // The string can be represented as a Float - Ok(v) => Ok(Number::Int(v)), - // This string is not a float - _ => Err(Error::ConvertTo { - from: self, - into: "int".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "int".into(), - }), - } - } - - /// Try to convert this value to a float `Number` - pub(crate) fn convert_to_float(self) -> Result { - 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(v)) => match v.try_into() { - // The Decimal can be represented as a Float - Ok(v) => Ok(Number::Float(v)), - // The Decimal loses precision - _ => Err(Error::ConvertTo { - from: self, - into: "float".into(), - }), - }, - // Attempt to convert a string value - Value::Strand(ref v) => match v.parse::() { - // The string can be represented as a Float - Ok(v) => Ok(Number::Float(v)), - // This string is not a float - _ => Err(Error::ConvertTo { - from: self, - into: "float".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "float".into(), - }), - } - } - - /// Try to convert this value to a decimal `Number` - pub(crate) fn convert_to_decimal(self) -> Result { - match self { - // Allow any decimal number - Value::Number(v) if v.is_decimal() => Ok(v), - // Attempt to convert an int number - // #[allow(clippy::unnecessary_fallible_conversions)] // `Decimal::from` can panic - // `clippy::unnecessary_fallible_conversions` not available on Rust < v1.75 - #[allow(warnings)] - Value::Number(Number::Int(ref v)) => match Decimal::try_from(*v) { - // The Int can be represented as a Decimal - Ok(v) => Ok(Number::Decimal(v)), - // This Int does not convert to a Decimal - _ => Err(Error::ConvertTo { - from: self, - into: "decimal".into(), - }), - }, - // Attempt to convert an float number - Value::Number(Number::Float(ref v)) => match Decimal::try_from(*v) { - // The Float can be represented as a Decimal - Ok(v) => Ok(Number::Decimal(v)), - // This Float does not convert to a Decimal - _ => Err(Error::ConvertTo { - from: self, - into: "decimal".into(), - }), - }, - // Attempt to convert a string value - Value::Strand(ref v) => match Decimal::from_str(v) { - // The string can be represented as a Decimal - Ok(v) => Ok(Number::Decimal(v)), - // This string is not a Decimal - _ => Err(Error::ConvertTo { - from: self, - into: "decimal".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "decimal".into(), - }), - } - } - - /// Try to convert this value to a `Number` - pub(crate) fn convert_to_number(self) -> Result { - match self { - // Allow any number - Value::Number(v) => Ok(v), - // Attempt to convert a string value - Value::Strand(ref v) => match Number::from_str(v) { - // The string can be represented as a Float - Ok(v) => Ok(v), - // This string is not a float - _ => Err(Error::ConvertTo { - from: self, - into: "number".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "number".into(), - }), - } - } - - /// Try to convert this value to a `String` - #[doc(hidden)] - pub fn convert_to_string(self) -> Result { - match self { - // Bytes can't convert to strings - Value::Bytes(_) => Err(Error::ConvertTo { - from: self, - into: "string".into(), - }), - // None can't convert to a string - Value::None => Err(Error::ConvertTo { - from: self, - into: "string".into(), - }), - // Null can't convert to a string - Value::Null => Err(Error::ConvertTo { - from: self, - into: "string".into(), - }), - // Stringify anything else - _ => Ok(self.as_string()), - } - } - - /// Try to convert this value to a `Strand` - pub(crate) fn convert_to_strand(self) -> Result { - match self { - // Bytes can't convert to strings - Value::Bytes(_) => Err(Error::ConvertTo { - from: self, - into: "string".into(), - }), - // None can't convert to a string - Value::None => Err(Error::ConvertTo { - from: self, - into: "string".into(), - }), - // Null can't convert to a string - Value::Null => Err(Error::ConvertTo { - from: self, - into: "string".into(), - }), - // Allow any string value - Value::Strand(v) => Ok(v), - // Stringify anything else - Value::Uuid(v) => Ok(v.to_raw().into()), - // Stringify anything else - Value::Datetime(v) => Ok(v.to_raw().into()), - // Stringify anything else - _ => Ok(self.to_string().into()), - } - } - - /// Try to convert this value to a `Uuid` - pub(crate) fn convert_to_uuid(self) -> Result { - match self { - // Uuids are allowed - Value::Uuid(v) => Ok(v), - // Attempt to parse a string - Value::Strand(ref v) => match Uuid::try_from(v.as_str()) { - // The string can be represented as a uuid - Ok(v) => Ok(v), - // This string is not a uuid - Err(_) => Err(Error::ConvertTo { - from: self, - into: "uuid".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "uuid".into(), - }), - } - } - - /// Try to convert this value to a `Datetime` - pub(crate) fn convert_to_datetime(self) -> Result { - match self { - // Datetimes are allowed - Value::Datetime(v) => Ok(v), - // Attempt to parse a string - Value::Strand(ref v) => match Datetime::try_from(v.as_str()) { - // The string can be represented as a datetime - Ok(v) => Ok(v), - // This string is not a datetime - Err(_) => Err(Error::ConvertTo { - from: self, - into: "datetime".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "datetime".into(), - }), - } - } - - /// Try to convert this value to a `Duration` - pub(crate) fn convert_to_duration(self) -> Result { - match self { - // Durations are allowed - Value::Duration(v) => Ok(v), - // Attempt to parse a string - Value::Strand(ref v) => match Duration::try_from(v.as_str()) { - // The string can be represented as a duration - Ok(v) => Ok(v), - // This string is not a duration - Err(_) => Err(Error::ConvertTo { - from: self, - into: "duration".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "duration".into(), - }), - } - } - - /// Try to convert this value to a `Bytes` - pub(crate) fn convert_to_bytes(self) -> Result { - match self { - // Bytes are allowed - Value::Bytes(v) => Ok(v), - // Strings can be converted to bytes - Value::Strand(s) => Ok(Bytes(s.0.into_bytes())), - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "bytes".into(), - }), - } - } - - /// Try to convert this value to an `Object` - pub(crate) fn convert_to_object(self) -> Result { - match self { - // Objects are allowed - Value::Object(v) => Ok(v), - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "object".into(), - }), - } - } - - /// Try to convert this value to an `Array` - pub(crate) fn convert_to_array(self) -> Result { - match self { - // Arrays are allowed - Value::Array(v) => Ok(v), - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "array".into(), - }), - } - } - - /// Try to convert this value to an `Geometry` point - pub(crate) fn convert_to_point(self) -> Result { - match self { - // Geometry points are allowed - Value::Geometry(Geometry::Point(v)) => Ok(v.into()), - // An array of two floats are allowed - Value::Array(ref v) if v.len() == 2 => match v.as_slice() { - // The array can be represented as a point - [Value::Number(v), Value::Number(w)] => Ok((v.to_float(), w.to_float()).into()), - // The array is not a geometry point - _ => Err(Error::ConvertTo { - from: self, - into: "point".into(), - }), - }, - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "point".into(), - }), - } - } - - /// Try to convert this value to a Record or `Thing` - pub(crate) fn convert_to_record(self) -> Result { - match self { - // Records are allowed - Value::Thing(v) => Ok(v), - Value::Strand(v) => Thing::try_from(v.as_str()).map_err(move |_| Error::ConvertTo { - from: Value::Strand(v), - into: "record".into(), - }), - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "record".into(), - }), - } - } - - /// Try to convert this value to an `Geometry` type - pub(crate) fn convert_to_geometry(self) -> Result { - match self { - // Geometries are allowed - Value::Geometry(v) => Ok(v), - // Anything else raises an error - _ => Err(Error::ConvertTo { - from: self, - into: "geometry".into(), - }), - } - } - - /// Try to convert this value to a Record of a certain type - pub(crate) fn convert_to_record_type(self, val: &[Table]) -> Result { - 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::ConvertTo { - from: self, - into: "record".into(), - }), - } - } - - /// Try to convert this value to a `Geometry` of a certain type - pub(crate) fn convert_to_geometry_type(self, val: &[String]) -> Result { - 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::ConvertTo { - from: self, - into: "geometry".into(), - }), - } - } - - /// Try to convert this value to ab `Array` of a certain type - pub(crate) fn convert_to_array_type(self, kind: &Kind) -> Result { - self.convert_to_array()? - .into_iter() - .map(|value| value.convert_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::ConvertTo { - from, - .. - } => Error::ConvertTo { - from, - into: format!("array<{kind}>"), - }, - e => e, - }) - } - - /// 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 { - self.convert_to_array()? - .into_iter() - .map(|value| value.convert_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::ConvertTo { - from, - .. - } => Error::ConvertTo { - from, - into: format!("array<{kind}, {len}>"), - }, - e => e, - }) - .and_then(|v| match v.len() { - v if v > *len as usize => Err(Error::LengthInvalid { - kind: format!("array<{kind}, {len}>"), - size: v, - }), - _ => 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 { - self.convert_to_array()? - .uniq() - .into_iter() - .map(|value| value.convert_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::ConvertTo { - from, - .. - } => Error::ConvertTo { - from, - into: format!("set<{kind}>"), - }, - 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 { - self.convert_to_array()? - .uniq() - .into_iter() - .map(|value| value.convert_to(kind)) - .collect::>() - .map_err(|e| match e { - Error::ConvertTo { - from, - .. - } => Error::ConvertTo { - from, - into: format!("set<{kind}, {len}>"), - }, - e => e, - }) - .and_then(|v| match v.len() { - v if v > *len as usize => Err(Error::LengthInvalid { - kind: format!("set<{kind}, {len}>"), - size: v, - }), - _ => Ok(v), - }) - } - - // ----------------------------------- - // Record ID extraction - // ----------------------------------- - - /// Fetch the record id if there is one - pub fn record(self) -> Option { - match self { - // This is an object so look for the id field - Value::Object(mut v) => match v.remove("id") { - Some(Value::Thing(v)) => Some(v), - _ => None, - }, - // This is an array so take the first item - Value::Array(mut v) => match v.len() { - 1 => v.remove(0).record(), - _ => None, - }, - // This is a record id already - Value::Thing(v) => Some(v), - // There is no valid record id - _ => None, - } - } - - // ----------------------------------- - // JSON Path conversion - // ----------------------------------- - - /// Converts this Value into a JSONPatch path - pub(crate) fn jsonpath(&self) -> Idiom { - self.to_raw_string() - .as_str() - .trim_start_matches('/') - .split(&['.', '/'][..]) - .map(Part::from) - .collect::>() - .into() - } - - // ----------------------------------- - // JSON Path conversion - // ----------------------------------- - - /// Checks whether this value is a static value - pub(crate) fn is_static(&self) -> bool { - match self { - Value::None => true, - Value::Null => true, - Value::Bool(_) => true, - Value::Bytes(_) => true, - Value::Uuid(_) => true, - Value::Number(_) => true, - Value::Strand(_) => true, - Value::Duration(_) => true, - Value::Datetime(_) => true, - Value::Geometry(_) => true, - Value::Array(v) => v.is_static(), - Value::Object(v) => v.is_static(), - Value::Expression(v) => v.is_static(), - Value::Function(v) => v.is_static(), - Value::Constant(_) => true, - _ => false, - } - } - - // ----------------------------------- - // Value operations - // ----------------------------------- - - /// Check if this Value is equal to another Value - pub fn equal(&self, other: &Value) -> bool { - match self { - Value::None => other.is_none(), - Value::Null => other.is_null(), - Value::Bool(v) => match other { - Value::Bool(w) => v == w, - _ => false, - }, - Value::Uuid(v) => match other { - Value::Uuid(w) => v == w, - Value::Regex(w) => w.regex().is_match(v.to_raw().as_str()), - _ => false, - }, - Value::Thing(v) => match other { - Value::Thing(w) => v == w, - Value::Regex(w) => w.regex().is_match(v.to_raw().as_str()), - _ => false, - }, - Value::Strand(v) => match other { - Value::Strand(w) => v == w, - Value::Regex(w) => w.regex().is_match(v.as_str()), - _ => false, - }, - Value::Regex(v) => match other { - Value::Regex(w) => v == w, - Value::Uuid(w) => v.regex().is_match(w.to_raw().as_str()), - Value::Thing(w) => v.regex().is_match(w.to_raw().as_str()), - Value::Strand(w) => v.regex().is_match(w.as_str()), - _ => false, - }, - Value::Array(v) => match other { - Value::Array(w) => v == w, - _ => false, - }, - Value::Object(v) => match other { - Value::Object(w) => v == w, - _ => false, - }, - Value::Number(v) => match other { - Value::Number(w) => v == w, - _ => false, - }, - Value::Geometry(v) => match other { - Value::Geometry(w) => v == w, - _ => false, - }, - Value::Duration(v) => match other { - Value::Duration(w) => v == w, - _ => false, - }, - Value::Datetime(v) => match other { - Value::Datetime(w) => v == w, - _ => false, - }, - _ => self == other, - } - } - - /// Check if all Values in an Array are equal to another Value - pub fn all_equal(&self, other: &Value) -> bool { - match self { - Value::Array(v) => v.iter().all(|v| v.equal(other)), - _ => self.equal(other), - } - } - - /// Check if any Values in an Array are equal to another Value - pub fn any_equal(&self, other: &Value) -> bool { - match self { - Value::Array(v) => v.iter().any(|v| v.equal(other)), - _ => self.equal(other), - } - } - - /// Fuzzy check if this Value is equal to another Value - pub fn fuzzy(&self, other: &Value) -> bool { - match self { - Value::Uuid(v) => match other { - Value::Strand(w) => v.to_raw().as_str().fuzzy_match(w.as_str()), - _ => false, - }, - Value::Strand(v) => match other { - Value::Strand(w) => v.as_str().fuzzy_match(w.as_str()), - _ => false, - }, - _ => self.equal(other), - } - } - - /// Fuzzy check if all Values in an Array are equal to another Value - pub fn all_fuzzy(&self, other: &Value) -> bool { - match self { - Value::Array(v) => v.iter().all(|v| v.fuzzy(other)), - _ => self.fuzzy(other), - } - } - - /// Fuzzy check if any Values in an Array are equal to another Value - pub fn any_fuzzy(&self, other: &Value) -> bool { - match self { - Value::Array(v) => v.iter().any(|v| v.fuzzy(other)), - _ => self.fuzzy(other), - } - } - - /// Check if this Value contains another Value - pub fn contains(&self, other: &Value) -> bool { - match self { - Value::Array(v) => v.iter().any(|v| v.equal(other)), - Value::Uuid(v) => match other { - Value::Strand(w) => v.to_raw().contains(w.as_str()), - _ => false, - }, - Value::Strand(v) => match other { - Value::Strand(w) => v.contains(w.as_str()), - _ => false, - }, - Value::Geometry(v) => match other { - Value::Geometry(w) => v.contains(w), - _ => false, - }, - _ => false, - } - } - - /// Check if all Values in an Array contain another Value - pub fn contains_all(&self, other: &Value) -> bool { - match other { - Value::Array(v) => v.iter().all(|v| match self { - Value::Array(w) => w.iter().any(|w| v.equal(w)), - Value::Geometry(_) => self.contains(v), - _ => false, - }), - _ => false, - } - } - - /// Check if any Values in an Array contain another Value - pub fn contains_any(&self, other: &Value) -> bool { - match other { - Value::Array(v) => v.iter().any(|v| match self { - Value::Array(w) => w.iter().any(|w| v.equal(w)), - Value::Geometry(_) => self.contains(v), - _ => false, - }), - _ => false, - } - } - - /// Check if this Value intersects another Value - pub fn intersects(&self, other: &Value) -> bool { - match self { - Value::Geometry(v) => match other { - Value::Geometry(w) => v.intersects(w), - _ => false, - }, - _ => false, - } - } - - // ----------------------------------- - // Sorting operations - // ----------------------------------- - - /// Compare this Value to another Value lexicographically - pub fn lexical_cmp(&self, other: &Value) -> Option { - match (self, other) { - (Value::Strand(a), Value::Strand(b)) => Some(lexicmp::lexical_cmp(a, b)), - _ => self.partial_cmp(other), - } - } - - /// Compare this Value to another Value using natural numerical comparison - pub fn natural_cmp(&self, other: &Value) -> Option { - match (self, other) { - (Value::Strand(a), Value::Strand(b)) => Some(lexicmp::natural_cmp(a, b)), - _ => self.partial_cmp(other), - } - } - - /// Compare this Value to another Value lexicographically and using natural numerical comparison - pub fn natural_lexical_cmp(&self, other: &Value) -> Option { - match (self, other) { - (Value::Strand(a), Value::Strand(b)) => Some(lexicmp::natural_lexical_cmp(a, b)), - _ => self.partial_cmp(other), - } - } -} - -impl fmt::Display for Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = Pretty::from(f); - match self { - Value::None => write!(f, "NONE"), - Value::Null => write!(f, "NULL"), - Value::Array(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::Model(v) => write!(f, "{v}"), - Value::Future(v) => write!(f, "{v}"), - Value::Geometry(v) => write!(f, "{v}"), - Value::Idiom(v) => write!(f, "{v}"), - Value::Mock(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::Query(v) => write!(f, "{v}"), - Value::Subquery(v) => write!(f, "{v}"), - Value::Table(v) => write!(f, "{v}"), - Value::Thing(v) => write!(f, "{v}"), - Value::Uuid(v) => write!(f, "{v}"), - } - } -} - -impl Value { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - match self { - Value::Block(v) => v.writeable(), - Value::Idiom(v) => v.writeable(), - Value::Array(v) => v.iter().any(Value::writeable), - Value::Object(v) => v.iter().any(|(_, v)| v.writeable()), - Value::Function(v) => { - v.is_custom() || v.is_script() || v.args().iter().any(Value::writeable) - } - Value::Model(m) => m.args.iter().any(Value::writeable), - Value::Subquery(v) => v.writeable(), - Value::Expression(v) => v.writeable(), - _ => false, - } - } - /// Process this type returning a computed simple Value - #[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 CursorDoc<'_>>, - ) -> Result { - // Prevent infinite recursion due to casting, expressions, etc. - let opt = &opt.dive(1)?; - - 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, - Value::Param(v) => v.compute(ctx, opt, txn, doc).await, - Value::Idiom(v) => v.compute(ctx, opt, txn, doc).await, - Value::Array(v) => v.compute(ctx, opt, txn, doc).await, - Value::Object(v) => v.compute(ctx, opt, txn, doc).await, - Value::Future(v) => v.compute(ctx, opt, txn, doc).await, - Value::Constant(v) => v.compute(ctx, opt, txn, doc).await, - Value::Function(v) => v.compute(ctx, opt, txn, doc).await, - Value::Model(v) => v.compute(ctx, opt, txn, doc).await, - Value::Subquery(v) => v.compute(ctx, opt, txn, doc).await, - Value::Expression(v) => v.compute(ctx, opt, txn, doc).await, - _ => Ok(self.to_owned()), - } - } -} - -// ------------------------------ - -pub(crate) trait TryAdd { - type Output; - fn try_add(self, rhs: Rhs) -> Result; -} - -impl TryAdd for Value { - type Output = Self; - fn try_add(self, other: Self) -> Result { - Ok(match (self, other) { - (Self::Number(v), Self::Number(w)) => Self::Number(v.try_add(w)?), - (Self::Strand(v), Self::Strand(w)) => Self::Strand(v + w), - (Self::Datetime(v), Self::Duration(w)) => Self::Datetime(w + v), - (Self::Duration(v), Self::Datetime(w)) => Self::Datetime(v + w), - (Self::Duration(v), Self::Duration(w)) => Self::Duration(v + w), - (v, w) => return Err(Error::TryAdd(v.to_raw_string(), w.to_raw_string())), - }) - } -} - -// ------------------------------ - -pub(crate) trait TrySub { - type Output; - fn try_sub(self, v: Self) -> Result; -} - -impl TrySub for Value { - type Output = Self; - fn try_sub(self, other: Self) -> Result { - Ok(match (self, other) { - (Self::Number(v), Self::Number(w)) => Self::Number(v.try_sub(w)?), - (Self::Datetime(v), Self::Datetime(w)) => Self::Duration(v - w), - (Self::Datetime(v), Self::Duration(w)) => Self::Datetime(w - v), - (Self::Duration(v), Self::Datetime(w)) => Self::Datetime(v - w), - (Self::Duration(v), Self::Duration(w)) => Self::Duration(v - w), - (v, w) => return Err(Error::TrySub(v.to_raw_string(), w.to_raw_string())), - }) - } -} - -// ------------------------------ - -pub(crate) trait TryMul { - type Output; - fn try_mul(self, v: Self) -> Result; -} - -impl TryMul for Value { - type Output = Self; - fn try_mul(self, other: Self) -> Result { - Ok(match (self, other) { - (Self::Number(v), Self::Number(w)) => Self::Number(v.try_mul(w)?), - (v, w) => return Err(Error::TryMul(v.to_raw_string(), w.to_raw_string())), - }) - } -} - -// ------------------------------ - -pub(crate) trait TryDiv { - type Output; - fn try_div(self, v: Self) -> Result; -} - -impl TryDiv for Value { - type Output = Self; - fn try_div(self, other: Self) -> Result { - Ok(match (self, other) { - (Self::Number(v), Self::Number(w)) => Self::Number(v.try_div(w)?), - (v, w) => return Err(Error::TryDiv(v.to_raw_string(), w.to_raw_string())), - }) - } -} - -// ------------------------------ - -pub(crate) trait TryRem { - type Output; - fn try_rem(self, v: Self) -> Result; -} - -impl TryRem for Value { - type Output = Self; - fn try_rem(self, other: Self) -> Result { - Ok(match (self, other) { - (Self::Number(v), Self::Number(w)) => Self::Number(v.try_rem(w)?), - (v, w) => return Err(Error::TryRem(v.to_raw_string(), w.to_raw_string())), - }) - } -} - -// ------------------------------ - -pub(crate) trait TryPow { - type Output; - fn try_pow(self, v: Self) -> Result; -} - -impl TryPow for Value { - type Output = Self; - fn try_pow(self, other: Self) -> Result { - Ok(match (self, other) { - (Value::Number(v), Value::Number(w)) => Self::Number(v.try_pow(w)?), - (v, w) => return Err(Error::TryPow(v.to_raw_string(), w.to_raw_string())), - }) - } -} - -// ------------------------------ - -pub(crate) trait TryNeg { - type Output; - fn try_neg(self) -> Result; -} - -impl TryNeg for Value { - type Output = Self; - fn try_neg(self) -> Result { - Ok(match self { - Self::Number(n) => Self::Number(n.try_neg()?), - v => return Err(Error::TryNeg(v.to_string())), - }) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[test] - fn check_none() { - assert!(Value::None.is_none()); - assert!(!Value::Null.is_none()); - assert!(!Value::from(1).is_none()); - } - - #[test] - fn check_null() { - assert!(Value::Null.is_null()); - assert!(!Value::None.is_null()); - assert!(!Value::from(1).is_null()); - } - - #[test] - fn check_true() { - assert!(!Value::None.is_true()); - assert!(Value::Bool(true).is_true()); - assert!(!Value::Bool(false).is_true()); - assert!(!Value::from(1).is_true()); - assert!(!Value::from("something").is_true()); - } - - #[test] - fn check_false() { - assert!(!Value::None.is_false()); - assert!(!Value::Bool(true).is_false()); - assert!(Value::Bool(false).is_false()); - assert!(!Value::from(1).is_false()); - assert!(!Value::from("something").is_false()); - } - - #[test] - fn convert_truthy() { - assert!(!Value::None.is_truthy()); - assert!(!Value::Null.is_truthy()); - assert!(Value::Bool(true).is_truthy()); - assert!(!Value::Bool(false).is_truthy()); - assert!(!Value::from(0).is_truthy()); - assert!(Value::from(1).is_truthy()); - assert!(Value::from(-1).is_truthy()); - assert!(Value::from(1.1).is_truthy()); - assert!(Value::from(-1.1).is_truthy()); - assert!(Value::from("true").is_truthy()); - assert!(!Value::from("false").is_truthy()); - assert!(Value::from("falsey").is_truthy()); - assert!(Value::from("something").is_truthy()); - assert!(Value::from(Uuid::new()).is_truthy()); - } - - #[test] - fn convert_string() { - assert_eq!(String::from("NONE"), Value::None.as_string()); - assert_eq!(String::from("NULL"), Value::Null.as_string()); - assert_eq!(String::from("true"), Value::Bool(true).as_string()); - assert_eq!(String::from("false"), Value::Bool(false).as_string()); - assert_eq!(String::from("0"), Value::from(0).as_string()); - assert_eq!(String::from("1"), Value::from(1).as_string()); - assert_eq!(String::from("-1"), Value::from(-1).as_string()); - assert_eq!(String::from("1.1f"), Value::from(1.1).as_string()); - assert_eq!(String::from("-1.1f"), Value::from(-1.1).as_string()); - assert_eq!(String::from("3"), Value::from("3").as_string()); - assert_eq!(String::from("true"), Value::from("true").as_string()); - assert_eq!(String::from("false"), Value::from("false").as_string()); - assert_eq!(String::from("something"), Value::from("something").as_string()); - } - - #[test] - fn check_size() { - assert!( - 64 >= std::mem::size_of::(), - "expected Value to be smaller then 64 bytes found {:?}", - std::mem::size_of::() - ); - assert!(112 >= std::mem::size_of::()); - assert!(112 >= std::mem::size_of::>()); - assert_eq!(24, std::mem::size_of::()); - assert_eq!(24, std::mem::size_of::()); - assert_eq!(16, std::mem::size_of::()); - assert_eq!(12, std::mem::size_of::()); - assert_eq!(24, std::mem::size_of::()); - assert_eq!(24, std::mem::size_of::()); - assert_eq!(56, std::mem::size_of::()); - assert_eq!(24, std::mem::size_of::()); - assert_eq!(24, std::mem::size_of::()); - assert_eq!(24, std::mem::size_of::()); - assert_eq!(56, std::mem::size_of::()); - assert_eq!(40, std::mem::size_of::()); - assert_eq!(32, std::mem::size_of::()); - assert_eq!(8, std::mem::size_of::>()); - assert_eq!(8, std::mem::size_of::>()); - assert_eq!(8, std::mem::size_of::>()); - assert_eq!(8, std::mem::size_of::>()); - assert_eq!(8, std::mem::size_of::>()); - } - - #[test] - fn check_serialize() { - let enc: Vec = Value::None.into(); - assert_eq!(2, enc.len()); - let enc: Vec = Value::Null.into(); - assert_eq!(2, enc.len()); - let enc: Vec = Value::Bool(true).into(); - assert_eq!(3, enc.len()); - let enc: Vec = Value::Bool(false).into(); - assert_eq!(3, enc.len()); - let enc: Vec = Value::from("test").into(); - assert_eq!(8, enc.len()); - let enc: Vec = Value::parse("{ hello: 'world' }").into(); - assert_eq!(19, enc.len()); - let enc: Vec = Value::parse("{ compact: true, schema: 0 }").into(); - assert_eq!(27, enc.len()); - } - - #[test] - fn serialize_deserialize() { - let val = Value::parse( - "{ test: { something: [1, 'two', null, test:tobie, { trueee: false, noneee: nulll }] } }", - ); - let res = Value::parse( - "{ test: { something: [1, 'two', null, test:tobie, { trueee: false, noneee: nulll }] } }", - ); - let enc: Vec = val.into(); - let dec: Value = enc.into(); - assert_eq!(res, dec); - } -} diff --git a/core/src/sql/v2/arbitrary.rs b/core/src/sql/v2/arbitrary.rs deleted file mode 100644 index 7f027f18..00000000 --- a/core/src/sql/v2/arbitrary.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::sql::{ - changefeed::ChangeFeed, datetime::Datetime, duration::Duration, regex::Regex, - statements::SleepStatement, -}; -use arbitrary::{Arbitrary, Result, Unstructured}; -use regex_syntax::ast::Ast; -use std::time; - -impl<'a> Arbitrary<'a> for Duration { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(Self::from(time::Duration::new(u64::arbitrary(u)?, u32::arbitrary(u)?))) - } -} - -impl<'a> Arbitrary<'a> for Datetime { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let result = chrono::DateTime::UNIX_EPOCH + chrono::Duration::seconds(i64::arbitrary(u)?); - Ok(Self(result)) - } -} - -impl<'a> Arbitrary<'a> for Regex { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let ast = Ast::arbitrary(u)?; - Ok(Self( - regex::Regex::new(&format!("{ast}")).map_err(|_| arbitrary::Error::IncorrectFormat)?, - )) - } -} - -impl<'a> Arbitrary<'a> for ChangeFeed { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(Self { - expiry: time::Duration::new(u64::arbitrary(u)?, u32::arbitrary(u)?), - store_original: bool::arbitrary(u)?, - }) - } -} - -impl<'a> Arbitrary<'a> for SleepStatement { - fn arbitrary(_u: &mut Unstructured<'a>) -> Result { - Ok(Self { - // When fuzzing we don't want to sleep, that's slow... we want insomnia. - duration: Duration(time::Duration::new(0, 0)), - }) - } -} diff --git a/core/src/sql/v2/base.rs b/core/src/sql/v2/base.rs deleted file mode 100644 index 4afc476f..00000000 --- a/core/src/sql/v2/base.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::sql::Ident; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Base { - Root, - Ns, - Db, - Sc(Ident), -} - -impl Default for Base { - fn default() -> Self { - Self::Root - } -} - -impl fmt::Display for Base { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Ns => f.write_str("NAMESPACE"), - Self::Db => f.write_str("DATABASE"), - Self::Sc(sc) => write!(f, "SCOPE {sc}"), - Self::Root => f.write_str("ROOT"), - } - } -} diff --git a/core/src/sql/v2/block.rs b/core/src/sql/v2/block.rs deleted file mode 100644 index 70f58a57..00000000 --- a/core/src/sql/v2/block.rs +++ /dev/null @@ -1,242 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::fmt::{is_pretty, pretty_indent, Fmt, Pretty}; -use crate::sql::statements::{ - BreakStatement, ContinueStatement, CreateStatement, DefineStatement, DeleteStatement, - ForeachStatement, IfelseStatement, InsertStatement, OutputStatement, RelateStatement, - RemoveStatement, SelectStatement, SetStatement, ThrowStatement, UpdateStatement, -}; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::fmt::{self, Display, Formatter, Write}; -use std::ops::Deref; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Block"; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Block")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Block(pub Vec); - -impl Deref for Block { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From for Block { - fn from(v: Value) -> Self { - Block(vec![Entry::Value(v)]) - } -} - -impl Block { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - self.iter().any(Entry::writeable) - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Duplicate context - let mut ctx = Context::new(ctx); - // Loop over the statements - for (i, v) in self.iter().enumerate() { - match v { - Entry::Set(v) => { - let val = v.compute(&ctx, opt, txn, doc).await?; - ctx.add_value(v.name.to_owned(), val); - } - Entry::Throw(v) => { - // Always errors immediately - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Break(v) => { - // Always errors immediately - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Continue(v) => { - // Always errors immediately - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Foreach(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Ifelse(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Select(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Create(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Update(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Delete(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Relate(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Insert(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Define(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Remove(v) => { - v.compute(&ctx, opt, txn, doc).await?; - } - Entry::Output(v) => { - // Return the RETURN value - return v.compute(&ctx, opt, txn, doc).await; - } - Entry::Value(v) => { - if i == self.len() - 1 { - // If the last entry then return the value - return v.compute(&ctx, opt, txn, doc).await; - } else { - // Otherwise just process the value - v.compute(&ctx, opt, txn, doc).await?; - } - } - } - } - // Return nothing - Ok(Value::None) - } -} - -impl Display for Block { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let mut f = Pretty::from(f); - match (self.len(), self.first()) { - (0, _) => f.write_str("{}"), - (1, Some(Entry::Value(v))) => { - write!(f, "{{ {v} }}") - } - (l, _) => { - f.write_char('{')?; - if l > 1 { - f.write_char('\n')?; - } else if !is_pretty() { - f.write_char(' ')?; - } - let indent = pretty_indent(); - if is_pretty() { - write!( - f, - "{}", - &Fmt::two_line_separated( - self.0.iter().map(|args| Fmt::new(args, |v, f| write!(f, "{};", v))), - ) - )?; - } else { - write!( - f, - "{}", - &Fmt::one_line_separated( - self.0.iter().map(|args| Fmt::new(args, |v, f| write!(f, "{};", v))), - ) - )?; - } - drop(indent); - if l > 1 { - f.write_char('\n')?; - } else if !is_pretty() { - f.write_char(' ')?; - } - f.write_char('}') - } - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Entry { - Value(Value), - Set(SetStatement), - Ifelse(IfelseStatement), - Select(SelectStatement), - Create(CreateStatement), - Update(UpdateStatement), - Delete(DeleteStatement), - Relate(RelateStatement), - Insert(InsertStatement), - Output(OutputStatement), - Define(DefineStatement), - Remove(RemoveStatement), - Throw(ThrowStatement), - Break(BreakStatement), - Continue(ContinueStatement), - Foreach(ForeachStatement), -} - -impl PartialOrd for Entry { - #[inline] - fn partial_cmp(&self, _: &Self) -> Option { - None - } -} - -impl Entry { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - match self { - Self::Set(v) => v.writeable(), - Self::Value(v) => v.writeable(), - Self::Ifelse(v) => v.writeable(), - Self::Select(v) => v.writeable(), - Self::Create(v) => v.writeable(), - Self::Update(v) => v.writeable(), - Self::Delete(v) => v.writeable(), - Self::Relate(v) => v.writeable(), - Self::Insert(v) => v.writeable(), - Self::Output(v) => v.writeable(), - Self::Define(v) => v.writeable(), - Self::Remove(v) => v.writeable(), - Self::Throw(v) => v.writeable(), - Self::Break(v) => v.writeable(), - Self::Continue(v) => v.writeable(), - Self::Foreach(v) => v.writeable(), - } - } -} - -impl Display for Entry { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Set(v) => write!(f, "{v}"), - Self::Value(v) => Display::fmt(v, f), - Self::Ifelse(v) => write!(f, "{v}"), - Self::Select(v) => write!(f, "{v}"), - Self::Create(v) => write!(f, "{v}"), - Self::Update(v) => write!(f, "{v}"), - Self::Delete(v) => write!(f, "{v}"), - Self::Relate(v) => write!(f, "{v}"), - Self::Insert(v) => write!(f, "{v}"), - Self::Output(v) => write!(f, "{v}"), - Self::Define(v) => write!(f, "{v}"), - Self::Remove(v) => write!(f, "{v}"), - Self::Throw(v) => write!(f, "{v}"), - Self::Break(v) => write!(f, "{v}"), - Self::Continue(v) => write!(f, "{v}"), - Self::Foreach(v) => write!(f, "{v}"), - } - } -} diff --git a/core/src/sql/v2/bytes.rs b/core/src/sql/v2/bytes.rs deleted file mode 100644 index 8989e945..00000000 --- a/core/src/sql/v2/bytes.rs +++ /dev/null @@ -1,95 +0,0 @@ -use base64_lib::{engine::general_purpose::STANDARD_NO_PAD, Engine}; -use revision::revisioned; -use serde::{ - de::{self, Visitor}, - Deserialize, Serialize, -}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Bytes(pub(crate) Vec); - -impl Bytes { - pub fn into_inner(self) -> Vec { - self.0 - } -} - -impl From> for Bytes { - fn from(v: Vec) -> Self { - Self(v) - } -} - -impl Deref for Bytes { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Bytes { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "encoding::base64::decode(\"{}\")", STANDARD_NO_PAD.encode(&self.0)) - } -} - -impl Serialize for Bytes { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_bytes(&self.0) - } -} - -impl<'de> Deserialize<'de> for Bytes { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct RawBytesVisitor; - - impl<'de> Visitor<'de> for RawBytesVisitor { - type Value = Bytes; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("bytes") - } - - fn visit_byte_buf(self, v: Vec) -> Result - where - E: de::Error, - { - Ok(Bytes(v)) - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: de::Error, - { - Ok(Bytes(v.to_owned())) - } - } - - deserializer.deserialize_byte_buf(RawBytesVisitor) - } -} - -#[cfg(test)] -mod tests { - use crate::sql::{Bytes, Value}; - - #[test] - fn serialize() { - let val = Value::Bytes(Bytes(vec![1, 2, 3, 5])); - let serialized: Vec = val.clone().into(); - println!("{serialized:?}"); - let deserialized = Value::from(serialized); - assert_eq!(val, deserialized); - } -} diff --git a/core/src/sql/v2/cast.rs b/core/src/sql/v2/cast.rs deleted file mode 100644 index df195297..00000000 --- a/core/src/sql/v2/cast.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{Idiom, Kind, Value}; -use async_recursion::async_recursion; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::fmt; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Cast"; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Cast")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Cast(pub Kind, pub Value); - -impl PartialOrd for Cast { - #[inline] - fn partial_cmp(&self, _: &Self) -> Option { - 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 CursorDoc<'_>>, - ) -> Result { - // 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) - } -} diff --git a/core/src/sql/v2/cond.rs b/core/src/sql/v2/cond.rs deleted file mode 100644 index 0cf86413..00000000 --- a/core/src/sql/v2/cond.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Cond(pub Value); - -impl Deref for Cond { - type Target = Value; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl fmt::Display for Cond { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "WHERE {}", self.0) - } -} diff --git a/core/src/sql/v2/constant.rs b/core/src/sql/v2/constant.rs deleted file mode 100644 index c6cc28f2..00000000 --- a/core/src/sql/v2/constant.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::value::Value; -use crate::sql::Datetime; -use chrono::TimeZone; -use chrono::Utc; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Constant"; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[serde(rename = "$surrealdb::private::sql::Constant")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Constant { - MathE, - MathFrac1Pi, - MathFrac1Sqrt2, - MathFrac2Pi, - MathFrac2SqrtPi, - MathFracPi2, - MathFracPi3, - MathFracPi4, - MathFracPi6, - MathFracPi8, - MathInf, - MathLn10, - MathLn2, - MathLog102, - MathLog10E, - MathLog210, - MathLog2E, - MathPi, - MathSqrt2, - MathTau, - TimeEpoch, - // Add new variants here -} - -/// A type of constant that may be converted to a value or JSON. -pub(crate) enum ConstantValue { - Float(f64), - Datetime(Datetime), -} - -impl Constant { - pub(crate) fn value(&self) -> ConstantValue { - use std::f64::consts as f64c; - match self { - Self::MathE => ConstantValue::Float(f64c::E), - Self::MathFrac1Pi => ConstantValue::Float(f64c::FRAC_1_PI), - Self::MathFrac1Sqrt2 => ConstantValue::Float(f64c::FRAC_1_SQRT_2), - Self::MathFrac2Pi => ConstantValue::Float(f64c::FRAC_2_PI), - Self::MathFrac2SqrtPi => ConstantValue::Float(f64c::FRAC_2_SQRT_PI), - Self::MathFracPi2 => ConstantValue::Float(f64c::FRAC_PI_2), - Self::MathFracPi3 => ConstantValue::Float(f64c::FRAC_PI_3), - Self::MathFracPi4 => ConstantValue::Float(f64c::FRAC_PI_4), - Self::MathFracPi6 => ConstantValue::Float(f64c::FRAC_PI_6), - Self::MathFracPi8 => ConstantValue::Float(f64c::FRAC_PI_8), - Self::MathInf => ConstantValue::Float(f64::INFINITY), - Self::MathLn10 => ConstantValue::Float(f64c::LN_10), - Self::MathLn2 => ConstantValue::Float(f64c::LN_2), - Self::MathLog102 => ConstantValue::Float(f64c::LOG10_2), - Self::MathLog10E => ConstantValue::Float(f64c::LOG10_E), - Self::MathLog210 => ConstantValue::Float(f64c::LOG2_10), - Self::MathLog2E => ConstantValue::Float(f64c::LOG2_E), - Self::MathPi => ConstantValue::Float(f64c::PI), - Self::MathSqrt2 => ConstantValue::Float(f64c::SQRT_2), - Self::MathTau => ConstantValue::Float(f64c::TAU), - Self::TimeEpoch => ConstantValue::Datetime(Datetime(Utc.timestamp_nanos(0))), - } - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - _opt: &Options, - _txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - Ok(match self.value() { - ConstantValue::Datetime(d) => d.into(), - ConstantValue::Float(f) => f.into(), - }) - } -} - -impl fmt::Display for Constant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Self::MathE => "math::E", - Self::MathFrac1Pi => "math::FRAC_1_PI", - Self::MathFrac1Sqrt2 => "math::FRAC_1_SQRT_2", - Self::MathFrac2Pi => "math::FRAC_2_PI", - Self::MathFrac2SqrtPi => "math::FRAC_2_SQRT_PI", - Self::MathFracPi2 => "math::FRAC_PI_2", - Self::MathFracPi3 => "math::FRAC_PI_3", - Self::MathFracPi4 => "math::FRAC_PI_4", - Self::MathFracPi6 => "math::FRAC_PI_6", - Self::MathFracPi8 => "math::FRAC_PI_8", - Self::MathInf => "math::INF", - Self::MathLn10 => "math::LN_10", - Self::MathLn2 => "math::LN_2", - Self::MathLog102 => "math::LOG10_2", - Self::MathLog10E => "math::LOG10_E", - Self::MathLog210 => "math::LOG2_10", - Self::MathLog2E => "math::LOG2_E", - Self::MathPi => "math::PI", - Self::MathSqrt2 => "math::SQRT_2", - Self::MathTau => "math::TAU", - Self::TimeEpoch => "time::EPOCH", - }) - } -} diff --git a/core/src/sql/v2/data.rs b/core/src/sql/v2/data.rs deleted file mode 100644 index 85f9fa9a..00000000 --- a/core/src/sql/v2/data.rs +++ /dev/null @@ -1,109 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::sql::fmt::Fmt; -use crate::sql::idiom::Idiom; -use crate::sql::operator::Operator; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Data { - EmptyExpression, - SetExpression(Vec<(Idiom, Operator, Value)>), - UnsetExpression(Vec), - PatchExpression(Value), - MergeExpression(Value), - ReplaceExpression(Value), - ContentExpression(Value), - SingleExpression(Value), - ValuesExpression(Vec>), - UpdateExpression(Vec<(Idiom, Operator, Value)>), -} - -impl Default for Data { - fn default() -> Self { - Self::EmptyExpression - } -} - -impl Data { - /// Fetch the 'id' field if one has been specified - pub(crate) async fn rid( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - ) -> Result, Error> { - match self { - Self::MergeExpression(v) => { - // This MERGE expression has an 'id' field - Ok(v.compute(ctx, opt, txn, None).await?.rid().some()) - } - Self::ReplaceExpression(v) => { - // This REPLACE expression has an 'id' field - Ok(v.compute(ctx, opt, txn, None).await?.rid().some()) - } - Self::ContentExpression(v) => { - // This CONTENT expression has an 'id' field - Ok(v.compute(ctx, opt, txn, None).await?.rid().some()) - } - Self::SetExpression(v) => match v.iter().find(|f| f.0.is_id()) { - Some((_, _, v)) => { - // This SET expression has an 'id' field - Ok(v.compute(ctx, opt, txn, None).await?.some()) - } - // This SET expression had no 'id' field - _ => Ok(None), - }, - // Generate a random id for all other data clauses - _ => Ok(None), - } - } -} - -impl Display for Data { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::EmptyExpression => Ok(()), - Self::SetExpression(v) => write!( - f, - "SET {}", - Fmt::comma_separated( - v.iter().map(|args| Fmt::new(args, |(l, o, r), f| write!(f, "{l} {o} {r}",))) - ) - ), - Self::UnsetExpression(v) => write!( - f, - "UNSET {}", - Fmt::comma_separated(v.iter().map(|args| Fmt::new(args, |l, f| write!(f, "{l}",)))) - ), - Self::PatchExpression(v) => write!(f, "PATCH {v}"), - Self::MergeExpression(v) => write!(f, "MERGE {v}"), - Self::ReplaceExpression(v) => write!(f, "REPLACE {v}"), - Self::ContentExpression(v) => write!(f, "CONTENT {v}"), - Self::SingleExpression(v) => Display::fmt(v, f), - Self::ValuesExpression(v) => write!( - f, - "({}) VALUES {}", - Fmt::comma_separated(v.first().unwrap().iter().map(|(v, _)| v)), - Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| write!( - f, - "({})", - Fmt::comma_separated(v.iter().map(|(_, v)| v)) - )))) - ), - Self::UpdateExpression(v) => write!( - f, - "ON DUPLICATE KEY UPDATE {}", - Fmt::comma_separated( - v.iter().map(|args| Fmt::new(args, |(l, o, r), f| write!(f, "{l} {o} {r}",))) - ) - ), - } - } -} diff --git a/core/src/sql/v2/datetime.rs b/core/src/sql/v2/datetime.rs deleted file mode 100644 index a76a880e..00000000 --- a/core/src/sql/v2/datetime.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::sql::duration::Duration; -use crate::sql::strand::Strand; -use crate::syn; -use chrono::{DateTime, SecondsFormat, Utc}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops; -use std::ops::Deref; -use std::str; -use std::str::FromStr; - -use super::escape::quote_str; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Datetime"; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Datetime")] -#[revisioned(revision = 1)] -pub struct Datetime(pub DateTime); - -impl Default for Datetime { - fn default() -> Self { - Self(Utc::now()) - } -} - -impl From> for Datetime { - fn from(v: DateTime) -> Self { - Self(v) - } -} - -impl From for DateTime { - fn from(x: Datetime) -> Self { - x.0 - } -} - -impl FromStr for Datetime { - type Err = (); - fn from_str(s: &str) -> Result { - Self::try_from(s) - } -} - -impl TryFrom for Datetime { - type Error = (); - fn try_from(v: String) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom for Datetime { - type Error = (); - fn try_from(v: Strand) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom<&str> for Datetime { - type Error = (); - fn try_from(v: &str) -> Result { - match syn::datetime_raw(v) { - Ok(v) => Ok(v), - _ => Err(()), - } - } -} - -impl Deref for Datetime { - type Target = DateTime; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Datetime { - /// Convert the Datetime to a raw String - pub fn to_raw(&self) -> String { - self.0.to_rfc3339_opts(SecondsFormat::AutoSi, true) - } -} - -impl Display for Datetime { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt("e_str(&self.to_raw()), f) - } -} - -impl ops::Sub for Datetime { - type Output = Duration; - fn sub(self, other: Self) -> Duration { - match (self.0 - other.0).to_std() { - Ok(d) => Duration::from(d), - Err(_) => Duration::default(), - } - } -} diff --git a/core/src/sql/v2/dir.rs b/core/src/sql/v2/dir.rs deleted file mode 100644 index 98b9df6d..00000000 --- a/core/src/sql/v2/dir.rs +++ /dev/null @@ -1,28 +0,0 @@ -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Dir { - In, - Out, - Both, -} - -impl Default for Dir { - fn default() -> Self { - Self::Both - } -} - -impl fmt::Display for Dir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Self::In => "<-", - Self::Out => "->", - Self::Both => "<->", - }) - } -} diff --git a/core/src/sql/v2/duration.rs b/core/src/sql/v2/duration.rs deleted file mode 100644 index ab10d38e..00000000 --- a/core/src/sql/v2/duration.rs +++ /dev/null @@ -1,291 +0,0 @@ -use crate::sql::datetime::Datetime; -use crate::sql::strand::Strand; -use crate::syn; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::iter::Sum; -use std::ops; -use std::ops::Deref; -use std::str::FromStr; -use std::time; - -pub(crate) static SECONDS_PER_YEAR: u64 = 365 * SECONDS_PER_DAY; -pub(crate) static SECONDS_PER_WEEK: u64 = 7 * SECONDS_PER_DAY; -pub(crate) static SECONDS_PER_DAY: u64 = 24 * SECONDS_PER_HOUR; -pub(crate) static SECONDS_PER_HOUR: u64 = 60 * SECONDS_PER_MINUTE; -pub(crate) static SECONDS_PER_MINUTE: u64 = 60; -pub(crate) static NANOSECONDS_PER_MILLISECOND: u32 = 1000000; -pub(crate) static NANOSECONDS_PER_MICROSECOND: u32 = 1000; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Duration"; - -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Duration")] -#[revisioned(revision = 1)] -pub struct Duration(pub time::Duration); - -impl From for Duration { - fn from(v: time::Duration) -> Self { - Self(v) - } -} - -impl From for time::Duration { - fn from(s: Duration) -> Self { - s.0 - } -} - -impl FromStr for Duration { - type Err = (); - fn from_str(s: &str) -> Result { - Self::try_from(s) - } -} - -impl TryFrom for Duration { - type Error = (); - fn try_from(v: String) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom for Duration { - type Error = (); - fn try_from(v: Strand) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom<&str> for Duration { - type Error = (); - fn try_from(v: &str) -> Result { - match syn::duration(v) { - Ok(v) => Ok(v), - _ => Err(()), - } - } -} - -impl Deref for Duration { - type Target = time::Duration; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Duration { - /// Convert the Duration to a raw String - pub fn to_raw(&self) -> String { - self.to_string() - } - /// Get the total number of nanoseconds - pub fn nanos(&self) -> u128 { - self.0.as_nanos() - } - /// Get the total number of microseconds - pub fn micros(&self) -> u128 { - self.0.as_micros() - } - /// Get the total number of milliseconds - pub fn millis(&self) -> u128 { - self.0.as_millis() - } - /// Get the total number of seconds - pub fn secs(&self) -> u64 { - self.0.as_secs() - } - /// Get the total number of minutes - pub fn mins(&self) -> u64 { - self.0.as_secs() / SECONDS_PER_MINUTE - } - /// Get the total number of hours - pub fn hours(&self) -> u64 { - self.0.as_secs() / SECONDS_PER_HOUR - } - /// Get the total number of dats - pub fn days(&self) -> u64 { - self.0.as_secs() / SECONDS_PER_DAY - } - /// Get the total number of months - pub fn weeks(&self) -> u64 { - self.0.as_secs() / SECONDS_PER_WEEK - } - /// Get the total number of years - pub fn years(&self) -> u64 { - self.0.as_secs() / SECONDS_PER_YEAR - } - /// Create a duration from nanoseconds - pub fn from_nanos(nanos: u64) -> Duration { - time::Duration::from_nanos(nanos).into() - } - /// Create a duration from microseconds - pub fn from_micros(micros: u64) -> Duration { - time::Duration::from_micros(micros).into() - } - /// Create a duration from milliseconds - pub fn from_millis(millis: u64) -> Duration { - time::Duration::from_millis(millis).into() - } - /// Create a duration from seconds - pub fn from_secs(secs: u64) -> Duration { - time::Duration::from_secs(secs).into() - } - /// Create a duration from minutes - pub fn from_mins(mins: u64) -> Duration { - time::Duration::from_secs(mins * SECONDS_PER_MINUTE).into() - } - /// Create a duration from hours - pub fn from_hours(hours: u64) -> Duration { - time::Duration::from_secs(hours * SECONDS_PER_HOUR).into() - } - /// Create a duration from days - pub fn from_days(days: u64) -> Duration { - time::Duration::from_secs(days * SECONDS_PER_DAY).into() - } - /// Create a duration from weeks - pub fn from_weeks(days: u64) -> Duration { - time::Duration::from_secs(days * SECONDS_PER_WEEK).into() - } -} - -impl fmt::Display for Duration { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Split up the duration - let secs = self.0.as_secs(); - let nano = self.0.subsec_nanos(); - // Ensure no empty output - if secs == 0 && nano == 0 { - return write!(f, "0ns"); - } - // Calculate the total years - let year = secs / SECONDS_PER_YEAR; - let secs = secs % SECONDS_PER_YEAR; - // Calculate the total weeks - let week = secs / SECONDS_PER_WEEK; - let secs = secs % SECONDS_PER_WEEK; - // Calculate the total days - let days = secs / SECONDS_PER_DAY; - let secs = secs % SECONDS_PER_DAY; - // Calculate the total hours - let hour = secs / SECONDS_PER_HOUR; - let secs = secs % SECONDS_PER_HOUR; - // Calculate the total minutes - let mins = secs / SECONDS_PER_MINUTE; - let secs = secs % SECONDS_PER_MINUTE; - // Calculate the total milliseconds - let msec = nano / NANOSECONDS_PER_MILLISECOND; - let nano = nano % NANOSECONDS_PER_MILLISECOND; - // Calculate the total microseconds - let usec = nano / NANOSECONDS_PER_MICROSECOND; - let nano = nano % NANOSECONDS_PER_MICROSECOND; - // Write the different parts - if year > 0 { - write!(f, "{year}y")?; - } - if week > 0 { - write!(f, "{week}w")?; - } - if days > 0 { - write!(f, "{days}d")?; - } - if hour > 0 { - write!(f, "{hour}h")?; - } - if mins > 0 { - write!(f, "{mins}m")?; - } - if secs > 0 { - write!(f, "{secs}s")?; - } - if msec > 0 { - write!(f, "{msec}ms")?; - } - if usec > 0 { - write!(f, "{usec}µs")?; - } - if nano > 0 { - write!(f, "{nano}ns")?; - } - Ok(()) - } -} - -impl ops::Add for Duration { - type Output = Self; - fn add(self, other: Self) -> Self { - match self.0.checked_add(other.0) { - Some(v) => Duration::from(v), - None => Duration::from(time::Duration::MAX), - } - } -} - -impl<'a, 'b> ops::Add<&'b Duration> for &'a Duration { - type Output = Duration; - fn add(self, other: &'b Duration) -> Duration { - match self.0.checked_add(other.0) { - Some(v) => Duration::from(v), - None => Duration::from(time::Duration::MAX), - } - } -} - -impl ops::Sub for Duration { - type Output = Self; - fn sub(self, other: Self) -> Self { - match self.0.checked_sub(other.0) { - Some(v) => Duration::from(v), - None => Duration::default(), - } - } -} - -impl<'a, 'b> ops::Sub<&'b Duration> for &'a Duration { - type Output = Duration; - fn sub(self, other: &'b Duration) -> Duration { - match self.0.checked_sub(other.0) { - Some(v) => Duration::from(v), - None => Duration::default(), - } - } -} - -impl ops::Add for Duration { - type Output = Datetime; - fn add(self, other: Datetime) -> Datetime { - match chrono::Duration::from_std(self.0) { - Ok(d) => Datetime::from(other.0 + d), - Err(_) => Datetime::default(), - } - } -} - -impl ops::Sub for Duration { - type Output = Datetime; - fn sub(self, other: Datetime) -> Datetime { - match chrono::Duration::from_std(self.0) { - Ok(d) => Datetime::from(other.0 - d), - Err(_) => Datetime::default(), - } - } -} - -impl Sum for Duration { - fn sum(iter: I) -> Duration - where - I: Iterator, - { - iter.fold(Duration::default(), |a, b| a + b) - } -} - -impl<'a> Sum<&'a Self> for Duration { - fn sum(iter: I) -> Duration - where - I: Iterator, - { - iter.fold(Duration::default(), |a, b| &a + b) - } -} diff --git a/core/src/sql/v2/edges.rs b/core/src/sql/v2/edges.rs deleted file mode 100644 index c05b745b..00000000 --- a/core/src/sql/v2/edges.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::sql::dir::Dir; -use crate::sql::table::Tables; -use crate::sql::thing::Thing; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Edges"; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Edges")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Edges { - pub dir: Dir, - pub from: Thing, - pub what: Tables, -} - -impl fmt::Display for Edges { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.what.len() { - 0 => write!(f, "{}{}?", self.from, self.dir,), - 1 => write!(f, "{}{}{}", self.from, self.dir, self.what), - _ => write!(f, "{}{}({})", self.from, self.dir, self.what), - } - } -} diff --git a/core/src/sql/v2/ending.rs b/core/src/sql/v2/ending.rs deleted file mode 100644 index 378382b0..00000000 --- a/core/src/sql/v2/ending.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::sql::comment::comment; -use crate::sql::comment::{mightbespace, shouldbespace}; -use crate::sql::error::IResult; -use crate::sql::operator::{assigner, binary}; -use nom::branch::alt; -use nom::bytes::complete::tag; -use nom::bytes::complete::tag_no_case; -use nom::character::complete::char; -use nom::character::complete::multispace1; -use nom::combinator::peek; -use nom::combinator::{eof, value}; -use nom::sequence::preceded; - -pub fn number(i: &str) -> IResult<&str, ()> { - peek(alt(( - value((), multispace1), // 1 + 1 - value((), binary), // 1+1 - value((), assigner), // 1=1 - value((), comment), // 1/*comment*/ - value((), char(')')), // (1) - value((), char(']')), // a[1] - value((), char('}')), // {k: 1} - value((), char('"')), - value((), char('\'')), - value((), char(';')), // SET a = 1; - value((), char(',')), // [1, 2] - value((), tag("..")), // thing:1..2 - value((), eof), // SET a = 1 - )))(i) -} - -pub fn ident(i: &str) -> IResult<&str, ()> { - peek(alt(( - value((), multispace1), // a + 1 - value((), binary), // a+1 - value((), assigner), // a+=1 - value((), comment), // a/*comment*/ - value((), char(')')), // (a) - value((), char(']')), // foo[a] - value((), char('}')), // {k: a} - value((), char(';')), // SET k = a; - value((), char(',')), // [a, b] - value((), char('.')), // a.k - value((), char('…')), // a… - value((), char('[')), // a[0] - value((), eof), // SET k = a - )))(i) -} - -/// none, false, etc. -pub fn keyword(i: &str) -> IResult<&str, ()> { - peek(alt(( - value((), multispace1), // false || true - value((), binary), // false||true - value((), comment), // false/*comment*/ - value((), char(')')), // (false) - value((), char(']')), // [WHERE k = false] - value((), char('}')), // {k: false} - value((), char(';')), // SET a = false; - value((), char(',')), // [false, true] - value((), eof), // SET a = false - )))(i) -} - -pub fn duration(i: &str) -> IResult<&str, ()> { - peek(alt(( - value((), multispace1), - value((), binary), - value((), assigner), - value((), comment), - value((), char(')')), - value((), char(']')), - value((), char('}')), - value((), char(';')), - value((), char(',')), - value((), char('.')), - value((), eof), - )))(i) -} - -pub fn field(i: &str) -> IResult<&str, ()> { - peek(alt(( - value( - (), - preceded( - shouldbespace, - alt((tag_no_case("FROM"), tag_no_case("TIMEOUT"), tag_no_case("PARALLEL"))), - ), - ), - value((), char(';')), - value((), eof), - )))(i) -} - -pub fn subquery(i: &str) -> IResult<&str, ()> { - peek(alt(( - value((), preceded(shouldbespace, tag_no_case("THEN"))), - value((), preceded(shouldbespace, tag_no_case("ELSE"))), - value((), preceded(shouldbespace, tag_no_case("END"))), - |i| { - let (i, _) = mightbespace(i)?; - alt(( - value((), eof), - value((), char(';')), - value((), char(',')), - value((), char('}')), - value((), char(')')), - value((), char(']')), - ))(i) - }, - )))(i) -} - -pub fn query(i: &str) -> IResult<&str, ()> { - peek(alt(( - value((), preceded(shouldbespace, tag_no_case("THEN"))), - value((), preceded(shouldbespace, tag_no_case("ELSE"))), - value((), preceded(shouldbespace, tag_no_case("END"))), - |i| { - let (i, _) = mightbespace(i)?; - alt(( - value((), eof), - value((), char(';')), - value((), char(',')), - value((), char('}')), - value((), char(')')), - value((), char(']')), - ))(i) - }, - )))(i) -} diff --git a/core/src/sql/v2/explain.rs b/core/src/sql/v2/explain.rs deleted file mode 100644 index 4f73551e..00000000 --- a/core/src/sql/v2/explain.rs +++ /dev/null @@ -1,18 +0,0 @@ -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Explain(pub bool); - -impl fmt::Display for Explain { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("EXPLAIN")?; - if self.0 { - f.write_str(" FULL")?; - } - Ok(()) - } -} diff --git a/core/src/sql/v2/fetch.rs b/core/src/sql/v2/fetch.rs deleted file mode 100644 index 6038c4c4..00000000 --- a/core/src/sql/v2/fetch.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::sql::fmt::Fmt; -use crate::sql::idiom::Idiom; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Fetchs(pub Vec); - -impl Deref for Fetchs { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Fetchs { - type Item = Fetch; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl fmt::Display for Fetchs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "FETCH {}", Fmt::comma_separated(&self.0)) - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Fetch(pub Idiom); - -impl Deref for Fetch { - type Target = Idiom; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Fetch { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&self.0, f) - } -} diff --git a/core/src/sql/v2/field.rs b/core/src/sql/v2/field.rs deleted file mode 100644 index 5134c570..00000000 --- a/core/src/sql/v2/field.rs +++ /dev/null @@ -1,271 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{fmt::Fmt, Idiom, Part, Value}; -use crate::syn; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::borrow::Cow; -use std::fmt::{self, Display, Formatter, Write}; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Fields(pub Vec, pub bool); - -impl Fields { - pub fn all() -> Self { - Self(vec![Field::All], false) - } - /// Check to see if this field is a * projection - pub fn is_all(&self) -> bool { - self.0.iter().any(|v| matches!(v, Field::All)) - } - /// Get all fields which are not an * projection - pub fn other(&self) -> impl Iterator { - self.0.iter().filter(|v| !matches!(v, Field::All)) - } - /// Check to see if this field is a single VALUE clause - pub fn single(&self) -> Option<&Field> { - match (self.0.len(), self.1) { - (1, true) => match self.0.first() { - Some(Field::All) => None, - Some(v) => Some(v), - _ => None, - }, - _ => None, - } - } -} - -impl Deref for Fields { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Fields { - type Item = Field; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Display for Fields { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self.single() { - Some(v) => write!(f, "VALUE {}", &v), - None => Display::fmt(&Fmt::comma_separated(&self.0), f), - } - } -} - -impl Fields { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - group: bool, - ) -> Result { - if let Some(doc) = doc { - self.compute_value(ctx, opt, txn, doc, group).await - } else { - let doc = (&Value::None).into(); - self.compute_value(ctx, opt, txn, &doc, group).await - } - } - - async fn compute_value( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: &CursorDoc<'_>, - group: bool, - ) -> Result { - // Ensure futures are run - let opt = &opt.new_with_futures(true); - // Process the desired output - let mut out = match self.is_all() { - true => doc.doc.compute(ctx, opt, txn, Some(doc)).await?, - false => Value::base(), - }; - for v in self.other() { - match v { - Field::All => (), - Field::Single { - expr, - alias, - } => { - let name = 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?, - }; - // Check if this is a single VALUE field expression - match self.single().is_some() { - false => out.set(ctx, opt, txn, name.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.doc.as_ref(), - }; - // 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 expression is a variable fields expression - Value::Function(f) if f.name() == Some("type::fields") => { - // Process the function using variable field projections - let expr = expr.compute(ctx, opt, txn, Some(doc)).await?; - // Check if this is a single VALUE field expression - match self.single().is_some() { - false => { - // Get the first argument which is guaranteed to exist - let args = match f.args().first().unwrap() { - Value::Param(v) => { - v.compute(ctx, opt, txn, Some(doc)).await? - } - v => v.to_owned(), - }; - // This value is always an array, so we can convert it - let expr: Vec = expr.try_into()?; - // This value is always an array, so we can convert it - let args: Vec = args.try_into()?; - // This value is always an array, so we can convert it - for (name, expr) in args.into_iter().zip(expr) { - // This value is always a string, so we can convert it - let name = syn::idiom(&name.to_raw_string())?; - // Check if this is a single VALUE field expression - out.set(ctx, opt, txn, name.as_ref(), expr).await? - } - } - true => out = expr, - } - } - // This expression is a variable field expression - Value::Function(f) if f.name() == Some("type::field") => { - // Process the function using variable field projections - let expr = expr.compute(ctx, opt, txn, Some(doc)).await?; - // Check if this is a single VALUE field expression - match self.single().is_some() { - false => { - // Get the first argument which is guaranteed to exist - let name = match f.args().first().unwrap() { - Value::Param(v) => { - v.compute(ctx, opt, txn, Some(doc)).await? - } - v => v.to_owned(), - }; - // find the name for the field, either from the argument or the - // alias. - let name = if let Some(x) = alias.as_ref().map(Cow::Borrowed) { - x - } else { - Cow::Owned(syn::idiom(&name.to_raw_string())?) - }; - // Add the projected field to the output document - out.set(ctx, opt, txn, name.as_ref(), expr).await? - } - true => out = expr, - } - } - // This expression is a normal field expression - _ => { - let expr = 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, name.as_ref(), expr).await?, - true => out = expr, - } - } - } - } - } - } - Ok(out) - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Field { - /// The `*` in `SELECT * FROM ...` - #[default] - 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::Single { - expr, - alias, - } => { - Display::fmt(expr, f)?; - if let Some(alias) = alias { - f.write_str(" AS ")?; - Display::fmt(alias, f) - } else { - Ok(()) - } - } - } - } -} diff --git a/core/src/sql/v2/filter.rs b/core/src/sql/v2/filter.rs deleted file mode 100644 index eeb285d8..00000000 --- a/core/src/sql/v2/filter.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::sql::language::Language; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fmt::Display; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Filter { - Ascii, - EdgeNgram(u16, u16), - Lowercase, - Ngram(u16, u16), - Snowball(Language), - Uppercase, -} - -impl Display for Filter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Ascii => f.write_str("ASCII"), - Self::EdgeNgram(min, max) => write!(f, "EDGENGRAM({},{})", min, max), - Self::Lowercase => f.write_str("LOWERCASE"), - Self::Ngram(min, max) => write!(f, "NGRAM({},{})", min, max), - Self::Snowball(lang) => write!(f, "SNOWBALL({})", lang), - Self::Uppercase => f.write_str("UPPERCASE"), - } - } -} diff --git a/core/src/sql/v2/function.rs b/core/src/sql/v2/function.rs deleted file mode 100644 index 4f2a0803..00000000 --- a/core/src/sql/v2/function.rs +++ /dev/null @@ -1,289 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::fnc; -use crate::iam::Action; -use crate::sql::fmt::Fmt; -use crate::sql::idiom::Idiom; -use crate::sql::script::Script; -use crate::sql::value::Value; -use crate::sql::Permission; -use async_recursion::async_recursion; -use futures::future::try_join_all; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::fmt; - -use super::Kind; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Function"; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Function")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Function { - Normal(String, Vec), - Custom(String, Vec), - Script(Script, Vec), - // Add new variants here -} - -pub(crate) enum OptimisedAggregate { - None, - Count, - MathMax, - MathMin, - MathSum, - MathMean, - TimeMax, - TimeMin, -} - -impl PartialOrd for Function { - #[inline] - fn partial_cmp(&self, _: &Self) -> Option { - None - } -} - -impl Function { - /// Get function name if applicable - pub fn name(&self) -> Option<&str> { - match self { - Self::Normal(n, _) => Some(n.as_str()), - Self::Custom(n, _) => Some(n.as_str()), - _ => None, - } - } - /// Get function arguments if applicable - pub fn args(&self) -> &[Value] { - match self { - Self::Normal(_, a) => a, - Self::Custom(_, a) => a, - _ => &[], - } - } - /// Convert function call to a field name - pub fn to_idiom(&self) -> Idiom { - match self { - Self::Script(_, _) => "function".to_string().into(), - Self::Normal(f, _) => f.to_owned().into(), - Self::Custom(f, _) => format!("fn::{f}").into(), - } - } - /// Convert this function to an aggregate - pub fn aggregate(&self, val: Value) -> Self { - match self { - Self::Normal(n, a) => { - let mut a = a.to_owned(); - match a.len() { - 0 => a.insert(0, val), - _ => { - a.remove(0); - a.insert(0, val); - } - } - Self::Normal(n.to_owned(), a) - } - _ => unreachable!(), - } - } - /// Check if this function is a custom function - pub fn is_custom(&self) -> bool { - matches!(self, Self::Custom(_, _)) - } - - /// Check if this function is a scripting function - pub fn is_script(&self) -> bool { - matches!(self, Self::Script(_, _)) - } - - /// Check if this function has static arguments - pub fn is_static(&self) -> bool { - match self { - Self::Normal(_, a) => a.iter().all(Value::is_static), - _ => false, - } - } - - /// Check if this function is a rolling function - pub fn is_rolling(&self) -> bool { - match self { - Self::Normal(f, _) if f == "count" => true, - Self::Normal(f, _) if f == "math::max" => true, - Self::Normal(f, _) if f == "math::mean" => true, - Self::Normal(f, _) if f == "math::min" => true, - Self::Normal(f, _) if f == "math::sum" => true, - Self::Normal(f, _) if f == "time::max" => true, - Self::Normal(f, _) if f == "time::min" => true, - _ => false, - } - } - /// Check if this function is a grouping function - pub fn is_aggregate(&self) -> bool { - match self { - Self::Normal(f, _) if f == "array::distinct" => true, - Self::Normal(f, _) if f == "array::first" => true, - Self::Normal(f, _) if f == "array::flatten" => true, - Self::Normal(f, _) if f == "array::group" => true, - Self::Normal(f, _) if f == "array::last" => true, - Self::Normal(f, _) if f == "count" => true, - Self::Normal(f, _) if f == "math::bottom" => true, - Self::Normal(f, _) if f == "math::interquartile" => true, - Self::Normal(f, _) if f == "math::max" => true, - Self::Normal(f, _) if f == "math::mean" => true, - Self::Normal(f, _) if f == "math::median" => true, - Self::Normal(f, _) if f == "math::midhinge" => true, - Self::Normal(f, _) if f == "math::min" => true, - Self::Normal(f, _) if f == "math::mode" => true, - Self::Normal(f, _) if f == "math::nearestrank" => true, - Self::Normal(f, _) if f == "math::percentile" => true, - Self::Normal(f, _) if f == "math::sample" => true, - Self::Normal(f, _) if f == "math::spread" => true, - Self::Normal(f, _) if f == "math::stddev" => true, - Self::Normal(f, _) if f == "math::sum" => true, - Self::Normal(f, _) if f == "math::top" => true, - Self::Normal(f, _) if f == "math::trimean" => true, - Self::Normal(f, _) if f == "math::variance" => true, - Self::Normal(f, _) if f == "time::max" => true, - Self::Normal(f, _) if f == "time::min" => true, - _ => false, - } - } - pub(crate) fn get_optimised_aggregate(&self) -> OptimisedAggregate { - match self { - Self::Normal(f, _) if f == "count" => OptimisedAggregate::Count, - Self::Normal(f, _) if f == "math::max" => OptimisedAggregate::MathMax, - Self::Normal(f, _) if f == "math::mean" => OptimisedAggregate::MathMean, - Self::Normal(f, _) if f == "math::min" => OptimisedAggregate::MathMin, - Self::Normal(f, _) if f == "math::sum" => OptimisedAggregate::MathSum, - Self::Normal(f, _) if f == "time::max" => OptimisedAggregate::TimeMax, - Self::Normal(f, _) if f == "time::min" => OptimisedAggregate::TimeMin, - _ => OptimisedAggregate::None, - } - } -} - -impl Function { - /// Process this type returning a computed simple Value - #[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 CursorDoc<'_>>, - ) -> Result { - // Ensure futures are run - let opt = &opt.new_with_futures(true); - // Process the function type - match self { - Self::Normal(s, x) => { - // Check this function is allowed - ctx.check_allowed_function(s)?; - // Compute the function arguments - let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?; - // Run the normal function - fnc::run(ctx, opt, txn, doc, s, a).await - } - Self::Custom(s, x) => { - // Check that a database is set to prevent a panic - opt.valid_for_db()?; - // Get the full name of this function - let name = format!("fn::{s}"); - // Check this function is allowed - ctx.check_allowed_function(name.as_str())?; - // Get the function definition - let val = { - // Claim transaction - let mut run = txn.lock().await; - // Get the function definition - run.get_and_cache_db_function(opt.ns(), opt.db(), s).await? - }; - // Check permissions - if opt.check_perms(Action::View) { - match &val.permissions { - Permission::Full => (), - Permission::None => { - return Err(Error::FunctionPermissions { - name: s.to_owned(), - }) - } - Permission::Specific(e) => { - // Disable permissions - let opt = &opt.new_with_perms(false); - // Process the PERMISSION clause - if !e.compute(ctx, opt, txn, doc).await?.is_truthy() { - return Err(Error::FunctionPermissions { - name: s.to_owned(), - }); - } - } - } - } - // Get the number of function arguments - let max_args_len = val.args.len(); - // Track the number of required arguments - let mut min_args_len = 0; - // Check for any final optional arguments - val.args.iter().rev().for_each(|(_, kind)| match kind { - Kind::Option(_) if min_args_len == 0 => {} - _ => min_args_len += 1, - }); - // Check the necessary arguments are passed - if x.len() < min_args_len || max_args_len < x.len() { - return Err(Error::InvalidArguments { - name: format!("fn::{}", val.name), - message: match (min_args_len, max_args_len) { - (1, 1) => String::from("The function expects 1 argument."), - (r, t) if r == t => format!("The function expects {r} arguments."), - (r, t) => format!("The function expects {r} to {t} arguments."), - }, - }); - } - // Compute the function arguments - let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?; - // Duplicate context - 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.coerce_to(kind)?); - } - // Run the custom function - val.block.compute(&ctx, opt, txn, doc).await - } - #[allow(unused_variables)] - Self::Script(s, x) => { - #[cfg(feature = "scripting")] - { - // Check if scripting is allowed - ctx.check_allowed_scripting()?; - // Compute the function arguments - let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?; - // Run the script function - fnc::script::run(ctx, opt, txn, doc, s, a).await - } - #[cfg(not(feature = "scripting"))] - { - Err(Error::InvalidScript { - message: String::from("Embedded functions are not enabled."), - }) - } - } - } - } -} - -impl fmt::Display for Function { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - 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)), - } - } -} diff --git a/core/src/sql/v2/future.rs b/core/src/sql/v2/future.rs deleted file mode 100644 index 564f5095..00000000 --- a/core/src/sql/v2/future.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::block::Block; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Future"; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Future")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Future(pub Block); - -impl From for Future { - fn from(v: Value) -> Self { - Future(Block::from(v)) - } -} - -impl Future { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Process the future if enabled - match opt.futures { - true => self.0.compute(ctx, opt, txn, doc).await?.ok(), - false => Ok(self.clone().into()), - } - } -} - -impl fmt::Display for Future { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, " {}", self.0) - } -} diff --git a/core/src/sql/v2/geometry.rs b/core/src/sql/v2/geometry.rs deleted file mode 100644 index d8de4084..00000000 --- a/core/src/sql/v2/geometry.rs +++ /dev/null @@ -1,611 +0,0 @@ -#![allow(clippy::derived_hash_with_manual_eq)] - -use crate::sql::array::Array; -use crate::sql::fmt::Fmt; -use crate::sql::value::Value; -use geo::algorithm::contains::Contains; -use geo::algorithm::intersects::Intersects; -use geo::{Coord, LineString, Point, Polygon}; -use geo_types::{MultiLineString, MultiPoint, MultiPolygon}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::iter::once; -use std::{fmt, hash}; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Geometry"; - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename = "$surrealdb::private::sql::Geometry")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Geometry { - Point(Point), - Line(LineString), - Polygon(Polygon), - MultiPoint(MultiPoint), - MultiLine(MultiLineString), - MultiPolygon(MultiPolygon), - Collection(Vec), - // Add new variants here -} - -impl Geometry { - /// Check if this is a Point - pub fn is_point(&self) -> bool { - matches!(self, Self::Point(_)) - } - /// Check if this is a Line - pub fn is_line(&self) -> bool { - matches!(self, Self::Line(_)) - } - /// Check if this is a Polygon - pub fn is_polygon(&self) -> bool { - matches!(self, Self::Polygon(_)) - } - /// Check if this is a MultiPoint - pub fn is_multipoint(&self) -> bool { - matches!(self, Self::MultiPoint(_)) - } - /// Check if this is a MultiLine - pub fn is_multiline(&self) -> bool { - matches!(self, Self::MultiLine(_)) - } - /// Check if this is a MultiPolygon - pub fn is_multipolygon(&self) -> bool { - matches!(self, Self::MultiPolygon(_)) - } - /// Check if this is not a Collection - pub fn is_geometry(&self) -> bool { - !matches!(self, Self::Collection(_)) - } - /// Check if this is a Collection - pub fn is_collection(&self) -> bool { - matches!(self, Self::Collection(_)) - } - /// Get the type of this Geometry as text - pub fn as_type(&self) -> &'static str { - match self { - Self::Point(_) => "Point", - Self::Line(_) => "LineString", - Self::Polygon(_) => "Polygon", - Self::MultiPoint(_) => "MultiPoint", - Self::MultiLine(_) => "MultiLineString", - Self::MultiPolygon(_) => "MultiPolygon", - Self::Collection(_) => "GeometryCollection", - } - } - /// Get the raw coordinates of this Geometry as an Array - pub fn as_coordinates(&self) -> Value { - fn point(v: &Point) -> Value { - Array::from(vec![v.x(), v.y()]).into() - } - - fn line(v: &LineString) -> Value { - v.points().map(|v| point(&v)).collect::>().into() - } - - fn polygon(v: &Polygon) -> Value { - once(v.exterior()).chain(v.interiors()).map(line).collect::>().into() - } - - fn multipoint(v: &MultiPoint) -> Value { - v.iter().map(point).collect::>().into() - } - - fn multiline(v: &MultiLineString) -> Value { - v.iter().map(line).collect::>().into() - } - - fn multipolygon(v: &MultiPolygon) -> Value { - v.iter().map(polygon).collect::>().into() - } - - fn collection(v: &[Geometry]) -> Value { - v.iter().map(Geometry::as_coordinates).collect::>().into() - } - - match self { - Self::Point(v) => point(v), - Self::Line(v) => line(v), - Self::Polygon(v) => polygon(v), - Self::MultiPoint(v) => multipoint(v), - Self::MultiLine(v) => multiline(v), - Self::MultiPolygon(v) => multipolygon(v), - Self::Collection(v) => collection(v), - } - } -} - -impl PartialOrd for Geometry { - #[rustfmt::skip] - fn partial_cmp(&self, other: &Self) -> Option { - fn coord(v: &Coord) -> (f64, f64) { - v.x_y() - } - - fn point(v: &Point) -> (f64, f64) { - coord(&v.0) - } - - fn line(v: &LineString) -> impl Iterator + '_ { - v.into_iter().map(coord) - } - - fn polygon(v: &Polygon) -> impl Iterator + '_ { - v.interiors().iter().chain(once(v.exterior())).flat_map(line) - } - - fn multipoint(v: &MultiPoint) -> impl Iterator + '_ { - v.iter().map(point) - } - - fn multiline(v: &MultiLineString) -> impl Iterator + '_ { - v.iter().flat_map(line) - } - - fn multipolygon(v: &MultiPolygon) -> impl Iterator + '_ { - v.iter().flat_map(polygon) - } - - match (self, other) { - // - (Self::Point(_), Self::Line(_)) => Some(Ordering::Less), - (Self::Point(_), Self::Polygon(_)) => Some(Ordering::Less), - (Self::Point(_), Self::MultiPoint(_)) => Some(Ordering::Less), - (Self::Point(_), Self::MultiLine(_)) => Some(Ordering::Less), - (Self::Point(_), Self::MultiPolygon(_)) => Some(Ordering::Less), - (Self::Point(_), Self::Collection(_)) => Some(Ordering::Less), - // - (Self::Line(_), Self::Point(_)) => Some(Ordering::Greater), - (Self::Line(_), Self::Polygon(_)) => Some(Ordering::Less), - (Self::Line(_), Self::MultiPoint(_)) => Some(Ordering::Less), - (Self::Line(_), Self::MultiLine(_)) => Some(Ordering::Less), - (Self::Line(_), Self::MultiPolygon(_)) => Some(Ordering::Less), - (Self::Line(_), Self::Collection(_)) => Some(Ordering::Less), - // - (Self::Polygon(_), Self::Point(_)) => Some(Ordering::Greater), - (Self::Polygon(_), Self::Line(_)) => Some(Ordering::Greater), - (Self::Polygon(_), Self::MultiPoint(_)) => Some(Ordering::Less), - (Self::Polygon(_), Self::MultiLine(_)) => Some(Ordering::Less), - (Self::Polygon(_), Self::MultiPolygon(_)) => Some(Ordering::Less), - (Self::Polygon(_), Self::Collection(_)) => Some(Ordering::Less), - // - (Self::MultiPoint(_), Self::Point(_)) => Some(Ordering::Greater), - (Self::MultiPoint(_), Self::Line(_)) => Some(Ordering::Greater), - (Self::MultiPoint(_), Self::Polygon(_)) => Some(Ordering::Greater), - (Self::MultiPoint(_), Self::MultiLine(_)) => Some(Ordering::Less), - (Self::MultiPoint(_), Self::MultiPolygon(_)) => Some(Ordering::Less), - (Self::MultiPoint(_), Self::Collection(_)) => Some(Ordering::Less), - // - (Self::MultiLine(_), Self::Point(_)) => Some(Ordering::Greater), - (Self::MultiLine(_), Self::Line(_)) => Some(Ordering::Greater), - (Self::MultiLine(_), Self::Polygon(_)) => Some(Ordering::Greater), - (Self::MultiLine(_), Self::MultiPoint(_)) => Some(Ordering::Greater), - (Self::MultiLine(_), Self::MultiPolygon(_)) => Some(Ordering::Less), - (Self::MultiLine(_), Self::Collection(_)) => Some(Ordering::Less), - // - (Self::MultiPolygon(_), Self::Point(_)) => Some(Ordering::Greater), - (Self::MultiPolygon(_), Self::Line(_)) => Some(Ordering::Greater), - (Self::MultiPolygon(_), Self::Polygon(_)) => Some(Ordering::Greater), - (Self::MultiPolygon(_), Self::MultiPoint(_)) => Some(Ordering::Greater), - (Self::MultiPolygon(_), Self::MultiLine(_)) => Some(Ordering::Greater), - (Self::MultiPolygon(_), Self::Collection(_)) => Some(Ordering::Less), - // - (Self::Collection(_), Self::Point(_)) => Some(Ordering::Greater), - (Self::Collection(_), Self::Line(_)) => Some(Ordering::Greater), - (Self::Collection(_), Self::Polygon(_)) => Some(Ordering::Greater), - (Self::Collection(_), Self::MultiPoint(_)) => Some(Ordering::Greater), - (Self::Collection(_), Self::MultiLine(_)) => Some(Ordering::Greater), - (Self::Collection(_), Self::MultiPolygon(_)) => Some(Ordering::Greater), - // - (Self::Point(a), Self::Point(b)) => point(a).partial_cmp(&point(b)), - (Self::Line(a), Self::Line(b)) => line(a).partial_cmp(line(b)), - (Self::Polygon(a), Self::Polygon(b)) => polygon(a).partial_cmp(polygon(b)), - (Self::MultiPoint(a), Self::MultiPoint(b)) => multipoint(a).partial_cmp(multipoint(b)), - (Self::MultiLine(a), Self::MultiLine(b)) => multiline(a).partial_cmp(multiline(b)), - (Self::MultiPolygon(a), Self::MultiPolygon(b)) => multipolygon(a).partial_cmp(multipolygon(b)), - (Self::Collection(a), Self::Collection(b)) => a.partial_cmp(b), - } - } -} - -impl From<(f64, f64)> for Geometry { - fn from(v: (f64, f64)) -> Self { - Self::Point(v.into()) - } -} - -impl From<[f64; 2]> for Geometry { - fn from(v: [f64; 2]) -> Self { - Self::Point(v.into()) - } -} - -impl From> for Geometry { - fn from(v: Point) -> Self { - Self::Point(v) - } -} - -impl From> for Geometry { - fn from(v: LineString) -> Self { - Self::Line(v) - } -} - -impl From> for Geometry { - fn from(v: Polygon) -> Self { - Self::Polygon(v) - } -} - -impl From> for Geometry { - fn from(v: MultiPoint) -> Self { - Self::MultiPoint(v) - } -} - -impl From> for Geometry { - fn from(v: MultiLineString) -> Self { - Self::MultiLine(v) - } -} - -impl From> for Geometry { - fn from(v: MultiPolygon) -> Self { - Self::MultiPolygon(v) - } -} - -impl From> for Geometry { - fn from(v: Vec) -> Self { - Self::Collection(v) - } -} - -impl From>> for Geometry { - fn from(v: Vec>) -> Self { - Self::MultiPoint(MultiPoint(v)) - } -} - -impl From>> for Geometry { - fn from(v: Vec>) -> Self { - Self::MultiLine(MultiLineString(v)) - } -} - -impl From>> for Geometry { - fn from(v: Vec>) -> Self { - Self::MultiPolygon(MultiPolygon(v)) - } -} - -impl From for geo::Geometry { - fn from(v: Geometry) -> Self { - match v { - Geometry::Point(v) => v.into(), - Geometry::Line(v) => v.into(), - Geometry::Polygon(v) => v.into(), - Geometry::MultiPoint(v) => v.into(), - Geometry::MultiLine(v) => v.into(), - Geometry::MultiPolygon(v) => v.into(), - Geometry::Collection(v) => v.into_iter().collect::>(), - } - } -} - -impl FromIterator for geo::Geometry { - fn from_iter>(iter: I) -> Self { - let mut c: Vec> = vec![]; - for i in iter { - c.push(i.into()) - } - geo::Geometry::GeometryCollection(geo::GeometryCollection(c)) - } -} - -impl Geometry { - // ----------------------------------- - // Value operations - // ----------------------------------- - - pub fn contains(&self, other: &Self) -> bool { - match self { - Self::Point(v) => match other { - Self::Point(w) => v.contains(w), - Self::MultiPoint(w) => w.iter().all(|x| v.contains(x)), - Self::Collection(w) => w.iter().all(|x| self.contains(x)), - _ => false, - }, - Self::Line(v) => match other { - Self::Point(w) => v.contains(w), - Self::Line(w) => v.contains(w), - Self::MultiLine(w) => w.iter().all(|x| w.contains(x)), - Self::Collection(w) => w.iter().all(|x| self.contains(x)), - _ => false, - }, - Self::Polygon(v) => match other { - Self::Point(w) => v.contains(w), - Self::Line(w) => v.contains(w), - Self::Polygon(w) => v.contains(w), - Self::MultiPolygon(w) => w.iter().all(|x| w.contains(x)), - Self::Collection(w) => w.iter().all(|x| self.contains(x)), - _ => false, - }, - Self::MultiPoint(v) => match other { - Self::Point(w) => v.contains(w), - Self::MultiPoint(w) => w.iter().all(|x| w.contains(x)), - Self::Collection(w) => w.iter().all(|x| self.contains(x)), - _ => false, - }, - Self::MultiLine(v) => match other { - Self::Point(w) => v.contains(w), - Self::Line(w) => v.contains(w), - Self::MultiLine(w) => w.iter().all(|x| w.contains(x)), - Self::Collection(w) => w.iter().all(|x| self.contains(x)), - _ => false, - }, - Self::MultiPolygon(v) => match other { - Self::Point(w) => v.contains(w), - Self::Line(w) => v.contains(w), - Self::Polygon(w) => v.contains(w), - Self::MultiPoint(w) => v.contains(w), - Self::MultiLine(w) => v.contains(w), - Self::MultiPolygon(w) => v.contains(w), - Self::Collection(w) => w.iter().all(|x| self.contains(x)), - }, - Self::Collection(v) => v.iter().all(|x| x.contains(other)), - } - } - - pub fn intersects(&self, other: &Self) -> bool { - match self { - Self::Point(v) => match other { - Self::Point(w) => v.intersects(w), - Self::Line(w) => v.intersects(w), - Self::Polygon(w) => v.intersects(w), - Self::MultiPoint(w) => v.intersects(w), - Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)), - Self::MultiPolygon(w) => v.intersects(w), - Self::Collection(w) => w.iter().all(|x| self.intersects(x)), - }, - Self::Line(v) => match other { - Self::Point(w) => v.intersects(w), - Self::Line(w) => v.intersects(w), - Self::Polygon(w) => v.intersects(w), - Self::MultiPoint(w) => v.intersects(w), - Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)), - Self::MultiPolygon(w) => v.intersects(w), - Self::Collection(w) => w.iter().all(|x| self.intersects(x)), - }, - Self::Polygon(v) => match other { - Self::Point(w) => v.intersects(w), - Self::Line(w) => v.intersects(w), - Self::Polygon(w) => v.intersects(w), - Self::MultiPoint(w) => v.intersects(w), - Self::MultiLine(w) => v.intersects(w), - Self::MultiPolygon(w) => v.intersects(w), - Self::Collection(w) => w.iter().all(|x| self.intersects(x)), - }, - Self::MultiPoint(v) => match other { - Self::Point(w) => v.intersects(w), - Self::Line(w) => v.intersects(w), - Self::Polygon(w) => v.intersects(w), - Self::MultiPoint(w) => v.intersects(w), - Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)), - Self::MultiPolygon(w) => v.intersects(w), - Self::Collection(w) => w.iter().all(|x| self.intersects(x)), - }, - Self::MultiLine(v) => match other { - Self::Point(w) => v.intersects(w), - Self::Line(w) => v.intersects(w), - Self::Polygon(w) => v.intersects(w), - Self::MultiPoint(w) => v.intersects(w), - Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)), - Self::MultiPolygon(w) => v.intersects(w), - Self::Collection(w) => w.iter().all(|x| self.intersects(x)), - }, - Self::MultiPolygon(v) => match other { - Self::Point(w) => v.intersects(w), - Self::Line(w) => v.intersects(w), - Self::Polygon(w) => v.intersects(w), - Self::MultiPoint(w) => v.intersects(w), - Self::MultiLine(w) => v.intersects(w), - Self::MultiPolygon(w) => v.intersects(w), - Self::Collection(w) => w.iter().all(|x| self.intersects(x)), - }, - Self::Collection(v) => v.iter().all(|x| x.intersects(other)), - } - } -} - -impl fmt::Display for Geometry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Point(v) => { - write!(f, "({}, {})", v.x(), v.y()) - } - Self::Line(v) => write!( - f, - "{{ type: 'LineString', coordinates: [{}] }}", - Fmt::comma_separated(v.points().map(|v| Fmt::new(v, |v, f| write!( - f, - "[{}, {}]", - v.x(), - v.y() - )))) - ), - Self::Polygon(v) => write!( - f, - "{{ type: 'Polygon', coordinates: [[{}]{}] }}", - Fmt::comma_separated(v.exterior().points().map(|v| Fmt::new(v, |v, f| write!( - f, - "[{}, {}]", - v.x(), - v.y() - )))), - Fmt::new(v.interiors(), |interiors, f| { - match interiors.len() { - 0 => Ok(()), - _ => write!( - f, - ", [{}]", - Fmt::comma_separated(interiors.iter().map(|i| Fmt::new(i, |i, f| { - write!( - f, - "[{}]", - Fmt::comma_separated(i.points().map(|v| Fmt::new( - v, - |v, f| write!(f, "[{}, {}]", v.x(), v.y()) - ))) - ) - }))) - ), - } - }) - ), - Self::MultiPoint(v) => { - write!( - f, - "{{ type: 'MultiPoint', coordinates: [{}] }}", - Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| write!( - f, - "[{}, {}]", - v.x(), - v.y() - )))) - ) - } - Self::MultiLine(v) => write!( - f, - "{{ type: 'MultiLineString', coordinates: [{}] }}", - Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| write!( - f, - "[{}]", - Fmt::comma_separated(v.points().map(|v| Fmt::new(v, |v, f| write!( - f, - "[{}, {}]", - v.x(), - v.y() - )))) - )))) - ), - Self::MultiPolygon(v) => write!( - f, - "{{ type: 'MultiPolygon', coordinates: [{}] }}", - Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| { - write!( - f, - "[[{}]{}]", - Fmt::comma_separated( - v.exterior().points().map(|v| Fmt::new(v, |v, f| write!( - f, - "[{}, {}]", - v.x(), - v.y() - ))) - ), - Fmt::new(v.interiors(), |interiors, f| { - match interiors.len() { - 0 => Ok(()), - _ => write!( - f, - ", [{}]", - Fmt::comma_separated(interiors.iter().map(|i| Fmt::new( - i, - |i, f| { - write!( - f, - "[{}]", - Fmt::comma_separated(i.points().map(|v| Fmt::new( - v, - |v, f| write!(f, "[{}, {}]", v.x(), v.y()) - ))) - ) - } - ))) - ), - } - }) - ) - }))), - ), - Self::Collection(v) => { - write!( - f, - "{{ type: 'GeometryCollection', geometries: [{}] }}", - Fmt::comma_separated(v) - ) - } - } - } -} - -impl hash::Hash for Geometry { - fn hash(&self, state: &mut H) { - match self { - Geometry::Point(p) => { - "Point".hash(state); - p.x().to_bits().hash(state); - p.y().to_bits().hash(state); - } - Geometry::Line(l) => { - "Line".hash(state); - l.points().for_each(|v| { - v.x().to_bits().hash(state); - v.y().to_bits().hash(state); - }); - } - Geometry::Polygon(p) => { - "Polygon".hash(state); - p.exterior().points().for_each(|ext| { - ext.x().to_bits().hash(state); - ext.y().to_bits().hash(state); - }); - p.interiors().iter().for_each(|int| { - int.points().for_each(|v| { - v.x().to_bits().hash(state); - v.y().to_bits().hash(state); - }); - }); - } - Geometry::MultiPoint(v) => { - "MultiPoint".hash(state); - v.0.iter().for_each(|v| { - v.x().to_bits().hash(state); - v.y().to_bits().hash(state); - }); - } - Geometry::MultiLine(ml) => { - "MultiLine".hash(state); - ml.0.iter().for_each(|ls| { - ls.points().for_each(|p| { - p.x().to_bits().hash(state); - p.y().to_bits().hash(state); - }); - }); - } - Geometry::MultiPolygon(mp) => { - "MultiPolygon".hash(state); - mp.0.iter().for_each(|p| { - p.exterior().points().for_each(|ext| { - ext.x().to_bits().hash(state); - ext.y().to_bits().hash(state); - }); - p.interiors().iter().for_each(|int| { - int.points().for_each(|v| { - v.x().to_bits().hash(state); - v.y().to_bits().hash(state); - }); - }); - }); - } - Geometry::Collection(v) => { - "GeometryCollection".hash(state); - v.iter().for_each(|v| v.hash(state)); - } - } - } -} diff --git a/core/src/sql/v2/graph.rs b/core/src/sql/v2/graph.rs deleted file mode 100644 index 88590579..00000000 --- a/core/src/sql/v2/graph.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::sql::cond::Cond; -use crate::sql::dir::Dir; -use crate::sql::field::Fields; -use crate::sql::group::Groups; -use crate::sql::idiom::Idiom; -use crate::sql::limit::Limit; -use crate::sql::order::Orders; -use crate::sql::split::Splits; -use crate::sql::start::Start; -use crate::sql::table::Tables; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter, Write}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Graph { - pub dir: Dir, - pub expr: Fields, - pub what: Tables, - pub cond: Option, - pub split: Option, - pub group: Option, - pub order: Option, - pub limit: Option, - pub start: Option, - pub alias: Option, -} - -impl Graph { - /// Convert the graph edge to a raw String - pub fn to_raw(&self) -> String { - self.to_string() - } -} - -impl Display for Graph { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if self.what.0.len() <= 1 && self.cond.is_none() && self.alias.is_none() { - Display::fmt(&self.dir, f)?; - match self.what.len() { - 0 => f.write_char('?'), - _ => Display::fmt(&self.what, f), - } - } else { - write!(f, "{}(", self.dir)?; - match self.what.len() { - 0 => f.write_char('?'), - _ => Display::fmt(&self.what, f), - }?; - if let Some(ref v) = self.cond { - write!(f, " {v}")? - } - if let Some(ref v) = self.split { - write!(f, " {v}")? - } - if let Some(ref v) = self.group { - write!(f, " {v}")? - } - if let Some(ref v) = self.order { - write!(f, " {v}")? - } - if let Some(ref v) = self.limit { - write!(f, " {v}")? - } - if let Some(ref v) = self.start { - write!(f, " {v}")? - } - if let Some(ref v) = self.alias { - write!(f, " AS {v}")? - } - f.write_char(')') - } - } -} diff --git a/core/src/sql/v2/group.rs b/core/src/sql/v2/group.rs deleted file mode 100644 index 4b92573b..00000000 --- a/core/src/sql/v2/group.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::sql::fmt::Fmt; -use crate::sql::idiom::Idiom; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Groups(pub Vec); - -impl Deref for Groups { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Groups { - type Item = Group; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Display for Groups { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if self.0.is_empty() { - write!(f, "GROUP ALL") - } else { - write!(f, "GROUP BY {}", Fmt::comma_separated(&self.0)) - } - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Group(pub Idiom); - -impl Deref for Group { - type Target = Idiom; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Group { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&self.0, f) - } -} diff --git a/core/src/sql/v2/id.rs b/core/src/sql/v2/id.rs deleted file mode 100644 index 11412781..00000000 --- a/core/src/sql/v2/id.rs +++ /dev/null @@ -1,206 +0,0 @@ -use crate::cnf::ID_CHARS; -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{escape::escape_rid, Array, Number, Object, Strand, Thing, Uuid, Value}; -use nanoid::nanoid; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use std::fmt::{self, Display, Formatter}; -use ulid::Ulid; - -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Gen { - Rand, - Ulid, - Uuid, -} - -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Id { - Number(i64), - String(String), - Array(Array), - Object(Object), - Generate(Gen), -} - -impl From for Id { - fn from(v: i64) -> Self { - Self::Number(v) - } -} - -impl From for Id { - fn from(v: i32) -> Self { - Self::Number(v as i64) - } -} - -impl From for Id { - fn from(v: u64) -> Self { - Self::Number(v as i64) - } -} - -impl From for Id { - fn from(v: String) -> Self { - Self::String(v) - } -} - -impl From for Id { - fn from(v: Array) -> Self { - Self::Array(v) - } -} - -impl From for Id { - fn from(v: Object) -> Self { - Self::Object(v) - } -} - -impl From for Id { - fn from(v: Uuid) -> Self { - Self::String(v.to_raw()) - } -} - -impl From for Id { - fn from(v: Strand) -> Self { - Self::String(v.as_string()) - } -} - -impl From<&str> for Id { - fn from(v: &str) -> Self { - Self::String(v.to_owned()) - } -} - -impl From<&String> for Id { - fn from(v: &String) -> Self { - Self::String(v.to_owned()) - } -} - -impl From> for Id { - fn from(v: Vec<&str>) -> Self { - Id::Array(v.into()) - } -} - -impl From> for Id { - fn from(v: Vec) -> Self { - Id::Array(v.into()) - } -} - -impl From> for Id { - fn from(v: Vec) -> Self { - Id::Array(v.into()) - } -} - -impl From> for Id { - fn from(v: BTreeMap) -> Self { - Id::Object(v.into()) - } -} - -impl From for Id { - fn from(v: Number) -> Self { - match v { - Number::Int(v) => v.into(), - Number::Float(v) => v.to_string().into(), - Number::Decimal(v) => v.to_string().into(), - } - } -} - -impl From for Id { - fn from(v: Thing) -> Self { - v.id - } -} - -impl Id { - /// Generate a new random ID - pub fn rand() -> Self { - Self::String(nanoid!(20, &ID_CHARS)) - } - /// Generate a new random ULID - pub fn ulid() -> Self { - Self::String(Ulid::new().to_string()) - } - /// Generate a new random UUID - pub fn uuid() -> Self { - Self::String(Uuid::new_v7().to_raw()) - } - /// Convert the Id to a raw String - pub fn to_raw(&self) -> String { - match self { - Self::Number(v) => v.to_string(), - Self::String(v) => v.to_string(), - Self::Array(v) => v.to_string(), - Self::Object(v) => v.to_string(), - Self::Generate(v) => match v { - Gen::Rand => "rand()".to_string(), - Gen::Ulid => "ulid()".to_string(), - Gen::Uuid => "uuid()".to_string(), - }, - } - } -} - -impl Display for Id { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Number(v) => Display::fmt(v, f), - Self::String(v) => Display::fmt(&escape_rid(v), f), - Self::Array(v) => Display::fmt(v, f), - Self::Object(v) => Display::fmt(v, f), - Self::Generate(v) => match v { - Gen::Rand => Display::fmt("rand()", f), - Gen::Ulid => Display::fmt("ulid()", f), - Gen::Uuid => Display::fmt("uuid()", f), - }, - } - } -} - -impl Id { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self { - Id::Number(v) => Ok(Id::Number(*v)), - Id::String(v) => Ok(Id::String(v.clone())), - Id::Array(v) => match v.compute(ctx, opt, txn, doc).await? { - Value::Array(v) => Ok(Id::Array(v)), - _ => unreachable!(), - }, - Id::Object(v) => match v.compute(ctx, opt, txn, doc).await? { - Value::Object(v) => Ok(Id::Object(v)), - _ => unreachable!(), - }, - Id::Generate(v) => match v { - Gen::Rand => Ok(Self::rand()), - Gen::Ulid => Ok(Self::ulid()), - Gen::Uuid => Ok(Self::uuid()), - }, - } - } -} diff --git a/core/src/sql/v2/ident.rs b/core/src/sql/v2/ident.rs deleted file mode 100644 index 20366292..00000000 --- a/core/src/sql/v2/ident.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::sql::{escape::escape_ident, strand::no_nul_bytes}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; -use std::str; - -#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Ident(#[serde(with = "no_nul_bytes")] pub String); - -impl From for Ident { - fn from(v: String) -> Self { - Self(v) - } -} - -impl From<&str> for Ident { - fn from(v: &str) -> Self { - Self::from(String::from(v)) - } -} - -impl Deref for Ident { - type Target = String; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Ident { - /// Convert the Ident to a raw String - pub fn to_raw(&self) -> String { - self.0.to_string() - } - /// Checks if this field is the `id` field - pub(crate) fn is_id(&self) -> bool { - self.0.as_str() == "id" - } - /// Checks if this field is the `type` field - pub(crate) fn is_type(&self) -> bool { - self.0.as_str() == "type" - } - /// Checks if this field is the `coordinates` field - pub(crate) fn is_coordinates(&self) -> bool { - self.0.as_str() == "coordinates" - } - /// Checks if this field is the `geometries` field - pub(crate) fn is_geometries(&self) -> bool { - self.0.as_str() == "geometries" - } -} - -impl Display for Ident { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&escape_ident(&self.0), f) - } -} diff --git a/core/src/sql/v2/idiom.rs b/core/src/sql/v2/idiom.rs deleted file mode 100644 index aa40210c..00000000 --- a/core/src/sql/v2/idiom.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{ - fmt::{fmt_separated_by, Fmt}, - part::Next, - paths::{ID, IN, META, OUT}, - Part, Value, -}; -use md5::{Digest, Md5}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; -use std::str; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Idiom"; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Idioms(pub Vec); - -impl Deref for Idioms { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Idioms { - type Item = Idiom; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Display for Idioms { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&Fmt::comma_separated(&self.0), f) - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Idiom")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Idiom(pub Vec); - -impl Deref for Idiom { - type Target = [Part]; - fn deref(&self) -> &Self::Target { - self.0.as_slice() - } -} - -impl From for Idiom { - fn from(v: String) -> Self { - Self(vec![Part::from(v)]) - } -} - -impl From> for Idiom { - fn from(v: Vec) -> Self { - Self(v) - } -} - -impl From<&[Part]> for Idiom { - fn from(v: &[Part]) -> Self { - Self(v.to_vec()) - } -} -impl From for Idiom { - fn from(v: Part) -> Self { - Self(vec![v]) - } -} - -impl Idiom { - /// Appends a part to the end of this Idiom - pub(crate) fn push(mut self, n: Part) -> Idiom { - self.0.push(n); - self - } - /// Convert this Idiom to a unique hash - pub(crate) fn to_hash(&self) -> String { - let mut hasher = Md5::new(); - hasher.update(self.to_string().as_str()); - format!("{:x}", hasher.finalize()) - } - /// Convert this Idiom to a JSON Path string - pub(crate) fn to_path(&self) -> String { - format!("/{self}").replace(']', "").replace(&['.', '['][..], "/") - } - /// Simplifies this Idiom for use in object keys - pub(crate) fn simplify(&self) -> Idiom { - self.0 - .iter() - .filter(|&p| { - matches!(p, Part::Field(_) | Part::Start(_) | Part::Value(_) | Part::Graph(_)) - }) - .cloned() - .collect::>() - .into() - } - /// Check if this Idiom is an 'id' field - pub(crate) fn is_id(&self) -> bool { - self.0.len() == 1 && self.0[0].eq(&ID[0]) - } - /// Check if this Idiom is an 'in' field - pub(crate) fn is_in(&self) -> bool { - self.0.len() == 1 && self.0[0].eq(&IN[0]) - } - /// Check if this Idiom is an 'out' field - pub(crate) fn is_out(&self) -> bool { - self.0.len() == 1 && self.0[0].eq(&OUT[0]) - } - /// Check if this Idiom is a 'meta' field - pub(crate) fn is_meta(&self) -> bool { - self.0.len() == 1 && self.0[0].eq(&META[0]) - } - /// Check if this is an expression with multiple yields - pub(crate) fn is_multi_yield(&self) -> bool { - self.iter().any(Self::split_multi_yield) - } - /// Check if the path part is a yield in a multi-yield expression - pub(crate) fn split_multi_yield(v: &Part) -> bool { - matches!(v, Part::Graph(g) if g.alias.is_some()) - } - /// Check if the path part is a yield in a multi-yield expression - pub(crate) fn remove_trailing_all(&mut self) { - if self.ends_with(&[Part::All]) { - self.0.truncate(self.len() - 1); - } - } -} - -impl Idiom { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - self.0.iter().any(|v| v.writeable()) - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self.first() { - // The starting part is a value - Some(Part::Start(v)) => { - v.compute(ctx, opt, txn, doc) - .await? - .get(ctx, opt, txn, doc, self.as_ref().next()) - .await? - .compute(ctx, opt, txn, doc) - .await - } - // Otherwise use the current document - _ => match doc { - // There is a current document - Some(v) => { - v.doc.get(ctx, opt, txn, doc, self).await?.compute(ctx, opt, txn, doc).await - } - // There isn't any document - None => Ok(Value::None), - }, - } - } -} - -impl Display for Idiom { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt( - &Fmt::new( - self.0.iter().enumerate().map(|args| { - Fmt::new(args, |(i, p), f| match (i, p) { - (0, Part::Field(v)) => Display::fmt(v, f), - _ => Display::fmt(p, f), - }) - }), - fmt_separated_by(""), - ), - f, - ) - } -} diff --git a/core/src/sql/v2/index.rs b/core/src/sql/v2/index.rs deleted file mode 100644 index f5820cb7..00000000 --- a/core/src/sql/v2/index.rs +++ /dev/null @@ -1,200 +0,0 @@ -use crate::err::Error; -use crate::fnc::util::math::vector::{ - ChebyshevDistance, CosineSimilarity, EuclideanDistance, HammingDistance, JaccardSimilarity, - ManhattanDistance, MinkowskiDistance, PearsonSimilarity, -}; -use crate::sql::ident::Ident; -use crate::sql::scoring::Scoring; -use crate::sql::Number; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fmt::{Display, Formatter}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Index { - /// (Basic) non unique - #[default] - Idx, - /// Unique index - Uniq, - /// Index with Full-Text search capabilities - Search(SearchParams), - /// M-Tree index for distance based metrics - MTree(MTreeParams), -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 2)] -pub struct SearchParams { - pub az: Ident, - pub hl: bool, - pub sc: Scoring, - pub doc_ids_order: u32, - pub doc_lengths_order: u32, - pub postings_order: u32, - pub terms_order: u32, - #[revision(start = 2)] - pub doc_ids_cache: u32, - #[revision(start = 2)] - pub doc_lengths_cache: u32, - #[revision(start = 2)] - pub postings_cache: u32, - #[revision(start = 2)] - pub terms_cache: u32, -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 2)] -pub struct MTreeParams { - pub dimension: u16, - #[revision(start = 1, end = 2, convert_fn = "convert_old_distance")] - pub _distance: Distance1, // TODO remove once 1.0 && 1.1 are EOL - #[revision(start = 2)] - pub distance: Distance, - pub vector_type: VectorType, - pub capacity: u16, - pub doc_ids_order: u32, - #[revision(start = 2)] - pub doc_ids_cache: u32, - #[revision(start = 2)] - pub mtree_cache: u32, -} - -impl MTreeParams { - fn convert_old_distance( - &mut self, - _revision: u16, - d1: Distance1, - ) -> Result<(), revision::Error> { - self.distance = match d1 { - Distance1::Euclidean => Distance::Euclidean, - Distance1::Manhattan => Distance::Manhattan, - Distance1::Cosine => Distance::Cosine, - Distance1::Hamming => Distance::Hamming, - Distance1::Minkowski(n) => Distance::Minkowski(n), - }; - Ok(()) - } -} - -#[derive(Clone, Default, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Distance1 { - #[default] - Euclidean, - Manhattan, - Cosine, - Hamming, - Minkowski(Number), -} - -#[derive(Clone, Default, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Distance { - Chebyshev, - Cosine, - #[default] - Euclidean, - Hamming, - Jaccard, - Manhattan, - Minkowski(Number), - Pearson, -} - -impl Distance { - pub(crate) fn compute(&self, v1: &Vec, v2: &Vec) -> Result { - match self { - Self::Cosine => v1.cosine_similarity(v2), - Self::Chebyshev => v1.chebyshev_distance(v2), - Self::Euclidean => v1.euclidean_distance(v2), - Self::Hamming => v1.hamming_distance(v2), - Self::Jaccard => v1.jaccard_similarity(v2), - Self::Manhattan => v1.manhattan_distance(v2), - Self::Minkowski(r) => v1.minkowski_distance(v2, r), - Self::Pearson => v1.pearson_similarity(v2), - } - } -} - -impl Display for Distance { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::Chebyshev => f.write_str("CHEBYSHEV"), - Self::Cosine => f.write_str("COSINE"), - Self::Euclidean => f.write_str("EUCLIDEAN"), - Self::Hamming => f.write_str("HAMMING"), - Self::Jaccard => f.write_str("JACCARD"), - Self::Manhattan => f.write_str("MANHATTAN"), - Self::Minkowski(order) => write!(f, "MINKOWSKI {}", order), - Self::Pearson => f.write_str("PEARSON"), - } - } -} - -#[derive(Clone, Copy, Default, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum VectorType { - #[default] - F64, - F32, - I64, - I32, - I16, -} - -impl Display for VectorType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::F64 => f.write_str("F64"), - Self::F32 => f.write_str("F32"), - Self::I64 => f.write_str("I64"), - Self::I32 => f.write_str("I32"), - Self::I16 => f.write_str("I16"), - } - } -} - -impl Display for Index { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Idx => Ok(()), - Self::Uniq => f.write_str("UNIQUE"), - Self::Search(p) => { - write!( - f, - "SEARCH ANALYZER {} {} DOC_IDS_ORDER {} DOC_LENGTHS_ORDER {} POSTINGS_ORDER {} TERMS_ORDER {} DOC_IDS_CACHE {} DOC_LENGTHS_CACHE {} POSTINGS_CACHE {} TERMS_CACHE {}", - p.az, - p.sc, - p.doc_ids_order, - p.doc_lengths_order, - p.postings_order, - p.terms_order, - p.doc_ids_cache, - p.doc_lengths_cache, - p.postings_cache, - p.terms_cache - )?; - if p.hl { - f.write_str(" HIGHLIGHTS")? - } - Ok(()) - } - Self::MTree(p) => { - write!( - f, - "MTREE DIMENSION {} DIST {} TYPE {} CAPACITY {} DOC_IDS_ORDER {} DOC_IDS_CACHE {} MTREE_CACHE {}", - p.dimension, p.distance, p.vector_type, p.capacity, p.doc_ids_order, p.doc_ids_cache, p.mtree_cache - ) - } - } - } -} diff --git a/core/src/sql/v2/kind.rs b/core/src/sql/v2/kind.rs deleted file mode 100644 index 1de38bbc..00000000 --- a/core/src/sql/v2/kind.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::sql::{fmt::Fmt, Table}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Kind { - Any, - Null, - Bool, - Bytes, - Datetime, - Decimal, - Duration, - Float, - Int, - Number, - Object, - Point, - String, - Uuid, - Record(Vec
), - Geometry(Vec), - Option(Box), - Either(Vec), - Set(Box, Option), - Array(Box, Option), -} - -impl Default for Kind { - fn default() -> Self { - Self::Any - } -} - -impl Kind { - fn is_any(&self) -> bool { - matches!(self, Kind::Any) - } - - // return the kind of the contained value. - // - // For example: for `array` or `set` this returns `number`. - // For `array | set` this returns `number | float`. - pub(crate) fn inner_kind(&self) -> Option { - let mut this = self; - loop { - match &this { - Kind::Any - | Kind::Null - | Kind::Bool - | Kind::Bytes - | Kind::Datetime - | Kind::Decimal - | Kind::Duration - | Kind::Float - | Kind::Int - | Kind::Number - | Kind::Object - | Kind::Point - | Kind::String - | Kind::Uuid - | Kind::Record(_) - | Kind::Geometry(_) => return None, - Kind::Option(x) => { - this = x; - } - Kind::Array(x, _) | Kind::Set(x, _) => return Some(x.as_ref().clone()), - Kind::Either(x) => { - // a either shouldn't be able to contain a either itself so recursing here - // should be fine. - let kinds: Vec = x.iter().filter_map(Self::inner_kind).collect(); - if kinds.is_empty() { - return None; - } - return Some(Kind::Either(kinds)); - } - } - } - } -} - -impl From<&Kind> for Box { - #[inline] - fn from(v: &Kind) -> Self { - Box::new(v.clone()) - } -} - -impl Display for Kind { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Kind::Any => f.write_str("any"), - Kind::Null => f.write_str("null"), - Kind::Bool => f.write_str("bool"), - Kind::Bytes => f.write_str("bytes"), - Kind::Datetime => f.write_str("datetime"), - Kind::Decimal => f.write_str("decimal"), - Kind::Duration => f.write_str("duration"), - Kind::Float => f.write_str("float"), - Kind::Int => f.write_str("int"), - Kind::Number => f.write_str("number"), - Kind::Object => f.write_str("object"), - Kind::Point => f.write_str("point"), - Kind::String => f.write_str("string"), - Kind::Uuid => f.write_str("uuid"), - Kind::Option(k) => write!(f, "option<{}>", k), - Kind::Record(k) => match k { - k if k.is_empty() => write!(f, "record"), - k => write!(f, "record<{}>", Fmt::verbar_separated(k)), - }, - Kind::Geometry(k) => match k { - k if k.is_empty() => write!(f, "geometry"), - k => write!(f, "geometry<{}>", Fmt::verbar_separated(k)), - }, - Kind::Set(k, l) => match (k, l) { - (k, None) if k.is_any() => write!(f, "set"), - (k, None) => write!(f, "set<{k}>"), - (k, Some(l)) => write!(f, "set<{k}, {l}>"), - }, - Kind::Array(k, l) => match (k, l) { - (k, None) if k.is_any() => write!(f, "array"), - (k, None) => write!(f, "array<{k}>"), - (k, Some(l)) => write!(f, "array<{k}, {l}>"), - }, - Kind::Either(k) => write!(f, "{}", Fmt::verbar_separated(k)), - } - } -} diff --git a/core/src/sql/v2/language.rs b/core/src/sql/v2/language.rs deleted file mode 100644 index 552d931f..00000000 --- a/core/src/sql/v2/language.rs +++ /dev/null @@ -1,57 +0,0 @@ -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fmt::Display; - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Language { - Arabic, - Danish, - Dutch, - English, - French, - German, - Greek, - Hungarian, - Italian, - Norwegian, - Portuguese, - Romanian, - Russian, - Spanish, - Swedish, - Tamil, - Turkish, -} - -impl Language { - pub fn as_str(&self) -> &'static str { - match self { - Self::Arabic => "ARABIC", - Self::Danish => "DANISH", - Self::Dutch => "DUTCH", - Self::English => "ENGLISH", - Self::French => "FRENCH", - Self::German => "GERMAN", - Self::Greek => "GREEK", - Self::Hungarian => "HUNGARIAN", - Self::Italian => "ITALIAN", - Self::Norwegian => "NORWEGIAN", - Self::Portuguese => "PORTUGUESE", - Self::Romanian => "ROMANIAN", - Self::Russian => "RUSSIAN", - Self::Spanish => "SPANISH", - Self::Swedish => "SWEDISH", - Self::Tamil => "TAMIL", - Self::Turkish => "TURKISH", - } - } -} - -impl Display for Language { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.as_str()) - } -} diff --git a/core/src/sql/v2/limit.rs b/core/src/sql/v2/limit.rs deleted file mode 100644 index 46f3e0c4..00000000 --- a/core/src/sql/v2/limit.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::number::Number; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Limit(pub Value); - -impl Limit { - pub(crate) async fn process( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self.0.compute(ctx, opt, txn, doc).await { - // This is a valid limiting number - Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize), - // An invalid value was specified - Ok(v) => Err(Error::InvalidLimit { - value: v.as_string(), - }), - // A different error occurred - Err(e) => Err(e), - } - } -} - -impl fmt::Display for Limit { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LIMIT {}", self.0) - } -} diff --git a/core/src/sql/v2/mock.rs b/core/src/sql/v2/mock.rs deleted file mode 100644 index 8e878082..00000000 --- a/core/src/sql/v2/mock.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::sql::{escape::escape_ident, Id, Thing}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Mock"; - -pub struct IntoIter { - model: Mock, - index: u64, -} - -impl Iterator for IntoIter { - type Item = Thing; - fn next(&mut self) -> Option { - match &self.model { - Mock::Count(tb, c) => { - if self.index < *c { - self.index += 1; - Some(Thing { - tb: tb.to_string(), - id: Id::rand(), - }) - } else { - None - } - } - Mock::Range(tb, b, e) => { - if self.index == 0 { - self.index = *b - 1; - } - if self.index < *e { - self.index += 1; - Some(Thing { - tb: tb.to_string(), - id: Id::from(self.index), - }) - } else { - None - } - } - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Mock")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Mock { - Count(String, u64), - Range(String, u64, u64), - // Add new variants here -} - -impl IntoIterator for Mock { - type Item = Thing; - type IntoIter = IntoIter; - fn into_iter(self) -> Self::IntoIter { - IntoIter { - model: self, - index: 0, - } - } -} - -impl fmt::Display for Mock { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Mock::Count(tb, c) => { - write!(f, "|{}:{}|", escape_ident(tb), c) - } - Mock::Range(tb, b, e) => { - write!(f, "|{}:{}..{}|", escape_ident(tb), b, e) - } - } - } -} diff --git a/core/src/sql/v2/mod.rs b/core/src/sql/v2/mod.rs deleted file mode 100644 index 776345c4..00000000 --- a/core/src/sql/v2/mod.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! The full type definitions for the SurrealQL query language - -pub(crate) mod algorithm; -#[cfg(feature = "arbitrary")] -pub(crate) mod arbitrary; -pub(crate) mod array; -pub(crate) mod base; -pub(crate) mod block; -pub(crate) mod bytes; -pub(crate) mod cast; -pub(crate) mod change_feed_include; -pub(crate) mod changefeed; -pub(crate) mod cond; -pub(crate) mod constant; -pub(crate) mod data; -pub(crate) mod datetime; -pub(crate) mod dir; -pub(crate) mod duration; -pub(crate) mod edges; -pub(crate) mod escape; -pub(crate) mod explain; -pub(crate) mod expression; -pub(crate) mod fetch; -pub(crate) mod field; -pub(crate) mod filter; -pub(crate) mod fmt; -pub(crate) mod function; -pub(crate) mod future; -pub(crate) mod geometry; -pub(crate) mod graph; -pub(crate) mod group; -pub(crate) mod id; -pub(crate) mod ident; -pub(crate) mod idiom; -pub(crate) mod kind; -pub(crate) mod language; -pub(crate) mod limit; -pub(crate) mod mock; -pub(crate) mod model; -pub(crate) mod number; -pub(crate) mod object; -pub(crate) mod operation; -pub(crate) mod operator; -pub(crate) mod order; -pub(crate) mod output; -pub(crate) mod param; -pub(crate) mod part; -pub(crate) mod paths; -pub(crate) mod permission; -pub(crate) mod query; -pub(crate) mod range; -pub(crate) mod regex; -pub(crate) mod scoring; -pub(crate) mod script; -pub(crate) mod split; -pub(crate) mod start; -pub(crate) mod statement; -pub(crate) mod strand; -pub(crate) mod subquery; -pub(crate) mod table; -pub(crate) mod thing; -pub(crate) mod timeout; -pub(crate) mod tokenizer; -pub(crate) mod uuid; -pub(crate) mod value; -pub(crate) mod version; -pub(crate) mod view; -pub(crate) mod with; - -#[doc(hidden)] -pub mod index; - -pub mod serde; -pub mod statements; - -pub use self::algorithm::Algorithm; -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::changefeed::ChangeFeed; -pub use self::cond::Cond; -pub use self::constant::Constant; -pub use self::data::Data; -pub use self::datetime::Datetime; -pub use self::dir::Dir; -pub use self::duration::Duration; -pub use self::edges::Edges; -pub use self::explain::Explain; -pub use self::expression::Expression; -pub use self::fetch::Fetch; -pub use self::fetch::Fetchs; -pub use self::field::Field; -pub use self::field::Fields; -pub use self::function::Function; -pub use self::future::Future; -pub use self::geometry::Geometry; -pub use self::graph::Graph; -pub use self::group::Group; -pub use self::group::Groups; -pub use self::id::Id; -pub use self::ident::Ident; -pub use self::idiom::Idiom; -pub use self::idiom::Idioms; -pub use self::index::Index; -pub use self::kind::Kind; -pub use self::limit::Limit; -pub use self::mock::Mock; -pub use self::model::Model; -pub use self::number::Number; -pub use self::object::Object; -pub use self::operation::Operation; -pub use self::operator::Operator; -pub use self::order::Order; -pub use self::order::Orders; -pub use self::output::Output; -pub use self::param::Param; -pub use self::part::Part; -pub use self::permission::Permission; -pub use self::permission::Permissions; -pub use self::query::Query; -pub use self::range::Range; -pub use self::regex::Regex; -pub use self::scoring::Scoring; -pub use self::script::Script; -pub use self::split::Split; -pub use self::split::Splits; -pub use self::start::Start; -pub use self::statement::Statement; -pub use self::statement::Statements; -pub use self::strand::Strand; -pub use self::subquery::Subquery; -pub use self::table::Table; -pub use self::table::Tables; -pub use self::thing::Thing; -pub use self::timeout::Timeout; -pub use self::tokenizer::Tokenizer; -pub use self::uuid::Uuid; -pub use self::value::serde::to_value; -#[doc(hidden)] -pub use self::value::serde::{from_value, FromValueError}; -pub use self::value::Value; -pub use self::value::Values; -pub use self::version::Version; -pub use self::view::View; -pub use self::with::With; - -// module reexporting parsing function to prevent a breaking change. -#[doc(hidden)] -mod parser { - pub use crate::syn::*; -} - -pub use self::parser::{idiom, json, parse, subquery, thing, value}; diff --git a/core/src/sql/v2/model.rs b/core/src/sql/v2/model.rs deleted file mode 100644 index 960e0617..00000000 --- a/core/src/sql/v2/model.rs +++ /dev/null @@ -1,211 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::value::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[cfg(any(feature = "ml", feature = "ml2"))] -use crate::iam::Action; -#[cfg(any(feature = "ml", feature = "ml2"))] -use crate::ml::execution::compute::ModelComputation; -#[cfg(any(feature = "ml", feature = "ml2"))] -use crate::ml::storage::surml_file::SurMlFile; -#[cfg(any(feature = "ml", feature = "ml2"))] -use crate::sql::Permission; -#[cfg(any(feature = "ml", feature = "ml2"))] -use futures::future::try_join_all; -#[cfg(any(feature = "ml", feature = "ml2"))] -use std::collections::HashMap; - -#[cfg(any(feature = "ml", feature = "ml2"))] -const ARGUMENTS: &str = "The model expects 1 argument. The argument can be either a number, an object, or an array of numbers."; - -#[derive(Clone, Debug, Default, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Model { - pub name: String, - pub version: String, - pub args: Vec, -} - -impl fmt::Display for Model { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ml::{}<{}>(", self.name, self.version)?; - for (idx, p) in self.args.iter().enumerate() { - if idx != 0 { - write!(f, ",")?; - } - write!(f, "{}", p)?; - } - write!(f, ")") - } -} - -impl Model { - #[cfg(any(feature = "ml", feature = "ml2"))] - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Ensure futures are run - let opt = &opt.new_with_futures(true); - // Get the full name of this model - let name = format!("ml::{}", self.name); - // Check this function is allowed - ctx.check_allowed_function(name.as_str())?; - // Get the model definition - let val = { - // Claim transaction - let mut run = txn.lock().await; - // Get the function definition - run.get_and_cache_db_model(opt.ns(), opt.db(), &self.name, &self.version).await? - }; - // Calculate the model path - let path = format!( - "ml/{}/{}/{}-{}-{}.surml", - opt.ns(), - opt.db(), - self.name, - self.version, - val.hash - ); - // Check permissions - if opt.check_perms(Action::View) { - match &val.permissions { - Permission::Full => (), - Permission::None => { - return Err(Error::FunctionPermissions { - name: self.name.to_owned(), - }) - } - Permission::Specific(e) => { - // Disable permissions - let opt = &opt.new_with_perms(false); - // Process the PERMISSION clause - if !e.compute(ctx, opt, txn, doc).await?.is_truthy() { - return Err(Error::FunctionPermissions { - name: self.name.to_owned(), - }); - } - } - } - } - // Compute the function arguments - let mut args = - try_join_all(self.args.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?; - // Check the minimum argument length - if args.len() != 1 { - return Err(Error::InvalidArguments { - name: format!("ml::{}<{}>", self.name, self.version), - message: ARGUMENTS.into(), - }); - } - // Take the first and only specified argument - match args.swap_remove(0) { - // Perform bufferered compute - Value::Object(v) => { - // Compute the model function arguments - let mut args = v - .into_iter() - .map(|(k, v)| Ok((k, Value::try_into(v)?))) - .collect::, Error>>() - .map_err(|_| Error::InvalidArguments { - name: format!("ml::{}<{}>", self.name, self.version), - message: ARGUMENTS.into(), - })?; - // Get the model file as bytes - let bytes = crate::obs::get(&path).await?; - // Run the compute in a blocking task - let outcome = tokio::task::spawn_blocking(move || { - let mut file = SurMlFile::from_bytes(bytes).unwrap(); - let compute_unit = ModelComputation { - surml_file: &mut file, - }; - compute_unit.buffered_compute(&mut args).map_err(Error::ModelComputation) - }) - .await - .unwrap()?; - // Convert the output to a value - Ok(outcome[0].into()) - } - // Perform raw compute - Value::Number(v) => { - // Compute the model function arguments - let args: f32 = v.try_into().map_err(|_| Error::InvalidArguments { - name: format!("ml::{}<{}>", self.name, self.version), - message: ARGUMENTS.into(), - })?; - // Get the model file as bytes - let bytes = crate::obs::get(&path).await?; - // Convert the argument to a tensor - let tensor = ndarray::arr1::(&[args]).into_dyn(); - // Run the compute in a blocking task - let outcome = tokio::task::spawn_blocking(move || { - let mut file = SurMlFile::from_bytes(bytes).unwrap(); - let compute_unit = ModelComputation { - surml_file: &mut file, - }; - compute_unit.raw_compute(tensor, None).map_err(Error::ModelComputation) - }) - .await - .unwrap()?; - // Convert the output to a value - Ok(outcome[0].into()) - } - // Perform raw compute - Value::Array(v) => { - // Compute the model function arguments - let args = v - .into_iter() - .map(Value::try_into) - .collect::, Error>>() - .map_err(|_| Error::InvalidArguments { - name: format!("ml::{}<{}>", self.name, self.version), - message: ARGUMENTS.into(), - })?; - // Get the model file as bytes - let bytes = crate::obs::get(&path).await?; - // Convert the argument to a tensor - let tensor = ndarray::arr1::(&args).into_dyn(); - // Run the compute in a blocking task - let outcome = tokio::task::spawn_blocking(move || { - let mut file = SurMlFile::from_bytes(bytes).unwrap(); - let compute_unit = ModelComputation { - surml_file: &mut file, - }; - compute_unit.raw_compute(tensor, None).map_err(Error::ModelComputation) - }) - .await - .unwrap()?; - // Convert the output to a value - Ok(outcome[0].into()) - } - // - _ => Err(Error::InvalidArguments { - name: format!("ml::{}<{}>", self.name, self.version), - message: ARGUMENTS.into(), - }), - } - } - - #[cfg(not(any(feature = "ml", feature = "ml2")))] - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - _opt: &Options, - _txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - Err(Error::InvalidModel { - message: String::from("Machine learning computation is not enabled."), - }) - } -} diff --git a/core/src/sql/v2/number.rs b/core/src/sql/v2/number.rs deleted file mode 100644 index d3d12b66..00000000 --- a/core/src/sql/v2/number.rs +++ /dev/null @@ -1,738 +0,0 @@ -use super::value::{TryAdd, TryDiv, TryMul, TryNeg, TryPow, TryRem, TrySub}; -use crate::err::Error; -use crate::sql::strand::Strand; -use revision::revisioned; -use rust_decimal::prelude::*; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::fmt::{self, Display, Formatter}; -use std::hash; -use std::iter::Product; -use std::iter::Sum; -use std::ops::{self, Add, Div, Mul, Neg, Rem, Sub}; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Number"; - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(rename = "$surrealdb::private::sql::Number")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Number { - Int(i64), - Float(f64), - Decimal(Decimal), - // Add new variants here -} - -impl Default for Number { - fn default() -> Self { - Self::Int(0) - } -} - -macro_rules! from_prim_ints { - ($($int: ty),*) => { - $( - impl From<$int> for Number { - fn from(i: $int) -> Self { - Self::Int(i as i64) - } - } - )* - }; -} - -from_prim_ints!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize); - -impl From for Number { - fn from(f: f32) -> Self { - Self::Float(f as f64) - } -} - -impl From for Number { - fn from(f: f64) -> Self { - Self::Float(f) - } -} - -impl From for Number { - fn from(v: Decimal) -> Self { - Self::Decimal(v) - } -} - -impl FromStr for Number { - type Err = (); - fn from_str(s: &str) -> Result { - Self::try_from(s) - } -} - -impl TryFrom for Number { - type Error = (); - fn try_from(v: String) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom for Number { - type Error = (); - fn try_from(v: Strand) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom<&str> for Number { - type Error = (); - fn try_from(v: &str) -> Result { - // Attempt to parse as i64 - match v.parse::() { - // Store it as an i64 - Ok(v) => Ok(Self::Int(v)), - // It wasn't parsed as a i64 so parse as a float - _ => match f64::from_str(v) { - // Store it as a float - Ok(v) => Ok(Self::Float(v)), - // It wasn't parsed as a number - _ => Err(()), - }, - } - } -} - -macro_rules! try_into_prim { - // TODO: switch to one argument per int once https://github.com/rust-lang/rust/issues/29599 is stable - ($($int: ty => $to_int: ident),*) => { - $( - impl TryFrom for $int { - type Error = Error; - fn try_from(value: Number) -> Result { - match value { - Number::Int(v) => match v.$to_int() { - Some(v) => Ok(v), - None => Err(Error::TryFrom(value.to_string(), stringify!($int))), - }, - Number::Float(v) => match v.$to_int() { - Some(v) => Ok(v), - None => Err(Error::TryFrom(value.to_string(), stringify!($int))), - }, - Number::Decimal(ref v) => match v.$to_int() { - Some(v) => Ok(v), - None => Err(Error::TryFrom(value.to_string(), stringify!($int))), - }, - } - } - } - )* - }; -} - -try_into_prim!( - i8 => to_i8, i16 => to_i16, i32 => to_i32, i64 => to_i64, i128 => to_i128, - u8 => to_u8, u16 => to_u16, u32 => to_u32, u64 => to_u64, u128 => to_u128, - f32 => to_f32, f64 => to_f64 -); - -impl TryFrom for Decimal { - type Error = Error; - fn try_from(value: Number) -> Result { - match value { - Number::Int(v) => match Decimal::from_i64(v) { - Some(v) => Ok(v), - None => Err(Error::TryFrom(value.to_string(), "Decimal")), - }, - Number::Float(v) => match Decimal::try_from(v) { - Ok(v) => Ok(v), - _ => Err(Error::TryFrom(value.to_string(), "Decimal")), - }, - Number::Decimal(x) => Ok(x), - } - } -} - -impl Display for Number { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Number::Int(v) => Display::fmt(v, f), - Number::Float(v) => { - if v.is_finite() { - // Add suffix to distinguish between int and float - write!(f, "{v}f") - } else { - // Don't add suffix for NaN, inf, -inf - Display::fmt(v, f) - } - } - Number::Decimal(v) => write!(f, "{v}dec"), - } - } -} - -impl Number { - // ----------------------------------- - // Constants - // ----------------------------------- - - pub const NAN: Number = Number::Float(f64::NAN); - - // ----------------------------------- - // Simple number detection - // ----------------------------------- - - pub fn is_nan(&self) -> bool { - matches!(self, Number::Float(v) if v.is_nan()) - } - - pub fn is_int(&self) -> bool { - matches!(self, Number::Int(_)) - } - - pub fn is_float(&self) -> bool { - matches!(self, Number::Float(_)) - } - - pub fn is_decimal(&self) -> bool { - matches!(self, Number::Decimal(_)) - } - - pub fn is_integer(&self) -> bool { - match self { - Number::Int(_) => true, - Number::Float(v) => v.fract() == 0.0, - Number::Decimal(v) => v.is_integer(), - } - } - - pub fn is_truthy(&self) -> bool { - match self { - Number::Int(v) => v != &0, - Number::Float(v) => v != &0.0, - Number::Decimal(v) => v != &Decimal::ZERO, - } - } - - pub fn is_positive(&self) -> bool { - match self { - Number::Int(v) => v > &0, - Number::Float(v) => v > &0.0, - Number::Decimal(v) => v > &Decimal::ZERO, - } - } - - pub fn is_negative(&self) -> bool { - match self { - Number::Int(v) => v < &0, - Number::Float(v) => v < &0.0, - Number::Decimal(v) => v < &Decimal::ZERO, - } - } - - pub fn is_zero(&self) -> bool { - match self { - Number::Int(v) => v == &0, - Number::Float(v) => v == &0.0, - Number::Decimal(v) => v == &Decimal::ZERO, - } - } - - pub fn is_zero_or_positive(&self) -> bool { - match self { - Number::Int(v) => v >= &0, - Number::Float(v) => v >= &0.0, - Number::Decimal(v) => v >= &Decimal::ZERO, - } - } - - pub fn is_zero_or_negative(&self) -> bool { - match self { - Number::Int(v) => v <= &0, - Number::Float(v) => v <= &0.0, - Number::Decimal(v) => v <= &Decimal::ZERO, - } - } - - // ----------------------------------- - // Simple conversion of number - // ----------------------------------- - - pub fn as_usize(self) -> usize { - match self { - Number::Int(v) => v as usize, - Number::Float(v) => v as usize, - Number::Decimal(v) => v.try_into().unwrap_or_default(), - } - } - - pub fn as_int(self) -> i64 { - match self { - Number::Int(v) => v, - Number::Float(v) => v as i64, - Number::Decimal(v) => v.try_into().unwrap_or_default(), - } - } - - pub fn as_float(self) -> f64 { - match self { - Number::Int(v) => v as f64, - Number::Float(v) => v, - Number::Decimal(v) => v.try_into().unwrap_or_default(), - } - } - - pub fn as_decimal(self) -> Decimal { - match self { - Number::Int(v) => Decimal::from(v), - Number::Float(v) => Decimal::try_from(v).unwrap_or_default(), - Number::Decimal(v) => v, - } - } - - // ----------------------------------- - // Complex conversion of number - // ----------------------------------- - - pub fn to_usize(&self) -> usize { - match self { - Number::Int(v) => *v as usize, - Number::Float(v) => *v as usize, - Number::Decimal(v) => v.to_usize().unwrap_or_default(), - } - } - - pub fn to_int(&self) -> i64 { - match self { - Number::Int(v) => *v, - Number::Float(v) => *v as i64, - Number::Decimal(v) => v.to_i64().unwrap_or_default(), - } - } - - pub fn to_float(&self) -> f64 { - match self { - Number::Int(v) => *v as f64, - Number::Float(v) => *v, - &Number::Decimal(v) => v.try_into().unwrap_or_default(), - } - } - - pub fn to_decimal(&self) -> Decimal { - match self { - // #[allow(clippy::unnecessary_fallible_conversions)] // `Decimal::from` can panic - // `clippy::unnecessary_fallible_conversions` not available on Rust < v1.75 - #[allow(warnings)] - Number::Int(v) => Decimal::try_from(*v).unwrap_or_default(), - Number::Float(v) => Decimal::try_from(*v).unwrap_or_default(), - Number::Decimal(v) => *v, - } - } - - // ----------------------------------- - // - // ----------------------------------- - - pub fn abs(self) -> Self { - match self { - Number::Int(v) => v.abs().into(), - Number::Float(v) => v.abs().into(), - Number::Decimal(v) => v.abs().into(), - } - } - - pub fn acos(self) -> Self { - self.to_float().acos().into() - } - - pub fn ceil(self) -> Self { - match self { - Number::Int(v) => v.into(), - Number::Float(v) => v.ceil().into(), - Number::Decimal(v) => v.ceil().into(), - } - } - - pub fn floor(self) -> Self { - match self { - Number::Int(v) => v.into(), - Number::Float(v) => v.floor().into(), - Number::Decimal(v) => v.floor().into(), - } - } - - pub fn round(self) -> Self { - match self { - Number::Int(v) => v.into(), - Number::Float(v) => v.round().into(), - Number::Decimal(v) => v.round().into(), - } - } - - pub fn fixed(self, precision: usize) -> Number { - match self { - Number::Int(v) => format!("{v:.precision$}").try_into().unwrap_or_default(), - Number::Float(v) => format!("{v:.precision$}").try_into().unwrap_or_default(), - Number::Decimal(v) => v.round_dp(precision as u32).into(), - } - } - - pub fn sqrt(self) -> Self { - match self { - Number::Int(v) => (v as f64).sqrt().into(), - Number::Float(v) => v.sqrt().into(), - Number::Decimal(v) => v.sqrt().unwrap_or_default().into(), - } - } - - pub fn pow(self, power: Number) -> Number { - match (self, power) { - (Number::Int(v), Number::Int(p)) => Number::Int(v.pow(p as u32)), - (Number::Decimal(v), Number::Int(p)) => v.powi(p).into(), - // TODO: (Number::Decimal(v), Number::Float(p)) => todo!(), - // TODO: (Number::Decimal(v), Number::Decimal(p)) => todo!(), - (v, p) => v.as_float().powf(p.as_float()).into(), - } - } -} - -impl Eq for Number {} - -impl Ord for Number { - fn cmp(&self, other: &Self) -> Ordering { - fn total_cmp_f64(a: f64, b: f64) -> Ordering { - if a == 0.0 && b == 0.0 { - // -0.0 = 0.0 - Ordering::Equal - } else { - // Handles NaN's - a.total_cmp(&b) - } - } - - match (self, other) { - (Number::Int(v), Number::Int(w)) => v.cmp(w), - (Number::Float(v), Number::Float(w)) => total_cmp_f64(*v, *w), - (Number::Decimal(v), Number::Decimal(w)) => v.cmp(w), - // ------------------------------ - (Number::Int(v), Number::Float(w)) => total_cmp_f64(*v as f64, *w), - (Number::Float(v), Number::Int(w)) => total_cmp_f64(*v, *w as f64), - // ------------------------------ - (Number::Int(v), Number::Decimal(w)) => Decimal::from(*v).cmp(w), - (Number::Decimal(v), Number::Int(w)) => v.cmp(&Decimal::from(*w)), - // ------------------------------ - (Number::Float(v), Number::Decimal(w)) => { - // `rust_decimal::Decimal` code comments indicate that `to_f64` is infallible - total_cmp_f64(*v, w.to_f64().unwrap()) - } - (Number::Decimal(v), Number::Float(w)) => total_cmp_f64(v.to_f64().unwrap(), *w), - } - } -} - -// Warning: Equal numbers may have different hashes, which violates -// the invariants of certain collections! -impl hash::Hash for Number { - fn hash(&self, state: &mut H) { - match self { - Number::Int(v) => v.hash(state), - Number::Float(v) => v.to_bits().hash(state), - Number::Decimal(v) => v.hash(state), - } - } -} - -impl PartialEq for Number { - fn eq(&self, other: &Self) -> bool { - fn total_eq_f64(a: f64, b: f64) -> bool { - a.to_bits().eq(&b.to_bits()) || (a == 0.0 && b == 0.0) - } - - match (self, other) { - (Number::Int(v), Number::Int(w)) => v.eq(w), - (Number::Float(v), Number::Float(w)) => total_eq_f64(*v, *w), - (Number::Decimal(v), Number::Decimal(w)) => v.eq(w), - // ------------------------------ - (Number::Int(v), Number::Float(w)) => total_eq_f64(*v as f64, *w), - (Number::Float(v), Number::Int(w)) => total_eq_f64(*v, *w as f64), - // ------------------------------ - (Number::Int(v), Number::Decimal(w)) => Decimal::from(*v).eq(w), - (Number::Decimal(v), Number::Int(w)) => v.eq(&Decimal::from(*w)), - // ------------------------------ - (Number::Float(v), Number::Decimal(w)) => total_eq_f64(*v, w.to_f64().unwrap()), - (Number::Decimal(v), Number::Float(w)) => total_eq_f64(v.to_f64().unwrap(), *w), - } - } -} - -impl PartialOrd for Number { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -macro_rules! impl_simple_try_op { - ($trt:ident, $fn:ident, $unchecked:ident, $checked:ident) => { - impl $trt for Number { - type Output = Self; - fn $fn(self, other: Self) -> Result { - Ok(match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int( - v.$checked(w).ok_or_else(|| Error::$trt(v.to_string(), w.to_string()))?, - ), - (Number::Float(v), Number::Float(w)) => Number::Float(v.$unchecked(w)), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal( - v.$checked(w).ok_or_else(|| Error::$trt(v.to_string(), w.to_string()))?, - ), - (Number::Int(v), Number::Float(w)) => Number::Float((v as f64).$unchecked(w)), - (Number::Float(v), Number::Int(w)) => Number::Float(v.$unchecked(w as f64)), - (v, w) => Number::Decimal( - v.to_decimal() - .$checked(w.to_decimal()) - .ok_or_else(|| Error::$trt(v.to_string(), w.to_string()))?, - ), - }) - } - } - }; -} - -impl_simple_try_op!(TryAdd, try_add, add, checked_add); -impl_simple_try_op!(TrySub, try_sub, sub, checked_sub); -impl_simple_try_op!(TryMul, try_mul, mul, checked_mul); -impl_simple_try_op!(TryDiv, try_div, div, checked_div); -impl_simple_try_op!(TryRem, try_rem, rem, checked_rem); - -impl TryPow for Number { - type Output = Self; - fn try_pow(self, power: Self) -> Result { - Ok(match (self, power) { - (Self::Int(v), Self::Int(p)) => Self::Int(match v { - 0 => match p.cmp(&0) { - // 0^(-x) - Ordering::Less => return Err(Error::TryPow(v.to_string(), p.to_string())), - // 0^0 - Ordering::Equal => 1, - // 0^x - Ordering::Greater => 0, - }, - // 1^p - 1 => 1, - -1 => { - if p % 2 == 0 { - // (-1)^even - 1 - } else { - // (-1)^odd - -1 - } - } - // try_into may cause an error, which would be wrong for the above cases. - _ => p - .try_into() - .ok() - .and_then(|p| v.checked_pow(p)) - .ok_or_else(|| Error::TryPow(v.to_string(), p.to_string()))?, - }), - (Self::Decimal(v), Self::Int(p)) => Self::Decimal( - v.checked_powi(p).ok_or_else(|| Error::TryPow(v.to_string(), p.to_string()))?, - ), - (Self::Decimal(v), Self::Float(p)) => Self::Decimal( - v.checked_powf(p).ok_or_else(|| Error::TryPow(v.to_string(), p.to_string()))?, - ), - (Self::Decimal(v), Self::Decimal(p)) => Self::Decimal( - v.checked_powd(p).ok_or_else(|| Error::TryPow(v.to_string(), p.to_string()))?, - ), - (v, p) => v.as_float().powf(p.as_float()).into(), - }) - } -} - -impl TryNeg for Number { - type Output = Self; - - fn try_neg(self) -> Result { - Ok(match self { - Self::Int(n) => { - Number::Int(n.checked_neg().ok_or_else(|| Error::TryNeg(n.to_string()))?) - } - Self::Float(n) => Number::Float(-n), - Self::Decimal(n) => Number::Decimal(-n), - }) - } -} - -impl ops::Add for Number { - type Output = Self; - fn add(self, other: Self) -> Self { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v + w), - (Number::Float(v), Number::Float(w)) => Number::Float(v + w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v + w), - (Number::Int(v), Number::Float(w)) => Number::Float(v as f64 + w), - (Number::Float(v), Number::Int(w)) => Number::Float(v + w as f64), - (v, w) => Number::from(v.as_decimal() + w.as_decimal()), - } - } -} - -impl<'a, 'b> ops::Add<&'b Number> for &'a Number { - type Output = Number; - fn add(self, other: &'b Number) -> Number { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v + w), - (Number::Float(v), Number::Float(w)) => Number::Float(v + w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v + w), - (Number::Int(v), Number::Float(w)) => Number::Float(*v as f64 + w), - (Number::Float(v), Number::Int(w)) => Number::Float(v + *w as f64), - (v, w) => Number::from(v.to_decimal() + w.to_decimal()), - } - } -} - -impl ops::Sub for Number { - type Output = Self; - fn sub(self, other: Self) -> Self { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v - w), - (Number::Float(v), Number::Float(w)) => Number::Float(v - w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v - w), - (Number::Int(v), Number::Float(w)) => Number::Float(v as f64 - w), - (Number::Float(v), Number::Int(w)) => Number::Float(v - w as f64), - (v, w) => Number::from(v.as_decimal() - w.as_decimal()), - } - } -} - -impl<'a, 'b> ops::Sub<&'b Number> for &'a Number { - type Output = Number; - fn sub(self, other: &'b Number) -> Number { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v - w), - (Number::Float(v), Number::Float(w)) => Number::Float(v - w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v - w), - (Number::Int(v), Number::Float(w)) => Number::Float(*v as f64 - w), - (Number::Float(v), Number::Int(w)) => Number::Float(v - *w as f64), - (v, w) => Number::from(v.to_decimal() - w.to_decimal()), - } - } -} - -impl ops::Mul for Number { - type Output = Self; - fn mul(self, other: Self) -> Self { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v * w), - (Number::Float(v), Number::Float(w)) => Number::Float(v * w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v * w), - (Number::Int(v), Number::Float(w)) => Number::Float(v as f64 * w), - (Number::Float(v), Number::Int(w)) => Number::Float(v * w as f64), - (v, w) => Number::from(v.as_decimal() * w.as_decimal()), - } - } -} - -impl<'a, 'b> ops::Mul<&'b Number> for &'a Number { - type Output = Number; - fn mul(self, other: &'b Number) -> Number { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v * w), - (Number::Float(v), Number::Float(w)) => Number::Float(v * w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v * w), - (Number::Int(v), Number::Float(w)) => Number::Float(*v as f64 * w), - (Number::Float(v), Number::Int(w)) => Number::Float(v * *w as f64), - (v, w) => Number::from(v.to_decimal() * w.to_decimal()), - } - } -} - -impl ops::Div for Number { - type Output = Self; - fn div(self, other: Self) -> Self { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v / w), - (Number::Float(v), Number::Float(w)) => Number::Float(v / w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v / w), - (Number::Int(v), Number::Float(w)) => Number::Float(v as f64 / w), - (Number::Float(v), Number::Int(w)) => Number::Float(v / w as f64), - (v, w) => Number::from(v.as_decimal() / w.as_decimal()), - } - } -} - -impl<'a, 'b> ops::Div<&'b Number> for &'a Number { - type Output = Number; - fn div(self, other: &'b Number) -> Number { - match (self, other) { - (Number::Int(v), Number::Int(w)) => Number::Int(v / w), - (Number::Float(v), Number::Float(w)) => Number::Float(v / w), - (Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v / w), - (Number::Int(v), Number::Float(w)) => Number::Float(*v as f64 / w), - (Number::Float(v), Number::Int(w)) => Number::Float(v / *w as f64), - (v, w) => Number::from(v.to_decimal() / w.to_decimal()), - } - } -} - -impl Neg for Number { - type Output = Self; - - fn neg(self) -> Self::Output { - match self { - Self::Int(n) => Number::Int(-n), - Self::Float(n) => Number::Float(-n), - Self::Decimal(n) => Number::Decimal(-n), - } - } -} - -// ------------------------------ - -impl Sum for Number { - fn sum(iter: I) -> Number - where - I: Iterator, - { - iter.fold(Number::Int(0), |a, b| a + b) - } -} - -impl<'a> Sum<&'a Self> for Number { - fn sum(iter: I) -> Number - where - I: Iterator, - { - iter.fold(Number::Int(0), |a, b| &a + b) - } -} - -impl Product for Number { - fn product(iter: I) -> Number - where - I: Iterator, - { - iter.fold(Number::Int(1), |a, b| a * b) - } -} - -impl<'a> Product<&'a Self> for Number { - fn product(iter: I) -> Number - where - I: Iterator, - { - iter.fold(Number::Int(1), |a, b| &a * b) - } -} - -pub struct Sorted(pub T); - -pub trait Sort { - fn sorted(&mut self) -> Sorted<&Self> - where - Self: Sized; -} - -impl Sort for Vec { - fn sorted(&mut self) -> Sorted<&Vec> { - self.sort(); - Sorted(self) - } -} diff --git a/core/src/sql/v2/object.rs b/core/src/sql/v2/object.rs deleted file mode 100644 index 18ac0695..00000000 --- a/core/src/sql/v2/object.rs +++ /dev/null @@ -1,322 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{ - escape::escape_key, - fmt::{is_pretty, pretty_indent, Fmt, Pretty}, - Operation, Thing, Value, -}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::fmt::{self, Display, Formatter, Write}; -use std::ops::Deref; -use std::ops::DerefMut; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Object"; - -/// Invariant: Keys never contain NUL bytes. -#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Object")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Object(#[serde(with = "no_nul_bytes_in_keys")] pub BTreeMap); - -impl From> for Object { - fn from(v: BTreeMap<&str, Value>) -> Self { - Self(v.into_iter().map(|(key, val)| (key.to_string(), val)).collect()) - } -} - -impl From> for Object { - fn from(v: BTreeMap) -> Self { - Self(v) - } -} - -impl From> for Object { - fn from(v: HashMap<&str, Value>) -> Self { - Self(v.into_iter().map(|(key, val)| (key.to_string(), val)).collect()) - } -} - -impl From> for Object { - fn from(v: HashMap) -> Self { - Self(v.into_iter().collect()) - } -} - -impl From> for Object { - fn from(v: Option) -> Self { - v.unwrap_or_default() - } -} - -impl From for Object { - fn from(v: Operation) -> Self { - Self(match v { - Operation::Add { - path, - value, - } => map! { - String::from("op") => Value::from("add"), - String::from("path") => path.to_path().into(), - String::from("value") => value - }, - Operation::Remove { - path, - } => map! { - String::from("op") => Value::from("remove"), - String::from("path") => path.to_path().into() - }, - Operation::Replace { - path, - value, - } => map! { - String::from("op") => Value::from("replace"), - String::from("path") => path.to_path().into(), - String::from("value") => value - }, - Operation::Change { - path, - value, - } => map! { - String::from("op") => Value::from("change"), - String::from("path") => path.to_path().into(), - String::from("value") => value - }, - Operation::Copy { - path, - from, - } => map! { - String::from("op") => Value::from("copy"), - String::from("path") => path.to_path().into(), - String::from("from") => from.to_path().into() - }, - Operation::Move { - path, - from, - } => map! { - String::from("op") => Value::from("move"), - String::from("path") => path.to_path().into(), - String::from("from") => from.to_path().into() - }, - Operation::Test { - path, - value, - } => map! { - String::from("op") => Value::from("test"), - String::from("path") => path.to_path().into(), - String::from("value") => value - }, - }) - } -} - -impl Deref for Object { - type Target = BTreeMap; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Object { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl IntoIterator for Object { - type Item = (String, Value); - type IntoIter = std::collections::btree_map::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Object { - /// Fetch the record id if there is one - pub fn rid(&self) -> Option { - match self.get("id") { - Some(Value::Thing(v)) => Some(v.clone()), - _ => None, - } - } - /// Convert this object to a diff-match-patch operation - pub fn to_operation(&self) -> Result { - match self.get("op") { - Some(op_val) => match self.get("path") { - Some(path_val) => { - let path = path_val.jsonpath(); - - let from = - self.get("from").map(|value| value.jsonpath()).ok_or(Error::InvalidPatch { - message: String::from("'from' key missing"), - }); - - let value = self.get("value").cloned().ok_or(Error::InvalidPatch { - message: String::from("'value' key missing"), - }); - - match op_val.clone().as_string().as_str() { - // Add operation - "add" => Ok(Operation::Add { - path, - value: value?, - }), - // Remove operation - "remove" => Ok(Operation::Remove { - path, - }), - // Replace operation - "replace" => Ok(Operation::Replace { - path, - value: value?, - }), - // Change operation - "change" => Ok(Operation::Change { - path, - value: value?, - }), - // Copy operation - "copy" => Ok(Operation::Copy { - path, - from: from?, - }), - // Move operation - "move" => Ok(Operation::Move { - path, - from: from?, - }), - // Test operation - "test" => Ok(Operation::Test { - path, - value: value?, - }), - unknown_op => Err(Error::InvalidPatch { - message: format!("unknown op '{unknown_op}'"), - }), - } - } - _ => Err(Error::InvalidPatch { - message: String::from("'path' key missing"), - }), - }, - _ => Err(Error::InvalidPatch { - message: String::from("'op' key missing"), - }), - } - } -} - -impl Object { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - let mut x = BTreeMap::new(); - for (k, v) in self.iter() { - match v.compute(ctx, opt, txn, doc).await { - Ok(v) => x.insert(k.clone(), v), - Err(e) => return Err(e), - }; - } - Ok(Value::Object(Object(x))) - } - - pub(crate) fn is_static(&self) -> bool { - self.values().all(Value::is_static) - } -} - -impl Display for Object { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let mut f = Pretty::from(f); - if is_pretty() { - f.write_char('{')?; - } else { - f.write_str("{ ")?; - } - if !self.is_empty() { - let indent = pretty_indent(); - write!( - f, - "{}", - Fmt::pretty_comma_separated( - self.0.iter().map(|args| Fmt::new(args, |(k, v), f| write!( - f, - "{}: {}", - escape_key(k), - v - ))), - ) - )?; - drop(indent); - } - if is_pretty() { - f.write_char('}') - } else { - f.write_str(" }") - } - } -} - -mod no_nul_bytes_in_keys { - use serde::{ - de::{self, Visitor}, - ser::SerializeMap, - Deserializer, Serializer, - }; - use std::{collections::BTreeMap, fmt}; - - use crate::sql::Value; - - pub(crate) fn serialize( - m: &BTreeMap, - serializer: S, - ) -> Result - where - S: Serializer, - { - let mut s = serializer.serialize_map(Some(m.len()))?; - for (k, v) in m { - debug_assert!(!k.contains('\0')); - s.serialize_entry(k, v)?; - } - s.end() - } - - pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - struct NoNulBytesInKeysVisitor; - - impl<'de> Visitor<'de> for NoNulBytesInKeysVisitor { - type Value = BTreeMap; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a map without any NUL bytes in its keys") - } - - fn visit_map(self, mut map: A) -> Result - where - A: de::MapAccess<'de>, - { - let mut ret = BTreeMap::new(); - while let Some((k, v)) = map.next_entry()? { - ret.insert(k, v); - } - Ok(ret) - } - } - - deserializer.deserialize_map(NoNulBytesInKeysVisitor) - } -} diff --git a/core/src/sql/v2/operation.rs b/core/src/sql/v2/operation.rs deleted file mode 100644 index 9304e0f1..00000000 --- a/core/src/sql/v2/operation.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::sql::idiom::Idiom; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(tag = "op")] -#[serde(rename_all = "lowercase")] -#[revisioned(revision = 1)] -pub enum Operation { - Add { - path: Idiom, - value: Value, - }, - Remove { - path: Idiom, - }, - Replace { - path: Idiom, - value: Value, - }, - Change { - path: Idiom, - value: Value, - }, - Copy { - path: Idiom, - from: Idiom, - }, - Move { - path: Idiom, - from: Idiom, - }, - Test { - path: Idiom, - value: Value, - }, -} diff --git a/core/src/sql/v2/order.rs b/core/src/sql/v2/order.rs deleted file mode 100644 index 61900398..00000000 --- a/core/src/sql/v2/order.rs +++ /dev/null @@ -1,71 +0,0 @@ -use crate::sql::fmt::Fmt; -use crate::sql::idiom::Idiom; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Orders(pub Vec); - -impl Deref for Orders { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Orders { - type Item = Order; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl fmt::Display for Orders { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ORDER BY {}", Fmt::comma_separated(&self.0)) - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Order { - pub order: Idiom, - pub random: bool, - pub collate: bool, - pub numeric: bool, - /// true if the direction is ascending - pub direction: bool, -} - -impl Deref for Order { - type Target = Idiom; - fn deref(&self) -> &Self::Target { - &self.order - } -} - -impl fmt::Display for Order { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.order)?; - if self.random { - write!(f, "RAND()")?; - } - if self.collate { - write!(f, " COLLATE")?; - } - if self.numeric { - write!(f, " NUMERIC")?; - } - match self.direction { - false => write!(f, " DESC")?, - true => (), - }; - Ok(()) - } -} diff --git a/core/src/sql/v2/output.rs b/core/src/sql/v2/output.rs deleted file mode 100644 index 76ce029a..00000000 --- a/core/src/sql/v2/output.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::sql::field::Fields; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Output { - None, - Null, - Diff, - After, - Before, - Fields(Fields), -} - -impl Default for Output { - fn default() -> Self { - Self::None - } -} - -impl Display for Output { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("RETURN ")?; - match self { - Self::None => f.write_str("NONE"), - Self::Null => f.write_str("NULL"), - Self::Diff => f.write_str("DIFF"), - Self::After => f.write_str("AFTER"), - Self::Before => f.write_str("BEFORE"), - Self::Fields(v) => Display::fmt(v, f), - } - } -} diff --git a/core/src/sql/v2/param.rs b/core/src/sql/v2/param.rs deleted file mode 100644 index 2e729403..00000000 --- a/core/src/sql/v2/param.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::{ - ctx::Context, - dbs::{Options, Transaction}, - doc::CursorDoc, - err::Error, - iam::Action, - sql::{ident::Ident, value::Value, Permission}, -}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::{fmt, ops::Deref, str}; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Param"; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Param")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Param(pub Ident); - -impl From for Param { - fn from(v: Ident) -> Self { - Self(v) - } -} - -impl From for Param { - fn from(v: String) -> Self { - Self(v.into()) - } -} - -impl From<&str> for Param { - fn from(v: &str) -> Self { - Self(v.into()) - } -} - -impl Deref for Param { - type Target = Ident; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Param { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Find the variable by name - match self.as_str() { - // This is a special param - "this" | "self" => match doc { - // The base document exists - Some(v) => v.doc.compute(ctx, opt, txn, doc).await, - // The base document does not exist - None => Ok(Value::None), - }, - // This is a normal param - v => match ctx.value(v) { - // The param has been set locally - Some(v) => v.compute(ctx, opt, txn, doc).await, - // The param has not been set locally - None => { - // Check that a database is set to prevent a panic - opt.valid_for_db()?; - let val = { - // Claim transaction - let mut run = txn.lock().await; - // Get the param definition - run.get_and_cache_db_param(opt.ns(), opt.db(), v).await - }; - // Check if the param has been set globally - match val { - // The param has been set globally - Ok(val) => { - // Check permissions - if opt.check_perms(Action::View) { - match &val.permissions { - Permission::Full => (), - Permission::None => { - return Err(Error::ParamPermissions { - name: v.to_owned(), - }) - } - Permission::Specific(e) => { - // Disable permissions - let opt = &opt.new_with_perms(false); - // Process the PERMISSION clause - if !e.compute(ctx, opt, txn, doc).await?.is_truthy() { - return Err(Error::ParamPermissions { - name: v.to_owned(), - }); - } - } - } - } - // Return the computed value - val.value.compute(ctx, opt, txn, doc).await - } - // The param has not been set globally - Err(_) => Ok(Value::None), - } - } - }, - } - } -} - -impl fmt::Display for Param { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "${}", &self.0 .0) - } -} diff --git a/core/src/sql/v2/part.rs b/core/src/sql/v2/part.rs deleted file mode 100644 index 3adb08fd..00000000 --- a/core/src/sql/v2/part.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::sql::{fmt::Fmt, strand::no_nul_bytes, Graph, Ident, Idiom, Number, Value}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::str; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum Part { - All, - Flatten, - Last, - First, - Field(Ident), - Index(Number), - Where(Value), - Graph(Graph), - Value(Value), - Start(Value), - Method(#[serde(with = "no_nul_bytes")] String, Vec), -} - -impl From for Part { - fn from(v: i32) -> Self { - Self::Index(v.into()) - } -} - -impl From for Part { - fn from(v: isize) -> Self { - Self::Index(v.into()) - } -} - -impl From for Part { - fn from(v: usize) -> Self { - Self::Index(v.into()) - } -} - -impl From for Part { - fn from(v: String) -> Self { - Self::Field(v.into()) - } -} - -impl From for Part { - fn from(v: Number) -> Self { - Self::Index(v) - } -} - -impl From for Part { - fn from(v: Ident) -> Self { - Self::Field(v) - } -} - -impl From for Part { - fn from(v: Graph) -> Self { - Self::Graph(v) - } -} - -impl From<&str> for Part { - fn from(v: &str) -> Self { - match v.parse::() { - Ok(v) => Self::from(v), - _ => Self::from(v.to_owned()), - } - } -} - -impl Part { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - match self { - Part::Start(v) => v.writeable(), - Part::Where(v) => v.writeable(), - Part::Value(v) => v.writeable(), - Part::Method(_, v) => v.iter().any(Value::writeable), - _ => false, - } - } - /// Returns a yield if an alias is specified - pub(crate) fn alias(&self) -> Option<&Idiom> { - match self { - Part::Graph(v) => v.alias.as_ref(), - _ => None, - } - } -} - -impl fmt::Display for Part { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Part::All => f.write_str("[*]"), - Part::Last => f.write_str("[$]"), - Part::First => f.write_str("[0]"), - Part::Start(v) => write!(f, "{v}"), - Part::Field(v) => write!(f, ".{v}"), - Part::Flatten => f.write_str("…"), - Part::Index(v) => write!(f, "[{v}]"), - Part::Where(v) => write!(f, "[WHERE {v}]"), - Part::Graph(v) => write!(f, "{v}"), - Part::Value(v) => write!(f, "[{v}]"), - Part::Method(v, a) => write!(f, ".{v}({})", Fmt::comma_separated(a)), - } - } -} - -// ------------------------------ - -pub trait Next<'a> { - fn next(&'a self) -> &[Part]; -} - -impl<'a> Next<'a> for &'a [Part] { - fn next(&'a self) -> &'a [Part] { - match self.len() { - 0 => &[], - _ => &self[1..], - } - } -} diff --git a/core/src/sql/v2/paths.rs b/core/src/sql/v2/paths.rs deleted file mode 100644 index eabbf656..00000000 --- a/core/src/sql/v2/paths.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::sql::part::Part; -use once_cell::sync::Lazy; - -pub static ID: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("id")]); - -pub static IP: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("ip")]); - -pub static NS: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("ns")]); - -pub static DB: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("db")]); - -pub static SC: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("sc")]); - -pub static SD: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("sd")]); - -pub static OR: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("or")]); - -pub static TK: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("tk")]); - -pub static IN: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("in")]); - -pub static OUT: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("out")]); - -pub static META: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("__")]); - -pub static EDGE: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("__")]); diff --git a/core/src/sql/v2/permission.rs b/core/src/sql/v2/permission.rs deleted file mode 100644 index 7fb88c25..00000000 --- a/core/src/sql/v2/permission.rs +++ /dev/null @@ -1,166 +0,0 @@ -use crate::sql::fmt::is_pretty; -use crate::sql::fmt::pretty_indent; -use crate::sql::fmt::pretty_sequence_item; -use crate::sql::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::Write; -use std::fmt::{self, Display, Formatter}; -use std::str; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Permissions { - pub select: Permission, - pub create: Permission, - pub update: Permission, - pub delete: Permission, -} - -impl Permissions { - pub fn none() -> Self { - Permissions { - select: Permission::None, - create: Permission::None, - update: Permission::None, - delete: Permission::None, - } - } - - pub fn full() -> Self { - Permissions { - select: Permission::Full, - create: Permission::Full, - update: Permission::Full, - delete: Permission::Full, - } - } - - pub fn is_none(&self) -> bool { - self.select == Permission::None - && self.create == Permission::None - && self.update == Permission::None - && self.delete == Permission::None - } - - pub fn is_full(&self) -> bool { - self.select == Permission::Full - && self.create == Permission::Full - && self.update == Permission::Full - && self.delete == Permission::Full - } -} - -impl Display for Permissions { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "PERMISSIONS")?; - if self.is_none() { - return write!(f, " NONE"); - } - if self.is_full() { - return write!(f, " FULL"); - } - let mut lines = Vec::<(Vec, &Permission)>::new(); - for (c, permission) in [ - PermissionKind::Select, - PermissionKind::Create, - PermissionKind::Update, - PermissionKind::Delete, - ] - .into_iter() - .zip([&self.select, &self.create, &self.update, &self.delete]) - { - if let Some((existing, _)) = lines.iter_mut().find(|(_, p)| *p == permission) { - existing.push(c); - } else { - lines.push((vec![c], permission)); - } - } - let indent = if is_pretty() { - Some(pretty_indent()) - } else { - f.write_char(' ')?; - None - }; - for (i, (kinds, permission)) in lines.into_iter().enumerate() { - if i > 0 { - if is_pretty() { - pretty_sequence_item(); - } else { - f.write_str(", ")?; - } - } - write!(f, "FOR ")?; - for (i, kind) in kinds.into_iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - f.write_str(kind.as_str())?; - } - match permission { - Permission::Specific(_) if is_pretty() => { - let _indent = pretty_indent(); - Display::fmt(permission, f)?; - } - _ => write!(f, " {permission}")?, - } - } - drop(indent); - Ok(()) - } -} - -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub(crate) enum PermissionKind { - Select, - Create, - Update, - Delete, -} - -impl PermissionKind { - fn as_str(&self) -> &str { - match self { - PermissionKind::Select => "select", - PermissionKind::Create => "create", - PermissionKind::Update => "update", - PermissionKind::Delete => "delete", - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Permission { - None, - Full, - Specific(Value), -} - -impl Default for Permission { - fn default() -> Self { - Self::Full - } -} - -impl Permission { - pub fn is_none(&self) -> bool { - matches!(self, Permission::None) - } - - pub fn is_full(&self) -> bool { - matches!(self, Permission::Full) - } -} - -impl Display for Permission { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::None => f.write_str("NONE"), - Self::Full => f.write_str("FULL"), - Self::Specific(ref v) => write!(f, "WHERE {v}"), - } - } -} diff --git a/core/src/sql/v2/query.rs b/core/src/sql/v2/query.rs deleted file mode 100644 index 6293fd13..00000000 --- a/core/src/sql/v2/query.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::sql::fmt::Pretty; -use crate::sql::statements::{DefineStatement, RemoveStatement}; -use crate::sql::{Statement, Statements}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::Write; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; -use std::str; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Query"; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[serde(rename = "$surrealdb::private::sql::Query")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Query(pub Statements); - -impl From for Query { - fn from(s: DefineStatement) -> Self { - Query(Statements(vec![Statement::Define(s)])) - } -} - -impl From for Query { - fn from(s: RemoveStatement) -> Self { - Query(Statements(vec![Statement::Remove(s)])) - } -} - -impl Deref for Query { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 .0 - } -} - -impl IntoIterator for Query { - type Item = Statement; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Display for Query { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(Pretty::from(f), "{}", &self.0) - } -} diff --git a/core/src/sql/v2/range.rs b/core/src/sql/v2/range.rs deleted file mode 100644 index e579c14c..00000000 --- a/core/src/sql/v2/range.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{strand::no_nul_bytes, Id, Value}; -use crate::syn; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::fmt; -use std::ops::Bound; -use std::str::FromStr; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Range"; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Range")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Range { - #[serde(with = "no_nul_bytes")] - pub tb: String, - pub beg: Bound, - pub end: Bound, -} - -impl FromStr for Range { - type Err = (); - fn from_str(s: &str) -> Result { - Self::try_from(s) - } -} - -impl TryFrom<&str> for Range { - type Error = (); - fn try_from(v: &str) -> Result { - match syn::range(v) { - Ok(v) => Ok(v), - _ => Err(()), - } - } -} - -impl Range { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - Ok(Value::Range(Box::new(Range { - tb: self.tb.clone(), - beg: match &self.beg { - Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?), - Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?), - Bound::Unbounded => Bound::Unbounded, - }, - end: match &self.end { - Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?), - Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?), - Bound::Unbounded => Bound::Unbounded, - }, - }))) - } -} - -impl PartialOrd for Range { - fn partial_cmp(&self, other: &Self) -> Option { - match self.tb.partial_cmp(&other.tb) { - Some(Ordering::Equal) => match &self.beg { - Bound::Unbounded => match &other.beg { - Bound::Unbounded => Some(Ordering::Equal), - _ => Some(Ordering::Less), - }, - Bound::Included(v) => match &other.beg { - Bound::Unbounded => Some(Ordering::Greater), - Bound::Included(w) => match v.partial_cmp(w) { - Some(Ordering::Equal) => match &self.end { - Bound::Unbounded => match &other.end { - Bound::Unbounded => Some(Ordering::Equal), - _ => Some(Ordering::Greater), - }, - Bound::Included(v) => match &other.end { - Bound::Unbounded => Some(Ordering::Less), - Bound::Included(w) => v.partial_cmp(w), - _ => Some(Ordering::Greater), - }, - Bound::Excluded(v) => match &other.end { - Bound::Excluded(w) => v.partial_cmp(w), - _ => Some(Ordering::Less), - }, - }, - ordering => ordering, - }, - _ => Some(Ordering::Less), - }, - Bound::Excluded(v) => match &other.beg { - Bound::Excluded(w) => match v.partial_cmp(w) { - Some(Ordering::Equal) => match &self.end { - Bound::Unbounded => match &other.end { - Bound::Unbounded => Some(Ordering::Equal), - _ => Some(Ordering::Greater), - }, - Bound::Included(v) => match &other.end { - Bound::Unbounded => Some(Ordering::Less), - Bound::Included(w) => v.partial_cmp(w), - _ => Some(Ordering::Greater), - }, - Bound::Excluded(v) => match &other.end { - Bound::Excluded(w) => v.partial_cmp(w), - _ => Some(Ordering::Less), - }, - }, - ordering => ordering, - }, - _ => Some(Ordering::Greater), - }, - }, - ordering => ordering, - } - } -} - -impl fmt::Display for Range { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}:", self.tb)?; - match &self.beg { - Bound::Unbounded => write!(f, ""), - Bound::Included(id) => write!(f, "{id}"), - Bound::Excluded(id) => write!(f, "{id}>"), - }?; - match &self.end { - Bound::Unbounded => write!(f, ".."), - Bound::Excluded(id) => write!(f, "..{id}"), - Bound::Included(id) => write!(f, "..={id}"), - }?; - Ok(()) - } -} diff --git a/core/src/sql/v2/scoring.rs b/core/src/sql/v2/scoring.rs deleted file mode 100644 index 12722400..00000000 --- a/core/src/sql/v2/scoring.rs +++ /dev/null @@ -1,72 +0,0 @@ -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::hash::{Hash, Hasher}; - -#[derive(Clone, Debug, PartialOrd, Serialize, Deserialize)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Scoring { - Bm { - k1: f32, - b: f32, - }, // BestMatching25 - Vs, // VectorSearch -} - -impl Eq for Scoring {} - -impl PartialEq for Scoring { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - Scoring::Bm { - k1, - b, - }, - Scoring::Bm { - k1: other_k1, - b: other_b, - }, - ) => k1.to_bits() == other_k1.to_bits() && b.to_bits() == other_b.to_bits(), - (Scoring::Vs, Scoring::Vs) => true, - _ => false, - } - } -} - -impl Hash for Scoring { - fn hash(&self, state: &mut H) { - match self { - Scoring::Bm { - k1, - b, - } => { - k1.to_bits().hash(state); - b.to_bits().hash(state); - } - Scoring::Vs => 0.hash(state), - } - } -} - -impl Scoring { - pub(crate) fn bm25() -> Self { - Self::Bm { - k1: 1.2, - b: 0.75, - } - } -} - -impl fmt::Display for Scoring { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Bm { - k1, - b, - } => write!(f, "BM25({},{})", k1, b), - Self::Vs => f.write_str("VS"), - } - } -} diff --git a/core/src/sql/v2/script.rs b/core/src/sql/v2/script.rs deleted file mode 100644 index 2f1e6fa1..00000000 --- a/core/src/sql/v2/script.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::sql::strand::no_nul_bytes; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; -use std::str; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Script(#[serde(with = "no_nul_bytes")] pub String); - -impl From for Script { - fn from(s: String) -> Self { - Self(s) - } -} - -impl From<&str> for Script { - fn from(s: &str) -> Self { - Self::from(String::from(s)) - } -} - -impl Deref for Script { - type Target = String; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Script { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&self.0, f) - } -} diff --git a/core/src/sql/v2/split.rs b/core/src/sql/v2/split.rs deleted file mode 100644 index 2e3f6013..00000000 --- a/core/src/sql/v2/split.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::sql::fmt::Fmt; -use crate::sql::idiom::Idiom; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Splits(pub Vec); - -impl Deref for Splits { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Splits { - type Item = Split; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl fmt::Display for Splits { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "SPLIT ON {}", Fmt::comma_separated(&self.0)) - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Split(pub Idiom); - -impl Deref for Split { - type Target = Idiom; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Split { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&self.0, f) - } -} diff --git a/core/src/sql/v2/start.rs b/core/src/sql/v2/start.rs deleted file mode 100644 index b6356758..00000000 --- a/core/src/sql/v2/start.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::number::Number; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Start(pub Value); - -impl Start { - pub(crate) async fn process( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self.0.compute(ctx, opt, txn, doc).await { - // This is a valid starting number - Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize), - // An invalid value was specified - Ok(v) => Err(Error::InvalidStart { - value: v.as_string(), - }), - // A different error occurred - Err(e) => Err(e), - } - } -} - -impl fmt::Display for Start { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "START {}", self.0) - } -} diff --git a/core/src/sql/v2/statement.rs b/core/src/sql/v2/statement.rs deleted file mode 100644 index 2c46881e..00000000 --- a/core/src/sql/v2/statement.rs +++ /dev/null @@ -1,203 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{ - fmt::{Fmt, Pretty}, - statements::{ - AnalyzeStatement, BeginStatement, BreakStatement, CancelStatement, CommitStatement, - ContinueStatement, CreateStatement, DefineStatement, DeleteStatement, ForeachStatement, - IfelseStatement, InfoStatement, InsertStatement, KillStatement, LiveStatement, - OptionStatement, OutputStatement, RelateStatement, RemoveStatement, SelectStatement, - SetStatement, ShowStatement, SleepStatement, ThrowStatement, UpdateStatement, UseStatement, - }, - value::Value, -}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::{ - fmt::{self, Display, Formatter, Write}, - ops::Deref, - time::Duration, -}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Statements(pub Vec); - -impl Deref for Statements { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl IntoIterator for Statements { - type Item = Statement; - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Display for Statements { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt( - &Fmt::one_line_separated(self.0.iter().map(|v| Fmt::new(v, |v, f| write!(f, "{v};")))), - f, - ) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Statement { - Value(Value), - Analyze(AnalyzeStatement), - Begin(BeginStatement), - Break(BreakStatement), - Continue(ContinueStatement), - Cancel(CancelStatement), - Commit(CommitStatement), - Create(CreateStatement), - Define(DefineStatement), - Delete(DeleteStatement), - Foreach(ForeachStatement), - Ifelse(IfelseStatement), - Info(InfoStatement), - Insert(InsertStatement), - Kill(KillStatement), - Live(LiveStatement), - Option(OptionStatement), - Output(OutputStatement), - Relate(RelateStatement), - Remove(RemoveStatement), - Select(SelectStatement), - Set(SetStatement), - Show(ShowStatement), - Sleep(SleepStatement), - Update(UpdateStatement), - Throw(ThrowStatement), - Use(UseStatement), -} - -impl Statement { - /// Get the statement timeout duration, if any - pub fn timeout(&self) -> Option { - match self { - Self::Create(v) => v.timeout.as_ref().map(|v| *v.0), - Self::Delete(v) => v.timeout.as_ref().map(|v| *v.0), - Self::Insert(v) => v.timeout.as_ref().map(|v| *v.0), - Self::Relate(v) => v.timeout.as_ref().map(|v| *v.0), - Self::Select(v) => v.timeout.as_ref().map(|v| *v.0), - Self::Update(v) => v.timeout.as_ref().map(|v| *v.0), - _ => None, - } - } - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - match self { - Self::Value(v) => v.writeable(), - Self::Analyze(_) => false, - Self::Break(_) => false, - Self::Continue(_) => false, - Self::Create(v) => v.writeable(), - Self::Define(_) => true, - Self::Delete(v) => v.writeable(), - Self::Foreach(v) => v.writeable(), - Self::Ifelse(v) => v.writeable(), - Self::Info(_) => false, - Self::Insert(v) => v.writeable(), - Self::Kill(_) => true, - Self::Live(_) => true, - Self::Output(v) => v.writeable(), - Self::Option(_) => false, - Self::Relate(v) => v.writeable(), - Self::Remove(_) => true, - Self::Select(v) => v.writeable(), - Self::Set(v) => v.writeable(), - Self::Show(_) => false, - Self::Sleep(_) => false, - Self::Throw(_) => false, - Self::Update(v) => v.writeable(), - Self::Use(_) => false, - _ => unreachable!(), - } - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self { - Self::Analyze(v) => v.compute(ctx, opt, txn, doc).await, - Self::Break(v) => v.compute(ctx, opt, txn, doc).await, - Self::Continue(v) => v.compute(ctx, opt, txn, doc).await, - Self::Create(v) => v.compute(ctx, opt, txn, doc).await, - Self::Delete(v) => v.compute(ctx, opt, txn, doc).await, - Self::Define(v) => v.compute(ctx, opt, txn, doc).await, - Self::Foreach(v) => v.compute(ctx, opt, txn, doc).await, - Self::Ifelse(v) => v.compute(ctx, opt, txn, doc).await, - Self::Info(v) => v.compute(ctx, opt, txn, doc).await, - Self::Insert(v) => v.compute(ctx, opt, txn, doc).await, - Self::Kill(v) => v.compute(ctx, opt, txn, doc).await, - Self::Live(v) => v.compute(ctx, opt, txn, doc).await, - Self::Output(v) => v.compute(ctx, opt, txn, doc).await, - Self::Relate(v) => v.compute(ctx, opt, txn, doc).await, - Self::Remove(v) => v.compute(ctx, opt, txn, doc).await, - Self::Select(v) => v.compute(ctx, opt, txn, doc).await, - Self::Set(v) => v.compute(ctx, opt, txn, doc).await, - Self::Show(v) => v.compute(ctx, opt, txn, doc).await, - Self::Sleep(v) => v.compute(ctx, opt, txn, doc).await, - Self::Throw(v) => v.compute(ctx, opt, txn, doc).await, - Self::Update(v) => v.compute(ctx, opt, txn, doc).await, - Self::Value(v) => { - // Ensure futures are processed - let opt = &opt.new_with_futures(true); - // Process the output value - v.compute(ctx, opt, txn, doc).await - } - _ => unreachable!(), - } - } -} - -impl Display for Statement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Value(v) => write!(Pretty::from(f), "{v}"), - Self::Analyze(v) => write!(Pretty::from(f), "{v}"), - Self::Begin(v) => write!(Pretty::from(f), "{v}"), - Self::Break(v) => write!(Pretty::from(f), "{v}"), - Self::Cancel(v) => write!(Pretty::from(f), "{v}"), - Self::Commit(v) => write!(Pretty::from(f), "{v}"), - Self::Continue(v) => write!(Pretty::from(f), "{v}"), - Self::Create(v) => write!(Pretty::from(f), "{v}"), - Self::Define(v) => write!(Pretty::from(f), "{v}"), - Self::Delete(v) => write!(Pretty::from(f), "{v}"), - Self::Foreach(v) => write!(Pretty::from(f), "{v}"), - Self::Insert(v) => write!(Pretty::from(f), "{v}"), - Self::Ifelse(v) => write!(Pretty::from(f), "{v}"), - Self::Info(v) => write!(Pretty::from(f), "{v}"), - Self::Kill(v) => write!(Pretty::from(f), "{v}"), - Self::Live(v) => write!(Pretty::from(f), "{v}"), - Self::Option(v) => write!(Pretty::from(f), "{v}"), - Self::Output(v) => write!(Pretty::from(f), "{v}"), - Self::Relate(v) => write!(Pretty::from(f), "{v}"), - Self::Remove(v) => write!(Pretty::from(f), "{v}"), - Self::Select(v) => write!(Pretty::from(f), "{v}"), - Self::Set(v) => write!(Pretty::from(f), "{v}"), - Self::Show(v) => write!(Pretty::from(f), "{v}"), - Self::Sleep(v) => write!(Pretty::from(f), "{v}"), - Self::Throw(v) => write!(Pretty::from(f), "{v}"), - Self::Update(v) => write!(Pretty::from(f), "{v}"), - Self::Use(v) => write!(Pretty::from(f), "{v}"), - } - } -} diff --git a/core/src/sql/v2/statements/analyze.rs b/core/src/sql/v2/statements/analyze.rs deleted file mode 100644 index 6c5ecbab..00000000 --- a/core/src/sql/v2/statements/analyze.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::Options; -use crate::dbs::Transaction; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::idx::ft::FtIndex; -use crate::idx::trees::mtree::MTreeIndex; -use crate::idx::IndexKeyBase; -use crate::kvs::TransactionType; -use crate::sql::ident::Ident; -use crate::sql::index::Index; -use crate::sql::value::Value; -use crate::sql::Base; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fmt::{Display, Formatter}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum AnalyzeStatement { - Idx(Ident, Ident), -} - -impl AnalyzeStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self { - AnalyzeStatement::Idx(tb, idx) => { - // Allowed to run? - opt.is_allowed(Action::View, ResourceKind::Index, &Base::Db)?; - // Read the index - let ix = txn - .lock() - .await - .get_and_cache_tb_index(opt.ns(), opt.db(), tb.as_str(), idx.as_str()) - .await?; - let ikb = IndexKeyBase::new(opt, &ix); - - // Index operation dispatching - let value: Value = match &ix.index { - Index::Search(p) => { - let ft = FtIndex::new( - ctx.get_index_stores(), - opt, - txn, - p.az.as_str(), - ikb, - p, - TransactionType::Read, - ) - .await?; - ft.statistics(txn).await?.into() - } - Index::MTree(p) => { - let mut tx = txn.lock().await; - let mt = MTreeIndex::new( - ctx.get_index_stores(), - &mut tx, - ikb, - p, - TransactionType::Read, - ) - .await?; - mt.statistics(&mut tx).await?.into() - } - _ => { - return Err(Error::FeatureNotYetImplemented { - feature: "Statistics on unique and non-unique indexes.".to_string(), - }) - } - }; - // Return the result object - Ok(value) - } - } - } -} - -impl Display for AnalyzeStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Idx(tb, idx) => write!(f, "ANALYZE INDEX {idx} ON {tb}"), - } - } -} diff --git a/core/src/sql/v2/statements/begin.rs b/core/src/sql/v2/statements/begin.rs deleted file mode 100644 index e57af359..00000000 --- a/core/src/sql/v2/statements/begin.rs +++ /dev/null @@ -1,15 +0,0 @@ -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct BeginStatement; - -impl fmt::Display for BeginStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("BEGIN TRANSACTION") - } -} diff --git a/core/src/sql/v2/statements/break.rs b/core/src/sql/v2/statements/break.rs deleted file mode 100644 index a3d6e3f3..00000000 --- a/core/src/sql/v2/statements/break.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::value::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct BreakStatement; - -impl BreakStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - false - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - _opt: &Options, - _txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - Err(Error::Break) - } -} - -impl fmt::Display for BreakStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("BREAK") - } -} diff --git a/core/src/sql/v2/statements/cancel.rs b/core/src/sql/v2/statements/cancel.rs deleted file mode 100644 index cd7a7670..00000000 --- a/core/src/sql/v2/statements/cancel.rs +++ /dev/null @@ -1,15 +0,0 @@ -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct CancelStatement; - -impl fmt::Display for CancelStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("CANCEL TRANSACTION") - } -} diff --git a/core/src/sql/v2/statements/commit.rs b/core/src/sql/v2/statements/commit.rs deleted file mode 100644 index c1a3ae9b..00000000 --- a/core/src/sql/v2/statements/commit.rs +++ /dev/null @@ -1,15 +0,0 @@ -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct CommitStatement; - -impl fmt::Display for CommitStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("COMMIT TRANSACTION") - } -} diff --git a/core/src/sql/v2/statements/continue.rs b/core/src/sql/v2/statements/continue.rs deleted file mode 100644 index 9bf2139a..00000000 --- a/core/src/sql/v2/statements/continue.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct ContinueStatement; - -impl ContinueStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - false - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - _opt: &Options, - _txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - Err(Error::Continue) - } -} - -impl fmt::Display for ContinueStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("CONTINUE") - } -} diff --git a/core/src/sql/v2/statements/create.rs b/core/src/sql/v2/statements/create.rs deleted file mode 100644 index e320dc6e..00000000 --- a/core/src/sql/v2/statements/create.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Iterator, Options, Statement, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{Data, Output, Timeout, Value, Values}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 2)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct CreateStatement { - #[revision(start = 2)] - pub only: bool, - pub what: Values, - pub data: Option, - pub output: Option, - pub timeout: Option, - pub parallel: bool, -} - -impl CreateStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - true - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Valid options? - opt.valid_for_db()?; - // Create a new iterator - let mut i = Iterator::new(); - // Assign the statement - let stm = Statement::from(self); - // Ensure futures are stored - let opt = &opt.new_with_futures(false); - // Loop over the create targets - for w in self.what.0.iter() { - let v = w.compute(ctx, opt, txn, doc).await?; - i.prepare(ctx, opt, txn, &stm, v).await.map_err(|e| match e { - Error::InvalidStatementTarget { - value: v, - } => Error::CreateStatement { - value: v, - }, - e => e, - })?; - } - // Output the results - match i.output(ctx, opt, txn, &stm).await? { - // This is a single record result - Value::Array(mut a) if self.only => match a.len() { - // There was exactly one result - 1 => Ok(a.remove(0)), - // There were no results - _ => Err(Error::SingleOnlyOutput), - }, - // This is standard query result - v => Ok(v), - } - } -} - -impl fmt::Display for CreateStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CREATE")?; - if self.only { - f.write_str(" ONLY")? - } - write!(f, " {}", self.what)?; - if let Some(ref v) = self.data { - write!(f, " {v}")? - } - if let Some(ref v) = self.output { - write!(f, " {v}")? - } - if let Some(ref v) = self.timeout { - write!(f, " {v}")? - } - if self.parallel { - f.write_str(" PARALLEL")? - } - Ok(()) - } -} diff --git a/core/src/sql/v2/statements/delete.rs b/core/src/sql/v2/statements/delete.rs deleted file mode 100644 index 90d84957..00000000 --- a/core/src/sql/v2/statements/delete.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Iterator, Options, Statement, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{Cond, Output, Timeout, Value, Values}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 2)] -pub struct DeleteStatement { - #[revision(start = 2)] - pub only: bool, - pub what: Values, - pub cond: Option, - pub output: Option, - pub timeout: Option, - pub parallel: bool, -} - -impl DeleteStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - true - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Valid options? - opt.valid_for_db()?; - // Create a new iterator - let mut i = Iterator::new(); - // Assign the statement - let stm = Statement::from(self); - // Ensure futures are stored - let opt = &opt.new_with_futures(false).with_projections(false); - // Loop over the delete targets - for w in self.what.0.iter() { - let v = w.compute(ctx, opt, txn, doc).await?; - i.prepare(ctx, opt, txn, &stm, v).await.map_err(|e| match e { - Error::InvalidStatementTarget { - value: v, - } => Error::DeleteStatement { - value: v, - }, - e => e, - })?; - } - // Output the results - match i.output(ctx, opt, txn, &stm).await? { - // This is a single record result - Value::Array(mut a) if self.only => match a.len() { - // There was exactly one result - 1 => Ok(a.remove(0)), - // There were no results - _ => Err(Error::SingleOnlyOutput), - }, - // This is standard query result - v => Ok(v), - } - } -} - -impl fmt::Display for DeleteStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DELETE")?; - if self.only { - f.write_str(" ONLY")? - } - write!(f, " {}", self.what)?; - if let Some(ref v) = self.cond { - write!(f, " {v}")? - } - if let Some(ref v) = self.output { - write!(f, " {v}")? - } - if let Some(ref v) = self.timeout { - write!(f, " {v}")? - } - if self.parallel { - f.write_str(" PARALLEL")? - } - Ok(()) - } -} diff --git a/core/src/sql/v2/statements/foreach.rs b/core/src/sql/v2/statements/foreach.rs deleted file mode 100644 index 31d63520..00000000 --- a/core/src/sql/v2/statements/foreach.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{block::Entry, Block, Param, Value}; -use async_recursion::async_recursion; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct ForeachStatement { - pub param: Param, - pub range: Value, - pub block: Block, -} - -impl ForeachStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - self.range.writeable() || self.block.writeable() - } - /// Process this type returning a computed simple Value - #[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 CursorDoc<'_>>, - ) -> Result { - // Check the loop data - match &self.range.compute(ctx, opt, txn, doc).await? { - Value::Array(arr) => { - // Loop over the values - 'foreach: for v in arr.iter() { - // Duplicate context - let mut ctx = Context::new(ctx); - // Set the current parameter - let key = self.param.0.to_raw(); - let val = v.compute(&ctx, opt, txn, doc).await?; - ctx.add_value(key, val); - // Loop over the code block statements - for v in self.block.iter() { - // Compute each block entry - let res = match v { - Entry::Set(v) => { - let val = v.compute(&ctx, opt, txn, doc).await?; - ctx.add_value(v.name.to_owned(), val); - Ok(Value::None) - } - Entry::Value(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Break(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Continue(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Foreach(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Ifelse(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Select(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Create(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Update(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Delete(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Relate(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Insert(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Define(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Remove(v) => v.compute(&ctx, opt, txn, doc).await, - Entry::Output(v) => { - return v.compute(&ctx, opt, txn, doc).await; - } - Entry::Throw(v) => { - return v.compute(&ctx, opt, txn, doc).await; - } - }; - // Catch any special errors - match res { - Err(Error::Continue) => continue 'foreach, - Err(Error::Break) => return Ok(Value::None), - Err(err) => return Err(err), - _ => (), - }; - } - } - // Ok all good - Ok(Value::None) - } - v => Err(Error::InvalidStatementTarget { - value: v.to_string(), - }), - } - } -} - -impl Display for ForeachStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "FOR {} IN {} {}", self.param, self.range, self.block) - } -} diff --git a/core/src/sql/v2/statements/ifelse.rs b/core/src/sql/v2/statements/ifelse.rs deleted file mode 100644 index 971dfc54..00000000 --- a/core/src/sql/v2/statements/ifelse.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::fmt::{fmt_separated_by, is_pretty, pretty_indent, Fmt, Pretty}; -use crate::sql::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Write}; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct IfelseStatement { - /// The first if condition followed by a body, followed by any number of else if's - pub exprs: Vec<(Value, Value)>, - /// the final else body, if there is one - pub close: Option, -} - -impl IfelseStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - for (cond, then) in self.exprs.iter() { - if cond.writeable() || then.writeable() { - return true; - } - } - self.close.as_ref().map_or(false, |v| v.writeable()) - } - /// Check if we require a writeable transaction - pub(crate) fn bracketed(&self) -> bool { - self.exprs.iter().all(|(_, v)| matches!(v, Value::Block(_))) - && (self.close.as_ref().is_none() - || self.close.as_ref().is_some_and(|v| matches!(v, Value::Block(_)))) - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - for (ref cond, ref then) in &self.exprs { - let v = cond.compute(ctx, opt, txn, doc).await?; - if v.is_truthy() { - return then.compute(ctx, opt, txn, doc).await; - } - } - match self.close { - Some(ref v) => v.compute(ctx, opt, txn, doc).await, - None => Ok(Value::None), - } - } -} - -impl Display for IfelseStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = Pretty::from(f); - match self.bracketed() { - true => { - write!( - f, - "{}", - &Fmt::new( - self.exprs.iter().map(|args| { - Fmt::new(args, |(cond, then), f| { - if is_pretty() { - write!(f, "IF {cond}")?; - let indent = pretty_indent(); - write!(f, "{then}")?; - drop(indent); - } else { - write!(f, "IF {cond} {then}")?; - } - Ok(()) - }) - }), - if is_pretty() { - fmt_separated_by("ELSE") - } else { - fmt_separated_by(" ELSE ") - }, - ), - )?; - if let Some(ref v) = self.close { - if is_pretty() { - write!(f, "ELSE")?; - let indent = pretty_indent(); - write!(f, "{v}")?; - drop(indent); - } else { - write!(f, " ELSE {v}")?; - } - } - Ok(()) - } - false => { - write!( - f, - "{}", - &Fmt::new( - self.exprs.iter().map(|args| { - Fmt::new(args, |(cond, then), f| { - if is_pretty() { - write!(f, "IF {cond} THEN")?; - let indent = pretty_indent(); - write!(f, "{then}")?; - drop(indent); - } else { - write!(f, "IF {cond} THEN {then}")?; - } - Ok(()) - }) - }), - if is_pretty() { - fmt_separated_by("ELSE") - } else { - fmt_separated_by(" ELSE ") - }, - ), - )?; - if let Some(ref v) = self.close { - if is_pretty() { - write!(f, "ELSE")?; - let indent = pretty_indent(); - write!(f, "{v}")?; - drop(indent); - } else { - write!(f, " ELSE {v}")?; - } - } - if is_pretty() { - f.write_str("END")?; - } else { - f.write_str(" END")?; - } - Ok(()) - } - } - } -} diff --git a/core/src/sql/v2/statements/info.rs b/core/src/sql/v2/statements/info.rs deleted file mode 100644 index 27995ddc..00000000 --- a/core/src/sql/v2/statements/info.rs +++ /dev/null @@ -1,235 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::Action; -use crate::iam::ResourceKind; -use crate::sql::{Base, Ident, Object, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum InfoStatement { - Root, - Ns, - Db, - Sc(Ident), - Tb(Ident), - User(Ident, Option), -} - -impl InfoStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - _ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - match self { - InfoStatement::Root => { - // Allowed to run? - opt.is_allowed(Action::View, ResourceKind::Any, &Base::Root)?; - // Claim transaction - let mut run = txn.lock().await; - // Create the result set - let mut res = Object::default(); - // Process the namespaces - let mut tmp = Object::default(); - for v in run.all_ns().await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("namespaces".to_owned(), tmp.into()); - // Process the users - let mut tmp = Object::default(); - for v in run.all_root_users().await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("users".to_owned(), tmp.into()); - // Ok all good - Value::from(res).ok() - } - InfoStatement::Ns => { - // Allowed to run? - opt.is_allowed(Action::View, ResourceKind::Any, &Base::Ns)?; - // Claim transaction - let mut run = txn.lock().await; - // Create the result set - let mut res = Object::default(); - // Process the databases - let mut tmp = Object::default(); - for v in run.all_db(opt.ns()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("databases".to_owned(), tmp.into()); - // Process the users - let mut tmp = Object::default(); - for v in run.all_ns_users(opt.ns()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("users".to_owned(), tmp.into()); - // Process the tokens - let mut tmp = Object::default(); - for v in run.all_ns_tokens(opt.ns()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("tokens".to_owned(), tmp.into()); - // Ok all good - Value::from(res).ok() - } - InfoStatement::Db => { - // Allowed to run? - opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Create the result set - let mut res = Object::default(); - // Process the users - let mut tmp = Object::default(); - for v in run.all_db_users(opt.ns(), opt.db()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("users".to_owned(), tmp.into()); - // Process the tokens - let mut tmp = Object::default(); - for v in run.all_db_tokens(opt.ns(), opt.db()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("tokens".to_owned(), tmp.into()); - // Process the functions - let mut tmp = Object::default(); - for v in run.all_db_functions(opt.ns(), opt.db()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("functions".to_owned(), tmp.into()); - // Process the models - let mut tmp = Object::default(); - for v in run.all_db_models(opt.ns(), opt.db()).await?.iter() { - tmp.insert(format!("{}<{}>", v.name, v.version), v.to_string().into()); - } - res.insert("models".to_owned(), tmp.into()); - // Process the params - let mut tmp = Object::default(); - for v in run.all_db_params(opt.ns(), opt.db()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("params".to_owned(), tmp.into()); - // Process the scopes - let mut tmp = Object::default(); - for v in run.all_sc(opt.ns(), opt.db()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("scopes".to_owned(), tmp.into()); - // Process the tables - let mut tmp = Object::default(); - for v in run.all_tb(opt.ns(), opt.db()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("tables".to_owned(), tmp.into()); - // Process the analyzers - let mut tmp = Object::default(); - for v in run.all_db_analyzers(opt.ns(), opt.db()).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("analyzers".to_owned(), tmp.into()); - // Ok all good - Value::from(res).ok() - } - InfoStatement::Sc(sc) => { - // Allowed to run? - opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Create the result set - let mut res = Object::default(); - // Process the tokens - let mut tmp = Object::default(); - for v in run.all_sc_tokens(opt.ns(), opt.db(), sc).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("tokens".to_owned(), tmp.into()); - // Ok all good - Value::from(res).ok() - } - InfoStatement::Tb(tb) => { - // Allowed to run? - opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?; - // Claim transaction - let mut run = txn.lock().await; - // Create the result set - let mut res = Object::default(); - // Process the events - let mut tmp = Object::default(); - for v in run.all_tb_events(opt.ns(), opt.db(), tb).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("events".to_owned(), tmp.into()); - // Process the fields - let mut tmp = Object::default(); - for v in run.all_tb_fields(opt.ns(), opt.db(), tb).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("fields".to_owned(), tmp.into()); - // Process the tables - let mut tmp = Object::default(); - for v in run.all_tb_views(opt.ns(), opt.db(), tb).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("tables".to_owned(), tmp.into()); - // Process the indexes - let mut tmp = Object::default(); - for v in run.all_tb_indexes(opt.ns(), opt.db(), tb).await?.iter() { - tmp.insert(v.name.to_string(), v.to_string().into()); - } - res.insert("indexes".to_owned(), tmp.into()); - // Process the live queries - let mut tmp = Object::default(); - for v in run.all_tb_lives(opt.ns(), opt.db(), tb).await?.iter() { - tmp.insert(v.id.to_raw(), v.to_string().into()); - } - res.insert("lives".to_owned(), tmp.into()); - // Ok all good - Value::from(res).ok() - } - InfoStatement::User(user, base) => { - let base = base.clone().unwrap_or(opt.selected_base()?); - // Allowed to run? - opt.is_allowed(Action::View, ResourceKind::Actor, &base)?; - - // Claim transaction - let mut run = txn.lock().await; - // Process the user - let res = match base { - Base::Root => run.get_root_user(user).await?, - Base::Ns => run.get_ns_user(opt.ns(), user).await?, - Base::Db => run.get_db_user(opt.ns(), opt.db(), user).await?, - _ => return Err(Error::InvalidLevel(base.to_string())), - }; - // Ok all good - Value::from(res.to_string()).ok() - } - } - } -} - -impl fmt::Display for InfoStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Root => f.write_str("INFO FOR ROOT"), - Self::Ns => f.write_str("INFO FOR NAMESPACE"), - Self::Db => f.write_str("INFO FOR DATABASE"), - Self::Sc(ref s) => write!(f, "INFO FOR SCOPE {s}"), - Self::Tb(ref t) => write!(f, "INFO FOR TABLE {t}"), - Self::User(ref u, ref b) => match b { - Some(ref b) => write!(f, "INFO FOR USER {u} ON {b}"), - None => write!(f, "INFO FOR USER {u}"), - }, - } - } -} diff --git a/core/src/sql/v2/statements/insert.rs b/core/src/sql/v2/statements/insert.rs deleted file mode 100644 index 25b047ef..00000000 --- a/core/src/sql/v2/statements/insert.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Iterable, Iterator, Options, Statement, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{Data, Output, Timeout, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct InsertStatement { - pub into: Value, - pub data: Data, - pub ignore: bool, - pub update: Option, - pub output: Option, - pub timeout: Option, - pub parallel: bool, -} - -impl InsertStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - true - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Valid options? - opt.valid_for_db()?; - // Create a new iterator - let mut i = Iterator::new(); - // Ensure futures are stored - let opt = &opt.new_with_futures(false).with_projections(false); - // Parse the expression - match self.into.compute(ctx, opt, txn, doc).await? { - Value::Table(into) => match &self.data { - // Check if this is a traditional statement - Data::ValuesExpression(v) => { - for v in v { - // Create a new empty base object - let mut o = Value::base(); - // Set each field from the expression - for (k, v) in v.iter() { - let v = v.compute(ctx, opt, txn, None).await?; - o.set(ctx, opt, txn, k, v).await?; - } - // Specify the new table record id - let id = o.rid().generate(&into, true)?; - // Pass the mergeable to the iterator - i.ingest(Iterable::Mergeable(id, o)); - } - } - // Check if this is a modern statement - Data::SingleExpression(v) => { - let v = v.compute(ctx, opt, txn, doc).await?; - match v { - Value::Array(v) => { - for v in v { - // Specify the new table record id - let id = v.rid().generate(&into, true)?; - // Pass the mergeable to the iterator - i.ingest(Iterable::Mergeable(id, v)); - } - } - Value::Object(_) => { - // Specify the new table record id - let id = v.rid().generate(&into, true)?; - // Pass the mergeable to the iterator - i.ingest(Iterable::Mergeable(id, v)); - } - v => { - return Err(Error::InsertStatement { - value: v.to_string(), - }) - } - } - } - _ => unreachable!(), - }, - v => { - return Err(Error::InsertStatement { - value: v.to_string(), - }) - } - } - // Assign the statement - let stm = Statement::from(self); - // Output the results - i.output(ctx, opt, txn, &stm).await - } -} - -impl fmt::Display for InsertStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("INSERT")?; - if self.ignore { - f.write_str(" IGNORE")? - } - write!(f, " INTO {} {}", self.into, self.data)?; - if let Some(ref v) = self.update { - write!(f, " {v}")? - } - if let Some(ref v) = self.output { - write!(f, " {v}")? - } - if let Some(ref v) = self.timeout { - write!(f, " {v}")? - } - if self.parallel { - f.write_str(" PARALLEL")? - } - Ok(()) - } -} diff --git a/core/src/sql/v2/statements/mod.rs b/core/src/sql/v2/statements/mod.rs deleted file mode 100644 index e777c783..00000000 --- a/core/src/sql/v2/statements/mod.rs +++ /dev/null @@ -1,65 +0,0 @@ -pub(crate) mod analyze; -pub(crate) mod begin; -pub(crate) mod r#break; -pub(crate) mod cancel; -pub(crate) mod commit; -pub(crate) mod r#continue; -pub(crate) mod create; -pub(crate) mod define; -pub(crate) mod delete; -pub(crate) mod foreach; -pub(crate) mod ifelse; -pub(crate) mod info; -pub(crate) mod insert; -pub(crate) mod kill; -pub(crate) mod live; -pub(crate) mod option; -pub(crate) mod output; -pub(crate) mod relate; -pub(crate) mod remove; -pub(crate) mod select; -pub(crate) mod set; -pub(crate) mod show; -pub(crate) mod sleep; -pub(crate) mod throw; -pub(crate) mod update; -pub(crate) mod r#use; - -pub use self::analyze::AnalyzeStatement; -pub use self::begin::BeginStatement; -pub use self::cancel::CancelStatement; -pub use self::commit::CommitStatement; -pub use self::create::CreateStatement; -pub use self::delete::DeleteStatement; -pub use self::foreach::ForeachStatement; -pub use self::ifelse::IfelseStatement; -pub use self::info::InfoStatement; -pub use self::insert::InsertStatement; -pub use self::kill::KillStatement; -pub use self::live::LiveStatement; -pub use self::option::OptionStatement; -pub use self::output::OutputStatement; -pub use self::r#break::BreakStatement; -pub use self::r#continue::ContinueStatement; -pub use self::r#use::UseStatement; -pub use self::relate::RelateStatement; -pub use self::select::SelectStatement; -pub use self::set::SetStatement; -pub use self::show::ShowStatement; -pub use self::sleep::SleepStatement; -pub use self::throw::ThrowStatement; -pub use self::update::UpdateStatement; - -pub use self::define::{ - DefineAnalyzerStatement, DefineDatabaseStatement, DefineEventStatement, DefineFieldStatement, - DefineFunctionStatement, DefineIndexStatement, DefineModelStatement, DefineNamespaceStatement, - DefineParamStatement, DefineScopeStatement, DefineStatement, DefineTableStatement, - DefineTokenStatement, DefineUserStatement, -}; - -pub use self::remove::{ - RemoveAnalyzerStatement, RemoveDatabaseStatement, RemoveEventStatement, RemoveFieldStatement, - RemoveFunctionStatement, RemoveIndexStatement, RemoveModelStatement, RemoveNamespaceStatement, - RemoveParamStatement, RemoveScopeStatement, RemoveStatement, RemoveTableStatement, - RemoveTokenStatement, RemoveUserStatement, -}; diff --git a/core/src/sql/v2/statements/option.rs b/core/src/sql/v2/statements/option.rs deleted file mode 100644 index c00f46cf..00000000 --- a/core/src/sql/v2/statements/option.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::sql::ident::Ident; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct OptionStatement { - pub name: Ident, - pub what: bool, -} - -impl fmt::Display for OptionStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.what { - write!(f, "OPTION {}", self.name) - } else { - write!(f, "OPTION {} = FALSE", self.name) - } - } -} diff --git a/core/src/sql/v2/statements/output.rs b/core/src/sql/v2/statements/output.rs deleted file mode 100644 index 507d4965..00000000 --- a/core/src/sql/v2/statements/output.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::fetch::Fetchs; -use crate::sql::value::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct OutputStatement { - pub what: Value, - pub fetch: Option, -} - -impl OutputStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - self.what.writeable() - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Ensure futures are processed - let opt = &opt.new_with_futures(true); - // Process the output value - let mut val = self.what.compute(ctx, opt, txn, doc).await?; - // Fetch any - if let Some(fetchs) = &self.fetch { - for fetch in fetchs.iter() { - val.fetch(ctx, opt, txn, fetch).await?; - } - } - // - Ok(val) - } -} - -impl fmt::Display for OutputStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RETURN {}", self.what)?; - if let Some(ref v) = self.fetch { - write!(f, " {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v2/statements/relate.rs b/core/src/sql/v2/statements/relate.rs deleted file mode 100644 index a5d3a7e1..00000000 --- a/core/src/sql/v2/statements/relate.rs +++ /dev/null @@ -1,196 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Iterable, Iterator, Options, Statement, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{Data, Output, Timeout, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 2)] -pub struct RelateStatement { - #[revision(start = 2)] - pub only: bool, - pub kind: Value, - pub from: Value, - pub with: Value, - pub uniq: bool, - pub data: Option, - pub output: Option, - pub timeout: Option, - pub parallel: bool, -} - -impl RelateStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - true - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Valid options? - opt.valid_for_db()?; - // Create a new iterator - let mut i = Iterator::new(); - // Ensure futures are stored - let opt = &opt.new_with_futures(false).with_projections(false); - // Loop over the from targets - let from = { - let mut out = Vec::new(); - match self.from.compute(ctx, opt, txn, doc).await? { - Value::Thing(v) => out.push(v), - Value::Array(v) => { - for v in v { - match v { - Value::Thing(v) => out.push(v), - Value::Object(v) => match v.rid() { - Some(v) => out.push(v), - _ => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - }, - v => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - } - } - } - Value::Object(v) => match v.rid() { - Some(v) => out.push(v), - None => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - }, - v => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - }; - // } - out - }; - // Loop over the with targets - let with = { - let mut out = Vec::new(); - match self.with.compute(ctx, opt, txn, doc).await? { - Value::Thing(v) => out.push(v), - Value::Array(v) => { - for v in v { - match v { - Value::Thing(v) => out.push(v), - Value::Object(v) => match v.rid() { - Some(v) => out.push(v), - None => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - }, - v => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - } - } - } - Value::Object(v) => match v.rid() { - Some(v) => out.push(v), - None => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - }, - v => { - return Err(Error::RelateStatement { - value: v.to_string(), - }) - } - }; - out - }; - // - for f in from.iter() { - for w in with.iter() { - let f = f.clone(); - let w = w.clone(); - match &self.kind { - // The relation has a specific record id - Value::Thing(id) => i.ingest(Iterable::Relatable(f, id.to_owned(), w)), - // The relation does not have a specific record id - Value::Table(tb) => match &self.data { - // There is a data clause so check for a record id - Some(data) => { - let id = match data.rid(ctx, opt, txn).await? { - Some(id) => id.generate(tb, false)?, - None => tb.generate(), - }; - i.ingest(Iterable::Relatable(f, id, w)) - } - // There is no data clause so create a record id - None => i.ingest(Iterable::Relatable(f, tb.generate(), w)), - }, - // The relation can not be any other type - _ => unreachable!(), - }; - } - } - // Assign the statement - let stm = Statement::from(self); - // Output the results - match i.output(ctx, opt, txn, &stm).await? { - // This is a single record result - Value::Array(mut a) if self.only => match a.len() { - // There was exactly one result - 1 => Ok(a.remove(0)), - // There were no results - _ => Err(Error::SingleOnlyOutput), - }, - // This is standard query result - v => Ok(v), - } - } -} - -impl fmt::Display for RelateStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RELATE")?; - if self.only { - f.write_str(" ONLY")? - } - write!(f, " {} -> {} -> {}", self.from, self.kind, self.with)?; - if self.uniq { - f.write_str(" UNIQUE")? - } - if let Some(ref v) = self.data { - write!(f, " {v}")? - } - if let Some(ref v) = self.output { - write!(f, " {v}")? - } - if let Some(ref v) = self.timeout { - write!(f, " {v}")? - } - if self.parallel { - f.write_str(" PARALLEL")? - } - Ok(()) - } -} diff --git a/core/src/sql/v2/statements/remove/mod.rs b/core/src/sql/v2/statements/remove/mod.rs deleted file mode 100644 index 601c8849..00000000 --- a/core/src/sql/v2/statements/remove/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ -mod analyzer; -mod database; -mod event; -mod field; -mod function; -mod index; -mod model; -mod namespace; -mod param; -mod scope; -mod table; -mod token; -mod user; - -pub use analyzer::RemoveAnalyzerStatement; -pub use database::RemoveDatabaseStatement; -pub use event::RemoveEventStatement; -pub use field::RemoveFieldStatement; -pub use function::RemoveFunctionStatement; -pub use index::RemoveIndexStatement; -pub use model::RemoveModelStatement; -pub use namespace::RemoveNamespaceStatement; -pub use param::RemoveParamStatement; -pub use scope::RemoveScopeStatement; -pub use table::RemoveTableStatement; -pub use token::RemoveTokenStatement; -pub use user::RemoveUserStatement; - -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub enum RemoveStatement { - Namespace(RemoveNamespaceStatement), - Database(RemoveDatabaseStatement), - Function(RemoveFunctionStatement), - Analyzer(RemoveAnalyzerStatement), - Token(RemoveTokenStatement), - Scope(RemoveScopeStatement), - Param(RemoveParamStatement), - Table(RemoveTableStatement), - Event(RemoveEventStatement), - Field(RemoveFieldStatement), - Index(RemoveIndexStatement), - User(RemoveUserStatement), - Model(RemoveModelStatement), -} - -impl RemoveStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - true - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - match self { - Self::Namespace(ref v) => v.compute(ctx, opt, txn).await, - Self::Database(ref v) => v.compute(ctx, opt, txn).await, - Self::Function(ref v) => v.compute(ctx, opt, txn).await, - Self::Token(ref v) => v.compute(ctx, opt, txn).await, - Self::Scope(ref v) => v.compute(ctx, opt, txn).await, - Self::Param(ref v) => v.compute(ctx, opt, txn).await, - Self::Table(ref v) => v.compute(ctx, opt, txn).await, - Self::Event(ref v) => v.compute(ctx, opt, txn).await, - Self::Field(ref v) => v.compute(ctx, opt, txn).await, - Self::Index(ref v) => v.compute(ctx, opt, txn).await, - Self::Analyzer(ref v) => v.compute(ctx, opt, txn).await, - Self::User(ref v) => v.compute(ctx, opt, txn).await, - Self::Model(ref v) => v.compute(ctx, opt, txn).await, - } - } -} - -impl Display for RemoveStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Namespace(v) => Display::fmt(v, f), - Self::Database(v) => Display::fmt(v, f), - Self::Function(v) => Display::fmt(v, f), - Self::Token(v) => Display::fmt(v, f), - Self::Scope(v) => Display::fmt(v, f), - Self::Param(v) => Display::fmt(v, f), - Self::Table(v) => Display::fmt(v, f), - Self::Event(v) => Display::fmt(v, f), - Self::Field(v) => Display::fmt(v, f), - Self::Index(v) => Display::fmt(v, f), - Self::Analyzer(v) => Display::fmt(v, f), - Self::User(v) => Display::fmt(v, f), - Self::Model(v) => Display::fmt(v, f), - } - } -} diff --git a/core/src/sql/v2/statements/select.rs b/core/src/sql/v2/statements/select.rs deleted file mode 100644 index 469207ce..00000000 --- a/core/src/sql/v2/statements/select.rs +++ /dev/null @@ -1,214 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Iterable, Iterator, Options, Statement, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::idx::planner::QueryPlanner; -use crate::sql::{ - Cond, Explain, Fetchs, Field, Fields, Groups, Idioms, Limit, Orders, Splits, Start, Timeout, - Value, Values, Version, With, -}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 2)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct SelectStatement { - pub expr: Fields, - pub omit: Option, - #[revision(start = 2)] - pub only: bool, - pub what: Values, - pub with: Option, - pub cond: Option, - pub split: Option, - pub group: Option, - pub order: Option, - pub limit: Option, - pub start: Option, - pub fetch: Option, - pub version: Option, - pub timeout: Option, - pub parallel: bool, - pub explain: Option, -} - -impl SelectStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - if self.expr.iter().any(|v| match v { - Field::All => false, - Field::Single { - expr, - .. - } => expr.writeable(), - }) { - return true; - } - if self.what.iter().any(|v| v.writeable()) { - return true; - } - self.cond.as_ref().map_or(false, |v| v.writeable()) - } - - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Valid options? - opt.valid_for_db()?; - // Create a new iterator - let mut i = Iterator::new(); - // Ensure futures are stored - let opt = &opt.new_with_futures(false).with_projections(true); - // Get a query planner - let mut planner = QueryPlanner::new(opt, &self.with, &self.cond); - // Used for ONLY: is the limit 1? - let limit_is_one_or_zero = match &self.limit { - Some(l) => l.process(ctx, opt, txn, doc).await? <= 1, - _ => false, - }; - // Fail for multiple targets without a limit - if self.only && !limit_is_one_or_zero && self.what.0.len() > 1 { - return Err(Error::SingleOnlyOutput); - } - // Loop over the select targets - for w in self.what.0.iter() { - let v = w.compute(ctx, opt, txn, doc).await?; - match v { - Value::Table(t) => { - if self.only && !limit_is_one_or_zero { - return Err(Error::SingleOnlyOutput); - } - - planner.add_iterables(ctx, txn, t, &mut i).await?; - } - Value::Thing(v) => i.ingest(Iterable::Thing(v)), - Value::Range(v) => { - if self.only && !limit_is_one_or_zero { - return Err(Error::SingleOnlyOutput); - } - - i.ingest(Iterable::Range(*v)) - } - Value::Edges(v) => { - if self.only && !limit_is_one_or_zero { - return Err(Error::SingleOnlyOutput); - } - - i.ingest(Iterable::Edges(*v)) - } - Value::Mock(v) => { - if self.only && !limit_is_one_or_zero { - return Err(Error::SingleOnlyOutput); - } - - for v in v { - i.ingest(Iterable::Thing(v)); - } - } - Value::Array(v) => { - if self.only && !limit_is_one_or_zero { - return Err(Error::SingleOnlyOutput); - } - - for v in v { - match v { - Value::Table(t) => { - planner.add_iterables(ctx, txn, t, &mut i).await?; - } - Value::Thing(v) => i.ingest(Iterable::Thing(v)), - Value::Edges(v) => i.ingest(Iterable::Edges(*v)), - Value::Mock(v) => { - for v in v { - i.ingest(Iterable::Thing(v)); - } - } - _ => i.ingest(Iterable::Value(v)), - } - } - } - v => i.ingest(Iterable::Value(v)), - }; - } - // Create a new context - let mut ctx = Context::new(ctx); - // Assign the statement - let stm = Statement::from(self); - // Add query executors if any - if planner.has_executors() { - ctx.set_query_planner(&planner); - } - // Output the results - match i.output(&ctx, opt, txn, &stm).await? { - // This is a single record result - Value::Array(mut a) if self.only => match a.len() { - // There were no results - 0 => Ok(Value::None), - // There was exactly one result - 1 => Ok(a.remove(0)), - // There were no results - _ => Err(Error::SingleOnlyOutput), - }, - // This is standard query result - v => Ok(v), - } - } -} - -impl fmt::Display for SelectStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "SELECT {}", self.expr)?; - if let Some(ref v) = self.omit { - write!(f, " OMIT {v}")? - } - write!(f, " FROM")?; - if self.only { - f.write_str(" ONLY")? - } - write!(f, " {}", self.what)?; - if let Some(ref v) = self.with { - write!(f, " {v}")? - } - if let Some(ref v) = self.cond { - write!(f, " {v}")? - } - if let Some(ref v) = self.split { - write!(f, " {v}")? - } - if let Some(ref v) = self.group { - write!(f, " {v}")? - } - if let Some(ref v) = self.order { - write!(f, " {v}")? - } - if let Some(ref v) = self.limit { - write!(f, " {v}")? - } - if let Some(ref v) = self.start { - write!(f, " {v}")? - } - if let Some(ref v) = self.fetch { - write!(f, " {v}")? - } - if let Some(ref v) = self.version { - write!(f, " {v}")? - } - if let Some(ref v) = self.timeout { - write!(f, " {v}")? - } - if self.parallel { - f.write_str(" PARALLEL")? - } - if let Some(ref v) = self.explain { - write!(f, " {v}")? - } - Ok(()) - } -} diff --git a/core/src/sql/v2/statements/set.rs b/core/src/sql/v2/statements/set.rs deleted file mode 100644 index c2b1be29..00000000 --- a/core/src/sql/v2/statements/set.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::cnf::PROTECTED_PARAM_NAMES; -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct SetStatement { - pub name: String, - pub what: Value, -} - -impl SetStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - self.what.writeable() - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Check if the variable is a protected variable - match PROTECTED_PARAM_NAMES.contains(&self.name.as_str()) { - // The variable isn't protected and can be stored - false => self.what.compute(ctx, opt, txn, doc).await, - // The user tried to set a protected variable - true => Err(Error::InvalidParam { - // Move the parameter name, as we no longer need it - name: self.name.to_owned(), - }), - } - } -} - -impl fmt::Display for SetStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LET ${} = {}", self.name, self.what) - } -} diff --git a/core/src/sql/v2/statements/sleep.rs b/core/src/sql/v2/statements/sleep.rs deleted file mode 100644 index f71aa85f..00000000 --- a/core/src/sql/v2/statements/sleep.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Duration, Value}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 1)] -pub struct SleepStatement { - pub(crate) duration: Duration, -} - -impl SleepStatement { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - _txn: &Transaction, - _doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Allowed to run? - opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Root)?; - // Calculate the sleep duration - let dur = match (ctx.timeout(), self.duration.0) { - (Some(t), d) if t < d => t, - (_, d) => d, - }; - // Sleep for the specified time - #[cfg(target_arch = "wasm32")] - wasmtimer::tokio::sleep(dur).await; - #[cfg(not(target_arch = "wasm32"))] - tokio::time::sleep(dur).await; - // Ok all good - Ok(Value::None) - } -} - -impl fmt::Display for SleepStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "SLEEP {}", self.duration) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::dbs::test::mock; - use std::time::{self, SystemTime}; - - #[tokio::test] - async fn test_sleep_compute() { - let time = SystemTime::now(); - let (ctx, opt, txn) = mock().await; - let stm = SleepStatement { - duration: Duration(time::Duration::from_micros(500)), - }; - let value = stm.compute(&ctx, &opt, &txn, None).await.unwrap(); - assert!(time.elapsed().unwrap() >= time::Duration::from_micros(500)); - assert_eq!(value, Value::None); - } -} diff --git a/core/src/sql/v2/statements/throw.rs b/core/src/sql/v2/statements/throw.rs deleted file mode 100644 index 6446b028..00000000 --- a/core/src/sql/v2/statements/throw.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::Value; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct ThrowStatement { - pub error: Value, -} - -impl ThrowStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - false - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - Err(Error::Thrown(self.error.compute(ctx, opt, txn, doc).await?.to_raw_string())) - } -} - -impl fmt::Display for ThrowStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "THROW {}", self.error) - } -} diff --git a/core/src/sql/v2/statements/update.rs b/core/src/sql/v2/statements/update.rs deleted file mode 100644 index 56027d47..00000000 --- a/core/src/sql/v2/statements/update.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Iterator, Options, Statement, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{Cond, Data, Output, Timeout, Value, Values}; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[revisioned(revision = 2)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct UpdateStatement { - #[revision(start = 2)] - pub only: bool, - pub what: Values, - pub data: Option, - pub cond: Option, - pub output: Option, - pub timeout: Option, - pub parallel: bool, -} - -impl UpdateStatement { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - true - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Valid options? - opt.valid_for_db()?; - // Create a new iterator - let mut i = Iterator::new(); - // Assign the statement - let stm = Statement::from(self); - // Ensure futures are stored - let opt = &opt.new_with_futures(false).with_projections(false); - // Loop over the update targets - for w in self.what.0.iter() { - let v = w.compute(ctx, opt, txn, doc).await?; - i.prepare(ctx, opt, txn, &stm, v).await.map_err(|e| match e { - Error::InvalidStatementTarget { - value: v, - } => Error::UpdateStatement { - value: v, - }, - e => e, - })?; - } - // Output the results - match i.output(ctx, opt, txn, &stm).await? { - // This is a single record result - Value::Array(mut a) if self.only => match a.len() { - // There was exactly one result - 1 => Ok(a.remove(0)), - // There were no results - _ => Err(Error::SingleOnlyOutput), - }, - // This is standard query result - v => Ok(v), - } - } -} - -impl fmt::Display for UpdateStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UPDATE")?; - if self.only { - f.write_str(" ONLY")? - } - write!(f, " {}", self.what)?; - if let Some(ref v) = self.data { - write!(f, " {v}")? - } - if let Some(ref v) = self.cond { - write!(f, " {v}")? - } - if let Some(ref v) = self.output { - write!(f, " {v}")? - } - if let Some(ref v) = self.timeout { - write!(f, " {v}")? - } - if self.parallel { - f.write_str(" PARALLEL")? - } - Ok(()) - } -} diff --git a/core/src/sql/v2/statements/use.rs b/core/src/sql/v2/statements/use.rs deleted file mode 100644 index 399661f6..00000000 --- a/core/src/sql/v2/statements/use.rs +++ /dev/null @@ -1,29 +0,0 @@ -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; - -use crate::sql::escape::escape_ident; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct UseStatement { - pub ns: Option, - pub db: Option, -} - -impl fmt::Display for UseStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("USE")?; - if let Some(ref ns) = self.ns { - let ns = escape_ident(ns); - write!(f, " NS {ns}")?; - } - if let Some(ref db) = self.db { - let db = escape_ident(db); - write!(f, " DB {db}")?; - } - Ok(()) - } -} diff --git a/core/src/sql/v2/strand.rs b/core/src/sql/v2/strand.rs deleted file mode 100644 index cee32486..00000000 --- a/core/src/sql/v2/strand.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crate::sql::escape::quote_plain_str; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; -use std::ops::{self}; -use std::str; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Strand"; - -/// A string that doesn't contain NUL bytes. -#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Strand")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Strand(#[serde(with = "no_nul_bytes")] pub String); - -impl From for Strand { - fn from(s: String) -> Self { - debug_assert!(!s.contains('\0')); - Strand(s) - } -} - -impl From<&str> for Strand { - fn from(s: &str) -> Self { - debug_assert!(!s.contains('\0')); - Self::from(String::from(s)) - } -} - -impl Deref for Strand { - type Target = String; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From for String { - fn from(s: Strand) -> Self { - s.0 - } -} - -impl Strand { - /// Get the underlying String slice - pub fn as_str(&self) -> &str { - self.0.as_str() - } - /// Returns the underlying String - pub fn as_string(self) -> String { - self.0 - } - /// Convert the Strand to a raw String - pub fn to_raw(self) -> String { - self.0 - } -} - -impl Display for Strand { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt("e_plain_str(&self.0), f) - } -} - -impl ops::Add for Strand { - type Output = Self; - fn add(mut self, other: Self) -> Self { - self.0.push_str(other.as_str()); - self - } -} - -// serde(with = no_nul_bytes) will (de)serialize with no NUL bytes. -pub(crate) mod no_nul_bytes { - use serde::{ - de::{self, Visitor}, - Deserializer, Serializer, - }; - use std::fmt; - - pub(crate) fn serialize(s: &str, serializer: S) -> Result - where - S: Serializer, - { - debug_assert!(!s.contains('\0')); - serializer.serialize_str(s) - } - - pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct NoNulBytesVisitor; - - impl<'de> Visitor<'de> for NoNulBytesVisitor { - type Value = String; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a string without any NUL bytes") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - if value.contains('\0') { - Err(de::Error::custom("contained NUL byte")) - } else { - Ok(value.to_owned()) - } - } - - fn visit_string(self, value: String) -> Result - where - E: de::Error, - { - if value.contains('\0') { - Err(de::Error::custom("contained NUL byte")) - } else { - Ok(value) - } - } - } - - deserializer.deserialize_string(NoNulBytesVisitor) - } -} - -#[cfg(test)] -mod test { - - #[cfg(not(feature = "experimental-parser"))] - #[test] - fn ensure_strands_are_prefixed() { - use super::Strand; - - let strand = Strand("a:b".to_owned()); - assert_eq!(strand.to_string().as_str(), "s'a:b'"); - - let strand = Strand("2012-04-23T18:25:43.0000511Z".to_owned()); - assert_eq!(strand.to_string().as_str(), "s'2012-04-23T18:25:43.0000511Z'"); - - let strand = Strand("b19bc00b-aa98-486c-ae37-c8e1c54295b1".to_owned()); - assert_eq!(strand.to_string().as_str(), "s'b19bc00b-aa98-486c-ae37-c8e1c54295b1'"); - } -} diff --git a/core/src/sql/v2/subquery.rs b/core/src/sql/v2/subquery.rs deleted file mode 100644 index ffd5cd18..00000000 --- a/core/src/sql/v2/subquery.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::statements::{ - CreateStatement, DefineStatement, DeleteStatement, IfelseStatement, InsertStatement, - OutputStatement, RelateStatement, RemoveStatement, SelectStatement, UpdateStatement, -}; -use crate::sql::value::Value; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::fmt::{self, Display, Formatter}; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Subquery"; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Subquery")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Subquery { - Value(Value), - Ifelse(IfelseStatement), - Output(OutputStatement), - Select(SelectStatement), - Create(CreateStatement), - Update(UpdateStatement), - Delete(DeleteStatement), - Relate(RelateStatement), - Insert(InsertStatement), - Define(DefineStatement), - Remove(RemoveStatement), - // Add new variants here -} - -impl PartialOrd for Subquery { - #[inline] - fn partial_cmp(&self, _: &Self) -> Option { - None - } -} - -impl Subquery { - /// Check if we require a writeable transaction - pub(crate) fn writeable(&self) -> bool { - match self { - Self::Value(v) => v.writeable(), - Self::Ifelse(v) => v.writeable(), - Self::Output(v) => v.writeable(), - Self::Select(v) => v.writeable(), - Self::Create(v) => v.writeable(), - Self::Update(v) => v.writeable(), - Self::Delete(v) => v.writeable(), - Self::Relate(v) => v.writeable(), - Self::Insert(v) => v.writeable(), - Self::Define(v) => v.writeable(), - Self::Remove(v) => v.writeable(), - } - } - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - // Duplicate context - let mut ctx = Context::new(ctx); - // Add parent document - if let Some(doc) = doc { - ctx.add_value("parent", doc.doc.as_ref()); - } - // Process the subquery - match self { - Self::Value(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Ifelse(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Output(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Define(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Remove(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Select(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Create(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Update(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Delete(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Relate(ref v) => v.compute(&ctx, opt, txn, doc).await, - Self::Insert(ref v) => v.compute(&ctx, opt, txn, doc).await, - } - } -} - -impl Display for Subquery { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Value(v) => write!(f, "({v})"), - Self::Output(v) => write!(f, "({v})"), - Self::Select(v) => write!(f, "({v})"), - Self::Create(v) => write!(f, "({v})"), - Self::Update(v) => write!(f, "({v})"), - Self::Delete(v) => write!(f, "({v})"), - Self::Relate(v) => write!(f, "({v})"), - Self::Insert(v) => write!(f, "({v})"), - Self::Define(v) => write!(f, "({v})"), - Self::Remove(v) => write!(f, "({v})"), - Self::Ifelse(v) => Display::fmt(v, f), - } - } -} diff --git a/core/src/sql/v2/table.rs b/core/src/sql/v2/table.rs deleted file mode 100644 index bca5f14a..00000000 --- a/core/src/sql/v2/table.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::sql::{escape::escape_ident, fmt::Fmt, strand::no_nul_bytes, Id, Ident, Thing}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; -use std::str; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Table"; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Tables(pub Vec
); - -impl From
for Tables { - fn from(v: Table) -> Self { - Tables(vec![v]) - } -} - -impl Deref for Tables { - type Target = Vec
; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Tables { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&Fmt::comma_separated(&self.0), f) - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[serde(rename = "$surrealdb::private::sql::Table")] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub struct Table(#[serde(with = "no_nul_bytes")] pub String); - -impl From for Table { - fn from(v: String) -> Self { - Self(v) - } -} - -impl From<&str> for Table { - fn from(v: &str) -> Self { - Self::from(String::from(v)) - } -} - -impl From for Table { - fn from(v: Ident) -> Self { - Self(v.0) - } -} - -impl Deref for Table { - type Target = String; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Table { - pub fn generate(&self) -> Thing { - Thing { - tb: self.0.to_owned(), - id: Id::rand(), - } - } -} - -impl Display for Table { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&escape_ident(&self.0), f) - } -} diff --git a/core/src/sql/v2/thing.rs b/core/src/sql/v2/thing.rs deleted file mode 100644 index 0aca04c0..00000000 --- a/core/src/sql/v2/thing.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::sql::{escape::escape_rid, id::Id, Strand, Value}; -use crate::syn; -use derive::Store; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::str::FromStr; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Thing"; - -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Store, Hash)] -#[serde(rename = "$surrealdb::private::sql::Thing")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Thing { - /// Table name - pub tb: String, - pub id: Id, -} - -impl From<(&str, Id)> for Thing { - fn from((tb, id): (&str, Id)) -> Self { - Self { - tb: tb.to_owned(), - id, - } - } -} - -impl From<(String, Id)> for Thing { - fn from((tb, id): (String, Id)) -> Self { - Self { - tb, - id, - } - } -} - -impl From<(String, String)> for Thing { - fn from((tb, id): (String, String)) -> Self { - Self::from((tb, Id::from(id))) - } -} - -impl From<(&str, &str)> for Thing { - fn from((tb, id): (&str, &str)) -> Self { - Self::from((tb.to_owned(), Id::from(id))) - } -} - -impl FromStr for Thing { - type Err = (); - fn from_str(s: &str) -> Result { - Self::try_from(s) - } -} - -impl TryFrom for Thing { - type Error = (); - fn try_from(v: String) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom for Thing { - type Error = (); - fn try_from(v: Strand) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom<&str> for Thing { - type Error = (); - fn try_from(v: &str) -> Result { - match syn::thing(v) { - Ok(v) => Ok(v), - _ => Err(()), - } - } -} - -impl Thing { - /// Convert the Thing to a raw String - pub fn to_raw(&self) -> String { - self.to_string() - } -} - -impl fmt::Display for Thing { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}:{}", escape_rid(&self.tb), self.id) - } -} - -impl Thing { - /// Process this type returning a computed simple Value - pub(crate) async fn compute( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&CursorDoc<'_>>, - ) -> Result { - Ok(Value::Thing(Thing { - tb: self.tb.clone(), - id: self.id.compute(ctx, opt, txn, doc).await?, - })) - } -} diff --git a/core/src/sql/v2/timeout.rs b/core/src/sql/v2/timeout.rs deleted file mode 100644 index 703fdcb7..00000000 --- a/core/src/sql/v2/timeout.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::sql::duration::Duration; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::ops::Deref; - -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Timeout(pub Duration); - -impl Deref for Timeout { - type Target = Duration; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl fmt::Display for Timeout { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TIMEOUT {}", self.0) - } -} diff --git a/core/src/sql/v2/tokenizer.rs b/core/src/sql/v2/tokenizer.rs deleted file mode 100644 index 2f8e05f5..00000000 --- a/core/src/sql/v2/tokenizer.rs +++ /dev/null @@ -1,25 +0,0 @@ -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fmt::Display; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[revisioned(revision = 1)] -pub enum Tokenizer { - Blank, - Camel, - Class, - Punct, -} - -impl Display for Tokenizer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Self::Blank => "BLANK", - Self::Camel => "CAMEL", - Self::Class => "CLASS", - Self::Punct => "PUNCT", - }) - } -} diff --git a/core/src/sql/v2/uuid.rs b/core/src/sql/v2/uuid.rs deleted file mode 100644 index 87723272..00000000 --- a/core/src/sql/v2/uuid.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::sql::{escape::quote_str, strand::Strand}; -use revision::revisioned; -use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; -use std::str; -use std::str::FromStr; - -pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Uuid"; - -#[derive( - Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, Hash, -)] -#[serde(rename = "$surrealdb::private::sql::Uuid")] -#[revisioned(revision = 1)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct Uuid(pub uuid::Uuid); - -impl From for Uuid { - fn from(v: uuid::Uuid) -> Self { - Uuid(v) - } -} - -impl From for uuid::Uuid { - fn from(s: Uuid) -> Self { - s.0 - } -} - -impl FromStr for Uuid { - type Err = (); - fn from_str(s: &str) -> Result { - Self::try_from(s) - } -} - -impl TryFrom for Uuid { - type Error = (); - fn try_from(v: String) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom for Uuid { - type Error = (); - fn try_from(v: Strand) -> Result { - Self::try_from(v.as_str()) - } -} - -impl TryFrom<&str> for Uuid { - type Error = (); - fn try_from(v: &str) -> Result { - match uuid::Uuid::try_parse(v) { - Ok(v) => Ok(Self(v)), - Err(_) => Err(()), - } - } -} - -impl Deref for Uuid { - type Target = uuid::Uuid; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Uuid { - /// Generate a new UUID - pub fn new() -> Self { - Self(uuid::Uuid::now_v7()) - } - /// Generate a new V4 UUID - pub fn new_v4() -> Self { - Self(uuid::Uuid::new_v4()) - } - /// Generate a new V7 UUID - pub fn new_v7() -> Self { - Self(uuid::Uuid::now_v7()) - } - /// Convert the Uuid to a raw String - pub fn to_raw(&self) -> String { - self.0.to_string() - } -} - -impl Display for Uuid { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt("e_str(&self.0.to_string()), f) - } -} diff --git a/core/src/sql/v2/value/all.rs b/core/src/sql/v2/value/all.rs deleted file mode 100644 index 471b900c..00000000 --- a/core/src/sql/v2/value/all.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - pub fn all(&self) -> Self { - self.pick(&[Part::All]) - } -} diff --git a/core/src/sql/v2/value/changed.rs b/core/src/sql/v2/value/changed.rs deleted file mode 100644 index b7c1ab05..00000000 --- a/core/src/sql/v2/value/changed.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::sql::idiom::Idiom; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn changed(&self, val: &Value) -> Value { - match (self, val) { - (Value::Object(a), Value::Object(b)) => { - // Create an object - let mut chg = Value::base(); - // Loop over old keys - for (key, _) in a.iter() { - if !b.contains_key(key) { - let path = Idiom::from(key.clone()); - chg.put(&path, Value::None); - } - } - // Loop over new keys - for (key, val) in b.iter() { - match a.get(key) { - // Key did not exist - None => { - let path = Idiom::from(key.clone()); - chg.put(&path, val.clone()); - } - Some(old) => { - if old != val { - let path = Idiom::from(key.clone()); - chg.put(&path, old.changed(val)); - } - } - } - } - // - chg - } - (_, _) => val.clone(), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[test] - fn changed_none() { - let old = Value::parse("{ test: true, text: 'text', other: { something: true } }"); - let now = Value::parse("{ test: true, text: 'text', other: { something: true } }"); - let res = Value::parse("{}"); - assert_eq!(res, old.changed(&now)); - } - - #[test] - fn changed_add() { - let old = Value::parse("{ test: true }"); - let now = Value::parse("{ test: true, other: 'test' }"); - let res = Value::parse("{ other: 'test' }"); - assert_eq!(res, old.changed(&now)); - } - - #[test] - fn changed_remove() { - let old = Value::parse("{ test: true, other: 'test' }"); - let now = Value::parse("{ test: true }"); - let res = Value::parse("{ other: NONE }]"); - assert_eq!(res, old.changed(&now)); - } - - #[test] - fn changed_add_array() { - let old = Value::parse("{ test: [1,2,3] }"); - let now = Value::parse("{ test: [1,2,3,4] }"); - let res = Value::parse("{ test: [1,2,3,4] }"); - assert_eq!(res, old.changed(&now)); - } - - #[test] - fn changed_replace_embedded() { - let old = Value::parse("{ test: { other: 'test' } }"); - let now = Value::parse("{ test: { other: false } }"); - let res = Value::parse("{ test: { other: false } }"); - assert_eq!(res, old.changed(&now)); - } - - #[test] - fn changed_change_text() { - let old = Value::parse("{ test: { other: 'test' } }"); - let now = Value::parse("{ test: { other: 'text' } }"); - let res = Value::parse("{ test: { other: 'text' } }"); - assert_eq!(res, old.changed(&now)); - } -} diff --git a/core/src/sql/v2/value/clear.rs b/core/src/sql/v2/value/clear.rs deleted file mode 100644 index bc749d2a..00000000 --- a/core/src/sql/v2/value/clear.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::err::Error; -use crate::sql::value::Value; - -impl Value { - pub fn clear(&mut self) -> Result<(), Error> { - *self = Value::None; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[tokio::test] - async fn clear_value() { - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::None; - val.clear().unwrap(); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/compare.rs b/core/src/sql/v2/value/compare.rs deleted file mode 100644 index e31c3c29..00000000 --- a/core/src/sql/v2/value/compare.rs +++ /dev/null @@ -1,204 +0,0 @@ -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::value::Value; -use std::cmp::Ordering; - -impl Value { - pub(crate) fn compare( - &self, - other: &Self, - path: &[Part], - collate: bool, - numeric: bool, - ) -> Option { - match path.first() { - // Get the current path part - Some(p) => match (self, other) { - // Current path part is an object - (Value::Object(a), Value::Object(b)) => match p { - Part::Field(f) => match (a.get(f.as_str()), b.get(f.as_str())) { - (Some(a), Some(b)) => a.compare(b, path.next(), collate, numeric), - (Some(_), None) => Some(Ordering::Greater), - (None, Some(_)) => Some(Ordering::Less), - (_, _) => Some(Ordering::Equal), - }, - _ => None, - }, - // Current path part is an array - (Value::Array(a), Value::Array(b)) => match p { - Part::All => { - for (a, b) in a.iter().zip(b.iter()) { - match a.compare(b, path.next(), collate, numeric) { - Some(Ordering::Equal) => continue, - None => continue, - o => return o, - } - } - match (a.len(), b.len()) { - (a, b) if a > b => Some(Ordering::Greater), - (a, b) if a < b => Some(Ordering::Less), - _ => Some(Ordering::Equal), - } - } - Part::First => match (a.first(), b.first()) { - (Some(a), Some(b)) => a.compare(b, path.next(), collate, numeric), - (Some(_), None) => Some(Ordering::Greater), - (None, Some(_)) => Some(Ordering::Less), - (_, _) => Some(Ordering::Equal), - }, - Part::Last => match (a.last(), b.last()) { - (Some(a), Some(b)) => a.compare(b, path.next(), collate, numeric), - (Some(_), None) => Some(Ordering::Greater), - (None, Some(_)) => Some(Ordering::Less), - (_, _) => Some(Ordering::Equal), - }, - Part::Index(i) => match (a.get(i.to_usize()), b.get(i.to_usize())) { - (Some(a), Some(b)) => a.compare(b, path.next(), collate, numeric), - (Some(_), None) => Some(Ordering::Greater), - (None, Some(_)) => Some(Ordering::Less), - (_, _) => Some(Ordering::Equal), - }, - _ => { - for (a, b) in a.iter().zip(b.iter()) { - match a.compare(b, path, collate, numeric) { - Some(Ordering::Equal) => continue, - None => continue, - o => return o, - } - } - match (a.len(), b.len()) { - (a, b) if a > b => Some(Ordering::Greater), - (a, b) if a < b => Some(Ordering::Less), - _ => Some(Ordering::Equal), - } - } - }, - // Ignore everything else - (a, b) => a.compare(b, path.next(), collate, numeric), - }, - // No more parts so get the value - None => match (collate, numeric) { - (true, true) => self.natural_lexical_cmp(other), - (true, false) => self.lexical_cmp(other), - (false, true) => self.natural_cmp(other), - _ => self.partial_cmp(other), - }, - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[test] - fn compare_none() { - let idi = Idiom::default(); - let one = Value::parse("{ test: { other: null, something: 456 } }"); - let two = Value::parse("{ test: { other: null, something: 123 } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)); - } - - #[test] - fn compare_basic() { - let idi = Idiom::parse("test.something"); - let one = Value::parse("{ test: { other: null, something: 456 } }"); - let two = Value::parse("{ test: { other: null, something: 123 } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)); - } - - #[test] - fn compare_basic_missing_left() { - let idi = Idiom::parse("test.something"); - let one = Value::parse("{ test: { other: null } }"); - let two = Value::parse("{ test: { other: null, something: 123 } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Less)); - } - - #[test] - fn compare_basic_missing_right() { - let idi = Idiom::parse("test.something"); - let one = Value::parse("{ test: { other: null, something: 456 } }"); - let two = Value::parse("{ test: { other: null } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)); - } - - #[test] - fn compare_array() { - let idi = Idiom::parse("test.something.*"); - let one = Value::parse("{ test: { other: null, something: [4, 5, 6] } }"); - let two = Value::parse("{ test: { other: null, something: [1, 2, 3] } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)); - } - - #[test] - fn compare_array_longer_left() { - let idi = Idiom::parse("test.something.*"); - let one = Value::parse("{ test: { other: null, something: [1, 2, 3, 4, 5, 6] } }"); - let two = Value::parse("{ test: { other: null, something: [1, 2, 3] } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)); - } - - #[test] - fn compare_array_longer_right() { - let idi = Idiom::parse("test.something.*"); - let one = Value::parse("{ test: { other: null, something: [1, 2, 3] } }"); - let two = Value::parse("{ test: { other: null, something: [1, 2, 3, 4, 5, 6] } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Less)); - } - - #[test] - fn compare_array_missing_left() { - let idi = Idiom::parse("test.something.*"); - let one = Value::parse("{ test: { other: null, something: null } }"); - let two = Value::parse("{ test: { other: null, something: [1, 2, 3] } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Less)); - } - - #[test] - fn compare_array_missing_right() { - let idi = Idiom::parse("test.something.*"); - let one = Value::parse("{ test: { other: null, something: [4, 5, 6] } }"); - let two = Value::parse("{ test: { other: null, something: null } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)); - } - - #[test] - fn compare_array_missing_value_left() { - let idi = Idiom::parse("test.something.*"); - let one = Value::parse("{ test: { other: null, something: [1, null, 3] } }"); - let two = Value::parse("{ test: { other: null, something: [1, 2, 3] } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Less)); - } - - #[test] - fn compare_array_missing_value_right() { - let idi = Idiom::parse("test.something.*"); - let one = Value::parse("{ test: { other: null, something: [1, 2, 3] } }"); - let two = Value::parse("{ test: { other: null, something: [1, null, 3] } }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)); - } - - #[test] - fn compare_last() { - let idi = Idiom::parse("test[$]"); - let one = Value::parse("{ test: [1,5] }"); - let two = Value::parse("{ test: [2,4] }"); - let res = one.compare(&two, &idi, false, false); - assert_eq!(res, Some(Ordering::Greater)) - } -} diff --git a/core/src/sql/v2/value/cut.rs b/core/src/sql/v2/value/cut.rs deleted file mode 100644 index c38a2774..00000000 --- a/core/src/sql/v2/value/cut.rs +++ /dev/null @@ -1,188 +0,0 @@ -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - /// Synchronous method for deleting a field from a `Value` - pub(crate) fn cut(&mut self, path: &[Part]) { - if let Some(p) = path.first() { - // Get the current value at path - match self { - // Current value at path is an object - Value::Object(v) => match p { - Part::Field(f) => match path.len() { - 1 => { - v.remove(f.as_str()); - } - _ => { - if let Some(v) = v.get_mut(f.as_str()) { - v.cut(path.next()) - } - } - }, - Part::Index(i) => match path.len() { - 1 => { - v.remove(&i.to_string()); - } - _ => { - if let Some(v) = v.get_mut(&i.to_string()) { - v.cut(path.next()) - } - } - }, - _ => {} - }, - // Current value at path is an array - Value::Array(v) => match p { - Part::All => match path.len() { - 1 => { - v.clear(); - } - _ => { - let path = path.next(); - v.iter_mut().for_each(|v| v.cut(path)); - } - }, - Part::First => match path.len() { - 1 => { - if !v.is_empty() { - let i = 0; - v.remove(i); - } - } - _ => { - if let Some(v) = v.first_mut() { - v.cut(path.next()) - } - } - }, - Part::Last => match path.len() { - 1 => { - if !v.is_empty() { - let i = v.len() - 1; - v.remove(i); - } - } - _ => { - if let Some(v) = v.last_mut() { - v.cut(path.next()) - } - } - }, - Part::Index(i) => match path.len() { - 1 => { - if v.len() > i.to_usize() { - v.remove(i.to_usize()); - } - } - _ => { - if let Some(v) = v.get_mut(i.to_usize()) { - v.cut(path.next()) - } - } - }, - _ => { - v.iter_mut().for_each(|v| v.cut(path)); - } - }, - // Ignore everything else - _ => (), - } - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn cut_none() { - let idi = Idiom::default(); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_reset() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_basic() { - let idi = Idiom::parse("test.something"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null } }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_wrong() { - let idi = Idiom::parse("test.something.wrong"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_other() { - let idi = Idiom::parse("test.other.something"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_array() { - let idi = Idiom::parse("test.something[1]"); - let mut val = Value::parse("{ test: { something: [123, 456, 789] } }"); - let res = Value::parse("{ test: { something: [123, 789] } }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_array_field() { - let idi = Idiom::parse("test.something[1].age"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_array_fields() { - let idi = Idiom::parse("test.something[*].age"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); - val.cut(&idi); - assert_eq!(res, val); - } - - #[tokio::test] - async fn cut_array_fields_flat() { - let idi = Idiom::parse("test.something.age"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); - val.cut(&idi); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/dec.rs b/core/src/sql/v2/value/dec.rs deleted file mode 100644 index f1609e39..00000000 --- a/core/src/sql/v2/value/dec.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::sql::number::Number; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - /// Synchronous method for decrementing a field in a `Value` - pub(crate) fn dec(&mut self, path: &[Part], val: Value) { - match self.pick(path) { - Value::Number(v) => { - if let Value::Number(x) = val { - self.put(path, Value::from(v - x)) - } - } - Value::Array(v) => match val { - Value::Array(x) => self.put(path, Value::from(v - x)), - x => self.put(path, Value::from(v - x)), - }, - Value::None => { - if let Value::Number(x) = val { - self.put(path, Value::from(Number::from(0) - x)) - } - } - _ => (), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn decrement_none() { - let idi = Idiom::parse("other"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 100, other: -10 }"); - val.dec(&idi, Value::from(10)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_number() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 90 }"); - val.dec(&idi, Value::from(10)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_array_number() { - let idi = Idiom::parse("test[1]"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 190, 300] }"); - val.dec(&idi, Value::from(10)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_array_value() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 300] }"); - val.dec(&idi, Value::from(200)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_array_array() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [200] }"); - val.dec(&idi, Value::parse("[100, 300]")); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/decrement.rs b/core/src/sql/v2/value/decrement.rs deleted file mode 100644 index a12d6efa..00000000 --- a/core/src/sql/v2/value/decrement.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::sql::number::Number; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - /// Asynchronous method for decrementing a field in a `Value` - pub(crate) async fn decrement( - &mut self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - path: &[Part], - val: Value, - ) -> Result<(), Error> { - match self.get(ctx, opt, txn, None, path).await? { - Value::Number(v) => match val { - Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await, - _ => Ok(()), - }, - Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await, - x => self.set(ctx, opt, txn, path, Value::from(v - x)).await, - }, - Value::None => match val { - Value::Number(x) => { - self.set(ctx, opt, txn, path, Value::from(Number::from(0) - x)).await - } - _ => Ok(()), - }, - _ => Ok(()), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::dbs::test::mock; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn decrement_none() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("other"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 100, other: -10 }"); - val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_number() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 90 }"); - val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_array_number() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test[1]"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 190, 300] }"); - val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_array_value() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 300] }"); - val.decrement(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn decrement_array_array() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [200] }"); - val.decrement(&ctx, &opt, &txn, &idi, Value::parse("[100, 300]")).await.unwrap(); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/def.rs b/core/src/sql/v2/value/def.rs deleted file mode 100644 index c98c6c99..00000000 --- a/core/src/sql/v2/value/def.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::sql::paths::ID; -use crate::sql::thing::Thing; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn def(&mut self, val: &Thing) { - self.put(ID.as_ref(), val.clone().into()) - } -} diff --git a/core/src/sql/v2/value/del.rs b/core/src/sql/v2/value/del.rs deleted file mode 100644 index 9de1eabc..00000000 --- a/core/src/sql/v2/value/del.rs +++ /dev/null @@ -1,337 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::exe::try_join_all_buffered; -use crate::sql::array::Abolish; -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::value::Value; -use async_recursion::async_recursion; -use std::collections::HashSet; - -impl Value { - /// Asynchronous method for deleting a field from a `Value` - #[cfg_attr(not(target_arch = "wasm32"), async_recursion)] - #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] - pub(crate) async fn del( - &mut self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - path: &[Part], - ) -> Result<(), Error> { - match path.first() { - // Get the current value at path - Some(p) => match self { - // Current value at path is an object - Value::Object(v) => match p { - Part::Field(f) => match path.len() { - 1 => { - v.remove(f.as_str()); - Ok(()) - } - _ => match v.get_mut(f.as_str()) { - Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await, - _ => Ok(()), - }, - }, - Part::Index(i) => match path.len() { - 1 => { - v.remove(&i.to_string()); - Ok(()) - } - _ => match v.get_mut(&i.to_string()) { - Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await, - _ => Ok(()), - }, - }, - Part::Value(x) => match x.compute(ctx, opt, txn, None).await? { - Value::Strand(f) => match path.len() { - 1 => { - v.remove(f.as_str()); - Ok(()) - } - _ => match v.get_mut(f.as_str()) { - Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await, - _ => Ok(()), - }, - }, - _ => Ok(()), - }, - _ => Ok(()), - }, - // Current value at path is an array - Value::Array(v) => match p { - Part::All => match path.len() { - 1 => { - v.clear(); - Ok(()) - } - _ => { - let path = path.next(); - let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path)); - try_join_all_buffered(futs).await?; - Ok(()) - } - }, - Part::First => match path.len() { - 1 => { - if !v.is_empty() { - let i = 0; - v.remove(i); - } - Ok(()) - } - _ => match v.first_mut() { - Some(v) => v.del(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - }, - Part::Last => match path.len() { - 1 => { - if !v.is_empty() { - let i = v.len() - 1; - v.remove(i); - } - Ok(()) - } - _ => match v.last_mut() { - Some(v) => v.del(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - }, - Part::Index(i) => match path.len() { - 1 => { - if v.len() > i.to_usize() { - v.remove(i.to_usize()); - } - Ok(()) - } - _ => match v.get_mut(i.to_usize()) { - Some(v) => v.del(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - }, - Part::Where(w) => match path.len() { - 1 => { - // TODO: If further optimization is desired, push indices to a vec, - // iterate in reverse, and call swap_remove - let mut m = HashSet::new(); - for (i, v) in v.iter().enumerate() { - let cur = v.into(); - if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { - m.insert(i); - }; - } - v.abolish(|i| m.contains(&i)); - Ok(()) - } - _ => match path.next().first() { - Some(Part::Index(_)) => { - let mut a = Vec::new(); - let mut p = Vec::new(); - // Store the elements and positions to update - for (i, o) in v.iter_mut().enumerate() { - let cur = o.into(); - if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { - a.push(o.clone()); - p.push(i); - } - } - // Convert the matched elements array to a value - let mut a = Value::from(a); - // Set the new value on the matches elements - a.del(ctx, opt, txn, path.next()).await?; - // Push the new values into the original array - for (i, p) in p.into_iter().enumerate().rev() { - match a.pick(&[Part::Index(i.into())]) { - Value::None => { - v.remove(i); - } - x => v[p] = x, - } - } - Ok(()) - } - _ => { - let path = path.next(); - for v in v.iter_mut() { - let cur = v.into(); - if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { - v.del(ctx, opt, txn, path).await?; - } - } - Ok(()) - } - }, - }, - Part::Value(x) => match x.compute(ctx, opt, txn, None).await? { - Value::Number(i) => match path.len() { - 1 => { - if v.len() > i.to_usize() { - v.remove(i.to_usize()); - } - Ok(()) - } - _ => match v.get_mut(i.to_usize()) { - Some(v) => v.del(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - }, - _ => Ok(()), - }, - _ => { - let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path)); - try_join_all_buffered(futs).await?; - Ok(()) - } - }, - // Ignore everything else - _ => Ok(()), - }, - // We are done - None => Ok(()), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::dbs::test::mock; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn del_none() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::default(); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_reset() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_basic() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_wrong() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something.wrong"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_other() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.other.something"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_array() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[1]"); - let mut val = Value::parse("{ test: { something: [123, 456, 789] } }"); - let res = Value::parse("{ test: { something: [123, 789] } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_array_field() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[1].age"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_array_fields() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[*].age"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_array_fields_flat() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something.age"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_array_where_field() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[WHERE age > 35].age"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_array_where_fields() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[WHERE age > 35]"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn del_array_where_fields_array_index() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[WHERE age > 30][0]"); - let mut val = Value::parse( - "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", - ); - let res = Value::parse("{ test: { something: [{ name: 'B', age: 36 }] } }"); - val.del(&ctx, &opt, &txn, &idi).await.unwrap(); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/diff.rs b/core/src/sql/v2/value/diff.rs deleted file mode 100644 index ac66f5db..00000000 --- a/core/src/sql/v2/value/diff.rs +++ /dev/null @@ -1,132 +0,0 @@ -use crate::sql::idiom::Idiom; -use crate::sql::operation::Operation; -use crate::sql::value::Value; -use std::cmp::min; - -impl Value { - pub(crate) fn diff(&self, val: &Value, path: Idiom) -> Vec { - let mut ops: Vec = vec![]; - match (self, val) { - (Value::Object(a), Value::Object(b)) if a != b => { - // Loop over old keys - for (key, _) in a.iter() { - if !b.contains_key(key) { - ops.push(Operation::Remove { - path: path.clone().push(key.clone().into()), - }) - } - } - // Loop over new keys - for (key, val) in b.iter() { - match a.get(key) { - None => ops.push(Operation::Add { - path: path.clone().push(key.clone().into()), - value: val.clone(), - }), - Some(old) => { - let path = path.clone().push(key.clone().into()); - ops.append(&mut old.diff(val, path)) - } - } - } - } - (Value::Array(a), Value::Array(b)) if a != b => { - let mut n = 0; - while n < min(a.len(), b.len()) { - let path = path.clone().push(n.into()); - ops.append(&mut a[n].diff(&b[n], path)); - n += 1; - } - while n < b.len() { - if n >= a.len() { - ops.push(Operation::Add { - path: path.clone().push(n.into()), - value: b[n].clone(), - }) - } - n += 1; - } - while n < a.len() { - if n >= b.len() { - ops.push(Operation::Remove { - path: path.clone().push(n.into()), - }) - } - n += 1; - } - } - (Value::Strand(a), Value::Strand(b)) if a != b => ops.push(Operation::Change { - path, - value: { - let dmp = dmp::new(); - let pch = dmp.patch_make1(a, b); - let txt = dmp.patch_to_text(&pch); - txt.into() - }, - }), - (a, b) if a != b => ops.push(Operation::Replace { - path, - value: val.clone(), - }), - (_, _) => (), - } - ops - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[test] - fn diff_none() { - let old = Value::parse("{ test: true, text: 'text', other: { something: true } }"); - let now = Value::parse("{ test: true, text: 'text', other: { something: true } }"); - let res = Value::parse("[]"); - assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default())); - } - - #[test] - fn diff_add() { - let old = Value::parse("{ test: true }"); - let now = Value::parse("{ test: true, other: 'test' }"); - let res = Value::parse("[{ op: 'add', path: '/other', value: 'test' }]"); - assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default())); - } - - #[test] - fn diff_remove() { - let old = Value::parse("{ test: true, other: 'test' }"); - let now = Value::parse("{ test: true }"); - let res = Value::parse("[{ op: 'remove', path: '/other' }]"); - assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default())); - } - - #[test] - fn diff_add_array() { - let old = Value::parse("{ test: [1,2,3] }"); - let now = Value::parse("{ test: [1,2,3,4] }"); - let res = Value::parse("[{ op: 'add', path: '/test/3', value: 4 }]"); - assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default())); - } - - #[test] - fn diff_replace_embedded() { - let old = Value::parse("{ test: { other: 'test' } }"); - let now = Value::parse("{ test: { other: false } }"); - let res = Value::parse("[{ op: 'replace', path: '/test/other', value: false }]"); - assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default())); - } - - #[test] - fn diff_change_text() { - let old = Value::parse("{ test: { other: 'test' } }"); - let now = Value::parse("{ test: { other: 'text' } }"); - let res = Value::parse( - "[{ op: 'change', path: '/test/other', value: '@@ -1,4 +1,4 @@\n te\n-s\n+x\n t\n' }]", - ); - assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default())); - } -} diff --git a/core/src/sql/v2/value/each.rs b/core/src/sql/v2/value/each.rs deleted file mode 100644 index 571c43c6..00000000 --- a/core/src/sql/v2/value/each.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::sql::idiom::Idiom; -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn each(&self, path: &[Part]) -> Vec { - self._each(path, Idiom::default()) - } - fn _each(&self, path: &[Part], prev: Idiom) -> Vec { - match path.first() { - // Get the current path part - Some(p) => match self { - // Current path part is an object - Value::Object(v) => match p { - Part::Field(f) => match v.get(f as &str) { - Some(v) => v._each(path.next(), prev.push(p.clone())), - None => vec![], - }, - Part::All => self._each(path.next(), prev.push(p.clone())), - _ => vec![], - }, - // Current path part is an array - Value::Array(v) => match p { - Part::All => v - .iter() - .enumerate() - .flat_map(|(i, v)| v._each(path.next(), prev.clone().push(Part::from(i)))) - .collect::>(), - Part::First => match v.first() { - Some(v) => v._each(path.next(), prev.push(p.clone())), - None => vec![], - }, - Part::Last => match v.last() { - Some(v) => v._each(path.next(), prev.push(p.clone())), - None => vec![], - }, - Part::Index(i) => match v.get(i.to_usize()) { - Some(v) => v._each(path.next(), prev.push(p.clone())), - None => vec![], - }, - _ => v - .iter() - .enumerate() - .flat_map(|(i, v)| v._each(path.next(), prev.clone().push(Part::from(i)))) - .collect::>(), - }, - // Ignore everything else - _ => vec![], - }, - // No more parts so get the value - None => vec![prev], - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[test] - fn each_none() { - let idi = Idiom::default(); - let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = vec![Idiom::default()]; - assert_eq!(res, val.each(&idi)); - assert_eq!(val.pick(&res[0]), Value::parse("{ test: { other: null, something: 123 } }")); - } - - #[test] - fn each_basic() { - let idi = Idiom::parse("test.something"); - let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = vec![Idiom::parse("test.something")]; - assert_eq!(res, val.each(&idi)); - assert_eq!(val.pick(&res[0]), Value::from(123)); - } - - #[test] - fn each_array() { - let idi = Idiom::parse("test.something"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = vec![Idiom::parse("test.something")]; - assert_eq!(res, val.each(&idi)); - assert_eq!(val.pick(&res[0]), Value::parse("[{ age: 34 }, { age: 36 }]")); - } - - #[test] - fn each_array_field() { - let idi = Idiom::parse("test.something[*].age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = - vec![Idiom::parse("test.something[0].age"), Idiom::parse("test.something[1].age")]; - assert_eq!(res, val.each(&idi)); - assert_eq!(val.pick(&res[0]), Value::from(34)); - assert_eq!(val.pick(&res[1]), Value::from(36)); - } - - #[test] - fn each_array_field_embedded() { - let idi = Idiom::parse("test.something[*].tags"); - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = - vec![Idiom::parse("test.something[0].tags"), Idiom::parse("test.something[1].tags")]; - assert_eq!(res, val.each(&idi)); - assert_eq!(val.pick(&res[0]), Value::parse("['code', 'databases']")); - assert_eq!(val.pick(&res[1]), Value::parse("['design', 'operations']")); - } - - #[test] - fn each_array_field_embedded_index() { - let idi = Idiom::parse("test.something[*].tags[1]"); - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = vec![ - Idiom::parse("test.something[0].tags[1]"), - Idiom::parse("test.something[1].tags[1]"), - ]; - assert_eq!(res, val.each(&idi)); - assert_eq!(val.pick(&res[0]), Value::from("databases")); - assert_eq!(val.pick(&res[1]), Value::from("operations")); - } - - #[test] - fn each_array_field_embedded_index_all() { - let idi = Idiom::parse("test.something[*].tags[*]"); - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = vec![ - Idiom::parse("test.something[0].tags[0]"), - Idiom::parse("test.something[0].tags[1]"), - Idiom::parse("test.something[1].tags[0]"), - Idiom::parse("test.something[1].tags[1]"), - ]; - assert_eq!(res, val.each(&idi)); - assert_eq!(val.pick(&res[0]), Value::from("code")); - assert_eq!(val.pick(&res[1]), Value::from("databases")); - assert_eq!(val.pick(&res[2]), Value::from("design")); - assert_eq!(val.pick(&res[3]), Value::from("operations")); - } -} diff --git a/core/src/sql/v2/value/every.rs b/core/src/sql/v2/value/every.rs deleted file mode 100644 index c9603c10..00000000 --- a/core/src/sql/v2/value/every.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::sql::idiom::Idiom; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn every(&self, path: Option<&[Part]>, steps: bool, arrays: bool) -> Vec { - match path { - Some(path) => self.pick(path)._every(steps, arrays, Idiom::from(path)), - None => self._every(steps, arrays, Idiom::default()), - } - } - fn _every(&self, steps: bool, arrays: bool, mut prev: Idiom) -> Vec { - match self { - // Current path part is an object and is not empty - Value::Object(v) if !v.is_empty() => { - // Remove any trailing * path parts - prev.remove_trailing_all(); - // Check if we should log intermediary nodes - match steps { - // Let's log all intermediary nodes - true if !prev.is_empty() => Some(prev.clone()) - .into_iter() - .chain(v.iter().flat_map(|(k, v)| { - let p = Part::from(k.to_owned()); - v._every(steps, arrays, prev.clone().push(p)) - })) - .collect::>(), - // Let's not log intermediary nodes - _ => v - .iter() - .flat_map(|(k, v)| { - let p = Part::from(k.to_owned()); - v._every(steps, arrays, prev.clone().push(p)) - }) - .collect::>(), - } - } - // Current path part is an array and is not empty - Value::Array(v) if !v.is_empty() => { - // Remove any trailing * path parts - prev.remove_trailing_all(); - // Check if we should log individual array items - match arrays { - // Let's log all individual array items - true => std::iter::once(prev.clone()) - .chain(v.iter().enumerate().rev().flat_map(|(i, v)| { - let p = Part::from(i.to_owned()); - v._every(steps, arrays, prev.clone().push(p)) - })) - .collect::>(), - // Let's not log individual array items - false => vec![prev], - } - } - // Process everything else - _ => vec![prev], - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[test] - fn every_with_empty_objects_arrays() { - let val = Value::parse("{ test: {}, status: false, something: {age: 45}, tags: []}"); - let res = vec![ - Idiom::parse("something.age"), - Idiom::parse("status"), - Idiom::parse("tags"), - Idiom::parse("test"), - ]; - assert_eq!(res, val.every(None, false, false)); - } - - #[test] - fn every_without_array_indexes() { - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = vec![Idiom::parse("test.something")]; - assert_eq!(res, val.every(None, false, false)); - } - - #[test] - fn every_including_array_indexes() { - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = vec![ - Idiom::parse("test.something"), - Idiom::parse("test.something[1].age"), - Idiom::parse("test.something[1].tags"), - Idiom::parse("test.something[1].tags[1]"), - Idiom::parse("test.something[1].tags[0]"), - Idiom::parse("test.something[0].age"), - Idiom::parse("test.something[0].tags"), - Idiom::parse("test.something[0].tags[1]"), - Idiom::parse("test.something[0].tags[0]"), - ]; - assert_eq!(res, val.every(None, false, true)); - } - - #[test] - fn every_including_intermediary_nodes_without_array_indexes() { - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = vec![Idiom::parse("test"), Idiom::parse("test.something")]; - assert_eq!(res, val.every(None, true, false)); - } - - #[test] - fn every_including_intermediary_nodes_including_array_indexes() { - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = vec![ - Idiom::parse("test"), - Idiom::parse("test.something"), - Idiom::parse("test.something[1]"), - Idiom::parse("test.something[1].age"), - Idiom::parse("test.something[1].tags"), - Idiom::parse("test.something[1].tags[1]"), - Idiom::parse("test.something[1].tags[0]"), - Idiom::parse("test.something[0]"), - Idiom::parse("test.something[0].age"), - Idiom::parse("test.something[0].tags"), - Idiom::parse("test.something[0].tags[1]"), - Idiom::parse("test.something[0].tags[0]"), - ]; - assert_eq!(res, val.every(None, true, true)); - } - - #[test] - fn every_including_intermediary_nodes_including_array_indexes_ending_all() { - let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"); - let res = vec![ - Idiom::parse("test.something"), - Idiom::parse("test.something[1]"), - Idiom::parse("test.something[1].age"), - Idiom::parse("test.something[1].tags"), - Idiom::parse("test.something[1].tags[1]"), - Idiom::parse("test.something[1].tags[0]"), - Idiom::parse("test.something[0]"), - Idiom::parse("test.something[0].age"), - Idiom::parse("test.something[0].tags"), - Idiom::parse("test.something[0].tags[1]"), - Idiom::parse("test.something[0].tags[0]"), - ]; - assert_eq!(res, val.every(Some(&Idiom::parse("test.something.*")), true, true)); - } -} diff --git a/core/src/sql/v2/value/extend.rs b/core/src/sql/v2/value/extend.rs deleted file mode 100644 index 8e602723..00000000 --- a/core/src/sql/v2/value/extend.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::sql::array::Uniq; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - pub(crate) async fn extend( - &mut self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - path: &[Part], - val: Value, - ) -> Result<(), Error> { - match self.get(ctx, opt, txn, None, path).await? { - Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await, - x => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await, - }, - Value::None => match val { - Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await, - x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await, - }, - _ => Ok(()), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::dbs::test::mock; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn extend_array_value() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 200, 300] }"); - val.extend(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn extend_array_array() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 200, 300, 400, 500] }"); - val.extend(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap(); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/fetch.rs b/core/src/sql/v2/value/fetch.rs deleted file mode 100644 index 3466bdb3..00000000 --- a/core/src/sql/v2/value/fetch.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::sql::edges::Edges; -use crate::sql::field::{Field, Fields}; -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::statements::select::SelectStatement; -use crate::sql::value::{Value, Values}; -use async_recursion::async_recursion; -use futures::future::try_join_all; - -impl Value { - #[cfg_attr(not(target_arch = "wasm32"), async_recursion)] - #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] - pub(crate) async fn fetch( - &mut self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - path: &[Part], - ) -> Result<(), Error> { - match path.first() { - // Get the current path part - Some(p) => match self { - // Current path part is an object - Value::Object(v) => match p { - Part::Graph(_) => match v.rid() { - Some(v) => Value::Thing(v).fetch(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - Part::Field(f) => match v.get_mut(f as &str) { - Some(v) => v.fetch(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - Part::Index(i) => match v.get_mut(&i.to_string()) { - Some(v) => v.fetch(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - Part::All => self.fetch(ctx, opt, txn, path.next()).await, - _ => Ok(()), - }, - // Current path part is an array - Value::Array(v) => match p { - Part::All => { - let path = path.next(); - let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path)); - try_join_all(futs).await?; - Ok(()) - } - Part::First => match v.first_mut() { - Some(v) => v.fetch(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - Part::Last => match v.last_mut() { - Some(v) => v.fetch(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - Part::Index(i) => match v.get_mut(i.to_usize()) { - Some(v) => v.fetch(ctx, opt, txn, path.next()).await, - None => Ok(()), - }, - Part::Where(w) => { - let path = path.next(); - for v in v.iter_mut() { - let cur = v.into(); - if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { - v.fetch(ctx, opt, txn, path).await?; - } - } - Ok(()) - } - _ => { - let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path)); - try_join_all(futs).await?; - Ok(()) - } - }, - // Current path part is a thing - Value::Thing(v) => { - // Clone the thing - let val = v.clone(); - // Fetch the remote embedded record - match p { - // This is a graph traversal expression - Part::Graph(g) => { - let stm = SelectStatement { - expr: Fields(vec![Field::All], false), - what: Values(vec![Value::from(Edges { - from: val, - dir: g.dir.clone(), - what: g.what.clone(), - })]), - cond: g.cond.clone(), - ..SelectStatement::default() - }; - *self = stm - .compute(ctx, opt, txn, None) - .await? - .all() - .get(ctx, opt, txn, None, path.next()) - .await? - .flatten() - .ok()?; - Ok(()) - } - // This is a remote field expression - _ => { - let stm = SelectStatement { - expr: Fields(vec![Field::All], false), - what: Values(vec![Value::from(val)]), - ..SelectStatement::default() - }; - *self = stm.compute(ctx, opt, txn, None).await?.first(); - Ok(()) - } - } - } - // Ignore everything else - _ => Ok(()), - }, - // No more parts so get the value - None => match self { - // Current path part is an array - Value::Array(v) => { - let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path)); - try_join_all(futs).await?; - Ok(()) - } - // Current path part is a thing - Value::Thing(v) => { - // Clone the thing - let val = v.clone(); - // Fetch the remote embedded record - let stm = SelectStatement { - expr: Fields(vec![Field::All], false), - what: Values(vec![Value::from(val)]), - ..SelectStatement::default() - }; - *self = stm.compute(ctx, opt, txn, None).await?.first(); - Ok(()) - } - // Ignore everything else - _ => Ok(()), - }, - } - } -} diff --git a/core/src/sql/v2/value/first.rs b/core/src/sql/v2/value/first.rs deleted file mode 100644 index 15b4dcbf..00000000 --- a/core/src/sql/v2/value/first.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - pub fn first(&self) -> Self { - self.pick(&[Part::First]) - } -} diff --git a/core/src/sql/v2/value/flatten.rs b/core/src/sql/v2/value/flatten.rs deleted file mode 100644 index 7f41357f..00000000 --- a/core/src/sql/v2/value/flatten.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::sql::array::Array; -use crate::sql::value::Value; - -impl Value { - pub fn flatten(self) -> Self { - match self { - Value::Array(v) => { - v.0.into_iter() - .flat_map(|v| match v { - Value::Array(v) => v, - _ => Array::from(v), - }) - .collect::>() - .into() - } - v => v, - } - } -} diff --git a/core/src/sql/v2/value/generate.rs b/core/src/sql/v2/value/generate.rs deleted file mode 100644 index e4db2dec..00000000 --- a/core/src/sql/v2/value/generate.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::err::Error; -use crate::sql::id::Id; -use crate::sql::table::Table; -use crate::sql::thing::Thing; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn generate(self, tb: &Table, retable: bool) -> Result { - match self { - // There is a floating point number for the id field - Value::Number(id) if id.is_float() => Ok(Thing { - tb: tb.to_string(), - id: id.as_int().into(), - }), - // There is an integer number for the id field - Value::Number(id) if id.is_int() => Ok(Thing { - tb: tb.to_string(), - id: id.as_int().into(), - }), - // There is a string for the id field - Value::Strand(id) if !id.is_empty() => Ok(Thing { - tb: tb.to_string(), - id: id.into(), - }), - // There is an object for the id field - Value::Object(id) => Ok(Thing { - tb: tb.to_string(), - id: id.into(), - }), - // There is an array for the id field - Value::Array(id) => Ok(Thing { - tb: tb.to_string(), - id: id.into(), - }), - // There is a UUID for the id field - Value::Uuid(id) => Ok(Thing { - tb: tb.to_string(), - id: id.into(), - }), - // There is no record id field - Value::None => Ok(Thing { - tb: tb.to_string(), - id: Id::rand(), - }), - // There is a record id defined - Value::Thing(id) => match retable { - // Let's re-table this record id - true => Ok(Thing { - tb: tb.to_string(), - id: id.id, - }), - // Let's use the specified record id - false => match tb.0 == id.tb { - // The record is from the same table - true => Ok(id), - // The record id is from another table - false => Ok(Thing { - tb: tb.to_string(), - id: id.id, - }), - }, - }, - // Any other value is wrong - id => Err(Error::IdInvalid { - value: id.to_string(), - }), - } - } -} diff --git a/core/src/sql/v2/value/get.rs b/core/src/sql/v2/value/get.rs deleted file mode 100644 index 0d782802..00000000 --- a/core/src/sql/v2/value/get.rs +++ /dev/null @@ -1,431 +0,0 @@ -use crate::cnf::MAX_COMPUTATION_DEPTH; -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::doc::CursorDoc; -use crate::err::Error; -use crate::exe::try_join_all_buffered; -use crate::sql::edges::Edges; -use crate::sql::field::{Field, Fields}; -use crate::sql::id::Id; -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::paths::ID; -use crate::sql::statements::select::SelectStatement; -use crate::sql::thing::Thing; -use crate::sql::value::{Value, Values}; -use async_recursion::async_recursion; - -impl Value { - /// Asynchronous method for getting a local or remote field from a `Value` - #[cfg_attr(not(target_arch = "wasm32"), async_recursion)] - #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] - pub(crate) async fn get( - &self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - doc: Option<&'async_recursion CursorDoc<'_>>, - path: &[Part], - ) -> Result { - // Limit recursion depth. - if path.len() > (*MAX_COMPUTATION_DEPTH).into() { - return Err(Error::ComputationDepthExceeded); - } - match path.first() { - // Get the current value at the path - Some(p) => match self { - // Current value at path is a geometry - Value::Geometry(v) => match p { - // If this is the 'type' field then continue - Part::Field(f) if f.is_type() => { - Value::from(v.as_type()).get(ctx, opt, txn, doc, path.next()).await - } - // If this is the 'coordinates' field then continue - Part::Field(f) if f.is_coordinates() && v.is_geometry() => { - v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await - } - // If this is the 'geometries' field then continue - Part::Field(f) if f.is_geometries() && v.is_collection() => { - v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await - } - // Otherwise return none - _ => Ok(Value::None), - }, - // Current value at path is a future - Value::Future(v) => { - // Check how many path parts are remaining - match path.len() { - // No further embedded fields, so just return this - 0 => Ok(Value::Future(v.clone())), - // Process the future and fetch the embedded field - _ => { - // Ensure the future is processed - let fut = &opt.new_with_futures(true); - // Get the future return value - let val = v.compute(ctx, fut, txn, doc).await?; - // Fetch the embedded field - val.get(ctx, opt, txn, doc, path).await - } - } - } - // Current value at path is an object - Value::Object(v) => match p { - // If requesting an `id` field, check if it is a complex Record ID - Part::Field(f) if f.is_id() && path.len() > 1 => match v.get(f.as_str()) { - Some(Value::Thing(Thing { - id: Id::Object(v), - .. - })) => Value::Object(v.clone()).get(ctx, opt, txn, doc, path.next()).await, - Some(Value::Thing(Thing { - id: Id::Array(v), - .. - })) => Value::Array(v.clone()).get(ctx, opt, txn, doc, path.next()).await, - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - Part::Graph(_) => match v.rid() { - Some(v) => Value::Thing(v).get(ctx, opt, txn, doc, path).await, - None => Ok(Value::None), - }, - Part::Field(f) => match v.get(f.as_str()) { - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - Part::Index(i) => match v.get(&i.to_string()) { - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - Part::Value(x) => match x.compute(ctx, opt, txn, doc).await? { - Value::Strand(f) => match v.get(f.as_str()) { - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - _ => Ok(Value::None), - }, - Part::All => self.get(ctx, opt, txn, doc, path.next()).await, - _ => Ok(Value::None), - }, - // Current value at path is an array - Value::Array(v) => match p { - // Current path is an `*` part - Part::All | Part::Flatten => { - let path = path.next(); - let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path)); - try_join_all_buffered(futs).await.map(Into::into) - } - Part::First => match v.first() { - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - Part::Last => match v.last() { - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - Part::Index(i) => match v.get(i.to_usize()) { - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - Part::Where(w) => { - let mut a = Vec::new(); - for v in v.iter() { - let cur = v.into(); - if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { - a.push(v.clone()); - } - } - Value::from(a).get(ctx, opt, txn, doc, path.next()).await - } - Part::Value(x) => match x.compute(ctx, opt, txn, doc).await? { - Value::Number(i) => match v.get(i.to_usize()) { - Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, - None => Ok(Value::None), - }, - _ => Ok(Value::None), - }, - _ => { - let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path)); - try_join_all_buffered(futs).await.map(Into::into) - } - }, - // Current value at path is an edges - Value::Edges(v) => { - // Clone the thing - let val = v.clone(); - // Check how many path parts are remaining - match path.len() { - // No remote embedded fields, so just return this - 0 => Ok(Value::Edges(val)), - // Remote embedded field, so fetch the thing - _ => { - let stm = SelectStatement { - expr: Fields(vec![Field::All], false), - what: Values(vec![Value::from(val)]), - ..SelectStatement::default() - }; - stm.compute(ctx, opt, txn, None) - .await? - .first() - .get(ctx, opt, txn, None, path) - .await - } - } - } - // Current value at path is a thing - Value::Thing(v) => { - // Clone the thing - let val = v.clone(); - // Check how many path parts are remaining - match path.len() { - // No remote embedded fields, so just return this - 0 => Ok(Value::Thing(val)), - // Remote embedded field, so fetch the thing - _ => match p { - // This is a graph traversal expression - Part::Graph(g) => { - let stm = SelectStatement { - expr: Fields(vec![Field::All], false), - what: Values(vec![Value::from(Edges { - from: val, - dir: g.dir.clone(), - what: g.what.clone(), - })]), - cond: g.cond.clone(), - ..SelectStatement::default() - }; - match path.len() { - 1 => stm - .compute(ctx, opt, txn, None) - .await? - .all() - .get(ctx, opt, txn, None, ID.as_ref()) - .await? - .flatten() - .ok(), - _ => stm - .compute(ctx, opt, txn, None) - .await? - .all() - .get(ctx, opt, txn, None, path.next()) - .await? - .flatten() - .ok(), - } - } - // This is a remote field expression - _ => { - let stm = SelectStatement { - expr: Fields(vec![Field::All], false), - what: Values(vec![Value::from(val)]), - ..SelectStatement::default() - }; - stm.compute(ctx, opt, txn, None) - .await? - .first() - .get(ctx, opt, txn, None, path) - .await - } - }, - } - } - v => { - if matches!(p, Part::Flatten) { - v.get(ctx, opt, txn, None, path.next()).await - } else { - // Ignore everything else - Ok(Value::None) - } - } - }, - // No more parts so get the value - None => Ok(self.clone()), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::dbs::test::mock; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn get_none() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::default(); - let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn get_basic() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something"); - let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, Value::from(123)); - } - - #[tokio::test] - async fn get_basic_deep_ok() { - let (ctx, opt, txn) = mock().await; - let depth = 20; - let idi = Idiom::parse(&format!("{}something", "test.".repeat(depth))); - let val = Value::parse(&format!( - "{} {{ other: null, something: 123 {} }}", - "{ test: ".repeat(depth), - "}".repeat(depth) - )); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, Value::from(123)); - } - - #[tokio::test] - async fn get_basic_deep_ko() { - let (ctx, opt, txn) = mock().await; - let depth = 2000; - let idi = Idiom::parse(&format!("{}something", "test.".repeat(depth))); - let val = Value::parse("{}"); // A deep enough object cannot be parsed. - let err = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap_err(); - assert!( - matches!(err, Error::ComputationDepthExceeded), - "expected computation depth exceeded, got {:?}", - err - ); - } - - #[tokio::test] - async fn get_thing() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.other"); - let val = Value::parse("{ test: { other: test:tobie, something: 123 } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!( - res, - Value::from(Thing { - tb: String::from("test"), - id: Id::from("tobie") - }) - ); - } - - #[tokio::test] - async fn get_array() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[1]"); - let val = Value::parse("{ test: { something: [123, 456, 789] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, Value::from(456)); - } - - #[tokio::test] - async fn get_array_thing() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[1]"); - let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!( - res, - Value::from(Thing { - tb: String::from("test"), - id: Id::from("jaime") - }) - ); - } - - #[tokio::test] - async fn get_array_field() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[1].age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, Value::from(36)); - } - - #[tokio::test] - async fn get_array_fields() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[*].age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, Value::from(vec![34, 36])); - } - - #[tokio::test] - async fn get_array_fields_flat() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something.age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, Value::from(vec![34, 36])); - } - - #[tokio::test] - async fn get_array_where_field() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[WHERE age > 35].age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!(res, Value::from(vec![36])); - } - - #[tokio::test] - async fn get_array_where_fields() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[WHERE age > 35]"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!( - res, - Value::from(vec![Value::from(map! { - "age".to_string() => Value::from(36), - })]) - ); - } - - #[tokio::test] - async fn get_array_where_fields_array_index() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[WHERE age > 30][0]"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!( - res, - Value::from(map! { - "age".to_string() => Value::from(34), - }) - ); - } - - #[tokio::test] - async fn get_future_embedded_field() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test.something[WHERE age > 35]"); - let val = Value::parse("{ test: { { something: [{ age: 34 }, { age: 36 }] } } }"); - let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); - assert_eq!( - res, - Value::from(vec![Value::from(map! { - "age".to_string() => Value::from(36), - })]) - ); - } - - #[tokio::test] - async fn get_future_embedded_field_with_reference() { - let (ctx, opt, txn) = mock().await; - let doc = Value::parse("{ name: 'Tobie', something: [{ age: 34 }, { age: 36 }] }"); - let idi = Idiom::parse("test.something[WHERE age > 35]"); - let val = Value::parse("{ test: { { something: something } } }"); - let cur = (&doc).into(); - let res = val.get(&ctx, &opt, &txn, Some(&cur), &idi).await.unwrap(); - assert_eq!( - res, - Value::from(vec![Value::from(map! { - "age".to_string() => Value::from(36), - })]) - ); - } -} diff --git a/core/src/sql/v2/value/inc.rs b/core/src/sql/v2/value/inc.rs deleted file mode 100644 index cd690879..00000000 --- a/core/src/sql/v2/value/inc.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::sql::number::Number; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - /// Synchronous method for incrementing a field in a `Value` - pub(crate) fn inc(&mut self, path: &[Part], val: Value) { - match self.pick(path) { - Value::Number(v) => { - if let Value::Number(x) = val { - self.put(path, Value::from(v + x)) - } - } - Value::Array(v) => match val { - Value::Array(x) => self.put(path, Value::from(v + x)), - x => self.put(path, Value::from(v + x)), - }, - Value::None => match val { - Value::Number(x) => self.put(path, Value::from(Number::from(0) + x)), - Value::Array(x) => self.put(path, Value::from(x)), - x => self.put(path, Value::from(vec![x])), - }, - _ => (), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn increment_none() { - let idi = Idiom::parse("other"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 100, other: +10 }"); - val.inc(&idi, Value::from(10)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_number() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 110 }"); - val.inc(&idi, Value::from(10)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_array_number() { - let idi = Idiom::parse("test[1]"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 210, 300] }"); - val.inc(&idi, Value::from(10)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_array_value() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 200, 300, 200] }"); - val.inc(&idi, Value::from(200)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_array_array() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 200, 300, 100, 300, 400, 500] }"); - val.inc(&idi, Value::parse("[100, 300, 400, 500]")); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/increment.rs b/core/src/sql/v2/value/increment.rs deleted file mode 100644 index 83634fe7..00000000 --- a/core/src/sql/v2/value/increment.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::{Options, Transaction}; -use crate::err::Error; -use crate::sql::number::Number; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - /// Asynchronous method for incrementing a field in a `Value` - pub(crate) async fn increment( - &mut self, - ctx: &Context<'_>, - opt: &Options, - txn: &Transaction, - path: &[Part], - val: Value, - ) -> Result<(), Error> { - match self.get(ctx, opt, txn, None, path).await? { - Value::Number(v) => match val { - Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await, - _ => Ok(()), - }, - Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await, - x => self.set(ctx, opt, txn, path, Value::from(v + x)).await, - }, - Value::None => match val { - Value::Number(x) => { - self.set(ctx, opt, txn, path, Value::from(Number::from(0) + x)).await - } - Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await, - x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await, - }, - _ => Ok(()), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::dbs::test::mock; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn increment_none() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("other"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 100, other: +10 }"); - val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_number() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: 100 }"); - let res = Value::parse("{ test: 110 }"); - val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_array_number() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test[1]"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 210, 300] }"); - val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_array_value() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 200, 300, 200] }"); - val.increment(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn increment_array_array() { - let (ctx, opt, txn) = mock().await; - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: [100, 200, 300] }"); - let res = Value::parse("{ test: [100, 200, 300, 100, 300, 400, 500] }"); - val.increment(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap(); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/last.rs b/core/src/sql/v2/value/last.rs deleted file mode 100644 index e4f02ef2..00000000 --- a/core/src/sql/v2/value/last.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - pub fn last(&self) -> Self { - self.pick(&[Part::Last]) - } -} diff --git a/core/src/sql/v2/value/merge.rs b/core/src/sql/v2/value/merge.rs deleted file mode 100644 index c42c1774..00000000 --- a/core/src/sql/v2/value/merge.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::err::Error; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn merge(&mut self, val: Value) -> Result<(), Error> { - // If this value is not an object, then error - if !val.is_object() { - return Err(Error::InvalidMerge { - value: val, - }); - } - // Otherwise loop through every object field - for k in val.every(None, false, false).iter() { - match val.pick(k) { - Value::None => self.cut(k), - v => self.put(k, v), - } - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[tokio::test] - async fn merge_none() { - let mut res = Value::parse( - "{ - name: { - first: 'Tobie', - last: 'Morgan Hitchcock', - initials: 'TMH', - }, - }", - ); - let none = Value::None; - match res.merge(none.clone()).unwrap_err() { - Error::InvalidMerge { - value, - } => assert_eq!(value, none), - error => panic!("unexpected error: {error:?}"), - } - } - - #[tokio::test] - async fn merge_basic() { - let mut res = Value::parse( - "{ - name: { - first: 'Tobie', - last: 'Morgan Hitchcock', - initials: 'TMH', - }, - }", - ); - let mrg = Value::parse( - "{ - name: { - title: 'Mr', - initials: NONE, - }, - tags: ['Rust', 'Golang', 'JavaScript'], - }", - ); - let val = Value::parse( - "{ - name: { - title: 'Mr', - first: 'Tobie', - last: 'Morgan Hitchcock', - }, - tags: ['Rust', 'Golang', 'JavaScript'], - }", - ); - res.merge(mrg).unwrap(); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/mod.rs b/core/src/sql/v2/value/mod.rs deleted file mode 100644 index e3c31a67..00000000 --- a/core/src/sql/v2/value/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -pub use self::value::*; - -pub(super) mod serde; - -#[allow(clippy::module_inception)] -mod value; - -mod all; -mod changed; -mod clear; -mod compare; -mod cut; -mod decrement; -mod def; -mod del; -mod diff; -mod each; -mod every; -mod extend; -mod fetch; -mod first; -mod flatten; -mod generate; -mod get; -mod inc; -mod increment; -mod last; -mod merge; -mod patch; -mod pick; -mod put; -mod replace; -mod rid; -mod set; -mod walk; diff --git a/core/src/sql/v2/value/patch.rs b/core/src/sql/v2/value/patch.rs deleted file mode 100644 index 507736e4..00000000 --- a/core/src/sql/v2/value/patch.rs +++ /dev/null @@ -1,238 +0,0 @@ -use crate::err::Error; -use crate::sql::operation::Operation; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn patch(&mut self, ops: Value) -> Result<(), Error> { - // This value is for test operation, value itself shouldn't change until all operations done. - // If test operations fails, nothing in value will be changed. - let mut tmp_val = self.clone(); - - for operation in ops.to_operations()?.into_iter() { - match operation { - Operation::Add { - path, - value, - } => match tmp_val.pick(&path) { - Value::Array(_) => tmp_val.inc(&path, value), - _ => tmp_val.put(&path, value), - }, - Operation::Remove { - path, - } => tmp_val.cut(&path), - Operation::Replace { - path, - value, - } => tmp_val.put(&path, value), - Operation::Change { - path, - value, - } => { - if let Value::Strand(p) = value { - if let Value::Strand(v) = tmp_val.pick(&path) { - let dmp = dmp::new(); - let pch = dmp.patch_from_text(p.as_string()).map_err(|e| { - Error::InvalidPatch { - message: format!("{e:?}"), - } - })?; - let (txt, _) = dmp.patch_apply(&pch, v.as_str()).map_err(|e| { - Error::InvalidPatch { - message: format!("{e:?}"), - } - })?; - let txt = txt.into_iter().collect::(); - tmp_val.put(&path, Value::from(txt)); - } - } - } - Operation::Copy { - path, - from, - } => { - let found_val = tmp_val.pick(&from); - tmp_val.put(&path, found_val); - } - Operation::Move { - path, - from, - } => { - let found_val = tmp_val.pick(&from); - tmp_val.put(&path, found_val); - tmp_val.cut(&from); - } - Operation::Test { - path, - value, - } => { - let found_val = tmp_val.pick(&path); - - if value != found_val { - return Err(Error::PatchTest { - expected: value.to_string(), - got: found_val.to_string(), - }); - } - } - } - } - - *self = tmp_val; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[tokio::test] - async fn patch_add_simple() { - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let ops = Value::parse("[{ op: 'add', path: '/temp', value: true }]"); - let res = Value::parse("{ test: { other: null, something: 123 }, temp: true }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_remove_simple() { - let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }"); - let ops = Value::parse("[{ op: 'remove', path: '/temp' }]"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_replace_simple() { - let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }"); - let ops = Value::parse("[{ op: 'replace', path: '/temp', value: 'text' }]"); - let res = Value::parse("{ test: { other: null, something: 123 }, temp: 'text' }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_change_simple() { - let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: 'test' }"); - let ops = Value::parse( - "[{ op: 'change', path: '/temp', value: '@@ -1,4 +1,4 @@\n te\n-s\n+x\n t\n' }]", - ); - let res = Value::parse("{ test: { other: null, something: 123 }, temp: 'text' }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_copy_simple() { - let mut val = Value::parse("{ test: 123, temp: true }"); - let ops = Value::parse("[{ op: 'copy', path: '/temp', from: '/test' }]"); - let res = Value::parse("{ test: 123, temp: 123 }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_move_simple() { - let mut val = Value::parse("{ temp: true, some: 123 }"); - let ops = Value::parse("[{ op: 'move', path: '/other', from: '/temp' }]"); - let res = Value::parse("{ other: true, some: 123 }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_test_simple() { - let mut val = Value::parse("{ test: { other: 'test', something: 123 }, temp: true }"); - let ops = Value::parse("[{ op: 'remove', path: '/test/something' }, { op: 'test', path: '/temp', value: true }]"); - let res = Value::parse("{ test: { other: 'test' }, temp: true }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_add_embedded() { - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let ops = Value::parse("[{ op: 'add', path: '/temp/test', value: true }]"); - let res = Value::parse("{ test: { other: null, something: 123 }, temp: { test: true } }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_remove_embedded() { - let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }"); - let ops = Value::parse("[{ op: 'remove', path: '/test/other' }]"); - let res = Value::parse("{ test: { something: 123 }, temp: true }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_replace_embedded() { - let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }"); - let ops = Value::parse("[{ op: 'replace', path: '/test/other', value: 'text' }]"); - let res = Value::parse("{ test: { other: 'text', something: 123 }, temp: true }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_change_embedded() { - let mut val = Value::parse("{ test: { other: 'test', something: 123 }, temp: true }"); - let ops = Value::parse( - "[{ op: 'change', path: '/test/other', value: '@@ -1,4 +1,4 @@\n te\n-s\n+x\n t\n' }]", - ); - let res = Value::parse("{ test: { other: 'text', something: 123 }, temp: true }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_copy_embedded() { - let mut val = Value::parse("{ test: { other: null }, temp: 123 }"); - let ops = Value::parse("[{ op: 'copy', path: '/test/other', from: '/temp' }]"); - let res = Value::parse("{ test: { other: 123 }, temp: 123 }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_move_embedded() { - let mut val = Value::parse("{ test: { other: ':3', some: 123 }}"); - let ops = Value::parse("[{ op: 'move', path: '/temp', from: '/test/other' }]"); - let res = Value::parse("{ test: { some: 123 }, temp: ':3' }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_test_embedded() { - let mut val = Value::parse("{ test: { other: 'test', something: 123 }, temp: true }"); - let ops = Value::parse("[{ op: 'remove', path: '/test/other' }, { op: 'test', path: '/test/something', value: 123 }]"); - let res = Value::parse("{ test: { something: 123 }, temp: true }"); - val.patch(ops).unwrap(); - assert_eq!(res, val); - } - - #[tokio::test] - async fn patch_change_invalid() { - // See https://github.com/surrealdb/surrealdb/issues/2001 - let mut val = Value::parse("{ test: { other: 'test', something: 123 }, temp: true }"); - let ops = Value::parse("[{ op: 'change', path: '/test/other', value: 'text' }]"); - assert!(val.patch(ops).is_err()); - } - - #[tokio::test] - async fn patch_test_invalid() { - let mut val = Value::parse("{ test: { other: 'test', something: 123 }, temp: true }"); - let should = val.clone(); - let ops = Value::parse("[{ op: 'remove', path: '/test/other' }, { op: 'test', path: '/test/something', value: 'not same' }]"); - assert!(val.patch(ops).is_err()); - // It is important to test if patches applied even if test operation fails - assert_eq!(val, should); - } -} diff --git a/core/src/sql/v2/value/pick.rs b/core/src/sql/v2/value/pick.rs deleted file mode 100644 index 79cfb2e1..00000000 --- a/core/src/sql/v2/value/pick.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - /// Synchronous method for getting a field from a `Value` - pub fn pick(&self, path: &[Part]) -> Self { - match path.first() { - // Get the current value at path - Some(p) => match self { - // Current value at path is an object - Value::Object(v) => match p { - Part::Field(f) => match v.get(f as &str) { - Some(v) => v.pick(path.next()), - None => Value::None, - }, - Part::Index(i) => match v.get(&i.to_string()) { - Some(v) => v.pick(path.next()), - None => Value::None, - }, - Part::All => self.pick(path.next()), - _ => Value::None, - }, - // Current value at path is an array - Value::Array(v) => match p { - Part::All => v.iter().map(|v| v.pick(path.next())).collect::>().into(), - Part::First => match v.first() { - Some(v) => v.pick(path.next()), - None => Value::None, - }, - Part::Last => match v.last() { - Some(v) => v.pick(path.next()), - None => Value::None, - }, - Part::Index(i) => match v.get(i.to_usize()) { - Some(v) => v.pick(path.next()), - None => Value::None, - }, - _ => v.iter().map(|v| v.pick(path)).collect::>().into(), - }, - // Ignore everything else - _ => Value::None, - }, - // No more parts so get the value - None => self.clone(), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::id::Id; - use crate::sql::idiom::Idiom; - use crate::sql::thing::Thing; - use crate::syn::Parse; - - #[test] - fn pick_none() { - let idi = Idiom::default(); - let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = val.pick(&idi); - assert_eq!(res, val); - } - - #[test] - fn pick_basic() { - let idi = Idiom::parse("test.something"); - let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = val.pick(&idi); - assert_eq!(res, Value::from(123)); - } - - #[test] - fn pick_thing() { - let idi = Idiom::parse("test.other"); - let val = Value::parse("{ test: { other: test:tobie, something: 123 } }"); - let res = val.pick(&idi); - assert_eq!( - res, - Value::from(Thing { - tb: String::from("test"), - id: Id::from("tobie") - }) - ); - } - - #[test] - fn pick_array() { - let idi = Idiom::parse("test.something[1]"); - let val = Value::parse("{ test: { something: [123, 456, 789] } }"); - let res = val.pick(&idi); - assert_eq!(res, Value::from(456)); - } - - #[test] - fn pick_array_thing() { - let idi = Idiom::parse("test.something[1]"); - let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }"); - let res = val.pick(&idi); - assert_eq!( - res, - Value::from(Thing { - tb: String::from("test"), - id: Id::from("jaime") - }) - ); - } - - #[test] - fn pick_array_field() { - let idi = Idiom::parse("test.something[1].age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.pick(&idi); - assert_eq!(res, Value::from(36)); - } - - #[test] - fn pick_array_fields() { - let idi = Idiom::parse("test.something[*].age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.pick(&idi); - assert_eq!(res, Value::from(vec![34, 36])); - } - - #[test] - fn pick_array_fields_flat() { - let idi = Idiom::parse("test.something.age"); - let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.pick(&idi); - assert_eq!(res, Value::from(vec![34, 36])); - } -} diff --git a/core/src/sql/v2/value/put.rs b/core/src/sql/v2/value/put.rs deleted file mode 100644 index a62199f9..00000000 --- a/core/src/sql/v2/value/put.rs +++ /dev/null @@ -1,199 +0,0 @@ -use crate::sql::part::Next; -use crate::sql::part::Part; -use crate::sql::value::Value; - -impl Value { - /// Synchronous method for setting a field on a `Value` - pub fn put(&mut self, path: &[Part], val: Value) { - match path.first() { - // Get the current value at path - Some(p) => match self { - // Current value at path is an object - Value::Object(v) => match p { - Part::Graph(g) => match v.get_mut(g.to_raw().as_str()) { - Some(v) if v.is_some() => v.put(path.next(), val), - _ => { - let mut obj = Value::base(); - obj.put(path.next(), val); - v.insert(g.to_raw(), obj); - } - }, - Part::Field(f) => match v.get_mut(f.to_raw().as_str()) { - Some(v) if v.is_some() => v.put(path.next(), val), - _ => { - let mut obj = Value::base(); - obj.put(path.next(), val); - v.insert(f.to_raw(), obj); - } - }, - Part::Index(i) => match v.get_mut(&i.to_string()) { - Some(v) if v.is_some() => v.put(path.next(), val), - _ => { - let mut obj = Value::base(); - obj.put(path.next(), val); - v.insert(i.to_string(), obj); - } - }, - _ => (), - }, - // Current value at path is an array - Value::Array(v) => match p { - Part::All => { - let path = path.next(); - v.iter_mut().for_each(|v| v.put(path, val.clone())); - } - Part::First => { - if let Some(v) = v.first_mut() { - v.put(path.next(), val) - } - } - Part::Last => { - if let Some(v) = v.last_mut() { - v.put(path.next(), val) - } - } - Part::Index(i) => { - if let Some(v) = v.get_mut(i.to_usize()) { - v.put(path.next(), val) - } - } - _ => { - v.iter_mut().for_each(|v| v.put(path, val.clone())); - } - }, - // Current value at path is empty - Value::Null => { - *self = Value::base(); - self.put(path, val) - } - // Current value at path is empty - Value::None => { - *self = Value::base(); - self.put(path, val) - } - // Ignore everything else - _ => (), - }, - // No more parts so put the value - None => { - *self = val; - } - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::idiom::Idiom; - use crate::syn::Parse; - - #[tokio::test] - async fn put_none() { - let idi = Idiom::default(); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("999"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_empty() { - let idi = Idiom::parse("test"); - let mut val = Value::None; - let res = Value::parse("{ test: 999 }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_blank() { - let idi = Idiom::parse("test.something"); - let mut val = Value::None; - let res = Value::parse("{ test: { something: 999 } }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_reput() { - let idi = Idiom::parse("test"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: 999 }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_basic() { - let idi = Idiom::parse("test.something"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 999 } }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_allow() { - let idi = Idiom::parse("test.something.allow"); - let mut val = Value::parse("{ test: { other: null } }"); - let res = Value::parse("{ test: { other: null, something: { allow: 999 } } }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_wrong() { - let idi = Idiom::parse("test.something.wrong"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_other() { - let idi = Idiom::parse("test.other.something"); - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ test: { other: { something: 999 }, something: 123 } }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_array() { - let idi = Idiom::parse("test.something[1]"); - let mut val = Value::parse("{ test: { something: [123, 456, 789] } }"); - let res = Value::parse("{ test: { something: [123, 999, 789] } }"); - val.put(&idi, Value::from(999)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_array_field() { - let idi = Idiom::parse("test.something[1].age"); - let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }"); - val.put(&idi, Value::from(21)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_array_fields() { - let idi = Idiom::parse("test.something[*].age"); - let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }"); - val.put(&idi, Value::from(21)); - assert_eq!(res, val); - } - - #[tokio::test] - async fn put_array_fields_flat() { - let idi = Idiom::parse("test.something.age"); - let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }"); - val.put(&idi, Value::from(21)); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/replace.rs b/core/src/sql/v2/value/replace.rs deleted file mode 100644 index 7dc39762..00000000 --- a/core/src/sql/v2/value/replace.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::err::Error; -use crate::sql::value::Value; - -impl Value { - pub(crate) fn replace(&mut self, val: Value) -> Result<(), Error> { - // If this value is not an object, then error - if !val.is_object() { - return Err(Error::InvalidContent { - value: val, - }); - } - // Otherwise replace the current value - *self = val; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::syn::Parse; - - #[tokio::test] - async fn replace() { - let mut val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::parse("{ other: true }"); - let obj = Value::parse("{ other: true }"); - val.replace(obj).unwrap(); - assert_eq!(res, val); - } -} diff --git a/core/src/sql/v2/value/rid.rs b/core/src/sql/v2/value/rid.rs deleted file mode 100644 index 545e7f2c..00000000 --- a/core/src/sql/v2/value/rid.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::sql::paths::ID; -use crate::sql::value::Value; - -impl Value { - pub fn rid(&self) -> Value { - self.pick(&*ID) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::sql::id::Id; - use crate::sql::thing::Thing; - use crate::syn::Parse; - - #[tokio::test] - async fn rid_none() { - let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = Value::None; - assert_eq!(res, val.rid()); - } - - #[tokio::test] - async fn rid_some() { - let val = Value::parse("{ id: test:id, test: { other: null, something: 123 } }"); - let res = Value::Thing(Thing { - tb: String::from("test"), - id: Id::from("id"), - }); - assert_eq!(res, val.rid()); - } -} diff --git a/core/src/sql/v2/value/serde/de/mod.rs b/core/src/sql/v2/value/serde/de/mod.rs deleted file mode 100644 index 17a675ee..00000000 --- a/core/src/sql/v2/value/serde/de/mod.rs +++ /dev/null @@ -1,698 +0,0 @@ -use crate::sql::constant::ConstantValue; -use crate::sql::id::Gen; -use crate::sql::Value; -use serde::de::DeserializeOwned; -use serde::Serialize; -use serde_json::json; -use serde_json::Map; -use serde_json::Value as JsonValue; - -impl From for serde_json::Value { - fn from(value: Value) -> Self { - into_json(value, true) - } -} - -fn into_json(value: Value, simplify: bool) -> JsonValue { - use crate::sql; - use crate::sql::Number; - - #[derive(Serialize)] - struct Array(Vec); - - impl From<(sql::Array, bool)> for Array { - fn from((arr, simplify): (sql::Array, bool)) -> Self { - let mut vec = Vec::with_capacity(arr.0.len()); - for value in arr.0 { - vec.push(into_json(value, simplify)); - } - Self(vec) - } - } - - #[derive(Serialize)] - struct Object(Map); - - impl From<(sql::Object, bool)> for Object { - fn from((obj, simplify): (sql::Object, bool)) -> Self { - let mut map = Map::with_capacity(obj.0.len()); - for (key, value) in obj.0 { - map.insert(key.to_owned(), into_json(value, simplify)); - } - Self(map) - } - } - - #[derive(Serialize)] - enum CoordinatesType { - Point, - LineString, - Polygon, - MultiPoint, - MultiLineString, - MultiPolygon, - } - - #[derive(Serialize)] - struct Coordinates { - #[serde(rename = "type")] - typ: CoordinatesType, - coordinates: JsonValue, - } - - struct GeometryCollection; - - impl Serialize for GeometryCollection { - fn serialize(&self, s: S) -> Result - where - S: serde::Serializer, - { - s.serialize_str("GeometryCollection") - } - } - - #[derive(Serialize)] - struct Geometries { - #[serde(rename = "type")] - typ: GeometryCollection, - geometries: Vec, - } - - #[derive(Serialize)] - struct Geometry(JsonValue); - - impl From for Geometry { - fn from(geo: sql::Geometry) -> Self { - Self(match geo { - sql::Geometry::Point(v) => json!(Coordinates { - typ: CoordinatesType::Point, - coordinates: vec![json!(v.x()), json!(v.y())].into(), - }), - sql::Geometry::Line(v) => json!(Coordinates { - typ: CoordinatesType::LineString, - coordinates: v - .points() - .map(|p| vec![json!(p.x()), json!(p.y())].into()) - .collect::>() - .into(), - }), - sql::Geometry::Polygon(v) => json!(Coordinates { - typ: CoordinatesType::Polygon, - coordinates: vec![v - .exterior() - .points() - .map(|p| vec![json!(p.x()), json!(p.y())].into()) - .collect::>()] - .into_iter() - .chain( - v.interiors() - .iter() - .map(|i| { - i.points() - .map(|p| vec![json!(p.x()), json!(p.y())].into()) - .collect::>() - }) - .collect::>>(), - ) - .collect::>>() - .into(), - }), - sql::Geometry::MultiPoint(v) => json!(Coordinates { - typ: CoordinatesType::MultiPoint, - coordinates: v - .0 - .iter() - .map(|v| vec![json!(v.x()), json!(v.y())].into()) - .collect::>() - .into() - }), - sql::Geometry::MultiLine(v) => json!(Coordinates { - typ: CoordinatesType::MultiLineString, - coordinates: v - .0 - .iter() - .map(|v| { - v.points() - .map(|v| vec![json!(v.x()), json!(v.y())].into()) - .collect::>() - }) - .collect::>>() - .into() - }), - sql::Geometry::MultiPolygon(v) => json!(Coordinates { - typ: CoordinatesType::MultiPolygon, - coordinates: v - .0 - .iter() - .map(|v| { - vec![v - .exterior() - .points() - .map(|p| vec![json!(p.x()), json!(p.y())].into()) - .collect::>()] - .into_iter() - .chain( - v.interiors() - .iter() - .map(|i| { - i.points() - .map(|p| vec![json!(p.x()), json!(p.y())].into()) - .collect::>() - }) - .collect::>>(), - ) - .collect::>>() - }) - .collect::>>>() - .into(), - }), - sql::Geometry::Collection(v) => json!(Geometries { - typ: GeometryCollection, - geometries: v.into_iter().map(Geometry::from).map(|x| x.0).collect(), - }), - }) - } - } - - #[derive(Serialize)] - enum Id { - Number(i64), - String(String), - Array(Array), - Object(Object), - } - - impl From<(sql::Id, bool)> for Id { - fn from((id, simplify): (sql::Id, bool)) -> Self { - match id { - sql::Id::Number(n) => Id::Number(n), - sql::Id::String(s) => Id::String(s), - sql::Id::Array(arr) => Id::Array((arr, simplify).into()), - sql::Id::Object(obj) => Id::Object((obj, simplify).into()), - sql::Id::Generate(v) => match v { - Gen::Rand => Id::from((sql::Id::rand(), simplify)), - Gen::Ulid => Id::from((sql::Id::ulid(), simplify)), - Gen::Uuid => Id::from((sql::Id::uuid(), simplify)), - }, - } - } - } - - #[derive(Serialize)] - struct Thing { - tb: String, - id: Id, - } - - impl From<(sql::Thing, bool)> for Thing { - fn from((thing, simplify): (sql::Thing, bool)) -> Self { - Self { - tb: thing.tb, - id: (thing.id, simplify).into(), - } - } - } - - match value { - // These value types are simple values which - // can be used in query responses sent to - // the client. - Value::None | Value::Null => JsonValue::Null, - Value::Bool(boolean) => boolean.into(), - Value::Number(number) => match number { - Number::Int(int) => int.into(), - Number::Float(float) => float.into(), - Number::Decimal(decimal) => json!(decimal), - }, - Value::Strand(strand) => strand.0.into(), - Value::Duration(duration) => match simplify { - true => duration.to_raw().into(), - false => json!(duration.0), - }, - Value::Datetime(datetime) => json!(datetime.0), - Value::Uuid(uuid) => json!(uuid.0), - Value::Array(array) => JsonValue::Array(Array::from((array, simplify)).0), - Value::Object(object) => JsonValue::Object(Object::from((object, simplify)).0), - Value::Geometry(geo) => match simplify { - true => Geometry::from(geo).0, - false => match geo { - sql::Geometry::Point(geo) => json!(geo), - sql::Geometry::Line(geo) => json!(geo), - sql::Geometry::Polygon(geo) => json!(geo), - sql::Geometry::MultiPoint(geo) => json!(geo), - sql::Geometry::MultiLine(geo) => json!(geo), - sql::Geometry::MultiPolygon(geo) => json!(geo), - sql::Geometry::Collection(geo) => json!(geo), - }, - }, - Value::Bytes(bytes) => json!(bytes.0), - Value::Thing(thing) => match simplify { - true => thing.to_string().into(), - false => json!(thing), - }, - // These Value types are un-computed values - // and are not used in query responses sent - // to the client. - Value::Param(param) => json!(param), - Value::Idiom(idiom) => json!(idiom), - Value::Table(table) => json!(table), - Value::Mock(mock) => json!(mock), - Value::Regex(regex) => json!(regex), - Value::Block(block) => json!(block), - Value::Range(range) => json!(range), - Value::Edges(edges) => json!(edges), - Value::Future(future) => json!(future), - Value::Constant(constant) => match simplify { - true => match constant.value() { - ConstantValue::Datetime(datetime) => json!(datetime.0), - ConstantValue::Float(float) => float.into(), - }, - false => json!(constant), - }, - Value::Cast(cast) => json!(cast), - Value::Function(function) => json!(function), - Value::Model(model) => json!(model), - Value::Query(query) => json!(query), - Value::Subquery(subquery) => json!(subquery), - Value::Expression(expression) => json!(expression), - } -} - -#[derive(Debug, Clone)] -#[doc(hidden)] -#[non_exhaustive] -pub struct FromValueError { - pub value: Value, - pub error: String, -} - -/// Deserializes a value `T` from `SurrealDB` [`Value`] -#[doc(hidden)] -pub fn from_value(value: Value) -> Result -where - T: DeserializeOwned, -{ - let json = into_json(value.clone(), false); - serde_json::from_value(json).map_err(|error| FromValueError { - value, - error: error.to_string(), - }) -} - -#[cfg(test)] -mod tests { - mod into_json { - use crate::sql; - use crate::sql::value::serde::de::from_value; - use crate::sql::value::serde::de::into_json; - use crate::sql::Value; - use chrono::DateTime; - use chrono::Utc; - use geo::line_string; - use geo::point; - use geo::polygon; - use geo::LineString; - use geo::MultiLineString; - use geo::MultiPoint; - use geo::MultiPolygon; - use geo::Point; - use geo::Polygon; - use rust_decimal::Decimal; - use serde_json::json; - use std::collections::BTreeMap; - use std::time::Duration; - use uuid::Uuid; - - #[test] - fn none_or_null() { - for value in [Value::None, Value::Null] { - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(null)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(null)); - - let response: Option = from_value(value).unwrap(); - assert_eq!(response, None); - } - } - - #[test] - fn bool() { - for boolean in [true, false] { - let value = Value::Bool(boolean); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(boolean)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(boolean)); - - let response: bool = from_value(value).unwrap(); - assert_eq!(response, boolean); - } - } - - #[test] - fn number_int() { - for num in [i64::MIN, 0, i64::MAX] { - let value = Value::Number(sql::Number::Int(num)); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(num)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(num)); - - let response: i64 = from_value(value).unwrap(); - assert_eq!(response, num); - } - } - - #[test] - fn number_float() { - for num in [f64::NEG_INFINITY, f64::MIN, 0.0, f64::MAX, f64::INFINITY, f64::NAN] { - let value = Value::Number(sql::Number::Float(num)); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(num)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(num)); - - if num.is_finite() { - let response: f64 = from_value(value).unwrap(); - assert_eq!(response, num); - } else { - let response: Option = from_value(value).unwrap(); - assert_eq!(response, None); - } - } - } - - #[test] - fn number_decimal() { - for num in [i64::MIN, 0, i64::MAX] { - let num = Decimal::new(num, 0); - let value = Value::Number(sql::Number::Decimal(num)); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(num.to_string())); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(num)); - - let response: Decimal = from_value(value).unwrap(); - assert_eq!(response, num); - } - } - - #[test] - fn strand() { - for str in ["", "foo"] { - let value = Value::Strand(str.into()); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(str)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(str)); - - let response: String = from_value(value).unwrap(); - assert_eq!(response, str); - } - } - - #[test] - fn duration() { - for duration in [Duration::ZERO, Duration::MAX] { - let value = Value::Duration(duration.into()); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(sql::Duration(duration).to_raw())); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(duration)); - - let response: Duration = from_value(value).unwrap(); - assert_eq!(response, duration); - } - } - - #[test] - fn datetime() { - for datetime in [DateTime::::MIN_UTC, DateTime::::MAX_UTC] { - let value = Value::Datetime(datetime.into()); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(datetime)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(datetime)); - - let response: DateTime = from_value(value).unwrap(); - assert_eq!(response, datetime); - } - } - - #[test] - fn uuid() { - for uuid in [Uuid::nil(), Uuid::max()] { - let value = Value::Uuid(uuid.into()); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(uuid)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(uuid)); - - let response: Uuid = from_value(value).unwrap(); - assert_eq!(response, uuid); - } - } - - #[test] - fn array() { - for vec in [vec![], vec![true, false]] { - let value = - Value::Array(sql::Array(vec.iter().copied().map(Value::from).collect())); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(vec)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(vec)); - - let response: Vec = from_value(value).unwrap(); - assert_eq!(response, vec); - } - } - - #[test] - fn object() { - for map in [BTreeMap::new(), map!("done".to_owned() => true)] { - let value = Value::Object(sql::Object( - map.iter().map(|(key, value)| (key.clone(), Value::from(*value))).collect(), - )); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(map)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(map)); - - let response: BTreeMap = from_value(value).unwrap(); - assert_eq!(response, map); - } - } - - #[test] - fn geometry_point() { - let point = point! { x: 10., y: 20. }; - let value = Value::Geometry(sql::Geometry::Point(point)); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!({ "type": "Point", "coordinates": [10., 20.]})); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(point)); - - let response: Point = from_value(value).unwrap(); - assert_eq!(response, point); - } - - #[test] - fn geometry_line() { - let line_string = line_string![ - ( x: 0., y: 0. ), - ( x: 10., y: 0. ), - ]; - let value = Value::Geometry(sql::Geometry::Line(line_string.clone())); - - let simple_json = into_json(value.clone(), true); - assert_eq!( - simple_json, - json!({ "type": "LineString", "coordinates": [[0., 0.], [10., 0.]]}) - ); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(line_string)); - - let response: LineString = from_value(value).unwrap(); - assert_eq!(response, line_string); - } - - #[test] - fn geometry_polygon() { - let polygon = polygon![ - (x: -111., y: 45.), - (x: -111., y: 41.), - (x: -104., y: 41.), - (x: -104., y: 45.), - ]; - let value = Value::Geometry(sql::Geometry::Polygon(polygon.clone())); - - let simple_json = into_json(value.clone(), true); - assert_eq!( - simple_json, - json!({ "type": "Polygon", "coordinates": [[ - [-111., 45.], - [-111., 41.], - [-104., 41.], - [-104., 45.], - [-111., 45.], - ]]}) - ); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(polygon)); - - let response: Polygon = from_value(value).unwrap(); - assert_eq!(response, polygon); - } - - #[test] - fn geometry_multi_point() { - let multi_point: MultiPoint = - vec![point! { x: 0., y: 0. }, point! { x: 1., y: 2. }].into(); - let value = Value::Geometry(sql::Geometry::MultiPoint(multi_point.clone())); - - let simple_json = into_json(value.clone(), true); - assert_eq!( - simple_json, - json!({ "type": "MultiPoint", "coordinates": [[0., 0.], [1., 2.]]}) - ); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(multi_point)); - - let response: MultiPoint = from_value(value).unwrap(); - assert_eq!(response, multi_point); - } - - #[test] - fn geometry_multi_line() { - let multi_line = MultiLineString::new(vec![line_string![ - ( x: 0., y: 0. ), - ( x: 1., y: 2. ), - ]]); - let value = Value::Geometry(sql::Geometry::MultiLine(multi_line.clone())); - - let simple_json = into_json(value.clone(), true); - assert_eq!( - simple_json, - json!({ "type": "MultiLineString", "coordinates": [[[0., 0.], [1., 2.]]]}) - ); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(multi_line)); - - let response: MultiLineString = from_value(value).unwrap(); - assert_eq!(response, multi_line); - } - - #[test] - fn geometry_multi_polygon() { - let multi_polygon: MultiPolygon = vec![polygon![ - (x: -111., y: 45.), - (x: -111., y: 41.), - (x: -104., y: 41.), - (x: -104., y: 45.), - ]] - .into(); - let value = Value::Geometry(sql::Geometry::MultiPolygon(multi_polygon.clone())); - - let simple_json = into_json(value.clone(), true); - assert_eq!( - simple_json, - json!({ "type": "MultiPolygon", "coordinates": [[[ - [-111., 45.], - [-111., 41.], - [-104., 41.], - [-104., 45.], - [-111., 45.], - ]]]}) - ); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(multi_polygon)); - - let response: MultiPolygon = from_value(value).unwrap(); - assert_eq!(response, multi_polygon); - } - - #[test] - fn geometry_collection() { - for geometries in [vec![], vec![sql::Geometry::Point(point! { x: 10., y: 20. })]] { - let value = Value::Geometry(geometries.clone().into()); - - let simple_json = into_json(value.clone(), true); - assert_eq!( - simple_json, - json!({ - "type": "GeometryCollection", - "geometries": geometries.clone().into_iter().map(|geo| into_json(Value::from(geo), true)).collect::>(), - }) - ); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(geometries)); - - let response: Vec = from_value(value).unwrap(); - assert_eq!(response, geometries); - } - } - - #[test] - fn bytes() { - for bytes in [vec![], b"foo".to_vec()] { - let value = Value::Bytes(sql::Bytes(bytes.clone())); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(bytes)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(bytes)); - - let response: Vec = from_value(value).unwrap(); - assert_eq!(response, bytes); - } - } - - #[test] - fn thing() { - let record_id = "foo:bar"; - let thing = sql::thing(record_id).unwrap(); - let value = Value::Thing(thing.clone()); - - let simple_json = into_json(value.clone(), true); - assert_eq!(simple_json, json!(record_id)); - - let json = into_json(value.clone(), false); - assert_eq!(json, json!(thing)); - - let response: sql::Thing = from_value(value).unwrap(); - assert_eq!(response, thing); - } - } -} diff --git a/core/src/sql/v2/value/serde/mod.rs b/core/src/sql/v2/value/serde/mod.rs deleted file mode 100644 index 227280c9..00000000 --- a/core/src/sql/v2/value/serde/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod de; -mod ser; - -pub use de::{from_value, FromValueError}; -pub use ser::to_value; diff --git a/core/src/sql/v2/value/serde/ser/algorithm/mod.rs b/core/src/sql/v2/value/serde/ser/algorithm/mod.rs deleted file mode 100644 index 17e57820..00000000 --- a/core/src/sql/v2/value/serde/ser/algorithm/mod.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Algorithm; -use serde::ser::Error as _; -use serde::ser::Impossible; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Algorithm; - 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 `Algorithm`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "EdDSA" => Ok(Algorithm::EdDSA), - "Es256" => Ok(Algorithm::Es256), - "Es384" => Ok(Algorithm::Es384), - "Es512" => Ok(Algorithm::Es512), - "Hs256" => Ok(Algorithm::Hs256), - "Hs384" => Ok(Algorithm::Hs384), - "Hs512" => Ok(Algorithm::Hs512), - "Ps256" => Ok(Algorithm::Ps256), - "Ps384" => Ok(Algorithm::Ps384), - "Ps512" => Ok(Algorithm::Ps512), - "Rs256" => Ok(Algorithm::Rs256), - "Rs384" => Ok(Algorithm::Rs384), - "Rs512" => Ok(Algorithm::Rs512), - variant => Err(Error::custom(format!("unknown variant `{name}::{variant}`"))), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - use serde::Serialize; - - #[test] - fn ed_dsa() { - let algo = Algorithm::EdDSA; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn es256() { - let algo = Algorithm::Es256; - let serialized: Algorithm = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn es384() { - let algo = Algorithm::Es384; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn es512() { - let algo = Algorithm::Es512; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn hs256() { - let algo = Algorithm::Hs256; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn hs384() { - let algo = Algorithm::Hs384; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn hs512() { - let algo = Algorithm::Hs512; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn ps256() { - let algo = Algorithm::Ps256; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn ps384() { - let algo = Algorithm::Ps384; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn ps512() { - let algo = Algorithm::Ps512; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn rs256() { - let algo = Algorithm::Rs256; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn rs384() { - let algo = Algorithm::Rs384; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } - - #[test] - fn rs512() { - let algo = Algorithm::Rs512; - let serialized = algo.serialize(Serializer.wrap()).unwrap(); - assert_eq!(algo, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/base/mod.rs b/core/src/sql/v2/value/serde/ser/base/mod.rs deleted file mode 100644 index 4efa0757..00000000 --- a/core/src/sql/v2/value/serde/ser/base/mod.rs +++ /dev/null @@ -1,94 +0,0 @@ -pub(super) mod opt; - -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Base; -use crate::sql::Ident; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Base; - 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 `Base`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "Root" => Ok(Base::Root), - "Ns" => Ok(Base::Ns), - "Db" => Ok(Base::Db), - variant => Err(Error::custom(format!("unexpected unit variant `{name}::{variant}`"))), - } - } - - #[inline] - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - match variant { - "Sc" => Ok(Base::Sc(Ident(value.serialize(ser::string::Serializer.wrap())?))), - variant => { - Err(Error::custom(format!("unexpected newtype variant `{name}::{variant}`"))) - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn root() { - let base = Base::Root; - let serialized = base.serialize(Serializer.wrap()).unwrap(); - assert_eq!(base, serialized); - } - - #[test] - fn ns() { - let base = Base::Ns; - let serialized = base.serialize(Serializer.wrap()).unwrap(); - assert_eq!(base, serialized); - } - - #[test] - fn db() { - let base = Base::Db; - let serialized = base.serialize(Serializer.wrap()).unwrap(); - assert_eq!(base, serialized); - } - - #[test] - fn sc() { - let base = Base::Sc(Default::default()); - let serialized = base.serialize(Serializer.wrap()).unwrap(); - assert_eq!(base, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/base/opt.rs b/core/src/sql/v2/value/serde/ser/base/opt.rs deleted file mode 100644 index 10ddefbb..00000000 --- a/core/src/sql/v2/value/serde/ser/base/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Base; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Option`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(value.serialize(super::Serializer.wrap())?)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(Base::default()); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/block/entry/mod.rs b/core/src/sql/v2/value/serde/ser/block/entry/mod.rs deleted file mode 100644 index 7335e721..00000000 --- a/core/src/sql/v2/value/serde/ser/block/entry/mod.rs +++ /dev/null @@ -1,157 +0,0 @@ -pub mod vec; - -use crate::err::Error; -use crate::sql::block::Entry; -use crate::sql::value::serde::ser; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Entry; - 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 `Entry`"; - - #[inline] - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - match variant { - "Value" => Ok(Entry::Value(value.serialize(ser::value::Serializer.wrap())?)), - "Set" => Ok(Entry::Set(value.serialize(ser::statement::set::Serializer.wrap())?)), - "Throw" => Ok(Entry::Throw(value.serialize(ser::statement::throw::Serializer.wrap())?)), - "Break" => { - Ok(Entry::Break(value.serialize(ser::statement::r#break::Serializer.wrap())?)) - } - "Ifelse" => { - Ok(Entry::Ifelse(value.serialize(ser::statement::ifelse::Serializer.wrap())?)) - } - "Select" => { - Ok(Entry::Select(value.serialize(ser::statement::select::Serializer.wrap())?)) - } - "Create" => { - Ok(Entry::Create(value.serialize(ser::statement::create::Serializer.wrap())?)) - } - "Update" => { - Ok(Entry::Update(value.serialize(ser::statement::update::Serializer.wrap())?)) - } - "Delete" => { - Ok(Entry::Delete(value.serialize(ser::statement::delete::Serializer.wrap())?)) - } - "Relate" => { - Ok(Entry::Relate(value.serialize(ser::statement::relate::Serializer.wrap())?)) - } - "Insert" => { - Ok(Entry::Insert(value.serialize(ser::statement::insert::Serializer.wrap())?)) - } - "Output" => { - Ok(Entry::Output(value.serialize(ser::statement::output::Serializer.wrap())?)) - } - "Define" => { - Ok(Entry::Define(value.serialize(ser::statement::define::Serializer.wrap())?)) - } - "Remove" => { - Ok(Entry::Remove(value.serialize(ser::statement::remove::Serializer.wrap())?)) - } - "Continue" => { - Ok(Entry::Continue(value.serialize(ser::statement::r#continue::Serializer.wrap())?)) - } - variant => Err(Error::custom(format!("unexpected variant `{name}::{variant}`"))), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - use serde::Serialize; - - #[test] - fn value() { - let entry = Entry::Value(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn set() { - let entry = Entry::Set(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn ifelse() { - let entry = Entry::Ifelse(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn select() { - let entry = Entry::Select(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn create() { - let entry = Entry::Create(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn update() { - let entry = Entry::Update(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn delete() { - let entry = Entry::Delete(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn relate() { - let entry = Entry::Relate(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn insert() { - let entry = Entry::Insert(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } - - #[test] - fn output() { - let entry = Entry::Output(Default::default()); - let serialized = entry.serialize(Serializer.wrap()).unwrap(); - assert_eq!(entry, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/block/entry/vec.rs b/core/src/sql/v2/value/serde/ser/block/entry/vec.rs deleted file mode 100644 index 3256ee74..00000000 --- a/core/src/sql/v2/value/serde/ser/block/entry/vec.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::err::Error; -use crate::sql::block::Entry; -use crate::sql::value::serde::ser; -use ser::Serializer as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeEntryVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "a `Vec`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeEntryVec(Vec::with_capacity(len.unwrap_or_default()))) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self.wrap()) - } -} - -pub struct SerializeEntryVec(Vec); - -impl serde::ser::SerializeSeq for SerializeEntryVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(value.serialize(super::Serializer.wrap())?); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn empty() { - let vec: Vec = Vec::new(); - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } - - #[test] - fn vec() { - let vec = vec![Entry::Value(Default::default())]; - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/block/mod.rs b/core/src/sql/v2/value/serde/ser/block/mod.rs deleted file mode 100644 index 10d38b95..00000000 --- a/core/src/sql/v2/value/serde/ser/block/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(super) mod entry; diff --git a/core/src/sql/v2/value/serde/ser/cast/mod.rs b/core/src/sql/v2/value/serde/ser/cast/mod.rs deleted file mode 100644 index 2b8b52c3..00000000 --- a/core/src/sql/v2/value/serde/ser/cast/mod.rs +++ /dev/null @@ -1,85 +0,0 @@ -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; - type SerializeTuple = Impossible; - type SerializeTupleStruct = SerializeCast; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "an struct `Cast`"; - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeCast::default()) - } -} - -#[derive(Default)] -pub(super) struct SerializeCast { - index: usize, - kind: Option, - value: Option, -} - -impl serde::ser::SerializeTupleStruct for SerializeCast { - type Ok = Cast; - type Error = Error; - - fn serialize_field(&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 { - 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); - } -} diff --git a/core/src/sql/v2/value/serde/ser/changefeed/mod.rs b/core/src/sql/v2/value/serde/ser/changefeed/mod.rs deleted file mode 100644 index 8a0f5835..00000000 --- a/core/src/sql/v2/value/serde/ser/changefeed/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -pub(super) mod opt; - -use crate::err::Error; -use crate::sql::changefeed::ChangeFeed; -use crate::sql::value::serde::ser; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; -use std::time::Duration; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = ChangeFeed; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeChangeFeed; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `ChangeFeed`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeChangeFeed::default()) - } -} - -#[derive(Default)] -pub struct SerializeChangeFeed { - expiry: Duration, - store_original: bool, -} - -impl serde::ser::SerializeStruct for SerializeChangeFeed { - type Ok = ChangeFeed; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "expiry" => { - self.expiry = value.serialize(ser::duration::Serializer.wrap())?; - } - "store_original" => { - self.store_original = value.serialize(ser::primitive::bool::Serializer.wrap())?; - } - key => { - return Err(Error::custom(format!("unexpected field `ChangeFeed::{key}`"))); - } - } - Ok(()) - } - - fn end(self) -> Result { - Ok(ChangeFeed { - expiry: self.expiry, - store_original: self.store_original, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let stmt = ChangeFeed::default(); - let value: ChangeFeed = stmt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(value, stmt); - } -} diff --git a/core/src/sql/v2/value/serde/ser/changefeed/opt.rs b/core/src/sql/v2/value/serde/ser/changefeed/opt.rs deleted file mode 100644 index 711e32f2..00000000 --- a/core/src/sql/v2/value/serde/ser/changefeed/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::changefeed::ChangeFeed; -use crate::sql::value::serde::ser; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Option`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(value.serialize(super::Serializer.wrap())?)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(ChangeFeed::default()); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/cond/mod.rs b/core/src/sql/v2/value/serde/ser/cond/mod.rs deleted file mode 100644 index 0db91d8e..00000000 --- a/core/src/sql/v2/value/serde/ser/cond/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(super) mod opt; diff --git a/core/src/sql/v2/value/serde/ser/cond/opt.rs b/core/src/sql/v2/value/serde/ser/cond/opt.rs deleted file mode 100644 index 3ab454a5..00000000 --- a/core/src/sql/v2/value/serde/ser/cond/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Cond; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Option`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(Cond(value.serialize(ser::value::Serializer.wrap())?))) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(Cond::default()); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/constant/mod.rs b/core/src/sql/v2/value/serde/ser/constant/mod.rs deleted file mode 100644 index 73d72f95..00000000 --- a/core/src/sql/v2/value/serde/ser/constant/mod.rs +++ /dev/null @@ -1,193 +0,0 @@ -use crate::err::Error; -use crate::sql::constant::Constant; -use crate::sql::value::serde::ser; -use serde::ser::Error as _; -use serde::ser::Impossible; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Constant; - 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 `Constant`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "MathE" => Ok(Constant::MathE), - "MathFrac1Pi" => Ok(Constant::MathFrac1Pi), - "MathFrac1Sqrt2" => Ok(Constant::MathFrac1Sqrt2), - "MathFrac2Pi" => Ok(Constant::MathFrac2Pi), - "MathFrac2SqrtPi" => Ok(Constant::MathFrac2SqrtPi), - "MathFracPi2" => Ok(Constant::MathFracPi2), - "MathFracPi3" => Ok(Constant::MathFracPi3), - "MathFracPi4" => Ok(Constant::MathFracPi4), - "MathFracPi6" => Ok(Constant::MathFracPi6), - "MathFracPi8" => Ok(Constant::MathFracPi8), - "MathLn10" => Ok(Constant::MathLn10), - "MathLn2" => Ok(Constant::MathLn2), - "MathLog102" => Ok(Constant::MathLog102), - "MathLog10E" => Ok(Constant::MathLog10E), - "MathLog210" => Ok(Constant::MathLog210), - "MathLog2E" => Ok(Constant::MathLog2E), - "MathPi" => Ok(Constant::MathPi), - "MathSqrt2" => Ok(Constant::MathSqrt2), - "MathTau" => Ok(Constant::MathTau), - variant => Err(Error::custom(format!("unknown variant `{name}::{variant}`"))), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - use serde::Serialize; - - #[test] - fn math_e() { - let constant = Constant::MathE; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_1pi() { - let constant = Constant::MathFrac1Pi; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_1sqrt2() { - let constant = Constant::MathFrac1Sqrt2; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_2pi() { - let constant = Constant::MathFrac2Pi; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_2sqrt_pi() { - let constant = Constant::MathFrac2SqrtPi; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_pi2() { - let constant = Constant::MathFracPi2; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_pi3() { - let constant = Constant::MathFracPi3; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_pi4() { - let constant = Constant::MathFracPi4; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_pi6() { - let constant = Constant::MathFracPi6; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_frac_pi8() { - let constant = Constant::MathFracPi8; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_ln10() { - let constant = Constant::MathLn10; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_ln2() { - let constant = Constant::MathLn2; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_log102() { - let constant = Constant::MathLog102; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_log10_e() { - let constant = Constant::MathLog10E; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_log210() { - let constant = Constant::MathLog210; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_log2_e() { - let constant = Constant::MathLog2E; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_pi() { - let constant = Constant::MathPi; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_sqrt2() { - let constant = Constant::MathSqrt2; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } - - #[test] - fn math_tau() { - let constant = Constant::MathTau; - let serialized = constant.serialize(Serializer.wrap()).unwrap(); - assert_eq!(constant, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/data/mod.rs b/core/src/sql/v2/value/serde/ser/data/mod.rs deleted file mode 100644 index 2a1d4548..00000000 --- a/core/src/sql/v2/value/serde/ser/data/mod.rs +++ /dev/null @@ -1,457 +0,0 @@ -pub(super) mod opt; - -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Data; -use crate::sql::Idiom; -use crate::sql::Operator; -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 = Data; - 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 `Data`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "EmptyExpression" => Ok(Data::EmptyExpression), - variant => Err(Error::custom(format!("unexpected unit variant `{name}::{variant}`"))), - } - } - - #[inline] - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - match variant { - "SetExpression" => { - Ok(Data::SetExpression(value.serialize(IdiomOperatorValueVecSerializer.wrap())?)) - } - "UnsetExpression" => { - Ok(Data::UnsetExpression(value.serialize(IdiomVecSerializer.wrap())?)) - } - "PatchExpression" => { - Ok(Data::PatchExpression(value.serialize(ser::value::Serializer.wrap())?)) - } - "MergeExpression" => { - Ok(Data::MergeExpression(value.serialize(ser::value::Serializer.wrap())?)) - } - "ReplaceExpression" => { - Ok(Data::ReplaceExpression(value.serialize(ser::value::Serializer.wrap())?)) - } - "ContentExpression" => { - Ok(Data::ContentExpression(value.serialize(ser::value::Serializer.wrap())?)) - } - "SingleExpression" => { - Ok(Data::SingleExpression(value.serialize(ser::value::Serializer.wrap())?)) - } - "ValuesExpression" => { - Ok(Data::ValuesExpression(value.serialize(IdiomValueVecVecSerializer.wrap())?)) - } - "UpdateExpression" => { - Ok(Data::UpdateExpression(value.serialize(IdiomOperatorValueVecSerializer.wrap())?)) - } - variant => { - Err(Error::custom(format!("unexpected newtype variant `{name}::{variant}`"))) - } - } - } -} - -struct IdiomVecSerializer; - -impl ser::Serializer for IdiomVecSerializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeIdiomVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Vec`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeIdiomVec(Vec::with_capacity(len.unwrap_or_default()))) - } -} - -struct SerializeIdiomVec(Vec); - -impl serde::ser::SerializeSeq for SerializeIdiomVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(Idiom(value.serialize(ser::part::vec::Serializer.wrap())?)); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -type IdiomOperatorValueTuple = (Idiom, Operator, Value); - -struct IdiomOperatorValueVecSerializer; - -impl ser::Serializer for IdiomOperatorValueVecSerializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeIdiomOperatorValueVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `(Idiom, Operator, Value)`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeIdiomOperatorValueVec(Vec::with_capacity(len.unwrap_or_default()))) - } -} - -struct SerializeIdiomOperatorValueVec(Vec); - -impl serde::ser::SerializeSeq for SerializeIdiomOperatorValueVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(value.serialize(IdiomOperatorValueTupleSerializer.wrap())?); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -struct IdiomOperatorValueTupleSerializer; - -impl ser::Serializer for IdiomOperatorValueTupleSerializer { - type Ok = IdiomOperatorValueTuple; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = SerializeIdiomOperatorValueTuple; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "an `(Idiom, Operator, Value)`"; - - fn serialize_tuple(self, _len: usize) -> Result { - Ok(SerializeIdiomOperatorValueTuple::default()) - } -} - -#[derive(Default)] -struct SerializeIdiomOperatorValueTuple { - index: usize, - idiom: Option, - operator: Option, - value: Option, -} - -impl serde::ser::SerializeTuple for SerializeIdiomOperatorValueTuple { - type Ok = IdiomOperatorValueTuple; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - match self.index { - 0 => { - self.idiom = Some(Idiom(value.serialize(ser::part::vec::Serializer.wrap())?)); - } - 1 => { - self.operator = Some(value.serialize(ser::operator::Serializer.wrap())?); - } - 2 => { - self.value = Some(value.serialize(ser::value::Serializer.wrap())?); - } - index => { - return Err(Error::custom(format!( - "unexpected tuple index `{index}` for `(Idiom, Operator, Value)`" - ))); - } - } - self.index += 1; - Ok(()) - } - - fn end(self) -> Result { - match (self.idiom, self.operator, self.value) { - (Some(idiom), Some(operator), Some(value)) => Ok((idiom, operator, value)), - _ => Err(Error::custom("`(Idiom, Operator, Value)` missing required value(s)")), - } - } -} - -type IdiomValueTuple = (Idiom, Value); - -struct IdiomValueVecVecSerializer; - -impl ser::Serializer for IdiomValueVecVecSerializer { - type Ok = Vec>; - type Error = Error; - - type SerializeSeq = SerializeIdiomValueVecVec; - type SerializeTuple = Impossible>, Error>; - type SerializeTupleStruct = Impossible>, Error>; - type SerializeTupleVariant = Impossible>, Error>; - type SerializeMap = Impossible>, Error>; - type SerializeStruct = Impossible>, Error>; - type SerializeStructVariant = Impossible>, Error>; - - const EXPECTED: &'static str = "a `Vec>`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeIdiomValueVecVec(Vec::with_capacity(len.unwrap_or_default()))) - } -} - -struct SerializeIdiomValueVecVec(Vec>); - -impl serde::ser::SerializeSeq for SerializeIdiomValueVecVec { - type Ok = Vec>; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(value.serialize(IdiomValueVecSerializer.wrap())?); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -struct IdiomValueVecSerializer; - -impl ser::Serializer for IdiomValueVecSerializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeIdiomValueVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "a `Vec<(Idiom, Value)>`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeIdiomValueVec(Vec::with_capacity(len.unwrap_or_default()))) - } -} - -struct SerializeIdiomValueVec(Vec); - -impl serde::ser::SerializeSeq for SerializeIdiomValueVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(value.serialize(IdiomValueTupleSerializer.wrap())?); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -struct IdiomValueTupleSerializer; - -impl ser::Serializer for IdiomValueTupleSerializer { - type Ok = IdiomValueTuple; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = SerializeIdiomValueTuple; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "an `(Idiom, Value)`"; - - fn serialize_tuple(self, _len: usize) -> Result { - Ok(SerializeIdiomValueTuple::default()) - } -} - -#[derive(Default)] -struct SerializeIdiomValueTuple { - index: usize, - idiom: Option, - value: Option, -} - -impl serde::ser::SerializeTuple for SerializeIdiomValueTuple { - type Ok = IdiomValueTuple; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - match self.index { - 0 => { - self.idiom = Some(Idiom(value.serialize(ser::part::vec::Serializer.wrap())?)); - } - 1 => { - self.value = Some(value.serialize(ser::value::Serializer.wrap())?); - } - index => { - return Err(Error::custom(format!( - "unexpected tuple index `{index}` for `(Idiom, Value)`" - ))); - } - } - self.index += 1; - Ok(()) - } - - fn end(self) -> Result { - match (self.idiom, self.value) { - (Some(idiom), Some(value)) => Ok((idiom, value)), - _ => Err(Error::custom("`(Idiom, Value)` missing required value(s)")), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn empty_expression() { - let data = Data::EmptyExpression; - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn set_expression() { - let data = - Data::SetExpression(vec![(Default::default(), Default::default(), Default::default())]); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn unset_expression() { - let data = Data::UnsetExpression(vec![Default::default()]); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn patch_expression() { - let data = Data::PatchExpression(Default::default()); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn merge_expression() { - let data = Data::MergeExpression(Default::default()); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn replace_expression() { - let data = Data::ReplaceExpression(Default::default()); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn content_expression() { - let data = Data::ContentExpression(Default::default()); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn single_expression() { - let data = Data::SingleExpression(Default::default()); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn values_expression() { - let data = Data::ValuesExpression(vec![vec![(Default::default(), Default::default())]]); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } - - #[test] - fn update_expression() { - let data = Data::UpdateExpression(vec![( - Default::default(), - Default::default(), - Default::default(), - )]); - let serialized = data.serialize(Serializer.wrap()).unwrap(); - assert_eq!(data, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/data/opt.rs b/core/src/sql/v2/value/serde/ser/data/opt.rs deleted file mode 100644 index 5db2ed3e..00000000 --- a/core/src/sql/v2/value/serde/ser/data/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Data; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Option`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(value.serialize(super::Serializer.wrap())?)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(Data::default()); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/datetime/mod.rs b/core/src/sql/v2/value/serde/ser/datetime/mod.rs deleted file mode 100644 index 9c9a7c8c..00000000 --- a/core/src/sql/v2/value/serde/ser/datetime/mod.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use chrono::offset::Utc; -use chrono::DateTime; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::Serialize; -use std::fmt::Display; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = DateTime; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "a struct `DateTime`"; - - #[inline] - fn collect_str(self, value: &T) -> Result - where - T: Display + ?Sized, - { - value.to_string().parse().map_err(Error::custom) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self.wrap()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn now() { - let dt = Utc::now(); - let serialized = dt.serialize(Serializer.wrap()).unwrap(); - assert_eq!(dt, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/decimal/mod.rs b/core/src/sql/v2/value/serde/ser/decimal/mod.rs deleted file mode 100644 index b240b510..00000000 --- a/core/src/sql/v2/value/serde/ser/decimal/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use rust_decimal::Decimal; -use serde::ser::Error as _; -use serde::ser::Impossible; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Decimal; - 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 = "a struct `Decimal`"; - - #[inline] - fn serialize_str(self, value: &str) -> Result { - value.parse::().map_err(Error::custom) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - use serde::Serialize; - - #[test] - fn from_i32() { - let decimal = Decimal::from(25); - let serialized = Serialize::serialize(&decimal, Serializer.wrap()).unwrap(); - assert_eq!(decimal, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/dir/mod.rs b/core/src/sql/v2/value/serde/ser/dir/mod.rs deleted file mode 100644 index 0b892f35..00000000 --- a/core/src/sql/v2/value/serde/ser/dir/mod.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Dir; -use serde::ser::Error as _; -use serde::ser::Impossible; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Dir; - 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 `Dir`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "In" => Ok(Dir::In), - "Out" => Ok(Dir::Out), - "Both" => Ok(Dir::Both), - variant => Err(Error::custom(format!("unexpected unit variant `{name}::{variant}`"))), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - use serde::Serialize; - - #[test] - fn r#in() { - let dir = Dir::In; - let serialized = dir.serialize(Serializer.wrap()).unwrap(); - assert_eq!(dir, serialized); - } - - #[test] - fn out() { - let dir = Dir::Out; - let serialized = dir.serialize(Serializer.wrap()).unwrap(); - assert_eq!(dir, serialized); - } - - #[test] - fn both() { - let dir = Dir::Both; - let serialized = dir.serialize(Serializer.wrap()).unwrap(); - assert_eq!(dir, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/distance/mod.rs b/core/src/sql/v2/value/serde/ser/distance/mod.rs deleted file mode 100644 index 0dd0f243..00000000 --- a/core/src/sql/v2/value/serde/ser/distance/mod.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::err::Error; -use crate::sql::index::Distance; -use crate::sql::value::serde::ser; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::Serialize; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Distance; - 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 `Distance`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "Chebyshev" => Ok(Distance::Chebyshev), - "Cosine" => Ok(Distance::Cosine), - "Euclidean" => Ok(Distance::Euclidean), - "Hamming" => Ok(Distance::Hamming), - "Jaccard" => Ok(Distance::Jaccard), - "Manhattan" => Ok(Distance::Manhattan), - "Pearson" => Ok(Distance::Pearson), - variant => Err(Error::custom(format!("unexpected unit variant `{name}::{variant}`"))), - } - } - - #[inline] - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - match variant { - "Minkowski" => { - Ok(Distance::Minkowski(value.serialize(ser::number::Serializer.wrap())?)) - } - variant => { - Err(Error::custom(format!("unexpected newtype variant `{name}::{variant}`"))) - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sql::value::serde::ser::Serializer; - - #[test] - fn distance_euclidean() { - for dist in [ - Distance::Chebyshev, - Distance::Cosine, - Distance::Euclidean, - Distance::Jaccard, - Distance::Hamming, - Distance::Manhattan, - Distance::Minkowski(7.into()), - Distance::Pearson, - ] { - let serialized = dist.serialize(Serializer.wrap()).unwrap(); - assert_eq!(dist, serialized, "{}", dist); - } - } -} diff --git a/core/src/sql/v2/value/serde/ser/duration/mod.rs b/core/src/sql/v2/value/serde/ser/duration/mod.rs deleted file mode 100644 index 868d5f96..00000000 --- a/core/src/sql/v2/value/serde/ser/duration/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -pub(super) mod opt; - -use crate::err::Error; -use crate::sql::value::serde::ser; -use ser::Serializer as _; -use serde::ser::Error as _; -use serde::ser::Impossible; -use serde::ser::Serialize; -use std::time::Duration; - -pub(super) struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Duration; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeDuration; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `Duration`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeDuration::default()) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self.wrap()) - } -} - -#[derive(Default)] -pub(super) struct SerializeDuration { - secs: Option, - nanos: Option, -} - -impl serde::ser::SerializeStruct for SerializeDuration { - type Ok = Duration; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "secs" => { - self.secs = Some(value.serialize(ser::primitive::u64::Serializer.wrap())?); - } - "nanos" => { - self.nanos = Some(value.serialize(ser::primitive::u32::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!("unexpected field `Duration::{key}`"))); - } - } - Ok(()) - } - - fn end(self) -> Result { - match (self.secs, self.nanos) { - (Some(secs), Some(nanos)) => Ok(Duration::new(secs, nanos)), - _ => Err(Error::custom("`Duration` missing required field(s)")), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use serde::Serialize; - - #[test] - fn default() { - let duration = Duration::default(); - let serialized = duration.serialize(Serializer.wrap()).unwrap(); - assert_eq!(duration, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/duration/opt.rs b/core/src/sql/v2/value/serde/ser/duration/opt.rs deleted file mode 100644 index 1d063e0d..00000000 --- a/core/src/sql/v2/value/serde/ser/duration/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use serde::ser::Impossible; -use serde::ser::Serialize; -use std::time::Duration; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Option`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(value.serialize(super::Serializer.wrap())?)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(Duration::default()); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/edges/mod.rs b/core/src/sql/v2/value/serde/ser/edges/mod.rs deleted file mode 100644 index d234d8c4..00000000 --- a/core/src/sql/v2/value/serde/ser/edges/mod.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Dir; -use crate::sql::Edges; -use crate::sql::Tables; -use crate::sql::Thing; -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 = Edges; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = SerializeEdges; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `Edges`"; - - #[inline] - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeEdges::default()) - } -} - -#[derive(Default)] -pub(super) struct SerializeEdges { - dir: Option, - from: Option, - what: Option, -} - -impl serde::ser::SerializeStruct for SerializeEdges { - type Ok = Edges; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "dir" => { - self.dir = Some(value.serialize(ser::dir::Serializer.wrap())?); - } - "from" => { - self.from = Some(value.serialize(ser::thing::Serializer.wrap())?); - } - "what" => { - self.what = Some(Tables(value.serialize(ser::table::vec::Serializer.wrap())?)); - } - key => { - return Err(Error::custom(format!("unexpected field `Edges::{key}`"))); - } - } - Ok(()) - } - - fn end(self) -> Result { - match (self.dir, self.from, self.what) { - (Some(dir), Some(from), Some(what)) => Ok(Edges { - dir, - from, - what, - }), - _ => Err(Error::custom("`Edges` missing required field(s)")), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sql::thing; - use serde::Serialize; - - #[test] - fn edges() { - let edges = Edges { - dir: Dir::Both, - from: thing("foo:bar").unwrap(), - what: Tables(Vec::new()), - }; - let serialized = edges.serialize(Serializer.wrap()).unwrap(); - assert_eq!(edges, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/explain/mod.rs b/core/src/sql/v2/value/serde/ser/explain/mod.rs deleted file mode 100644 index 0db91d8e..00000000 --- a/core/src/sql/v2/value/serde/ser/explain/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(super) mod opt; diff --git a/core/src/sql/v2/value/serde/ser/explain/opt.rs b/core/src/sql/v2/value/serde/ser/explain/opt.rs deleted file mode 100644 index 0218b9e3..00000000 --- a/core/src/sql/v2/value/serde/ser/explain/opt.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Explain; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Option`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self.wrap()) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(Explain(value.serialize(ser::primitive::bool::Serializer.wrap())?))) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some_default() { - let option = Some(Explain::default()); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some_full() { - let option = Some(Explain(true)); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/expression/mod.rs b/core/src/sql/v2/value/serde/ser/expression/mod.rs deleted file mode 100644 index 391913e6..00000000 --- a/core/src/sql/v2/value/serde/ser/expression/mod.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Expression; -use crate::sql::Operator; -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 = Expression; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = SerializeExpression; - - const EXPECTED: &'static str = "an enum `Expression`"; - - #[inline] - fn serialize_struct_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result { - debug_assert_eq!(name, crate::sql::expression::TOKEN); - match variant { - "Unary" => Ok(SerializeExpression::Unary(Default::default())), - "Binary" => Ok(SerializeExpression::Binary(Default::default())), - _ => Err(Error::custom(format!("unexpected `Expression::{name}`"))), - } - } -} - -pub(super) enum SerializeExpression { - Unary(SerializeUnary), - Binary(SerializeBinary), -} - -impl serde::ser::SerializeStructVariant for SerializeExpression { - type Ok = Expression; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match self { - Self::Unary(unary) => unary.serialize_field(key, value), - Self::Binary(binary) => binary.serialize_field(key, value), - } - } - - fn end(self) -> Result { - match self { - Self::Unary(unary) => unary.end(), - Self::Binary(binary) => binary.end(), - } - } -} - -#[derive(Default)] -pub(super) struct SerializeUnary { - o: Option, - v: Option, -} - -impl serde::ser::SerializeStructVariant for SerializeUnary { - type Ok = Expression; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "o" => { - self.o = Some(value.serialize(ser::operator::Serializer.wrap())?); - } - "v" => { - self.v = Some(value.serialize(ser::value::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `Expression::Unary{{{key}}}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - match (self.o, self.v) { - (Some(o), Some(v)) => Ok(Expression::Unary { - o, - v, - }), - _ => Err(Error::custom("`Expression::Unary` missing required field(s)")), - } - } -} - -#[derive(Default)] -pub(super) struct SerializeBinary { - l: Option, - o: Option, - r: Option, -} - -impl serde::ser::SerializeStructVariant for SerializeBinary { - type Ok = Expression; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> - where - T: ?Sized + Serialize, - { - match key { - "l" => { - self.l = Some(value.serialize(ser::value::Serializer.wrap())?); - } - "o" => { - self.o = Some(value.serialize(ser::operator::Serializer.wrap())?); - } - "r" => { - self.r = Some(value.serialize(ser::value::Serializer.wrap())?); - } - key => { - return Err(Error::custom(format!( - "unexpected field `Expression::Binary{{{key}}}`" - ))); - } - } - Ok(()) - } - - fn end(self) -> Result { - match (self.l, self.o, self.r) { - (Some(l), Some(o), Some(r)) => Ok(Expression::Binary { - l, - o, - r, - }), - _ => Err(Error::custom("`Expression::Binary` missing required field(s)")), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use serde::Serialize; - - #[test] - fn default() { - let expression = Expression::default(); - let serialized = expression.serialize(Serializer.wrap()).unwrap(); - assert_eq!(expression, serialized); - } - - #[test] - fn unary() { - let expression = Expression::Unary { - o: Operator::Not, - v: "Bar".into(), - }; - let serialized = expression.serialize(Serializer.wrap()).unwrap(); - assert_eq!(expression, serialized); - } - - #[test] - fn foo_equals_bar() { - let expression = Expression::Binary { - l: "foo".into(), - o: Operator::Equal, - r: "Bar".into(), - }; - let serialized = expression.serialize(Serializer.wrap()).unwrap(); - assert_eq!(expression, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/fetch/mod.rs b/core/src/sql/v2/value/serde/ser/fetch/mod.rs deleted file mode 100644 index 5537a772..00000000 --- a/core/src/sql/v2/value/serde/ser/fetch/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(super) mod vec; diff --git a/core/src/sql/v2/value/serde/ser/fetch/vec/mod.rs b/core/src/sql/v2/value/serde/ser/fetch/vec/mod.rs deleted file mode 100644 index bd1862a0..00000000 --- a/core/src/sql/v2/value/serde/ser/fetch/vec/mod.rs +++ /dev/null @@ -1,80 +0,0 @@ -pub mod opt; - -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Fetch; -use crate::sql::Idiom; -use ser::Serializer as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeFetchVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "a `Vec`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeFetchVec(Vec::with_capacity(len.unwrap_or_default()))) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self.wrap()) - } -} - -pub struct SerializeFetchVec(Vec); - -impl serde::ser::SerializeSeq for SerializeFetchVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(Fetch(Idiom(value.serialize(ser::part::vec::Serializer.wrap())?))); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn empty() { - let vec: Vec = Vec::new(); - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } - - #[test] - fn vec() { - let vec = vec![Fetch::default()]; - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/fetch/vec/opt.rs b/core/src/sql/v2/value/serde/ser/fetch/vec/opt.rs deleted file mode 100644 index c8431a3f..00000000 --- a/core/src/sql/v2/value/serde/ser/fetch/vec/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Fetch; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option>; - type Error = Error; - - type SerializeSeq = Impossible>, Error>; - type SerializeTuple = Impossible>, Error>; - type SerializeTupleStruct = Impossible>, Error>; - type SerializeTupleVariant = Impossible>, Error>; - type SerializeMap = Impossible>, Error>; - type SerializeStruct = Impossible>, Error>; - type SerializeStructVariant = Impossible>, Error>; - - const EXPECTED: &'static str = "an `Option>`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(value.serialize(super::Serializer.wrap())?)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option> = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(vec![Fetch::default()]); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/fetchs/mod.rs b/core/src/sql/v2/value/serde/ser/fetchs/mod.rs deleted file mode 100644 index 0db91d8e..00000000 --- a/core/src/sql/v2/value/serde/ser/fetchs/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(super) mod opt; diff --git a/core/src/sql/v2/value/serde/ser/fetchs/opt.rs b/core/src/sql/v2/value/serde/ser/fetchs/opt.rs deleted file mode 100644 index 2292e569..00000000 --- a/core/src/sql/v2/value/serde/ser/fetchs/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Fetchs; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option; - type Error = Error; - - type SerializeSeq = Impossible, Error>; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "an `Option`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(Fetchs(value.serialize(ser::fetch::vec::Serializer.wrap())?))) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(Fetchs::default()); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/field/mod.rs b/core/src/sql/v2/value/serde/ser/field/mod.rs deleted file mode 100644 index 2b8972b2..00000000 --- a/core/src/sql/v2/value/serde/ser/field/mod.rs +++ /dev/null @@ -1,156 +0,0 @@ -pub(super) mod vec; - -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Field; -use crate::sql::Idiom; -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 = Field; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = SerializeValueIdiomTuple; - - const EXPECTED: &'static str = "an enum `Field`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "All" => Ok(Field::All), - variant => Err(Error::custom(format!("unexpected unit variant `{name}::{variant}`"))), - } - } - - fn serialize_struct_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result { - match variant { - "Single" => Ok(SerializeValueIdiomTuple::default()), - variant => Err(Error::custom(format!("unexpected struct variant `{name}::{variant}`"))), - } - } -} - -#[derive(Default)] -pub(super) struct SerializeValueIdiomTuple { - value: Option, - idiom: Option>, -} - -impl serde::ser::SerializeStructVariant for SerializeValueIdiomTuple { - type Ok = Field; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - match key { - "expr" => { - self.value = Some(value.serialize(ser::value::Serializer.wrap())?); - } - "alias" => { - self.idiom = Some(value.serialize(SerializeOptionIdiom.wrap())?); - } - key => { - return Err(Error::custom(format!("unexpected `Field::Single` field `{key}`"))); - } - } - Ok(()) - } - - fn end(self) -> Result { - match (self.value, self.idiom) { - (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::*; - use serde::Serialize; - - #[test] - fn all() { - let field = Field::All; - let serialized = field.serialize(Serializer.wrap()).unwrap(); - assert_eq!(field, serialized); - } - - #[test] - fn alone() { - 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::Single { - expr: Default::default(), - alias: Some(Default::default()), - }; - let serialized = field.serialize(Serializer.wrap()).unwrap(); - assert_eq!(field, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/field/vec.rs b/core/src/sql/v2/value/serde/ser/field/vec.rs deleted file mode 100644 index 65216f7a..00000000 --- a/core/src/sql/v2/value/serde/ser/field/vec.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Field; -use ser::Serializer as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeFieldVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "a `Vec`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeFieldVec(Vec::with_capacity(len.unwrap_or_default()))) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self.wrap()) - } -} - -pub struct SerializeFieldVec(Vec); - -impl serde::ser::SerializeSeq for SerializeFieldVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(value.serialize(ser::field::Serializer.wrap())?); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn empty() { - let vec: Vec = Vec::new(); - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } - - #[test] - fn vec() { - let vec = vec![Field::default()]; - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/fields/mod.rs b/core/src/sql/v2/value/serde/ser/fields/mod.rs deleted file mode 100644 index 72cdfb26..00000000 --- a/core/src/sql/v2/value/serde/ser/fields/mod.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Field; -use crate::sql::Fields; -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 = Fields; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = SerializeFields; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "a struct `Fields`"; - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeFields::default()) - } -} - -#[derive(Default)] -pub(super) struct SerializeFields { - index: usize, - fields: Option>, - boolean: Option, -} - -impl serde::ser::SerializeTupleStruct for SerializeFields { - type Ok = Fields; - type Error = Error; - - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - match self.index { - 0 => { - self.fields = Some(value.serialize(ser::field::vec::Serializer.wrap())?); - } - 1 => { - self.boolean = Some(value.serialize(ser::primitive::bool::Serializer.wrap())?); - } - index => { - return Err(Error::custom(format!("unexpected `Fields` index `{index}`"))); - } - } - self.index += 1; - Ok(()) - } - - fn end(self) -> Result { - match (self.fields, self.boolean) { - (Some(fields), Some(boolean)) => Ok(Fields(fields, boolean)), - _ => Err(Error::custom("`Fields` missing required value(s)")), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default() { - let fields = Fields::default(); - let serialized = fields.serialize(Serializer.wrap()).unwrap(); - assert_eq!(fields, serialized); - } - - #[test] - fn all() { - let fields = Fields(vec![Field::All], true); - let serialized = fields.serialize(Serializer.wrap()).unwrap(); - assert_eq!(fields, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/filter/mod.rs b/core/src/sql/v2/value/serde/ser/filter/mod.rs deleted file mode 100644 index 07bc3edd..00000000 --- a/core/src/sql/v2/value/serde/ser/filter/mod.rs +++ /dev/null @@ -1,154 +0,0 @@ -pub(super) mod vec; - -use crate::err::Error; -use crate::sql::filter::Filter; -use crate::sql::value::serde::ser; -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 = Filter; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = SerializeFilter; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "an enum `Filter`"; - - #[inline] - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - match variant { - "Ascii" => Ok(Filter::Ascii), - "Lowercase" => Ok(Filter::Lowercase), - "Uppercase" => Ok(Filter::Uppercase), - variant => Err(Error::custom(format!("unexpected unit variant `{name}::{variant}`"))), - } - } - - #[inline] - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - match variant { - "Snowball" => Ok(Filter::Snowball(value.serialize(ser::language::Serializer.wrap())?)), - variant => { - Err(Error::custom(format!("unexpected newtype variant `{name}::{variant}`"))) - } - } - } - - fn serialize_tuple_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result { - let inner = match variant { - "EdgeNgram" => Inner::EdgeNgram(Default::default(), Default::default()), - "Ngram" => Inner::Ngram(Default::default(), Default::default()), - variant => { - return Err(Error::custom(format!("unexpected tuple variant `{name}::{variant}`"))); - } - }; - Ok(SerializeFilter { - inner, - index: 0, - }) - } -} - -pub(super) struct SerializeFilter { - index: usize, - inner: Inner, -} - -enum Inner { - EdgeNgram(u16, u16), - Ngram(u16, u16), -} - -impl serde::ser::SerializeTupleVariant for SerializeFilter { - type Ok = Filter; - type Error = Error; - - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - match (self.index, &mut self.inner) { - (0, Inner::EdgeNgram(ref mut var, _) | Inner::Ngram(ref mut var, _)) => { - *var = value.serialize(ser::primitive::u16::Serializer.wrap())?; - } - (1, Inner::EdgeNgram(_, ref mut var) | Inner::Ngram(_, ref mut var)) => { - *var = value.serialize(ser::primitive::u16::Serializer.wrap())?; - } - (index, inner) => { - let variant = match inner { - Inner::EdgeNgram(..) => "EdgeNgram", - Inner::Ngram(..) => "Ngram", - }; - return Err(Error::custom(format!( - "unexpected `Filter::{variant}` index `{index}`" - ))); - } - } - self.index += 1; - Ok(()) - } - - fn end(self) -> Result { - match self.inner { - Inner::EdgeNgram(one, two) => Ok(Filter::EdgeNgram(one, two)), - Inner::Ngram(one, two) => Ok(Filter::Ngram(one, two)), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sql::language::Language; - - #[test] - fn ascii() { - let filter = Filter::Ascii; - let serialized = filter.serialize(Serializer.wrap()).unwrap(); - assert_eq!(filter, serialized); - } - - #[test] - fn lowercase() { - let filter = Filter::Lowercase; - let serialized = filter.serialize(Serializer.wrap()).unwrap(); - assert_eq!(filter, serialized); - } - - #[test] - fn snowball() { - let filter = Filter::Snowball(Language::English); - let serialized = filter.serialize(Serializer.wrap()).unwrap(); - assert_eq!(filter, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/filter/vec/mod.rs b/core/src/sql/v2/value/serde/ser/filter/vec/mod.rs deleted file mode 100644 index 4806b734..00000000 --- a/core/src/sql/v2/value/serde/ser/filter/vec/mod.rs +++ /dev/null @@ -1,79 +0,0 @@ -pub mod opt; - -use crate::err::Error; -use crate::sql::filter::Filter; -use crate::sql::value::serde::ser; -use ser::Serializer as _; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Vec; - type Error = Error; - - type SerializeSeq = SerializeFilterVec; - type SerializeTuple = Impossible, Error>; - type SerializeTupleStruct = Impossible, Error>; - type SerializeTupleVariant = Impossible, Error>; - type SerializeMap = Impossible, Error>; - type SerializeStruct = Impossible, Error>; - type SerializeStructVariant = Impossible, Error>; - - const EXPECTED: &'static str = "a `Vec`"; - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeFilterVec(Vec::with_capacity(len.unwrap_or_default()))) - } - - #[inline] - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self.wrap()) - } -} - -pub struct SerializeFilterVec(Vec); - -impl serde::ser::SerializeSeq for SerializeFilterVec { - type Ok = Vec; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize + ?Sized, - { - self.0.push(value.serialize(super::Serializer.wrap())?); - Ok(()) - } - - fn end(self) -> Result { - Ok(self.0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn empty() { - let vec: Vec = Vec::new(); - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } - - #[test] - fn vec() { - let vec = vec![Filter::Ascii]; - let serialized = vec.serialize(Serializer.wrap()).unwrap(); - assert_eq!(vec, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/filter/vec/opt.rs b/core/src/sql/v2/value/serde/ser/filter/vec/opt.rs deleted file mode 100644 index 1c015fa6..00000000 --- a/core/src/sql/v2/value/serde/ser/filter/vec/opt.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::err::Error; -use crate::sql::filter::Filter; -use crate::sql::value::serde::ser; -use serde::ser::Impossible; -use serde::ser::Serialize; - -pub struct Serializer; - -impl ser::Serializer for Serializer { - type Ok = Option>; - type Error = Error; - - type SerializeSeq = Impossible>, Error>; - type SerializeTuple = Impossible>, Error>; - type SerializeTupleStruct = Impossible>, Error>; - type SerializeTupleVariant = Impossible>, Error>; - type SerializeMap = Impossible>, Error>; - type SerializeStruct = Impossible>, Error>; - type SerializeStructVariant = Impossible>, Error>; - - const EXPECTED: &'static str = "an `Option>`"; - - #[inline] - fn serialize_none(self) -> Result { - Ok(None) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - Ok(Some(value.serialize(super::Serializer.wrap())?)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ser::Serializer as _; - - #[test] - fn none() { - let option: Option> = None; - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } - - #[test] - fn some() { - let option = Some(vec![Filter::Ascii]); - let serialized = option.serialize(Serializer.wrap()).unwrap(); - assert_eq!(option, serialized); - } -} diff --git a/core/src/sql/v2/value/serde/ser/function/mod.rs b/core/src/sql/v2/value/serde/ser/function/mod.rs deleted file mode 100644 index 55a478ab..00000000 --- a/core/src/sql/v2/value/serde/ser/function/mod.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::err::Error; -use crate::sql::value::serde::ser; -use crate::sql::Function; -use crate::sql::Script; -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 = Function; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = SerializeFunction; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - const EXPECTED: &'static str = "an enum `Function`"; - - fn serialize_tuple_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result { - let inner = match variant { - "Normal" => Inner::Normal(None, None), - "Custom" => Inner::Custom(None, None), - "Script" => Inner::Script(None, None), - variant => { - return Err(Error::custom(format!("unexpected tuple variant `{name}::{variant}`"))); - } - }; - Ok(SerializeFunction { - inner, - index: 0, - }) - } -} - -pub(super) struct SerializeFunction { - index: usize, - inner: Inner, -} - -enum Inner { - Normal(Option, Option>), - Custom(Option, Option>), - Script(Option