Continue with initial code
This commit is contained in:
parent
ab0014ad02
commit
5d57c105b9
109 changed files with 4224 additions and 1814 deletions
Cargo.lockCargo.toml
app
src
cli
ctx
dbs
doc
err
fnc
kvs
lib.rsmain.rssql
algorithm.rsarray.rsbase.rscommon.rscond.rsdata.rsdatetime.rsdefinition.rsduration.rsexpression.rsfetch.rsfield.rsfilter.rsfunction.rsgroup.rsident.rsidiom.rskind.rslimit.rsliteral.rsmod.rsmodel.rsnumber.rsobject.rsoperator.rsorder.rsoutput.rsparam.rsparser.rspermission.rspoint.rspolygon.rsquery.rsregex.rssplit.rsstart.rsstatement.rs
statements
begin.rscancel.rscommit.rscreate.rsdefine.rsdelete.rsifelse.rsinfo.rsinsert.rskill.rslive.rsoption.rsoutput.rsrelate.rsremove.rsselect.rsset.rsupdate.rsupsert.rsyuse.rs
strand.rssubquery.rstable.rsthing.rs
1289
Cargo.lock
generated
1289
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
45
Cargo.toml
45
Cargo.toml
|
@ -5,56 +5,57 @@ edition = "2018"
|
|||
version = "0.0.0"
|
||||
authors = ["Tobie Morgan Hitchcock <tobie@surrealdb.com>"]
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.1"
|
||||
failure = "0.1.8"
|
||||
futures = "0.3.5"
|
||||
log = "0.4.8"
|
||||
maplit = "1.0.2"
|
||||
nom = "5.1.2"
|
||||
regex = "1.3.9"
|
||||
http = "0.2"
|
||||
bytes = "0.5.5"
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies.ctx]
|
||||
version = "0.2.0"
|
||||
package = "io-context"
|
||||
[dependencies]
|
||||
anyhow = "1.0.40"
|
||||
bytes = "1.0.1"
|
||||
clap = "2.33.3"
|
||||
futures = "0.3.13"
|
||||
http = "0.2.3"
|
||||
log = "0.4.14"
|
||||
maplit = "1.0.2"
|
||||
nom = "6.1.2"
|
||||
regex = "1.4.5"
|
||||
thiserror = "1.0.24"
|
||||
wasm-bindgen = "0.2.72"
|
||||
xid = "1.0.0"
|
||||
|
||||
[dependencies.dec]
|
||||
version = "1.6.0"
|
||||
version = "1.10.3"
|
||||
package = "rust_decimal"
|
||||
features = ["serde-float"]
|
||||
|
||||
[dependencies.fern]
|
||||
version = "0.6.0"
|
||||
features = ["colored"]
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
features = ["serde", "v4"]
|
||||
|
||||
[dependencies.warp]
|
||||
version = "0.2.3"
|
||||
version = "0.3.1"
|
||||
features = ["compression", "websocket"]
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "0.2"
|
||||
version = "1.4.0"
|
||||
features = ["macros"]
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.10.6"
|
||||
version = "0.11.2"
|
||||
features = ["blocking"]
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "0.4.11"
|
||||
version = "0.4.19"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.111"
|
||||
version = "1.0.125"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.serde_cbor]
|
||||
version = "0.11.1"
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "1.0.55"
|
||||
version = "1.0.64"
|
||||
|
|
1
app/index.html
Normal file
1
app/index.html
Normal file
|
@ -0,0 +1 @@
|
|||
<meta http-equiv="refresh" content="0;url=https://app.surrealdb.com/" />
|
|
@ -1,7 +1,7 @@
|
|||
use reqwest::header::CONTENT_TYPE;
|
||||
use anyhow::Error;
|
||||
use reqwest::blocking::Body;
|
||||
use reqwest::blocking::Client;
|
||||
use failure::Error;
|
||||
use reqwest::header::CONTENT_TYPE;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::copy;
|
||||
|
||||
|
@ -38,11 +38,7 @@ pub fn init(matches: &clap::ArgMatches) -> Result<(), Error> {
|
|||
fn backup_file_to_file(_: &clap::ArgMatches, from: &str, into: &str) -> Result<(), Error> {
|
||||
let mut from = OpenOptions::new().read(true).open(from)?;
|
||||
|
||||
let mut into = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(into)?;
|
||||
let mut into = OpenOptions::new().write(true).create(true).truncate(true).open(into)?;
|
||||
|
||||
copy(&mut from, &mut into)?;
|
||||
|
||||
|
@ -63,11 +59,7 @@ fn backup_http_to_file(matches: &clap::ArgMatches, from: &str, into: &str) -> Re
|
|||
.send()?
|
||||
.error_for_status()?;
|
||||
|
||||
let mut into = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(into)?;
|
||||
let mut into = OpenOptions::new().write(true).create(true).truncate(true).open(into)?;
|
||||
|
||||
copy(&mut from, &mut into)?;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use reqwest::header::CONTENT_TYPE;
|
||||
use anyhow::Error;
|
||||
use reqwest::blocking::Client;
|
||||
use failure::Error;
|
||||
use reqwest::header::CONTENT_TYPE;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::copy;
|
||||
|
||||
|
@ -15,11 +15,7 @@ pub fn init(matches: &clap::ArgMatches) -> Result<(), Error> {
|
|||
// and if there is a problem opening
|
||||
// the file, then return an error.
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(file)?;
|
||||
let mut file = OpenOptions::new().write(true).create(true).truncate(true).open(file)?;
|
||||
|
||||
// Parse all other cli arguments
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use reqwest::header::CONTENT_TYPE;
|
||||
use anyhow::Error;
|
||||
use reqwest::blocking::Client;
|
||||
use failure::Error;
|
||||
use reqwest::header::CONTENT_TYPE;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::prelude::*;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extern crate std;
|
||||
extern crate log;
|
||||
extern crate fern;
|
||||
extern crate chrono;
|
||||
extern crate fern;
|
||||
extern crate log;
|
||||
extern crate std;
|
||||
|
||||
use self::fern::colors::Color;
|
||||
use self::fern::colors::ColoredLevelConfig;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::kvs;
|
||||
use crate::web;
|
||||
use anyhow::Error;
|
||||
use clap;
|
||||
use failure::Error;
|
||||
|
||||
const LOGO: &'static str = "
|
||||
.d8888b. 888 8888888b. 888888b.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Error;
|
||||
use clap;
|
||||
use failure::Error;
|
||||
|
||||
const NAME: &'static str = env!("CARGO_PKG_NAME");
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
@ -15,13 +15,7 @@ pub fn init(_: &clap::ArgMatches) -> Result<(), Error> {
|
|||
|
||||
get_cfg!(target_arch: "x86", "x86_64", "mips", "powerpc", "powerpc64", "arm", "aarch64");
|
||||
|
||||
println!(
|
||||
"{} {} for {} on {}",
|
||||
NAME,
|
||||
VERSION,
|
||||
target_os(),
|
||||
target_arch()
|
||||
);
|
||||
println!("{} {} for {} on {}", NAME, VERSION, target_os(), target_arch());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
20
src/ctx/canceller.rs
Normal file
20
src/ctx/canceller.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Canceller {
|
||||
/// A reference to the canceled value of a context.
|
||||
cancelled: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Canceller {
|
||||
// Create a new Canceller
|
||||
pub fn new(cancelled: Arc<AtomicBool>) -> Canceller {
|
||||
Canceller {
|
||||
cancelled,
|
||||
}
|
||||
}
|
||||
// Cancel the context.
|
||||
pub fn cancel(self) {
|
||||
self.cancelled.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
177
src/ctx/context.rs
Normal file
177
src/ctx/context.rs
Normal file
|
@ -0,0 +1,177 @@
|
|||
use crate::ctx::canceller::Canceller;
|
||||
use crate::ctx::reason::Reason;
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub type Parent = Arc<Context>;
|
||||
|
||||
pub struct Context {
|
||||
// An optional parent context.
|
||||
parent: Option<Arc<Context>>,
|
||||
// An optional deadline.
|
||||
deadline: Option<Instant>,
|
||||
// Wether or not this context is cancelled.
|
||||
cancelled: Arc<AtomicBool>,
|
||||
// A collection of read only values stored in this context.
|
||||
values: Option<HashMap<&'static str, Box<dyn Any + Send + Sync>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
// Create an empty background context.
|
||||
pub fn background() -> Context {
|
||||
Context {
|
||||
values: None,
|
||||
parent: None,
|
||||
deadline: None,
|
||||
cancelled: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new child from a frozen context.
|
||||
pub fn new(parent: &Arc<Context>) -> Context {
|
||||
Context {
|
||||
values: None,
|
||||
parent: Some(Arc::clone(parent)),
|
||||
deadline: parent.deadline,
|
||||
cancelled: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
// Freeze the context so it can be used to create child contexts. The
|
||||
// parent context can no longer be modified once it has been frozen.
|
||||
pub fn freeze(mut self) -> Arc<Context> {
|
||||
if let Some(ref mut values) = self.values {
|
||||
values.shrink_to_fit();
|
||||
}
|
||||
Arc::new(self)
|
||||
}
|
||||
|
||||
// Add cancelation to the context. The value that is returned will cancel
|
||||
// the context and it's children once called.
|
||||
pub fn add_cancel(&mut self) -> Canceller {
|
||||
let cancelled = self.cancelled.clone();
|
||||
Canceller::new(cancelled)
|
||||
}
|
||||
|
||||
// Add a deadline to the context. If the current deadline is sooner than
|
||||
// the provided deadline, this method does nothing.
|
||||
pub fn add_deadline(&mut self, deadline: Instant) {
|
||||
match self.deadline {
|
||||
Some(current) if current < deadline => (),
|
||||
_ => self.deadline = Some(deadline),
|
||||
}
|
||||
}
|
||||
|
||||
// Add a timeout to the context. If the current timeout is sooner than
|
||||
// the provided timeout, this method does nothing.
|
||||
pub fn add_timeout(&mut self, timeout: Duration) {
|
||||
self.add_deadline(Instant::now() + timeout)
|
||||
}
|
||||
|
||||
// Add a value to the context. It overwrites any previously set values
|
||||
// with the same key.
|
||||
pub fn add_value<V>(&mut self, key: &'static str, value: V)
|
||||
where
|
||||
V: Any + Send + Sync + Sized,
|
||||
{
|
||||
if let Some(ref mut values) = self.values {
|
||||
values.insert(key, Box::new(value));
|
||||
} else {
|
||||
self.values = Some(HashMap::new());
|
||||
self.add_value(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the deadline for this operation, if any. This is useful for
|
||||
// checking if a long job should be started or not.
|
||||
pub fn deadline(&self) -> Option<Instant> {
|
||||
self.deadline
|
||||
}
|
||||
|
||||
// Check if the context is done. If it returns `None` the operation may
|
||||
// proceed, otherwise the operation should be stopped.
|
||||
pub fn done(&self) -> Option<Reason> {
|
||||
match self.deadline {
|
||||
Some(deadline) if deadline <= Instant::now() => Some(Reason::Timedout),
|
||||
// TODO: see if we can relax the ordering.
|
||||
_ if self.cancelled.load(Ordering::SeqCst) => Some(Reason::Canceled),
|
||||
_ => match self.parent {
|
||||
Some(ref parent_ctx) => parent_ctx.done(),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the context is ok to continue.
|
||||
pub fn is_ok(&self) -> bool {
|
||||
self.done().is_none()
|
||||
}
|
||||
|
||||
// Check if the context is not ok to continue.
|
||||
pub fn is_err(&self) -> bool {
|
||||
self.done().is_some()
|
||||
}
|
||||
|
||||
// Check if the context is not ok to continue.
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.done().is_some()
|
||||
}
|
||||
|
||||
// Check if the context is not ok to continue, because it timed out.
|
||||
pub fn is_timedout(&self) -> bool {
|
||||
match self.done() {
|
||||
Some(Reason::Timedout) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the context is not ok to continue, because it was cancelled.
|
||||
pub fn is_cancelled(&self) -> bool {
|
||||
match self.done() {
|
||||
Some(Reason::Canceled) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the status of the context. This will return a Result, with an Ok
|
||||
// if the operation may proceed, and an Error if it should be stopped.
|
||||
pub fn check(&self) -> Result<(), Reason> {
|
||||
match self.done() {
|
||||
Some(reason) => Err(reason),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
// Get a value from the context. If no value is stored under the
|
||||
// provided key, then this will return None.
|
||||
pub fn value<V>(&self, key: &'static str) -> Option<&V>
|
||||
where
|
||||
V: Any + Send + Sync + Sized,
|
||||
{
|
||||
if let Some(ref values) = self.values {
|
||||
if let Some(value) = values.get(&key) {
|
||||
let value: &dyn Any = &**value;
|
||||
return value.downcast_ref::<V>();
|
||||
}
|
||||
}
|
||||
match self.parent {
|
||||
Some(ref parent) => parent.value(key),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Context {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Context")
|
||||
.field("parent", &self.parent)
|
||||
.field("deadline", &self.deadline)
|
||||
.field("cancelled", &self.cancelled)
|
||||
.field("values", &self.values.as_ref().map(|_| "values"))
|
||||
.finish()
|
||||
}
|
||||
}
|
16
src/ctx/mod.rs
Normal file
16
src/ctx/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2017 Thomas de Zeeuw
|
||||
//
|
||||
// https://docs.rs/io-context/0.2.0/io_context/
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT
|
||||
// or http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// used, copied, modified, or distributed except according to those terms.
|
||||
|
||||
pub use self::canceller::*;
|
||||
pub use self::context::*;
|
||||
pub use self::reason::*;
|
||||
|
||||
pub mod canceller;
|
||||
pub mod context;
|
||||
pub mod reason;
|
30
src/ctx/reason.rs
Normal file
30
src/ctx/reason.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Reason {
|
||||
Timedout,
|
||||
Canceled,
|
||||
}
|
||||
|
||||
impl Error for Reason {}
|
||||
|
||||
impl fmt::Display for Reason {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Reason::Timedout => write!(f, "Context timedout"),
|
||||
Reason::Canceled => write!(f, "Context canceled"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Reason> for io::Error {
|
||||
fn from(reason: Reason) -> Self {
|
||||
let kind = match reason {
|
||||
Reason::Timedout => io::ErrorKind::TimedOut,
|
||||
Reason::Canceled => io::ErrorKind::Other,
|
||||
};
|
||||
io::Error::new(kind, reason.to_string())
|
||||
}
|
||||
}
|
|
@ -1,29 +1,29 @@
|
|||
use crate::dbs::exe::Executor;
|
||||
use crate::dbs::res::Responses;
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::executor::Executor;
|
||||
use crate::dbs::response::Responses;
|
||||
use crate::err::Error;
|
||||
use crate::sql;
|
||||
use crate::sql::query::Query;
|
||||
use ctx::Context;
|
||||
use std::collections::HashMap;
|
||||
|
||||
type Vars<'a> = Option<HashMap<&'a str, String>>;
|
||||
pub type Vars<'a> = Option<HashMap<&'a str, String>>;
|
||||
|
||||
pub fn execute(txt: &str, vars: Vars) -> Result<Responses, Error> {
|
||||
// Parse the SQL query into an AST
|
||||
let ast = sql::parse(txt)?;
|
||||
// Create a new execution context
|
||||
let ctx = Context::background().freeze();
|
||||
// Create a new query executor
|
||||
let exe = Executor::new();
|
||||
// Process all of the queries
|
||||
exe.execute(ast)
|
||||
exe.execute(&ctx, ast)
|
||||
}
|
||||
|
||||
pub fn process(ast: Query, vars: Vars) -> Result<Responses, Error> {
|
||||
// Create a new execution context
|
||||
// let ctx = None;
|
||||
// ctx.set("server.ip");
|
||||
// ctx.set("client.ip");
|
||||
let ctx = Context::background().freeze();
|
||||
// Create a new query executor
|
||||
let exe = Executor::new();
|
||||
// Process all of the queries
|
||||
exe.execute(ast)
|
||||
exe.execute(&ctx, ast)
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
use crate::dbs::res::{Response, Responses};
|
||||
use crate::err::Error;
|
||||
use crate::sql::query::Query;
|
||||
use crate::sql::statement::Statement;
|
||||
use ctx::Context;
|
||||
use std::fs;
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct Executor {
|
||||
id: String,
|
||||
ns: String,
|
||||
db: String,
|
||||
}
|
||||
|
||||
impl Executor {
|
||||
pub fn new() -> Executor {
|
||||
Executor {
|
||||
id: String::from("id"),
|
||||
ns: String::from("ns"),
|
||||
db: String::from("db"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(&self, qry: Query) -> Result<Responses, Error> {
|
||||
let mut r: Vec<Response> = vec![];
|
||||
|
||||
for stm in qry.statements().iter() {
|
||||
let now = Instant::now();
|
||||
let res = stm.execute();
|
||||
let dur = now.elapsed();
|
||||
r.push(Response {
|
||||
sql: format!("{}", stm),
|
||||
time: format!("{:?}", dur),
|
||||
status: String::from(""),
|
||||
detail: String::from(""),
|
||||
result: Some(res),
|
||||
});
|
||||
}
|
||||
Ok(Responses(r))
|
||||
}
|
||||
}
|
50
src/dbs/executor.rs
Normal file
50
src/dbs/executor.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs::response::{Response, Responses};
|
||||
use crate::dbs::Process;
|
||||
use crate::err::Error;
|
||||
use crate::sql::query::Query;
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Executor {
|
||||
pub id: String,
|
||||
pub ns: String,
|
||||
pub db: String,
|
||||
}
|
||||
|
||||
impl Executor {
|
||||
pub fn new() -> Executor {
|
||||
Executor {
|
||||
id: String::from("id"),
|
||||
ns: String::from("ns"),
|
||||
db: String::from("db"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(&self, ctx: &Parent, qry: Query) -> Result<Responses, Error> {
|
||||
let mut r: Vec<Response> = vec![];
|
||||
|
||||
for stm in qry.statements().iter() {
|
||||
// Get the statement start time
|
||||
let now = Instant::now();
|
||||
// Process a single statement
|
||||
let res = stm.process(&ctx, self, None);
|
||||
// Get the statement end time
|
||||
let dur = now.elapsed();
|
||||
|
||||
r.push(Response {
|
||||
sql: format!("{}", stm),
|
||||
time: format!("{:?}", dur),
|
||||
status: match res {
|
||||
Ok(_) => String::from("OK"),
|
||||
Err(_) => String::from("ERR"),
|
||||
},
|
||||
result: match res {
|
||||
Ok(v) => Some(v),
|
||||
Err(_) => None,
|
||||
},
|
||||
})
|
||||
}
|
||||
Ok(Responses(r))
|
||||
}
|
||||
}
|
21
src/dbs/iterator.rs
Normal file
21
src/dbs/iterator.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs::Executor;
|
||||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
|
||||
pub struct Iterator {}
|
||||
|
||||
impl Iterator {
|
||||
pub fn new() -> Iterator {
|
||||
Iterator {}
|
||||
}
|
||||
pub fn process_query(&self, ctx: &Parent, exe: &Executor) {}
|
||||
pub fn process_table(&self, ctx: &Parent, exe: &Executor) {}
|
||||
pub fn process_thing(&self, ctx: &Parent, exe: &Executor) {}
|
||||
pub fn process_model(&self, ctx: &Parent, exe: &Executor) {}
|
||||
pub fn process_array(&self, ctx: &Parent, exe: &Executor) {}
|
||||
pub fn process_object(&self, ctx: &Parent, exe: &Executor) {}
|
||||
pub fn output(&self, ctx: &Parent, exe: &Executor) -> Result<Literal, Error> {
|
||||
Ok(Literal::Null)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
mod dbs;
|
||||
mod exe;
|
||||
mod res;
|
||||
mod executor;
|
||||
mod iterator;
|
||||
mod process;
|
||||
mod response;
|
||||
|
||||
pub use self::dbs::*;
|
||||
pub use self::executor::*;
|
||||
pub use self::iterator::*;
|
||||
pub use self::process::*;
|
||||
|
|
14
src/dbs/process.rs
Normal file
14
src/dbs/process.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs::executor::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
|
||||
pub trait Process {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error>;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
use crate::sql::statement::Statement;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// pub type Output = std::result::Result<warp::reply::Json, ErrorResponse>;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Responses(pub Vec<Response>);
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Response {
|
||||
pub sql: String,
|
||||
pub time: String,
|
||||
pub status: String,
|
||||
pub detail: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result: Option<String>,
|
||||
}
|
15
src/dbs/response.rs
Normal file
15
src/dbs/response.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use crate::sql::literal::Literal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Responses(pub Vec<Response>);
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Response {
|
||||
pub sql: String,
|
||||
pub time: String,
|
||||
pub status: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub result: Option<String>,
|
||||
pub result: Option<Literal>,
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Document {}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -1,67 +1,68 @@
|
|||
use crate::sql::duration::Duration;
|
||||
use crate::sql::thing::Thing;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_cbor::error::Error as CborError;
|
||||
use serde_json::Error as JsonError;
|
||||
use serde_json::error::Error as JsonError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[fail(display = "Specify a namespace to use")]
|
||||
NSError,
|
||||
#[error("Specify a namespace to use")]
|
||||
NsError,
|
||||
|
||||
#[fail(display = "Specify a database to use")]
|
||||
DBError,
|
||||
#[error("Specify a database to use")]
|
||||
DbError,
|
||||
|
||||
#[fail(display = "Specify some SQL code to execute")]
|
||||
#[error("Specify some SQL code to execute")]
|
||||
EmptyError,
|
||||
|
||||
#[fail(display = "Parse error at position {} when parsing '{}'", pos, sql)]
|
||||
ParseError { pos: usize, sql: String },
|
||||
#[error("Parse error at position {pos} when parsing '{sql}'")]
|
||||
ParseError {
|
||||
pos: usize,
|
||||
sql: String,
|
||||
},
|
||||
|
||||
#[fail(display = "Query timeout of {} exceeded", timer)]
|
||||
TimerError { timer: Duration },
|
||||
#[error("Wrong number of arguments at position {pos} when parsing '{sql}'")]
|
||||
CountError {
|
||||
pos: usize,
|
||||
sql: String,
|
||||
},
|
||||
|
||||
#[fail(display = "Database record `{}` already exists", thing)]
|
||||
ExistError { thing: Thing },
|
||||
#[error("Query timeout of {timer} exceeded")]
|
||||
TimerError {
|
||||
timer: Duration,
|
||||
},
|
||||
|
||||
#[fail(display = "Database index `{}` already contains `{}`", index, thing)]
|
||||
IndexError { index: String, thing: Thing },
|
||||
#[error("Database record `{thing}` already exists")]
|
||||
ExistError {
|
||||
thing: Thing,
|
||||
},
|
||||
|
||||
#[fail(display = "You don't have permission to perform the query `{}`", query)]
|
||||
PermsError { query: String },
|
||||
#[error("Database index `{index}` already contains `{thing}`")]
|
||||
IndexError {
|
||||
index: String,
|
||||
thing: Thing,
|
||||
},
|
||||
|
||||
#[fail(
|
||||
display = "Unable to write to the `{}` table while setup as a view",
|
||||
table
|
||||
)]
|
||||
WriteError { table: String },
|
||||
#[error("You don't have permission to perform the query `{query}`")]
|
||||
PermsError {
|
||||
query: String,
|
||||
},
|
||||
|
||||
#[fail(
|
||||
display = "You don't have permission to perform this query on the `{}` table",
|
||||
table
|
||||
)]
|
||||
TableError { table: String },
|
||||
#[error("Unable to write to the `{table}` table while setup as a view")]
|
||||
WriteError {
|
||||
table: String,
|
||||
},
|
||||
|
||||
#[fail(display = "JSON Error: {}", _0)]
|
||||
JsonError(#[cause] JsonError),
|
||||
#[error("You don't have permission to perform this query on the `{table}` table")]
|
||||
TableError {
|
||||
table: String,
|
||||
},
|
||||
|
||||
#[fail(display = "CBOR Error: {}", _0)]
|
||||
CborError(#[cause] CborError),
|
||||
}
|
||||
#[error("JSON Error: {0}")]
|
||||
JsonError(JsonError),
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Message {
|
||||
pub code: usize,
|
||||
pub info: String,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn build(&self) -> Message {
|
||||
Message {
|
||||
code: 400,
|
||||
info: format!("{}", self),
|
||||
}
|
||||
}
|
||||
#[error("CBOR Error: {0}")]
|
||||
CborError(CborError),
|
||||
}
|
||||
|
||||
impl From<JsonError> for Error {
|
||||
|
|
48
src/fnc/cast.rs
Normal file
48
src/fnc/cast.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
|
||||
pub fn run(ctx: &Context, name: &String, val: Literal) -> Result<Literal, Error> {
|
||||
match name.as_str() {
|
||||
"bool" => bool(ctx, val),
|
||||
"int" => int(ctx, val),
|
||||
"float" => float(ctx, val),
|
||||
"string" => string(ctx, val),
|
||||
"number" => number(ctx, val),
|
||||
"decimal" => number(ctx, val),
|
||||
"datetime" => datetime(ctx, val),
|
||||
"duration" => duration(ctx, val),
|
||||
_ => Ok(val),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool(ctx: &Context, val: Literal) -> Result<Literal, Error> {
|
||||
match val.as_bool() {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn int(ctx: &Context, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Int(val.as_int()))
|
||||
}
|
||||
|
||||
pub fn float(ctx: &Context, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Float(val.as_float()))
|
||||
}
|
||||
|
||||
pub fn string(ctx: &Context, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Strand(val.as_strand()))
|
||||
}
|
||||
|
||||
pub fn number(ctx: &Context, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Number(val.as_number()))
|
||||
}
|
||||
|
||||
pub fn datetime(ctx: &Context, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Datetime(val.as_datetime()))
|
||||
}
|
||||
|
||||
pub fn duration(ctx: &Context, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Duration(val.as_duration()))
|
||||
}
|
7
src/fnc/future.rs
Normal file
7
src/fnc/future.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
|
||||
pub fn run(ctx: &Parent, args: Literal) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
11
src/fnc/mod.rs
Normal file
11
src/fnc/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
|
||||
pub mod cast;
|
||||
pub mod future;
|
||||
pub mod operate;
|
||||
|
||||
pub fn run(ctx: &Parent, name: &String, args: Vec<Literal>) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
435
src/fnc/operate.rs
Normal file
435
src/fnc/operate.rs
Normal file
|
@ -0,0 +1,435 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn or(a: Literal, b: Literal) -> Result<Literal, Error> {
|
||||
match a.as_bool() {
|
||||
true => Ok(a),
|
||||
false => Ok(b),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and(a: Literal, b: Literal) -> Result<Literal, Error> {
|
||||
match a.as_bool() {
|
||||
true => match b.as_bool() {
|
||||
_ => Ok(b),
|
||||
},
|
||||
false => Ok(a),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a + b))
|
||||
}
|
||||
|
||||
pub fn sub(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a - b))
|
||||
}
|
||||
|
||||
pub fn mul(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a * b))
|
||||
}
|
||||
|
||||
pub fn div(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a / b))
|
||||
}
|
||||
|
||||
pub fn equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::None => Ok(Literal::from(b.is_none() == true)),
|
||||
Literal::Null => Ok(Literal::from(b.is_null() == true)),
|
||||
Literal::Void => Ok(Literal::from(b.is_void() == true)),
|
||||
Literal::True => Ok(Literal::from(b.is_true() == true)),
|
||||
Literal::False => Ok(Literal::from(b.is_false() == true)),
|
||||
Literal::Int(v) => Ok(Literal::from(v == &b.as_int())),
|
||||
Literal::Float(v) => Ok(Literal::from(v == &b.as_float())),
|
||||
Literal::Thing(v) => match b {
|
||||
Literal::Thing(w) => Ok(Literal::from(v == w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Regex(v) => match b {
|
||||
Literal::Regex(w) => Ok(Literal::from(v == w)),
|
||||
Literal::Strand(w) => match v.value {
|
||||
Some(ref r) => Ok(Literal::from(r.is_match(w.value.as_str()) == true)),
|
||||
None => Ok(Literal::False),
|
||||
},
|
||||
_ => Ok(Literal::False),
|
||||
},
|
||||
Literal::Point(v) => match b {
|
||||
Literal::Point(w) => Ok(Literal::from(v == w)),
|
||||
_ => Ok(Literal::False),
|
||||
},
|
||||
Literal::Array(v) => match b {
|
||||
Literal::Array(w) => Ok(Literal::from(v == w)),
|
||||
_ => Ok(Literal::False),
|
||||
},
|
||||
Literal::Object(v) => match b {
|
||||
Literal::Object(w) => Ok(Literal::from(v == w)),
|
||||
_ => Ok(Literal::False),
|
||||
},
|
||||
Literal::Strand(v) => match b {
|
||||
Literal::Strand(w) => Ok(Literal::from(v == w)),
|
||||
Literal::Regex(w) => match w.value {
|
||||
Some(ref r) => Ok(Literal::from(r.is_match(v.value.as_str()) == true)),
|
||||
None => Ok(Literal::False),
|
||||
},
|
||||
_ => Ok(Literal::from(v == &b.as_strand())),
|
||||
},
|
||||
Literal::Number(v) => Ok(Literal::from(v == &b.as_number())),
|
||||
Literal::Polygon(v) => match b {
|
||||
Literal::Polygon(w) => Ok(Literal::from(v == w)),
|
||||
_ => Ok(Literal::False),
|
||||
},
|
||||
Literal::Duration(v) => match b {
|
||||
Literal::Duration(w) => Ok(Literal::from(v == w)),
|
||||
_ => Ok(Literal::False),
|
||||
},
|
||||
Literal::Datetime(v) => match b {
|
||||
Literal::Datetime(w) => Ok(Literal::from(v == w)),
|
||||
_ => Ok(Literal::False),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::None => Ok(Literal::from(b.is_none() != true)),
|
||||
Literal::Null => Ok(Literal::from(b.is_null() != true)),
|
||||
Literal::Void => Ok(Literal::from(b.is_void() != true)),
|
||||
Literal::True => Ok(Literal::from(b.is_true() != true)),
|
||||
Literal::False => Ok(Literal::from(b.is_false() != true)),
|
||||
Literal::Int(v) => Ok(Literal::from(v != &b.as_int())),
|
||||
Literal::Float(v) => Ok(Literal::from(v != &b.as_float())),
|
||||
Literal::Thing(v) => match b {
|
||||
Literal::Thing(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Regex(v) => match b {
|
||||
Literal::Regex(w) => Ok(Literal::from(v != w)),
|
||||
Literal::Strand(w) => match v.value {
|
||||
Some(ref r) => Ok(Literal::from(r.is_match(w.value.as_str()) != true)),
|
||||
None => Ok(Literal::True),
|
||||
},
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Point(v) => match b {
|
||||
Literal::Point(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Array(v) => match b {
|
||||
Literal::Array(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Object(v) => match b {
|
||||
Literal::Object(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Number(v) => match b {
|
||||
Literal::Number(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Strand(v) => match b {
|
||||
Literal::Strand(w) => Ok(Literal::from(v != w)),
|
||||
Literal::Regex(w) => match w.value {
|
||||
Some(ref r) => Ok(Literal::from(r.is_match(v.value.as_str()) != true)),
|
||||
None => Ok(Literal::False),
|
||||
},
|
||||
_ => Ok(Literal::from(v != &b.as_strand())),
|
||||
},
|
||||
Literal::Polygon(v) => match b {
|
||||
Literal::Polygon(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Duration(v) => match b {
|
||||
Literal::Duration(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
Literal::Datetime(v) => match b {
|
||||
Literal::Datetime(w) => Ok(Literal::from(v != w)),
|
||||
_ => Ok(Literal::True),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(ref v) => match v.value.iter().all(|x| match x {
|
||||
Value::Literal(v) => equal(v, b).is_ok(),
|
||||
_ => unreachable!(),
|
||||
}) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
},
|
||||
_ => equal(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn any_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(ref v) => match v.value.iter().any(|x| match x {
|
||||
Value::Literal(v) => equal(v, b).is_ok(),
|
||||
_ => unreachable!(),
|
||||
}) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
},
|
||||
_ => equal(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn not_like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn all_like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn any_like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn less_than(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a.lt(&b) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn less_than_or_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a.le(&b) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn more_than(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a.gt(&b) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn more_than_or_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a.ge(&b) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_contain(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain_all(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain_some(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain_none(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_inside(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside_all(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside_some(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside_none(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersects(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn or_true() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(2);
|
||||
let res = or(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or_false_one() {
|
||||
let one = Literal::from(0);
|
||||
let two = Literal::from(1);
|
||||
let res = or(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or_false_two() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(0);
|
||||
let res = or(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and_true() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(2);
|
||||
let res = and(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("2", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and_false_one() {
|
||||
let one = Literal::from(0);
|
||||
let two = Literal::from(1);
|
||||
let res = and(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("0", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and_false_two() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(0);
|
||||
let res = and(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("0", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = add(&one, &two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("9", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = sub(&one, &two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = mul(&one, &two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("20", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn div_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = div(&one, &two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1.25", format!("{}", out));
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use failure::Error;
|
||||
use anyhow::Error;
|
||||
|
||||
pub fn init(opts: &clap::ArgMatches) -> Result<(), Error> {
|
||||
let pth = opts.value_of("path").unwrap();
|
||||
|
|
16
src/lib.rs
Normal file
16
src/lib.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
#[macro_use]
|
||||
extern crate maplit;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod ctx;
|
||||
mod dbs;
|
||||
mod doc;
|
||||
mod err;
|
||||
mod fnc;
|
||||
mod kvs;
|
||||
mod sql;
|
||||
|
||||
fn main() {
|
||||
// cli::init(); // Initiate the command line
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
#[macro_use]
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate maplit;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod cli;
|
||||
mod ctx;
|
||||
mod dbs;
|
||||
mod doc;
|
||||
mod err;
|
||||
mod fnc;
|
||||
mod kvs;
|
||||
mod sql;
|
||||
mod web;
|
||||
|
|
|
@ -5,7 +5,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Algorithm {
|
||||
Es256,
|
||||
Es384,
|
||||
|
|
|
@ -1,39 +1,94 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::expression::expression;
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::value::Value;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::separated_list;
|
||||
use nom::multi::separated_list0;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Array(Vec<Expression>);
|
||||
const NAME: &'static str = "Array";
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Array {
|
||||
pub value: Vec<Value>,
|
||||
}
|
||||
|
||||
impl fmt::Display for Array {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"[{}]",
|
||||
self.0
|
||||
.iter()
|
||||
.map(|ref v| format!("{}", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
self.value.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for Array {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
self.value
|
||||
.iter()
|
||||
.map(|v| match v.process(ctx, exe, doc) {
|
||||
Ok(v) => Ok(Value::from(v)),
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map(|v| {
|
||||
Literal::Array(Array {
|
||||
value: v,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Array {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_some(&self.value)
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct(NAME, 1)?;
|
||||
val.serialize_field("value", &self.value)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array(i: &str) -> IResult<&str, Array> {
|
||||
let (i, _) = tag("[")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = separated_list(commas, expression)(i)?;
|
||||
let (i, v) = separated_list0(commas, item)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(tag(","))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("]")(i)?;
|
||||
Ok((i, Array(v)))
|
||||
Ok((
|
||||
i,
|
||||
Array {
|
||||
value: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn item(i: &str) -> IResult<&str, Value> {
|
||||
let (i, v) = expression(i)?;
|
||||
Ok((i, Value::from(v)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -48,7 +103,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("[1, 2, 3]", format!("{}", out));
|
||||
assert_eq!(out.0.len(), 3);
|
||||
assert_eq!(out.value.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -58,7 +113,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("[1, 2, 3]", format!("{}", out));
|
||||
assert_eq!(out.0.len(), 3);
|
||||
assert_eq!(out.value.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -68,6 +123,6 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("[1, 2, 3 + 1]", format!("{}", out));
|
||||
assert_eq!(out.0.len(), 3);
|
||||
assert_eq!(out.value.len(), 3);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Base {
|
||||
Kv,
|
||||
Ns,
|
||||
|
|
|
@ -5,6 +5,7 @@ use nom::character::complete::multispace0;
|
|||
use nom::character::is_alphanumeric;
|
||||
use nom::combinator::map;
|
||||
use nom::error::ErrorKind;
|
||||
use nom::error::Error;
|
||||
use nom::multi::many1;
|
||||
use nom::IResult;
|
||||
use std::ops::RangeBounds;
|
||||
|
@ -75,6 +76,6 @@ pub fn take_digits_range(i: &str, n: usize, range: impl RangeBounds<u32>) -> IRe
|
|||
if range.contains(&v) {
|
||||
Ok((i, v))
|
||||
} else {
|
||||
Err(nom::Err::Error((i, ErrorKind::Eof)))
|
||||
Err(nom::Err::Error(Error::new(i, ErrorKind::Eof)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Cond {
|
||||
pub expr: Expression,
|
||||
}
|
||||
|
@ -20,7 +20,12 @@ pub fn cond(i: &str) -> IResult<&str, Cond> {
|
|||
let (i, _) = tag_no_case("WHERE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = expression(i)?;
|
||||
Ok((i, Cond { expr: v }))
|
||||
Ok((
|
||||
i,
|
||||
Cond {
|
||||
expr: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -43,9 +48,6 @@ mod tests {
|
|||
let res = cond(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(
|
||||
"WHERE field = true AND other.field = false",
|
||||
format!("{}", out)
|
||||
);
|
||||
assert_eq!("WHERE field = true AND other.field = false", format!("{}", out));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ use crate::sql::object::{object, Object};
|
|||
use crate::sql::operator::{assigner, Operator};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Data {
|
||||
SetExpression(Vec<(Idiom, Operator, Expression)>),
|
||||
DiffExpression(Array),
|
||||
|
@ -46,7 +46,7 @@ pub fn data(i: &str) -> IResult<&str, Data> {
|
|||
fn set(i: &str) -> IResult<&str, Data> {
|
||||
let (i, _) = tag_no_case("SET")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = separated_nonempty_list(commas, |i| {
|
||||
let (i, v) = separated_list1(commas, |i| {
|
||||
let (i, l) = idiom(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, o) = assigner(i)?;
|
||||
|
|
|
@ -5,29 +5,51 @@ use nom::bytes::complete::tag;
|
|||
use nom::combinator::map;
|
||||
use nom::sequence::delimited;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Datetime(DateTime<Utc>);
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Datetime {
|
||||
pub value: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Default for Datetime {
|
||||
fn default() -> Self {
|
||||
Datetime(Utc::now())
|
||||
Datetime {
|
||||
value: Utc::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Datetime {
|
||||
fn from(s: &str) -> Self {
|
||||
datetime_raw(s).unwrap().1
|
||||
match datetime_raw(s) {
|
||||
Ok((_, v)) => v,
|
||||
Err(_) => Datetime::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Datetime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "\"{:?}\"", self.0)
|
||||
write!(f, "\"{:?}\"", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Datetime {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_some(&self.value)
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct("Datetime", 1)?;
|
||||
val.serialize_field("value", &self.value)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +60,7 @@ pub fn datetime(i: &str) -> IResult<&str, Datetime> {
|
|||
))(i)
|
||||
}
|
||||
|
||||
fn datetime_raw(i: &str) -> IResult<&str, Datetime> {
|
||||
pub fn datetime_raw(i: &str) -> IResult<&str, Datetime> {
|
||||
alt((nano, time, date))(i)
|
||||
}
|
||||
|
||||
|
@ -50,7 +72,12 @@ fn date(i: &str) -> IResult<&str, Datetime> {
|
|||
let (i, day) = day(i)?;
|
||||
|
||||
let d = Utc.ymd(year, mon, day).and_hms(0, 0, 0);
|
||||
Ok((i, Datetime(d)))
|
||||
Ok((
|
||||
i,
|
||||
Datetime {
|
||||
value: d,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn time(i: &str) -> IResult<&str, Datetime> {
|
||||
|
@ -71,11 +98,15 @@ fn time(i: &str) -> IResult<&str, Datetime> {
|
|||
Some(z) => {
|
||||
let d = z.ymd(year, mon, day).and_hms(hour, min, sec);
|
||||
let d = d.with_timezone(&Utc);
|
||||
Datetime(d)
|
||||
Datetime {
|
||||
value: d,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let d = Utc.ymd(year, mon, day).and_hms(hour, min, sec);
|
||||
Datetime(d)
|
||||
Datetime {
|
||||
value: d,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -101,11 +132,15 @@ fn nano(i: &str) -> IResult<&str, Datetime> {
|
|||
Some(z) => {
|
||||
let d = z.ymd(year, mon, day).and_hms_nano(hour, min, sec, nano);
|
||||
let d = d.with_timezone(&Utc);
|
||||
Datetime(d)
|
||||
Datetime {
|
||||
value: d,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let d = Utc.ymd(year, mon, day).and_hms_nano(hour, min, sec, nano);
|
||||
Datetime(d)
|
||||
Datetime {
|
||||
value: d,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
use crate::sql::literal::{literal, Literal};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::map;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Definition {
|
||||
All,
|
||||
Void,
|
||||
Empty,
|
||||
Filled,
|
||||
Literal(Literal),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Definition {
|
||||
fn from(s: &str) -> Self {
|
||||
definition(s).unwrap().1
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Literal> for Definition {
|
||||
fn from(v: Literal) -> Self {
|
||||
Definition::Literal(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Definition {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Definition::All => write!(f, "*"),
|
||||
Definition::Void => write!(f, "VOID"),
|
||||
Definition::Empty => write!(f, "EMPTY"),
|
||||
Definition::Filled => write!(f, "FILLED"),
|
||||
Definition::Literal(v) => write!(f, "{}", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn definition(i: &str) -> IResult<&str, Definition> {
|
||||
alt((
|
||||
map(tag_no_case("*"), |_| Definition::All),
|
||||
map(tag_no_case("VOID"), |_| Definition::Void),
|
||||
map(tag_no_case("EMPTY"), |_| Definition::Empty),
|
||||
map(tag_no_case("FILLED"), |_| Definition::Filled),
|
||||
map(tag_no_case("MISSING"), |_| Definition::Empty),
|
||||
map(literal, |v| Definition::Literal(v)),
|
||||
))(i)
|
||||
}
|
|
@ -2,12 +2,13 @@ use nom::branch::alt;
|
|||
use nom::bytes::complete::is_a;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::time;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Duration {
|
||||
pub input: String,
|
||||
pub value: time::Duration,
|
||||
|
@ -15,7 +16,10 @@ pub struct Duration {
|
|||
|
||||
impl<'a> From<&'a str> for Duration {
|
||||
fn from(s: &str) -> Self {
|
||||
duration(s).unwrap().1
|
||||
match duration(s) {
|
||||
Ok((_, v)) => v,
|
||||
Err(_) => Duration::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +29,27 @@ impl fmt::Display for Duration {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Duration {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_some(&self.value)
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct("Duration", 2)?;
|
||||
val.serialize_field("input", &self.input)?;
|
||||
val.serialize_field("value", &self.value)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn duration(i: &str) -> IResult<&str, Duration> {
|
||||
duration_raw(i)
|
||||
}
|
||||
|
||||
pub fn duration_raw(i: &str) -> IResult<&str, Duration> {
|
||||
let (i, v) = part(i)?;
|
||||
let (i, u) = unit(i)?;
|
||||
Ok((
|
||||
|
@ -54,16 +78,7 @@ fn part(i: &str) -> IResult<&str, u64> {
|
|||
}
|
||||
|
||||
fn unit(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
tag("ns"),
|
||||
tag("µs"),
|
||||
tag("ms"),
|
||||
tag("s"),
|
||||
tag("m"),
|
||||
tag("h"),
|
||||
tag("d"),
|
||||
tag("w"),
|
||||
))(i)
|
||||
alt((tag("ns"), tag("µs"), tag("ms"), tag("s"), tag("m"), tag("h"), tag("d"), tag("w")))(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -110,4 +125,24 @@ mod tests {
|
|||
assert_eq!("86400s", format!("{}", out));
|
||||
assert_eq!(out.value, Duration::from("1d").value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_days() {
|
||||
let sql = "5d";
|
||||
let res = duration(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("5d", format!("{}", out));
|
||||
assert_eq!(out.value, Duration::from("5d").value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_weeks() {
|
||||
let sql = "4w";
|
||||
let res = duration(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("4w", format!("{}", out));
|
||||
assert_eq!(out.value, Duration::from("4w").value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::fnc;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::definition::{definition, Definition};
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::literal::{literal, Literal};
|
||||
use crate::sql::operator::{operator, Operator};
|
||||
use nom::branch::alt;
|
||||
use nom::IResult;
|
||||
|
@ -8,14 +13,16 @@ use serde::{Deserialize, Serialize};
|
|||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Expression {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub lhs: Option<Box<Definition>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub op: Option<Operator>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rhs: Option<Box<Expression>>,
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum Expression {
|
||||
Single(Box<Literal>),
|
||||
Binary(Box<Literal>, Operator, Box<Expression>),
|
||||
}
|
||||
|
||||
impl Default for Expression {
|
||||
fn default() -> Expression {
|
||||
Expression::Single(Box::new(Literal::Null))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Expression {
|
||||
|
@ -26,57 +33,153 @@ impl<'a> From<&'a str> for Expression {
|
|||
|
||||
impl From<Literal> for Expression {
|
||||
fn from(v: Literal) -> Self {
|
||||
Expression {
|
||||
lhs: Some(Box::new(Definition::from(v))),
|
||||
op: None,
|
||||
rhs: None,
|
||||
}
|
||||
Expression::Single(Box::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Expression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(ref lhs) = self.lhs {
|
||||
write!(f, "{}", lhs)?
|
||||
match self {
|
||||
Expression::Single(ref l) => write!(f, "{}", l),
|
||||
Expression::Binary(ref l, ref o, ref r) => write!(f, "{} {} {}", l, o, r),
|
||||
}
|
||||
if let Some(ref op) = self.op {
|
||||
write!(f, " {} ", op)?
|
||||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for Expression {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
match self {
|
||||
Expression::Single(ref l) => l.process(ctx, exe, doc),
|
||||
Expression::Binary(ref l, ref o, ref r) => {
|
||||
let l = l.process(ctx, exe, doc)?;
|
||||
match o {
|
||||
Operator::Or => match l.as_bool() {
|
||||
true => return Ok(l), // No need to continue
|
||||
_ => {} // Continue
|
||||
},
|
||||
Operator::And => match l.as_bool() {
|
||||
false => return Ok(l), // No need to continue
|
||||
_ => {} // Continue
|
||||
},
|
||||
_ => {} // Continue
|
||||
}
|
||||
let r = r.process(ctx, exe, doc)?;
|
||||
match o {
|
||||
Operator::Or => fnc::operate::or(l, r),
|
||||
Operator::And => fnc::operate::and(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::Equal => fnc::operate::equal(&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::ContainSome => fnc::operate::contain_some(&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::SomeInside => fnc::operate::inside_some(&l, &r),
|
||||
Operator::NoneInside => fnc::operate::inside_none(&l, &r),
|
||||
Operator::Intersects => fnc::operate::intersects(&l, &r),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref rhs) = self.rhs {
|
||||
write!(f, "{}", rhs)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expression(i: &str) -> IResult<&str, Expression> {
|
||||
alt((dual, lone))(i)
|
||||
alt((binary, single))(i)
|
||||
}
|
||||
|
||||
fn dual(i: &str) -> IResult<&str, Expression> {
|
||||
let (i, l) = definition(i)?;
|
||||
fn binary(i: &str) -> IResult<&str, Expression> {
|
||||
let (i, l) = literal(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, o) = operator(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, r) = expression(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Expression {
|
||||
lhs: Some(Box::new(l)),
|
||||
op: Some(o),
|
||||
rhs: Some(Box::new(r)),
|
||||
},
|
||||
))
|
||||
Ok((i, Expression::Binary(Box::new(l), o, Box::new(r))))
|
||||
}
|
||||
|
||||
fn lone(i: &str) -> IResult<&str, Expression> {
|
||||
let (i, l) = definition(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Expression {
|
||||
lhs: Some(Box::new(l)),
|
||||
op: None,
|
||||
rhs: None,
|
||||
},
|
||||
))
|
||||
fn single(i: &str) -> IResult<&str, Expression> {
|
||||
let (i, l) = literal(i)?;
|
||||
Ok((i, Expression::Single(Box::new(l))))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn expression_single() {
|
||||
let sql = "true";
|
||||
let res = expression(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("true", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expression_double() {
|
||||
let sql = "true AND false";
|
||||
let res = expression(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("true AND false", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expression_left_opened() {
|
||||
let sql = "3 * 3 * 3 = 27";
|
||||
let res = expression(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("3 * 3 * 3 = 27", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expression_left_closed() {
|
||||
let sql = "(3 * 3 * 3) = 27";
|
||||
let res = expression(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("(3 * 3 * 3) = 27", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expression_both_opened() {
|
||||
let sql = "3 * 3 * 3 = 3 * 3 * 3";
|
||||
let res = expression(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("3 * 3 * 3 = 3 * 3 * 3", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expression_both_closed() {
|
||||
let sql = "(3 * 3 * 3) = (3 * 3 * 3)";
|
||||
let res = expression(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("(3 * 3 * 3) = (3 * 3 * 3)", format!("{}", out));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@ use crate::sql::comment::shouldbespace;
|
|||
use crate::sql::common::commas;
|
||||
use crate::sql::idiom::{idiom, Idiom};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Fetchs(Vec<Fetch>);
|
||||
|
||||
impl fmt::Display for Fetchs {
|
||||
|
@ -15,16 +15,12 @@ impl fmt::Display for Fetchs {
|
|||
write!(
|
||||
f,
|
||||
"FETCH {}",
|
||||
self.0
|
||||
.iter()
|
||||
.map(|ref v| format!("{}", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
self.0.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Fetch {
|
||||
pub fetch: Idiom,
|
||||
}
|
||||
|
@ -38,13 +34,18 @@ impl fmt::Display for Fetch {
|
|||
pub fn fetch(i: &str) -> IResult<&str, Fetchs> {
|
||||
let (i, _) = tag_no_case("FETCH")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = separated_nonempty_list(commas, fetch_raw)(i)?;
|
||||
let (i, v) = separated_list1(commas, fetch_raw)(i)?;
|
||||
Ok((i, Fetchs(v)))
|
||||
}
|
||||
|
||||
fn fetch_raw(i: &str) -> IResult<&str, Fetch> {
|
||||
let (i, v) = idiom(i)?;
|
||||
Ok((i, Fetch { fetch: v }))
|
||||
Ok((
|
||||
i,
|
||||
Fetch {
|
||||
fetch: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -2,14 +2,14 @@ use crate::sql::comment::shouldbespace;
|
|||
use crate::sql::common::commas;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::idiom::{idiom, Idiom};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Fields(Vec<Field>);
|
||||
|
||||
impl fmt::Display for Fields {
|
||||
|
@ -19,45 +19,54 @@ impl fmt::Display for Fields {
|
|||
}
|
||||
|
||||
pub fn fields(i: &str) -> IResult<&str, Fields> {
|
||||
let (i, v) = separated_nonempty_list(commas, field)(i)?;
|
||||
let (i, v) = separated_list1(commas, field)(i)?;
|
||||
Ok((i, Fields(v)))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Field {
|
||||
pub field: Expression,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub alias: Option<Idiom>,
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Field {
|
||||
All,
|
||||
Alone(Expression),
|
||||
Alias(Expression, Idiom),
|
||||
}
|
||||
|
||||
impl Default for Field {
|
||||
fn default() -> Field {
|
||||
Field::All
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Field {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(ref a) = self.alias {
|
||||
write!(f, "{} AS {}", self.field, a)
|
||||
} else {
|
||||
write!(f, "{}", self.field)
|
||||
match self {
|
||||
Field::All => write!(f, "*"),
|
||||
Field::Alone(ref e) => write!(f, "{}", e),
|
||||
Field::Alias(ref e, ref a) => write!(f, "{} AS {}", e, a),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field(i: &str) -> IResult<&str, Field> {
|
||||
let (i, f) = expression(i)?;
|
||||
let (i, a) = opt(alias)(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Field {
|
||||
field: f,
|
||||
alias: a,
|
||||
},
|
||||
))
|
||||
alt((all, alias, alone))(i)
|
||||
}
|
||||
|
||||
fn alias(i: &str) -> IResult<&str, Idiom> {
|
||||
fn all(i: &str) -> IResult<&str, Field> {
|
||||
let (i, _) = tag_no_case("*")(i)?;
|
||||
Ok((i, Field::All))
|
||||
}
|
||||
|
||||
fn alone(i: &str) -> IResult<&str, Field> {
|
||||
let (i, f) = expression(i)?;
|
||||
Ok((i, Field::Alone(f)))
|
||||
}
|
||||
|
||||
fn alias(i: &str) -> IResult<&str, Field> {
|
||||
let (i, f) = expression(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("AS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = idiom(i)?;
|
||||
Ok((i, v))
|
||||
let (i, a) = idiom(i)?;
|
||||
Ok((i, Field::Alias(f, a)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -65,6 +74,15 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn field_all() {
|
||||
let sql = "*";
|
||||
let res = fields(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("*", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn field_single() {
|
||||
let sql = "field";
|
||||
|
|
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum Filter {
|
||||
All,
|
||||
Last,
|
||||
|
|
|
@ -1,54 +1,129 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::fnc;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::literal::simple;
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::multi::separated_list;
|
||||
use nom::multi::separated_list0;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
pub args: Vec<Expression>,
|
||||
pub cast: bool,
|
||||
pub func: bool,
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Function {
|
||||
Future(Expression),
|
||||
Cast(String, Expression),
|
||||
Normal(String, Vec<Expression>),
|
||||
}
|
||||
|
||||
impl PartialOrd for Function {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Function {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.func {
|
||||
return write!(
|
||||
match self {
|
||||
Function::Future(ref e) => write!(f, "fn() -> {{ {} }}", e),
|
||||
Function::Cast(ref s, ref e) => write!(f, "<{}>{}", s, e),
|
||||
Function::Normal(ref s, ref e) => write!(
|
||||
f,
|
||||
"{}() -> {{ {} }}",
|
||||
self.name,
|
||||
self.args.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", "),
|
||||
);
|
||||
"{}({})",
|
||||
s,
|
||||
e.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", ")
|
||||
),
|
||||
}
|
||||
if self.cast {
|
||||
return write!(
|
||||
f,
|
||||
"<{}>{}",
|
||||
self.name,
|
||||
self.args.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", "),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for Function {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
match self {
|
||||
Function::Future(ref e) => {
|
||||
let a = e.process(ctx, exe, doc)?;
|
||||
fnc::future::run(ctx, a)
|
||||
}
|
||||
Function::Cast(ref s, ref e) => {
|
||||
let a = e.process(ctx, exe, doc)?;
|
||||
fnc::cast::run(ctx, s, a)
|
||||
}
|
||||
Function::Normal(ref s, ref e) => {
|
||||
let mut a: Vec<Literal> = vec![];
|
||||
for v in e {
|
||||
let v = v.process(ctx, exe, doc)?;
|
||||
a.push(v);
|
||||
}
|
||||
fnc::run(ctx, s, a)
|
||||
}
|
||||
}
|
||||
write!(
|
||||
f,
|
||||
"{}({})",
|
||||
self.name,
|
||||
self.args.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", "),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn function(i: &str) -> IResult<&str, Function> {
|
||||
alt((casts, future, normal))(i)
|
||||
}
|
||||
|
||||
fn future(i: &str) -> IResult<&str, Function> {
|
||||
let (i, _) = tag("fn()")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("->")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("{")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = expression(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("}")(i)?;
|
||||
Ok((i, Function::Future(v)))
|
||||
}
|
||||
|
||||
fn casts(i: &str) -> IResult<&str, Function> {
|
||||
let (i, _) = tag("<")(i)?;
|
||||
let (i, s) = function_casts(i)?;
|
||||
let (i, _) = tag(">")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = expression(i)?;
|
||||
Ok((i, Function::Cast(s.to_string(), v)))
|
||||
}
|
||||
|
||||
fn normal(i: &str) -> IResult<&str, Function> {
|
||||
let (i, s) = function_names(i)?;
|
||||
let (i, _) = tag("(")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = separated_list0(commas, expression)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag(")")(i)?;
|
||||
Ok((i, Function::Normal(s.to_string(), v)))
|
||||
}
|
||||
|
||||
fn function_casts(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
tag("bool"),
|
||||
tag("int"),
|
||||
tag("float"),
|
||||
tag("string"),
|
||||
tag("number"),
|
||||
tag("decimal"),
|
||||
tag("datetime"),
|
||||
tag("duration"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_names(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
casts,
|
||||
future,
|
||||
function_all,
|
||||
function_array,
|
||||
function_count,
|
||||
function_geo,
|
||||
|
@ -64,314 +139,233 @@ pub fn function(i: &str) -> IResult<&str, Function> {
|
|||
))(i)
|
||||
}
|
||||
|
||||
fn casts(i: &str) -> IResult<&str, Function> {
|
||||
fn function_array(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
cast("bool"),
|
||||
cast("int16"),
|
||||
cast("int32"),
|
||||
cast("int64"),
|
||||
cast("int128"),
|
||||
cast("uint16"),
|
||||
cast("uint32"),
|
||||
cast("uint64"),
|
||||
cast("uint128"),
|
||||
cast("float32"),
|
||||
cast("float64"),
|
||||
cast("decimal"),
|
||||
cast("number"),
|
||||
cast("string"),
|
||||
cast("binary"),
|
||||
cast("bytes"),
|
||||
cast("datetime"),
|
||||
cast("duration"),
|
||||
tag("array::difference"),
|
||||
tag("array::distinct"),
|
||||
tag("array::intersect"),
|
||||
tag("array::union"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn future(i: &str) -> IResult<&str, Function> {
|
||||
let (i, _) = tag("fn()")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("->")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("{")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = expression(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("}")(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Function {
|
||||
name: String::from("fn"),
|
||||
args: vec![v],
|
||||
cast: false,
|
||||
func: true,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn function_all(i: &str) -> IResult<&str, Function> {
|
||||
alt((func("if"), func("either")))(i)
|
||||
}
|
||||
|
||||
fn function_array(i: &str) -> IResult<&str, Function> {
|
||||
fn function_count(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("array::difference"),
|
||||
func("array::distinct"),
|
||||
func("array::intersect"),
|
||||
func("array::union"),
|
||||
tag("count::all"),
|
||||
tag("count::if"),
|
||||
tag("count::not"),
|
||||
tag("count::oneof"),
|
||||
tag("count::between"),
|
||||
tag("count"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_count(i: &str) -> IResult<&str, Function> {
|
||||
alt((func("count"), func("count::if"), func("count::not")))(i)
|
||||
}
|
||||
|
||||
fn function_geo(i: &str) -> IResult<&str, Function> {
|
||||
fn function_geo(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("geo::circle"),
|
||||
func("geo::distance"),
|
||||
func("geo::point"),
|
||||
func("geo::polygon"),
|
||||
func("geo::hash::decode"),
|
||||
func("geo::hash::encode"),
|
||||
tag("geo::distance"),
|
||||
tag("geo::latitude"),
|
||||
tag("geo::longitude"),
|
||||
tag("geo::hash::decode"),
|
||||
tag("geo::hash::encode"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_hash(i: &str) -> IResult<&str, Function> {
|
||||
fn function_hash(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("hash::md5"),
|
||||
func("hash::sha1"),
|
||||
func("hash::sha256"),
|
||||
func("hash::sha512"),
|
||||
func("hash::bcrypt"),
|
||||
func("hash::bcrypt::compare"),
|
||||
func("hash::bcrypt::generate"),
|
||||
func("hash::scrypt"),
|
||||
func("hash::scrypt::compare"),
|
||||
func("hash::scrypt::generate"),
|
||||
tag("hash::md5"),
|
||||
tag("hash::sha1"),
|
||||
tag("hash::sha256"),
|
||||
tag("hash::sha512"),
|
||||
tag("hash::bcrypt::compare"),
|
||||
tag("hash::bcrypt::generate"),
|
||||
tag("hash::scrypt::compare"),
|
||||
tag("hash::scrypt::generate"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_http(i: &str) -> IResult<&str, Function> {
|
||||
fn function_http(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("http::head"),
|
||||
func("http::get"),
|
||||
func("http::put"),
|
||||
func("http::post"),
|
||||
func("http::patch"),
|
||||
func("http::delete"),
|
||||
func("http::async::head"),
|
||||
func("http::async::get"),
|
||||
func("http::async::put"),
|
||||
func("http::async::post"),
|
||||
func("http::async::patch"),
|
||||
func("http::async::delete"),
|
||||
tag("http::head"),
|
||||
tag("http::get"),
|
||||
tag("http::put"),
|
||||
tag("http::post"),
|
||||
tag("http::patch"),
|
||||
tag("http::delete"),
|
||||
tag("http::async::head"),
|
||||
tag("http::async::get"),
|
||||
tag("http::async::put"),
|
||||
tag("http::async::post"),
|
||||
tag("http::async::patch"),
|
||||
tag("http::async::delete"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_is(i: &str) -> IResult<&str, Function> {
|
||||
fn function_is(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("is::alpha"),
|
||||
func("is::alphanum"),
|
||||
func("is::ascii"),
|
||||
func("is::domain"),
|
||||
func("is::email"),
|
||||
func("is::hexadecimal"),
|
||||
func("is::latitude"),
|
||||
func("is::longitude"),
|
||||
func("is::numeric"),
|
||||
func("is::semver"),
|
||||
func("is::uuid"),
|
||||
tag("is::alphanum"),
|
||||
tag("is::alpha"),
|
||||
tag("is::ascii"),
|
||||
tag("is::domain"),
|
||||
tag("is::email"),
|
||||
tag("is::hexadecimal"),
|
||||
tag("is::latitude"),
|
||||
tag("is::longitude"),
|
||||
tag("is::numeric"),
|
||||
tag("is::semver"),
|
||||
tag("is::uuid"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_math(i: &str) -> IResult<&str, Function> {
|
||||
fn function_math(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
alt((
|
||||
func("math::abs"),
|
||||
func("math::bottom"),
|
||||
func("math::ceil"),
|
||||
func("math::correlation"),
|
||||
func("math::count"),
|
||||
func("math::covariance"),
|
||||
func("math::fixed"),
|
||||
func("math::floor"),
|
||||
func("math::geometricmean"),
|
||||
func("math::harmonicmean"),
|
||||
func("math::interquartile"),
|
||||
tag("math::abs"),
|
||||
tag("math::bottom"),
|
||||
tag("math::ceil"),
|
||||
tag("math::correlation"),
|
||||
tag("math::count"),
|
||||
tag("math::covariance"),
|
||||
tag("math::fixed"),
|
||||
tag("math::floor"),
|
||||
tag("math::geometricmean"),
|
||||
tag("math::harmonicmean"),
|
||||
tag("math::interquartile"),
|
||||
)),
|
||||
alt((
|
||||
func("math::max"),
|
||||
func("math::mean"),
|
||||
func("math::median"),
|
||||
func("math::midhinge"),
|
||||
func("math::min"),
|
||||
func("math::mode"),
|
||||
tag("math::max"),
|
||||
tag("math::mean"),
|
||||
tag("math::median"),
|
||||
tag("math::midhinge"),
|
||||
tag("math::min"),
|
||||
tag("math::mode"),
|
||||
)),
|
||||
alt((
|
||||
func("math::nearestrank"),
|
||||
func("math::percentile"),
|
||||
func("math::round"),
|
||||
func("math::sample"),
|
||||
func("math::spread"),
|
||||
func("math::sqrt"),
|
||||
func("math::stddev"),
|
||||
func("math::sum"),
|
||||
func("math::top"),
|
||||
func("math::trimean"),
|
||||
func("math::variance"),
|
||||
tag("math::nearestrank"),
|
||||
tag("math::percentile"),
|
||||
tag("math::round"),
|
||||
tag("math::sample"),
|
||||
tag("math::spread"),
|
||||
tag("math::sqrt"),
|
||||
tag("math::stddev"),
|
||||
tag("math::sum"),
|
||||
tag("math::top"),
|
||||
tag("math::trimean"),
|
||||
tag("math::variance"),
|
||||
)),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_parse(i: &str) -> IResult<&str, Function> {
|
||||
fn function_parse(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("parse::email::domain"),
|
||||
func("parse::email::user"),
|
||||
func("parse::url::domain"),
|
||||
func("parse::url::host"),
|
||||
func("parse::url::port"),
|
||||
func("parse::url::path"),
|
||||
tag("parse::email::domain"),
|
||||
tag("parse::email::user"),
|
||||
tag("parse::url::domain"),
|
||||
tag("parse::url::host"),
|
||||
tag("parse::url::port"),
|
||||
tag("parse::url::path"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_rand(i: &str) -> IResult<&str, Function> {
|
||||
fn function_rand(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
alt((
|
||||
func("rand"),
|
||||
func("guid"),
|
||||
func("uuid"),
|
||||
func("rand::bool"),
|
||||
func("rand::guid"),
|
||||
func("rand::uuid"),
|
||||
func("rand::enum"),
|
||||
func("rand::time"),
|
||||
func("rand::string"),
|
||||
func("rand::integer"),
|
||||
func("rand::decimal"),
|
||||
func("rand::sentence"),
|
||||
func("rand::paragraph"),
|
||||
tag("guid"),
|
||||
tag("uuid"),
|
||||
tag("rand::bool"),
|
||||
tag("rand::guid"),
|
||||
tag("rand::uuid"),
|
||||
tag("rand::enum"),
|
||||
tag("rand::time"),
|
||||
tag("rand::string"),
|
||||
tag("rand::integer"),
|
||||
tag("rand::decimal"),
|
||||
tag("rand::sentence"),
|
||||
tag("rand::paragraph"),
|
||||
)),
|
||||
alt((
|
||||
func("rand::person::email"),
|
||||
func("rand::person::phone"),
|
||||
func("rand::person::fullname"),
|
||||
func("rand::person::firstname"),
|
||||
func("rand::person::lastname"),
|
||||
func("rand::person::username"),
|
||||
func("rand::person::jobtitle"),
|
||||
tag("rand::person::email"),
|
||||
tag("rand::person::phone"),
|
||||
tag("rand::person::fullname"),
|
||||
tag("rand::person::firstname"),
|
||||
tag("rand::person::lastname"),
|
||||
tag("rand::person::username"),
|
||||
tag("rand::person::jobtitle"),
|
||||
)),
|
||||
alt((
|
||||
func("rand::location::name"),
|
||||
func("rand::location::address"),
|
||||
func("rand::location::street"),
|
||||
func("rand::location::city"),
|
||||
func("rand::location::state"),
|
||||
func("rand::location::county"),
|
||||
func("rand::location::zipcode"),
|
||||
func("rand::location::postcode"),
|
||||
func("rand::location::country"),
|
||||
func("rand::location::altitude"),
|
||||
func("rand::location::latitude"),
|
||||
func("rand::location::longitude"),
|
||||
tag("rand::location::name"),
|
||||
tag("rand::location::address"),
|
||||
tag("rand::location::street"),
|
||||
tag("rand::location::city"),
|
||||
tag("rand::location::state"),
|
||||
tag("rand::location::county"),
|
||||
tag("rand::location::zipcode"),
|
||||
tag("rand::location::postcode"),
|
||||
tag("rand::location::country"),
|
||||
tag("rand::location::altitude"),
|
||||
tag("rand::location::latitude"),
|
||||
tag("rand::location::longitude"),
|
||||
)),
|
||||
tag("rand"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_string(i: &str) -> IResult<&str, Function> {
|
||||
fn function_string(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("string::concat"),
|
||||
func("string::contains"),
|
||||
func("string::endsWith"),
|
||||
func("string::format"),
|
||||
func("string::includes"),
|
||||
func("string::join"),
|
||||
func("string::length"),
|
||||
func("string::lowercase"),
|
||||
func("string::repeat"),
|
||||
func("string::replace"),
|
||||
func("string::reverse"),
|
||||
func("string::search"),
|
||||
func("string::slice"),
|
||||
func("string::slug"),
|
||||
func("string::split"),
|
||||
func("string::startsWith"),
|
||||
func("string::substr"),
|
||||
func("string::trim"),
|
||||
func("string::uppercase"),
|
||||
func("string::words"),
|
||||
tag("string::concat"),
|
||||
tag("string::contains"),
|
||||
tag("string::endsWith"),
|
||||
tag("string::format"),
|
||||
tag("string::includes"),
|
||||
tag("string::join"),
|
||||
tag("string::length"),
|
||||
tag("string::lowercase"),
|
||||
tag("string::repeat"),
|
||||
tag("string::replace"),
|
||||
tag("string::reverse"),
|
||||
tag("string::search"),
|
||||
tag("string::slice"),
|
||||
tag("string::slug"),
|
||||
tag("string::split"),
|
||||
tag("string::startsWith"),
|
||||
tag("string::substr"),
|
||||
tag("string::trim"),
|
||||
tag("string::uppercase"),
|
||||
tag("string::words"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_time(i: &str) -> IResult<&str, Function> {
|
||||
fn function_time(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("time::now"),
|
||||
func("time::add"),
|
||||
func("time::age"),
|
||||
func("time::floor"),
|
||||
func("time::round"),
|
||||
func("time::day"),
|
||||
func("time::hour"),
|
||||
func("time::mins"),
|
||||
func("time::month"),
|
||||
func("time::nano"),
|
||||
func("time::secs"),
|
||||
func("time::unix"),
|
||||
func("time::wday"),
|
||||
func("time::week"),
|
||||
func("time::yday"),
|
||||
func("time::year"),
|
||||
tag("time::now"),
|
||||
tag("time::add"),
|
||||
tag("time::age"),
|
||||
tag("time::floor"),
|
||||
tag("time::round"),
|
||||
tag("time::day"),
|
||||
tag("time::hour"),
|
||||
tag("time::mins"),
|
||||
tag("time::month"),
|
||||
tag("time::nano"),
|
||||
tag("time::secs"),
|
||||
tag("time::unix"),
|
||||
tag("time::wday"),
|
||||
tag("time::week"),
|
||||
tag("time::yday"),
|
||||
tag("time::year"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn function_type(i: &str) -> IResult<&str, Function> {
|
||||
fn function_type(i: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
func("type::batch"),
|
||||
func("type::model"),
|
||||
func("type::regex"),
|
||||
func("type::table"),
|
||||
func("type::thing"),
|
||||
tag("type::batch"),
|
||||
tag("type::model"),
|
||||
tag("type::point"),
|
||||
tag("type::polygon"),
|
||||
tag("type::regex"),
|
||||
tag("type::table"),
|
||||
tag("type::thing"),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn cast<'b, 'a: 'b>(f: &'a str) -> impl Fn(&'b str) -> IResult<&'b str, Function> where {
|
||||
move |i: &'b str| {
|
||||
let (i, _) = tag("<")(i)?;
|
||||
let (i, n) = tag(f)(i)?;
|
||||
let (i, _) = tag(">")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, a) = simple(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Function {
|
||||
name: n.to_string(),
|
||||
args: vec![Expression::from(a)],
|
||||
cast: true,
|
||||
func: false,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn func<'b, 'a: 'b>(f: &'a str) -> impl Fn(&'b str) -> IResult<&'b str, Function> where {
|
||||
move |i: &'b str| {
|
||||
let (i, n) = tag(f)(i)?;
|
||||
let (i, _) = tag("(")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = separated_list(commas, expression)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag(")")(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Function {
|
||||
name: n.to_string(),
|
||||
args: v,
|
||||
cast: false,
|
||||
func: false,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
@ -384,15 +378,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("count()", format!("{}", out));
|
||||
assert_eq!(
|
||||
out,
|
||||
Function {
|
||||
name: String::from("count"),
|
||||
args: vec![],
|
||||
cast: false,
|
||||
func: false,
|
||||
}
|
||||
);
|
||||
assert_eq!(out, Function::Normal(String::from("count"), vec![]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -402,15 +388,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("count::if()", format!("{}", out));
|
||||
assert_eq!(
|
||||
out,
|
||||
Function {
|
||||
name: String::from("count::if"),
|
||||
args: vec![],
|
||||
cast: false,
|
||||
func: false,
|
||||
}
|
||||
);
|
||||
assert_eq!(out, Function::Normal(String::from("count::if"), vec![]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -422,31 +400,18 @@ mod tests {
|
|||
assert_eq!("is::numeric(NULL)", format!("{}", out));
|
||||
assert_eq!(
|
||||
out,
|
||||
Function {
|
||||
name: String::from("is::numeric"),
|
||||
args: vec![Expression::from("null")],
|
||||
cast: false,
|
||||
func: false,
|
||||
}
|
||||
Function::Normal(String::from("is::numeric"), vec![Expression::from("null")])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_casting_number() {
|
||||
let sql = "<uint64>1.2345";
|
||||
let sql = "<int>1.2345";
|
||||
let res = function(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("<uint64>1.2345", format!("{}", out));
|
||||
assert_eq!(
|
||||
out,
|
||||
Function {
|
||||
name: String::from("uint64"),
|
||||
args: vec![Expression::from("1.2345")],
|
||||
cast: true,
|
||||
func: false,
|
||||
}
|
||||
);
|
||||
assert_eq!("<int>1.2345", format!("{}", out));
|
||||
assert_eq!(out, Function::Cast(String::from("int"), Expression::from("1.2345")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -456,15 +421,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("<string>1.2345", format!("{}", out));
|
||||
assert_eq!(
|
||||
out,
|
||||
Function {
|
||||
name: String::from("string"),
|
||||
args: vec![Expression::from("1.2345")],
|
||||
cast: true,
|
||||
func: false,
|
||||
}
|
||||
);
|
||||
assert_eq!(out, Function::Cast(String::from("string"), Expression::from("1.2345")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -474,14 +431,6 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("fn() -> { 1.2345 + 5.4321 }", format!("{}", out));
|
||||
assert_eq!(
|
||||
out,
|
||||
Function {
|
||||
name: String::from("fn"),
|
||||
args: vec![Expression::from("1.2345 + 5.4321")],
|
||||
cast: false,
|
||||
func: true,
|
||||
}
|
||||
);
|
||||
assert_eq!(out, Function::Future(Expression::from("1.2345 + 5.4321")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ use crate::sql::common::commas;
|
|||
use crate::sql::idiom::{idiom, Idiom};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::sequence::tuple;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Groups(Vec<Group>);
|
||||
|
||||
impl fmt::Display for Groups {
|
||||
|
@ -22,7 +22,7 @@ impl fmt::Display for Groups {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Group {
|
||||
pub group: Idiom,
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ pub fn group(i: &str) -> IResult<&str, Groups> {
|
|||
let (i, _) = tag_no_case("GROUP")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("BY"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = separated_nonempty_list(commas, group_raw)(i)?;
|
||||
let (i, v) = separated_list1(commas, group_raw)(i)?;
|
||||
Ok((i, Groups(v)))
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Ident {
|
||||
pub name: String,
|
||||
}
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::common::{escape, val_char};
|
||||
use crate::sql::filter::{filter, Filter};
|
||||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Idioms(Vec<Idiom>);
|
||||
|
||||
impl fmt::Display for Idioms {
|
||||
|
@ -20,11 +26,11 @@ impl fmt::Display for Idioms {
|
|||
}
|
||||
|
||||
pub fn idioms(i: &str) -> IResult<&str, Idioms> {
|
||||
let (i, v) = separated_nonempty_list(commas, idiom)(i)?;
|
||||
let (i, v) = separated_list1(commas, idiom)(i)?;
|
||||
Ok((i, Idioms(v)))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct Idiom {
|
||||
pub parts: Vec<(String, Option<Filter>)>,
|
||||
}
|
||||
|
@ -67,8 +73,19 @@ impl fmt::Display for Idiom {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for Idiom {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn idiom(i: &str) -> IResult<&str, Idiom> {
|
||||
let (i, v) = separated_nonempty_list(tag("."), all)(i)?;
|
||||
let (i, v) = separated_list1(tag("."), all)(i)?;
|
||||
Ok((i, Idiom::from(v)))
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Kind {
|
||||
Any,
|
||||
Array,
|
||||
|
|
|
@ -7,7 +7,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Limit {
|
||||
pub expr: u64,
|
||||
}
|
||||
|
@ -23,7 +23,12 @@ pub fn limit(i: &str) -> IResult<&str, Limit> {
|
|||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("BY"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = take_u64(i)?;
|
||||
Ok((i, Limit { expr: v }))
|
||||
Ok((
|
||||
i,
|
||||
Limit {
|
||||
expr: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -37,7 +42,12 @@ mod tests {
|
|||
let res = limit(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(out, Limit { expr: 100 });
|
||||
assert_eq!(
|
||||
out,
|
||||
Limit {
|
||||
expr: 100
|
||||
}
|
||||
);
|
||||
assert_eq!("LIMIT 100", format!("{}", out));
|
||||
}
|
||||
|
||||
|
@ -47,7 +57,12 @@ mod tests {
|
|||
let res = limit(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(out, Limit { expr: 100 });
|
||||
assert_eq!(
|
||||
out,
|
||||
Limit {
|
||||
expr: 100
|
||||
}
|
||||
);
|
||||
assert_eq!("LIMIT 100", format!("{}", out));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,42 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::fnc;
|
||||
use crate::sql::array::{array, Array};
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::datetime::{datetime, Datetime};
|
||||
use crate::sql::duration::{duration, Duration};
|
||||
use crate::sql::datetime::{datetime, datetime_raw, Datetime};
|
||||
use crate::sql::duration::{duration, duration_raw, Duration};
|
||||
use crate::sql::function::{function, Function};
|
||||
use crate::sql::idiom::{idiom, Idiom};
|
||||
use crate::sql::model::{model, Model};
|
||||
use crate::sql::number::{number, Number};
|
||||
use crate::sql::object::{object, Object};
|
||||
use crate::sql::param::{param, Param};
|
||||
use crate::sql::point::{point, Point};
|
||||
use crate::sql::polygon::{polygon, Polygon};
|
||||
use crate::sql::regex::{regex, Regex};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::subquery::{subquery, Subquery};
|
||||
use crate::sql::table::{table, Table};
|
||||
use crate::sql::thing::{thing, Thing};
|
||||
use dec::prelude::ToPrimitive;
|
||||
use dec::Decimal;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::map;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::combinator::rest;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Literals(Vec<Literal>);
|
||||
const NAME: &'static str = "Literal";
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Literals(pub Vec<Literal>);
|
||||
|
||||
impl fmt::Display for Literals {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -28,88 +44,432 @@ impl fmt::Display for Literals {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
impl IntoIterator for Literals {
|
||||
type Item = Literal;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn literals(i: &str) -> IResult<&str, Literals> {
|
||||
let (i, v) = separated_list1(commas, literal)(i)?;
|
||||
Ok((i, Literals(v)))
|
||||
}
|
||||
|
||||
pub fn whats(i: &str) -> IResult<&str, Literals> {
|
||||
let (i, v) = separated_list1(commas, what)(i)?;
|
||||
Ok((i, Literals(v)))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Deserialize)]
|
||||
pub enum Literal {
|
||||
None,
|
||||
Void,
|
||||
Null,
|
||||
Bool(bool),
|
||||
False,
|
||||
True,
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Param(Param),
|
||||
Idiom(Idiom),
|
||||
Table(Table),
|
||||
Thing(Thing),
|
||||
Model(Model),
|
||||
Regex(Regex),
|
||||
Point(Point),
|
||||
Array(Array),
|
||||
Object(Object),
|
||||
Number(Number),
|
||||
Strand(Strand),
|
||||
Polygon(Polygon),
|
||||
Duration(Duration),
|
||||
Datetime(Datetime),
|
||||
Function(Function),
|
||||
Subquery(Subquery),
|
||||
}
|
||||
|
||||
impl Eq for Literal {}
|
||||
|
||||
impl Default for Literal {
|
||||
fn default() -> Literal {
|
||||
Literal::Null
|
||||
Literal::None
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Literal {
|
||||
fn from(v: bool) -> Self {
|
||||
match v {
|
||||
true => Literal::True,
|
||||
false => Literal::False,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i8> for Literal {
|
||||
fn from(v: i8) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i16> for Literal {
|
||||
fn from(v: i16) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Literal {
|
||||
fn from(v: i32) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Literal {
|
||||
fn from(v: i64) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Literal {
|
||||
fn from(v: u8) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Literal {
|
||||
fn from(v: u16) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Literal {
|
||||
fn from(v: u32) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Literal {
|
||||
fn from(v: u64) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Literal {
|
||||
fn from(f: f32) -> Self {
|
||||
Literal::Number(Number::from(f))
|
||||
fn from(v: f32) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Literal {
|
||||
fn from(f: f64) -> Self {
|
||||
Literal::Number(Number::from(f))
|
||||
fn from(v: f64) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Number> for Literal {
|
||||
fn from(v: Number) -> Self {
|
||||
Literal::Number(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Decimal> for Literal {
|
||||
fn from(v: Decimal) -> Self {
|
||||
Literal::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Strand> for Literal {
|
||||
fn from(v: Strand) -> Self {
|
||||
Literal::Strand(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Literal {
|
||||
fn from(v: String) -> Self {
|
||||
Literal::Strand(Strand::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Literal {
|
||||
fn from(s: &str) -> Self {
|
||||
Literal::Strand(Strand::from(s))
|
||||
fn from(v: &str) -> Self {
|
||||
Literal::Strand(Strand::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
pub fn is_none(&self) -> bool {
|
||||
match self {
|
||||
Literal::None => true,
|
||||
Literal::Void => true,
|
||||
Literal::Null => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_void(&self) -> bool {
|
||||
match self {
|
||||
Literal::None => true,
|
||||
Literal::Void => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_null(&self) -> bool {
|
||||
match self {
|
||||
Literal::None => true,
|
||||
Literal::Null => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_true(&self) -> bool {
|
||||
match self {
|
||||
Literal::True => true,
|
||||
Literal::Strand(ref v) => v.value.to_ascii_lowercase() == "true",
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_false(&self) -> bool {
|
||||
match self {
|
||||
Literal::False => true,
|
||||
Literal::Strand(ref v) => v.value.to_ascii_lowercase() == "false",
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bool(&self) -> bool {
|
||||
match self {
|
||||
Literal::True => true,
|
||||
Literal::False => false,
|
||||
Literal::Int(v) => v > &0,
|
||||
Literal::Float(v) => v > &0.0,
|
||||
Literal::Thing(_) => true,
|
||||
Literal::Point(_) => true,
|
||||
Literal::Polygon(_) => true,
|
||||
Literal::Array(ref v) => v.value.len() > 0,
|
||||
Literal::Object(ref v) => v.value.len() > 0,
|
||||
Literal::Strand(ref v) => v.value.to_ascii_lowercase() != "false",
|
||||
Literal::Number(ref v) => v.value > Decimal::new(0, 0),
|
||||
Literal::Duration(ref v) => v.value.as_nanos() > 0,
|
||||
Literal::Datetime(ref v) => v.value.timestamp() > 0,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int(&self) -> i64 {
|
||||
match self {
|
||||
Literal::True => 1,
|
||||
Literal::Int(ref v) => v.clone(),
|
||||
Literal::Float(ref v) => *v as i64,
|
||||
Literal::Strand(ref v) => v.value.parse::<i64>().unwrap_or(0),
|
||||
Literal::Number(ref v) => v.value.to_i64().unwrap_or(0),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float(&self) -> f64 {
|
||||
match self {
|
||||
Literal::True => 1.0,
|
||||
Literal::Int(ref v) => *v as f64,
|
||||
Literal::Float(ref v) => v.clone(),
|
||||
Literal::Strand(ref v) => v.value.parse::<f64>().unwrap_or(0.0),
|
||||
Literal::Number(ref v) => v.value.to_f64().unwrap_or(0.0),
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_strand(&self) -> Strand {
|
||||
match self {
|
||||
Literal::Strand(ref v) => v.clone(),
|
||||
_ => Strand::from(self.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_number(&self) -> Number {
|
||||
match self {
|
||||
Literal::True => Number::from(1),
|
||||
Literal::Int(ref v) => Number::from(*v),
|
||||
Literal::Float(ref v) => Number::from(*v),
|
||||
Literal::Number(ref v) => v.clone(),
|
||||
Literal::Strand(ref v) => Number::from(v.value.as_str()),
|
||||
Literal::Duration(ref v) => v.value.as_secs().into(),
|
||||
Literal::Datetime(ref v) => v.value.timestamp().into(),
|
||||
_ => Number::from(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_datetime(&self) -> Datetime {
|
||||
match self {
|
||||
Literal::Strand(ref v) => Datetime::from(v.value.as_str()),
|
||||
Literal::Datetime(ref v) => v.clone(),
|
||||
_ => Datetime::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_duration(&self) -> Duration {
|
||||
match self {
|
||||
Literal::Strand(ref v) => Duration::from(v.value.as_str()),
|
||||
Literal::Duration(ref v) => v.clone(),
|
||||
_ => Duration::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Literal::None => write!(f, "NONE"),
|
||||
Literal::Void => write!(f, "VOID"),
|
||||
Literal::Null => write!(f, "NULL"),
|
||||
Literal::Bool(true) => write!(f, "true"),
|
||||
Literal::Bool(false) => write!(f, "false"),
|
||||
Literal::Param(v) => write!(f, "{}", v),
|
||||
Literal::Idiom(v) => write!(f, "{}", v),
|
||||
Literal::Thing(v) => write!(f, "{}", v),
|
||||
Literal::Model(v) => write!(f, "{}", v),
|
||||
Literal::Array(v) => write!(f, "{}", v),
|
||||
Literal::Object(v) => write!(f, "{}", v),
|
||||
Literal::Number(v) => write!(f, "{}", v),
|
||||
Literal::Strand(v) => write!(f, "{}", v),
|
||||
Literal::Duration(v) => write!(f, "{}", v),
|
||||
Literal::Datetime(v) => write!(f, "{}", v),
|
||||
Literal::Function(v) => write!(f, "{}", v),
|
||||
Literal::Subquery(v) => write!(f, "{}", v),
|
||||
Literal::True => write!(f, "true"),
|
||||
Literal::False => write!(f, "false"),
|
||||
Literal::Int(v) => write!(f, "{}", v),
|
||||
Literal::Float(v) => write!(f, "{}", v),
|
||||
Literal::Param(ref v) => write!(f, "{}", v),
|
||||
Literal::Idiom(ref v) => write!(f, "{}", v),
|
||||
Literal::Table(ref v) => write!(f, "{}", v),
|
||||
Literal::Thing(ref v) => write!(f, "{}", v),
|
||||
Literal::Model(ref v) => write!(f, "{}", v),
|
||||
Literal::Regex(ref v) => write!(f, "{}", v),
|
||||
Literal::Point(ref v) => write!(f, "{}", v),
|
||||
Literal::Array(ref v) => write!(f, "{}", v),
|
||||
Literal::Object(ref v) => write!(f, "{}", v),
|
||||
Literal::Number(ref v) => write!(f, "{}", v),
|
||||
Literal::Strand(ref v) => write!(f, "{}", v),
|
||||
Literal::Polygon(ref v) => write!(f, "{}", v),
|
||||
Literal::Duration(ref v) => write!(f, "{}", v),
|
||||
Literal::Datetime(ref v) => write!(f, "{}", v),
|
||||
Literal::Function(ref v) => write!(f, "{}", v),
|
||||
Literal::Subquery(ref v) => write!(f, "{}", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn literals(i: &str) -> IResult<&str, Literals> {
|
||||
let (i, v) = separated_nonempty_list(commas, literal)(i)?;
|
||||
Ok((i, Literals(v)))
|
||||
impl dbs::Process for Literal {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
match self {
|
||||
Literal::None => Ok(Literal::None),
|
||||
Literal::Void => Ok(Literal::Void),
|
||||
Literal::Null => Ok(Literal::Null),
|
||||
Literal::True => Ok(Literal::True),
|
||||
Literal::False => Ok(Literal::False),
|
||||
Literal::Param(ref v) => v.process(ctx, exe, doc),
|
||||
Literal::Idiom(ref v) => v.process(ctx, exe, doc),
|
||||
Literal::Array(ref v) => v.process(ctx, exe, doc),
|
||||
Literal::Object(ref v) => v.process(ctx, exe, doc),
|
||||
Literal::Function(ref v) => v.process(ctx, exe, doc),
|
||||
Literal::Subquery(ref v) => v.process(ctx, exe, doc),
|
||||
_ => Ok(self.to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Literal {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if s.is_human_readable() {
|
||||
match self {
|
||||
Literal::None => s.serialize_none(),
|
||||
Literal::Void => s.serialize_none(),
|
||||
Literal::Null => s.serialize_none(),
|
||||
Literal::True => s.serialize_bool(true),
|
||||
Literal::False => s.serialize_bool(false),
|
||||
Literal::Int(v) => s.serialize_i64(*v),
|
||||
Literal::Float(v) => s.serialize_f64(*v),
|
||||
Literal::Thing(ref v) => s.serialize_some(v),
|
||||
Literal::Point(ref v) => s.serialize_some(v),
|
||||
Literal::Array(ref v) => s.serialize_some(v),
|
||||
Literal::Object(ref v) => s.serialize_some(v),
|
||||
Literal::Number(ref v) => s.serialize_some(v),
|
||||
Literal::Strand(ref v) => s.serialize_some(v),
|
||||
Literal::Polygon(ref v) => s.serialize_some(v),
|
||||
Literal::Duration(ref v) => s.serialize_some(v),
|
||||
Literal::Datetime(ref v) => s.serialize_some(v),
|
||||
_ => s.serialize_none(),
|
||||
}
|
||||
} else {
|
||||
match self {
|
||||
Literal::None => s.serialize_unit_variant(NAME, 0, "None"),
|
||||
Literal::Void => s.serialize_unit_variant(NAME, 2, "Void"),
|
||||
Literal::Null => s.serialize_unit_variant(NAME, 1, "Null"),
|
||||
Literal::True => s.serialize_unit_variant(NAME, 3, "True"),
|
||||
Literal::False => s.serialize_unit_variant(NAME, 4, "False"),
|
||||
Literal::Int(ref v) => s.serialize_newtype_variant(NAME, 5, "Int", v),
|
||||
Literal::Float(ref v) => s.serialize_newtype_variant(NAME, 6, "Float", v),
|
||||
Literal::Param(ref v) => s.serialize_newtype_variant(NAME, 7, "Param", v),
|
||||
Literal::Idiom(ref v) => s.serialize_newtype_variant(NAME, 8, "Idiom", v),
|
||||
Literal::Table(ref v) => s.serialize_newtype_variant(NAME, 9, "Table", v),
|
||||
Literal::Thing(ref v) => s.serialize_newtype_variant(NAME, 10, "Thing", v),
|
||||
Literal::Model(ref v) => s.serialize_newtype_variant(NAME, 11, "Model", v),
|
||||
Literal::Regex(ref v) => s.serialize_newtype_variant(NAME, 12, "Regex", v),
|
||||
Literal::Point(ref v) => s.serialize_newtype_variant(NAME, 13, "Point", v),
|
||||
Literal::Array(ref v) => s.serialize_newtype_variant(NAME, 14, "Array", v),
|
||||
Literal::Object(ref v) => s.serialize_newtype_variant(NAME, 15, "Object", v),
|
||||
Literal::Number(ref v) => s.serialize_newtype_variant(NAME, 16, "Number", v),
|
||||
Literal::Strand(ref v) => s.serialize_newtype_variant(NAME, 17, "Strand", v),
|
||||
Literal::Polygon(ref v) => s.serialize_newtype_variant(NAME, 18, "Polygon", v),
|
||||
Literal::Duration(ref v) => s.serialize_newtype_variant(NAME, 19, "Duration", v),
|
||||
Literal::Datetime(ref v) => s.serialize_newtype_variant(NAME, 20, "Datetime", v),
|
||||
Literal::Function(ref v) => s.serialize_newtype_variant(NAME, 21, "Function", v),
|
||||
Literal::Subquery(ref v) => s.serialize_newtype_variant(NAME, 22, "Subquery", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add for Literal {
|
||||
type Output = Self;
|
||||
fn add(self, other: Self) -> Self {
|
||||
fnc::operate::add(&self, &other).unwrap_or(Literal::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Literal {
|
||||
type Output = Self;
|
||||
fn sub(self, other: Self) -> Self {
|
||||
fnc::operate::sub(&self, &other).unwrap_or(Literal::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul for Literal {
|
||||
type Output = Self;
|
||||
fn mul(self, other: Self) -> Self {
|
||||
fnc::operate::mul(&self, &other).unwrap_or(Literal::Null)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div for Literal {
|
||||
type Output = Self;
|
||||
fn div(self, other: Self) -> Self {
|
||||
fnc::operate::div(&self, &other).unwrap_or(Literal::Null)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn literal(i: &str) -> IResult<&str, Literal> {
|
||||
alt((
|
||||
map(tag_no_case("NONE"), |_| Literal::None),
|
||||
map(tag_no_case("VOID"), |_| Literal::Void),
|
||||
map(tag_no_case("NULL"), |_| Literal::Null),
|
||||
map(tag_no_case("true"), |_| Literal::Bool(true)),
|
||||
map(tag_no_case("false"), |_| Literal::Bool(false)),
|
||||
map(tag_no_case("true"), |_| Literal::True),
|
||||
map(tag_no_case("false"), |_| Literal::False),
|
||||
map(subquery, |v| Literal::Subquery(v)),
|
||||
map(function, |v| Literal::Function(v)),
|
||||
map(datetime, |v| Literal::Datetime(v)),
|
||||
map(duration, |v| Literal::Duration(v)),
|
||||
map(polygon, |v| Literal::Polygon(v)),
|
||||
map(number, |v| Literal::Number(v)),
|
||||
map(strand, |v| Literal::Strand(v)),
|
||||
map(object, |v| Literal::Object(v)),
|
||||
map(array, |v| Literal::Array(v)),
|
||||
map(point, |v| Literal::Point(v)),
|
||||
map(param, |v| Literal::Param(v)),
|
||||
map(thing, |v| Literal::Thing(v)),
|
||||
map(model, |v| Literal::Model(v)),
|
||||
|
@ -117,11 +477,168 @@ pub fn literal(i: &str) -> IResult<&str, Literal> {
|
|||
))(i)
|
||||
}
|
||||
|
||||
pub fn simple(i: &str) -> IResult<&str, Literal> {
|
||||
pub fn what(i: &str) -> IResult<&str, Literal> {
|
||||
alt((
|
||||
map(number, |v| Literal::Number(v)),
|
||||
map(strand, |v| Literal::Strand(v)),
|
||||
map(object, |v| Literal::Object(v)),
|
||||
map(array, |v| Literal::Array(v)),
|
||||
map(param, |v| Literal::Param(v)),
|
||||
map(model, |v| Literal::Model(v)),
|
||||
map(regex, |v| Literal::Regex(v)),
|
||||
map(thing, |v| Literal::Thing(v)),
|
||||
map(table, |v| Literal::Table(v)),
|
||||
))(i)
|
||||
}
|
||||
|
||||
pub fn json(i: &str) -> IResult<&str, Literal> {
|
||||
alt((
|
||||
map(tag_no_case("NULL"), |_| Literal::Null),
|
||||
map(tag_no_case("true"), |_| Literal::True),
|
||||
map(tag_no_case("false"), |_| Literal::False),
|
||||
map(datetime_raw, |v| Literal::Datetime(v)),
|
||||
map(duration_raw, |v| Literal::Duration(v)),
|
||||
map(number, |v| Literal::Number(v)),
|
||||
map(object, |v| Literal::Object(v)),
|
||||
map(array, |v| Literal::Array(v)),
|
||||
map(rest, |v| Literal::Strand(Strand::from(v))),
|
||||
))(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn check_none() {
|
||||
assert_eq!(true, Literal::None.is_none());
|
||||
assert_eq!(true, Literal::Void.is_none());
|
||||
assert_eq!(true, Literal::Null.is_none());
|
||||
assert_eq!(false, Literal::from(1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_void() {
|
||||
assert_eq!(true, Literal::None.is_void());
|
||||
assert_eq!(true, Literal::Void.is_void());
|
||||
assert_eq!(false, Literal::Null.is_void());
|
||||
assert_eq!(false, Literal::from(1).is_void());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_null() {
|
||||
assert_eq!(true, Literal::None.is_null());
|
||||
assert_eq!(false, Literal::Void.is_null());
|
||||
assert_eq!(true, Literal::Null.is_null());
|
||||
assert_eq!(false, Literal::from(1).is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_true() {
|
||||
assert_eq!(false, Literal::None.is_true());
|
||||
assert_eq!(true, Literal::True.is_true());
|
||||
assert_eq!(false, Literal::False.is_true());
|
||||
assert_eq!(false, Literal::from(1).is_true());
|
||||
assert_eq!(true, Literal::from("true").is_true());
|
||||
assert_eq!(false, Literal::from("false").is_true());
|
||||
assert_eq!(false, Literal::from("something").is_true());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_false() {
|
||||
assert_eq!(false, Literal::None.is_false());
|
||||
assert_eq!(false, Literal::True.is_false());
|
||||
assert_eq!(true, Literal::False.is_false());
|
||||
assert_eq!(false, Literal::from(1).is_false());
|
||||
assert_eq!(false, Literal::from("true").is_false());
|
||||
assert_eq!(true, Literal::from("false").is_false());
|
||||
assert_eq!(false, Literal::from("something").is_false());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_bool() {
|
||||
assert_eq!(false, Literal::None.as_bool());
|
||||
assert_eq!(false, Literal::Null.as_bool());
|
||||
assert_eq!(false, Literal::Void.as_bool());
|
||||
assert_eq!(true, Literal::True.as_bool());
|
||||
assert_eq!(false, Literal::False.as_bool());
|
||||
assert_eq!(false, Literal::from(0).as_bool());
|
||||
assert_eq!(true, Literal::from(1).as_bool());
|
||||
assert_eq!(false, Literal::from(-1).as_bool());
|
||||
assert_eq!(true, Literal::from(1.1).as_bool());
|
||||
assert_eq!(false, Literal::from(-1.1).as_bool());
|
||||
assert_eq!(true, Literal::from("true").as_bool());
|
||||
assert_eq!(false, Literal::from("false").as_bool());
|
||||
assert_eq!(true, Literal::from("falsey").as_bool());
|
||||
assert_eq!(true, Literal::from("something").as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_int() {
|
||||
assert_eq!(0, Literal::None.as_int());
|
||||
assert_eq!(0, Literal::Null.as_int());
|
||||
assert_eq!(0, Literal::Void.as_int());
|
||||
assert_eq!(1, Literal::True.as_int());
|
||||
assert_eq!(0, Literal::False.as_int());
|
||||
assert_eq!(0, Literal::from(0).as_int());
|
||||
assert_eq!(1, Literal::from(1).as_int());
|
||||
assert_eq!(-1, Literal::from(-1).as_int());
|
||||
assert_eq!(1, Literal::from(1.1).as_int());
|
||||
assert_eq!(-1, Literal::from(-1.1).as_int());
|
||||
assert_eq!(3, Literal::from("3").as_int());
|
||||
assert_eq!(0, Literal::from("true").as_int());
|
||||
assert_eq!(0, Literal::from("false").as_int());
|
||||
assert_eq!(0, Literal::from("something").as_int());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_float() {
|
||||
assert_eq!(0.0, Literal::None.as_float());
|
||||
assert_eq!(0.0, Literal::Null.as_float());
|
||||
assert_eq!(0.0, Literal::Void.as_float());
|
||||
assert_eq!(1.0, Literal::True.as_float());
|
||||
assert_eq!(0.0, Literal::False.as_float());
|
||||
assert_eq!(0.0, Literal::from(0).as_float());
|
||||
assert_eq!(1.0, Literal::from(1).as_float());
|
||||
assert_eq!(-1.0, Literal::from(-1).as_float());
|
||||
assert_eq!(1.1, Literal::from(1.1).as_float());
|
||||
assert_eq!(-1.1, Literal::from(-1.1).as_float());
|
||||
assert_eq!(3.0, Literal::from("3").as_float());
|
||||
assert_eq!(0.0, Literal::from("true").as_float());
|
||||
assert_eq!(0.0, Literal::from("false").as_float());
|
||||
assert_eq!(0.0, Literal::from("something").as_float());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_number() {
|
||||
assert_eq!(Number::from(0), Literal::None.as_number());
|
||||
assert_eq!(Number::from(0), Literal::Null.as_number());
|
||||
assert_eq!(Number::from(0), Literal::Void.as_number());
|
||||
assert_eq!(Number::from(1), Literal::True.as_number());
|
||||
assert_eq!(Number::from(0), Literal::False.as_number());
|
||||
assert_eq!(Number::from(0), Literal::from(0).as_number());
|
||||
assert_eq!(Number::from(1), Literal::from(1).as_number());
|
||||
assert_eq!(Number::from(-1), Literal::from(-1).as_number());
|
||||
assert_eq!(Number::from(1.1), Literal::from(1.1).as_number());
|
||||
assert_eq!(Number::from(-1.1), Literal::from(-1.1).as_number());
|
||||
assert_eq!(Number::from(3), Literal::from("3").as_number());
|
||||
assert_eq!(Number::from(0), Literal::from("true").as_number());
|
||||
assert_eq!(Number::from(0), Literal::from("false").as_number());
|
||||
assert_eq!(Number::from(0), Literal::from("something").as_number());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_strand() {
|
||||
assert_eq!(Strand::from("NONE"), Literal::None.as_strand());
|
||||
assert_eq!(Strand::from("NULL"), Literal::Null.as_strand());
|
||||
assert_eq!(Strand::from("VOID"), Literal::Void.as_strand());
|
||||
assert_eq!(Strand::from("true"), Literal::True.as_strand());
|
||||
assert_eq!(Strand::from("false"), Literal::False.as_strand());
|
||||
assert_eq!(Strand::from("0"), Literal::from(0).as_strand());
|
||||
assert_eq!(Strand::from("1"), Literal::from(1).as_strand());
|
||||
assert_eq!(Strand::from("-1"), Literal::from(-1).as_strand());
|
||||
assert_eq!(Strand::from("1.1"), Literal::from(1.1).as_strand());
|
||||
assert_eq!(Strand::from("-1.1"), Literal::from(-1.1).as_strand());
|
||||
assert_eq!(Strand::from("3"), Literal::from("3").as_strand());
|
||||
assert_eq!(Strand::from("true"), Literal::from("true").as_strand());
|
||||
assert_eq!(Strand::from("false"), Literal::from("false").as_strand());
|
||||
assert_eq!(Strand::from("something"), Literal::from("something").as_strand());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ pub mod common;
|
|||
pub mod cond;
|
||||
pub mod data;
|
||||
pub mod datetime;
|
||||
pub mod definition;
|
||||
pub mod duration;
|
||||
pub mod expression;
|
||||
pub mod fetch;
|
||||
|
@ -30,6 +29,8 @@ pub mod output;
|
|||
pub mod param;
|
||||
pub mod parser;
|
||||
pub mod permission;
|
||||
pub mod point;
|
||||
pub mod polygon;
|
||||
pub mod query;
|
||||
pub mod regex;
|
||||
pub mod split;
|
||||
|
@ -41,6 +42,6 @@ pub mod subquery;
|
|||
pub mod table;
|
||||
pub mod thing;
|
||||
pub mod timeout;
|
||||
pub mod value;
|
||||
pub mod version;
|
||||
pub mod view;
|
||||
pub mod what;
|
||||
|
|
|
@ -8,7 +8,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct Model {
|
||||
pub table: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -19,14 +19,20 @@ pub struct Model {
|
|||
|
||||
impl fmt::Display for Model {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "|{}:", escape(&self.table, &val_char, "`"))?;
|
||||
if let Some(ref v) = self.count {
|
||||
write!(f, "{}", v)?
|
||||
match self.count {
|
||||
Some(ref c) => {
|
||||
let t = escape(&self.table, &val_char, "`");
|
||||
write!(f, "|{}:{}|", t, c)?;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if let Some(ref v) = self.range {
|
||||
write!(f, "{}..{}", v.0, v.1)?
|
||||
match self.range {
|
||||
Some((ref b, ref e)) => {
|
||||
let t = escape(&self.table, &val_char, "`");
|
||||
write!(f, "|{}:{}..{}|", t, b, e)?;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
write!(f, "|")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,93 @@
|
|||
use dec::Decimal;
|
||||
use nom::number::complete::double;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Number {
|
||||
pub value: Decimal,
|
||||
}
|
||||
|
||||
impl Default for Number {
|
||||
fn default() -> Self {
|
||||
Number { value: 0i32.into() }
|
||||
Number {
|
||||
value: 0i32.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i8> for Number {
|
||||
fn from(i: i8) -> Self {
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i16> for Number {
|
||||
fn from(i: i16) -> Self {
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Number {
|
||||
fn from(i: i32) -> Self {
|
||||
Number { value: i.into() }
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Number {
|
||||
fn from(i: i64) -> Self {
|
||||
Number { value: i.into() }
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Number {
|
||||
fn from(i: u8) -> Self {
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Number {
|
||||
fn from(i: u16) -> Self {
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Number {
|
||||
fn from(i: u32) -> Self {
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Number {
|
||||
fn from(i: u64) -> Self {
|
||||
Number {
|
||||
value: i.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Number {
|
||||
fn from(f: f32) -> Self {
|
||||
Number {
|
||||
value: Decimal::from_str(&f.to_string()).unwrap(),
|
||||
value: Decimal::from_str(&f.to_string()).unwrap_or(Decimal::new(0, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +95,7 @@ impl From<f32> for Number {
|
|||
impl From<f64> for Number {
|
||||
fn from(f: f64) -> Self {
|
||||
Number {
|
||||
value: Decimal::from_str(&f.to_string()).unwrap(),
|
||||
value: Decimal::from_str(&f.to_string()).unwrap_or(Decimal::new(0, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +103,7 @@ impl From<f64> for Number {
|
|||
impl<'a> From<&'a str> for Number {
|
||||
fn from(s: &str) -> Self {
|
||||
Number {
|
||||
value: Decimal::from_str(s).unwrap(),
|
||||
value: Decimal::from_str(s).unwrap_or(Decimal::new(0, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +111,15 @@ impl<'a> From<&'a str> for Number {
|
|||
impl From<String> for Number {
|
||||
fn from(s: String) -> Self {
|
||||
Number {
|
||||
value: Decimal::from_str(&s).unwrap(),
|
||||
value: Decimal::from_str(&s).unwrap_or(Decimal::new(0, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Decimal> for Number {
|
||||
fn from(v: Decimal) -> Self {
|
||||
Number {
|
||||
value: v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +130,49 @@ impl fmt::Display for Number {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Number {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_some(&self.value)
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct("Number", 1)?;
|
||||
val.serialize_field("value", &self.value)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add for Number {
|
||||
type Output = Self;
|
||||
fn add(self, other: Self) -> Self {
|
||||
Number::from(self.value + other.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Number {
|
||||
type Output = Self;
|
||||
fn sub(self, other: Self) -> Self {
|
||||
Number::from(self.value - other.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul for Number {
|
||||
type Output = Self;
|
||||
fn mul(self, other: Self) -> Self {
|
||||
Number::from(self.value * other.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div for Number {
|
||||
type Output = Self;
|
||||
fn div(self, other: Self) -> Self {
|
||||
Number::from(self.value / other.value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn number(i: &str) -> IResult<&str, Number> {
|
||||
let (i, v) = double(i)?;
|
||||
Ok((i, Number::from(v)))
|
||||
|
|
|
@ -1,26 +1,39 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::{commas, escape, val_char};
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::expression::expression;
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::value::Value;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::is_not;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::take_while1;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::separated_list;
|
||||
use nom::multi::separated_list0;
|
||||
use nom::sequence::delimited;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeMap;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Object(Vec<(String, Expression)>);
|
||||
const NAME: &'static str = "Object";
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Object {
|
||||
pub value: Vec<(String, Value)>,
|
||||
}
|
||||
|
||||
impl fmt::Display for Object {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{{ {} }}",
|
||||
self.0
|
||||
self.value
|
||||
.iter()
|
||||
.map(|(ref k, ref v)| format!("{}: {}", escape(&k, &val_char, "\""), v))
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -29,24 +42,71 @@ impl fmt::Display for Object {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for Object {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
self.value
|
||||
.iter()
|
||||
.map(|(k, v)| match v.process(ctx, exe, doc) {
|
||||
Ok(v) => Ok((k.clone(), Value::from(v))),
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map(|v| {
|
||||
Literal::Object(Object {
|
||||
value: v,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Object {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
let mut map = serializer.serialize_map(Some(self.value.len()))?;
|
||||
for (ref k, ref v) in &self.value {
|
||||
map.serialize_key(k)?;
|
||||
map.serialize_value(v)?;
|
||||
}
|
||||
map.end()
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct(NAME, 1)?;
|
||||
val.serialize_field("value", &self.value)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn object(i: &str) -> IResult<&str, Object> {
|
||||
let (i, _) = tag("{")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = separated_list(commas, item)(i)?;
|
||||
let (i, v) = separated_list0(commas, item)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(tag(","))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("}")(i)?;
|
||||
Ok((i, Object(v)))
|
||||
Ok((
|
||||
i,
|
||||
Object {
|
||||
value: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn item(i: &str) -> IResult<&str, (String, Expression)> {
|
||||
fn item(i: &str) -> IResult<&str, (String, Value)> {
|
||||
let (i, k) = key(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag(":")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = expression(i)?;
|
||||
Ok((i, (String::from(k), v)))
|
||||
Ok((i, (String::from(k), Value::from(v))))
|
||||
}
|
||||
|
||||
fn key(i: &str) -> IResult<&str, &str> {
|
||||
|
@ -77,7 +137,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("{ one: 1, two: 2, tre: 3 }", format!("{}", out));
|
||||
assert_eq!(out.0.len(), 3);
|
||||
assert_eq!(out.value.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -87,7 +147,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("{ one: 1, two: 2, tre: 3 }", format!("{}", out));
|
||||
assert_eq!(out.0.len(), 3);
|
||||
assert_eq!(out.value.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -97,6 +157,6 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("{ one: 1, two: 2, tre: 3 + 1 }", format!("{}", out));
|
||||
assert_eq!(out.0.len(), 3);
|
||||
assert_eq!(out.value.len(), 3);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum Operator {
|
||||
And, // &&
|
||||
Or, // ||
|
||||
And, // &&
|
||||
//
|
||||
Add, // +
|
||||
Sub, // -
|
||||
|
@ -18,9 +18,6 @@ pub enum Operator {
|
|||
Inc, // +=
|
||||
Dec, // -=
|
||||
//
|
||||
Exact, // ==
|
||||
NotExact, // !==
|
||||
//
|
||||
Equal, // =
|
||||
NotEqual, // !=
|
||||
AllEqual, // *=
|
||||
|
@ -58,16 +55,14 @@ impl Default for Operator {
|
|||
impl fmt::Display for Operator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Operator::And => write!(f, "AND"),
|
||||
Operator::Or => write!(f, "OR"),
|
||||
Operator::And => write!(f, "AND"),
|
||||
Operator::Add => write!(f, "+"),
|
||||
Operator::Sub => write!(f, "-"),
|
||||
Operator::Mul => write!(f, "*"),
|
||||
Operator::Div => write!(f, "/"),
|
||||
Operator::Inc => write!(f, "+="),
|
||||
Operator::Dec => write!(f, "-="),
|
||||
Operator::Exact => write!(f, "=="),
|
||||
Operator::NotExact => write!(f, "!=="),
|
||||
Operator::Equal => write!(f, "="),
|
||||
Operator::NotEqual => write!(f, "!="),
|
||||
Operator::AllEqual => write!(f, "*="),
|
||||
|
@ -119,8 +114,6 @@ pub fn operator(i: &str) -> IResult<&str, Operator> {
|
|||
map(tag("!="), |_| Operator::NotEqual),
|
||||
map(tag("*="), |_| Operator::AllEqual),
|
||||
map(tag("?="), |_| Operator::AnyEqual),
|
||||
map(tag("=="), |_| Operator::Exact),
|
||||
map(tag("!=="), |_| Operator::NotExact),
|
||||
)),
|
||||
alt((
|
||||
map(tag("~"), |_| Operator::Like),
|
||||
|
|
|
@ -4,13 +4,13 @@ use crate::sql::idiom::{idiom, Idiom};
|
|||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::{map, opt};
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::sequence::tuple;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Orders(Vec<Order>);
|
||||
|
||||
impl fmt::Display for Orders {
|
||||
|
@ -23,7 +23,7 @@ impl fmt::Display for Orders {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Order {
|
||||
pub order: Idiom,
|
||||
pub random: bool,
|
||||
|
@ -56,7 +56,7 @@ pub fn order(i: &str) -> IResult<&str, Orders> {
|
|||
let (i, _) = tag_no_case("ORDER")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("BY"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = alt((order_rand, separated_nonempty_list(commas, order_raw)))(i)?;
|
||||
let (i, v) = alt((order_rand, separated_list1(commas, order_raw)))(i)?;
|
||||
Ok((i, Orders(v)))
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Output {
|
||||
Null,
|
||||
None,
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::common::val_char;
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::take_while1;
|
||||
use nom::IResult;
|
||||
|
@ -6,7 +12,7 @@ use serde::{Deserialize, Serialize};
|
|||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct Param {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -25,6 +31,21 @@ impl fmt::Display for Param {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for Param {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// 1. Loop through the context variables
|
||||
// 2. Find a variable with the right name
|
||||
// 3. Process the variable value
|
||||
// 4. Return the processed value
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn param(i: &str) -> IResult<&str, Param> {
|
||||
let (i, _) = tag("$")(i)?;
|
||||
let (i, v) = take_while1(val_char)(i)?;
|
||||
|
|
|
@ -13,13 +13,13 @@ pub fn parse(input: &str) -> Result<Query, Error> {
|
|||
Ok(query)
|
||||
}
|
||||
}
|
||||
Err(Err::Error((i, _))) => Err(Error::ParseError {
|
||||
pos: input.len() - i.len(),
|
||||
sql: String::from(i),
|
||||
Err(Err::Error(e)) => Err(Error::ParseError {
|
||||
pos: input.len() - e.input.len(),
|
||||
sql: String::from(e.input),
|
||||
}),
|
||||
Err(Err::Failure((i, _))) => Err(Error::ParseError {
|
||||
pos: input.len() - i.len(),
|
||||
sql: String::from(i),
|
||||
Err(Err::Failure(e)) => Err(Error::ParseError {
|
||||
pos: input.len() - e.input.len(),
|
||||
sql: String::from(e.input),
|
||||
}),
|
||||
Err(Err::Incomplete(_)) => Err(Error::EmptyError),
|
||||
}
|
||||
|
@ -78,9 +78,10 @@ mod tests {
|
|||
test AS `some thing`,
|
||||
'2012-04-23T18:25:43.511Z' AS utctime,
|
||||
'2012-04-23T18:25:43.511-08:00' AS pacifictime,
|
||||
{ key: (3 + 1 + 2), 'some thing': { otherkey: 'text', } } AS object
|
||||
{ key: (3 + 1 + 2), other: 9 * 7, 'some thing': { otherkey: 'text', } } AS object
|
||||
FROM $param, test, temp, test:thingy, |test:10|, |test:1..10|
|
||||
WHERE IF true THEN 'YAY' ELSE 'OOPS' END
|
||||
AND (0.1341, 0.5719) INSIDE ( (0.1341, 0.5719), (0.1341, 0.5719) )
|
||||
AND (3 + 3 * 4)=6
|
||||
AND 3 + 3 * 4 = 6
|
||||
AND ages CONTAINS 18
|
||||
|
@ -94,8 +95,9 @@ mod tests {
|
|||
let res = parse(sql);
|
||||
assert!(res.is_ok());
|
||||
let tmp = res.unwrap();
|
||||
println!("{:#?}", serde_json::to_string(&tmp).unwrap());
|
||||
println!("{}", serde_cbor::to_vec(&tmp).unwrap().len());
|
||||
println!("{}", tmp)
|
||||
|
||||
let enc = serde_cbor::to_vec(&tmp).unwrap();
|
||||
let dec: Query = serde_cbor::from_slice(&enc).unwrap();
|
||||
assert_eq!(tmp, dec);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ use crate::sql::expression::{expression, Expression};
|
|||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::map;
|
||||
use nom::{multi::separated_list, sequence::tuple, IResult};
|
||||
use nom::{multi::separated_list0, sequence::tuple, IResult};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Permissions {
|
||||
pub select: Permission,
|
||||
pub create: Permission,
|
||||
|
@ -85,7 +85,7 @@ fn full(i: &str) -> IResult<&str, Permissions> {
|
|||
}
|
||||
|
||||
fn specific(i: &str) -> IResult<&str, Permissions> {
|
||||
let (i, perms) = separated_list(commas, permission)(i)?;
|
||||
let (i, perms) = separated_list0(commas, permission)(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Permissions {
|
||||
|
@ -129,7 +129,7 @@ fn specific(i: &str) -> IResult<&str, Permissions> {
|
|||
))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Permission {
|
||||
None,
|
||||
Full,
|
||||
|
@ -160,7 +160,7 @@ impl fmt::Display for Permission {
|
|||
fn permission(i: &str) -> IResult<&str, Vec<(Permission, Permission)>> {
|
||||
let (i, _) = tag_no_case("FOR")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, kind) = separated_list(
|
||||
let (i, kind) = separated_list0(
|
||||
commas,
|
||||
alt((
|
||||
map(tag_no_case("SELECT"), |_| Permission::Select),
|
||||
|
|
73
src/sql/point.rs
Normal file
73
src/sql/point.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::number::{number, Number};
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::ser::SerializeTupleStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Point(Number, Number);
|
||||
|
||||
impl fmt::Display for Point {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({}, {})", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Point {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
let mut arr = serializer.serialize_seq(Some(2))?;
|
||||
arr.serialize_element(&self.0)?;
|
||||
arr.serialize_element(&self.1)?;
|
||||
arr.end()
|
||||
} else {
|
||||
let mut val = serializer.serialize_tuple_struct("Point", 2)?;
|
||||
val.serialize_field(&self.0)?;
|
||||
val.serialize_field(&self.1)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn point(i: &str) -> IResult<&str, Point> {
|
||||
let (i, _) = tag("(")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, lat) = number(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag(",")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, lng) = number(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag(")")(i)?;
|
||||
Ok((i, Point(lat, lng)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn point_simple() {
|
||||
let sql = "(0, 0)";
|
||||
let res = point(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("(0, 0)", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn point_complex() {
|
||||
let sql = "(51.509865, -0.118092)";
|
||||
let res = point(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("(51.509865, -0.118092)", format!("{}", out));
|
||||
}
|
||||
}
|
77
src/sql/polygon.rs
Normal file
77
src/sql/polygon.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::point::{point, Point};
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::multi::separated_list0;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Polygon {
|
||||
pub points: Vec<Point>,
|
||||
}
|
||||
|
||||
impl fmt::Display for Polygon {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"( {} )",
|
||||
self.points.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", "),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Polygon {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_some(&self.points)
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct("Polygon", 1)?;
|
||||
val.serialize_field("points", &self.points)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn polygon(i: &str) -> IResult<&str, Polygon> {
|
||||
let (i, _) = tag("(")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = separated_list0(commas, point)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag(")")(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Polygon {
|
||||
points: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn polygon_simple() {
|
||||
let sql = "( (0, 0), (0, 0) )";
|
||||
let res = polygon(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("( (0, 0), (0, 0) )", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn polygon_complex() {
|
||||
let sql = "( (51.509865, -0.118092), (51.509865, -0.118092) )";
|
||||
let res = polygon(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("( (51.509865, -0.118092), (51.509865, -0.118092) )", format!("{}", out));
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Query {
|
||||
statements: Statements,
|
||||
}
|
||||
|
@ -28,7 +28,12 @@ impl fmt::Display for Query {
|
|||
|
||||
pub fn query(i: &str) -> IResult<&str, Query> {
|
||||
let (i, v) = all_consuming(statements)(i)?;
|
||||
Ok((i, Query { statements: v }))
|
||||
Ok((
|
||||
i,
|
||||
Query {
|
||||
statements: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -3,25 +3,45 @@ use nom::bytes::complete::tag;
|
|||
use nom::sequence::delimited;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Regex {
|
||||
pub value: String,
|
||||
pub input: String,
|
||||
#[serde(skip)]
|
||||
pub value: Option<regex::Regex>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Regex {
|
||||
fn from(r: &str) -> Regex {
|
||||
Regex {
|
||||
value: String::from(r),
|
||||
input: String::from(r),
|
||||
value: match regex::Regex::new(r) {
|
||||
Ok(v) => Some(v),
|
||||
Err(_) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Regex {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.input == other.input
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Regex {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.input.cmp(&other.input))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Regex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "/{}/", &self.value)
|
||||
write!(f, "/{}/", &self.input)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ use crate::sql::common::commas;
|
|||
use crate::sql::idiom::{idiom, Idiom};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::sequence::tuple;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Splits(Vec<Split>);
|
||||
|
||||
impl fmt::Display for Splits {
|
||||
|
@ -17,16 +17,12 @@ impl fmt::Display for Splits {
|
|||
write!(
|
||||
f,
|
||||
"SPLIT ON {}",
|
||||
self.0
|
||||
.iter()
|
||||
.map(|ref v| format!("{}", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
self.0.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Split {
|
||||
pub split: Idiom,
|
||||
}
|
||||
|
@ -41,13 +37,18 @@ pub fn split(i: &str) -> IResult<&str, Splits> {
|
|||
let (i, _) = tag_no_case("SPLIT")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("ON"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = separated_nonempty_list(commas, split_raw)(i)?;
|
||||
let (i, v) = separated_list1(commas, split_raw)(i)?;
|
||||
Ok((i, Splits(v)))
|
||||
}
|
||||
|
||||
fn split_raw(i: &str) -> IResult<&str, Split> {
|
||||
let (i, v) = idiom(i)?;
|
||||
Ok((i, Split { split: v }))
|
||||
Ok((
|
||||
i,
|
||||
Split {
|
||||
split: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -7,7 +7,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Start {
|
||||
pub expr: u64,
|
||||
}
|
||||
|
@ -23,7 +23,12 @@ pub fn start(i: &str) -> IResult<&str, Start> {
|
|||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("AT"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = take_u64(i)?;
|
||||
Ok((i, Start { expr: v }))
|
||||
Ok((
|
||||
i,
|
||||
Start {
|
||||
expr: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -37,7 +42,12 @@ mod tests {
|
|||
let res = start(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(out, Start { expr: 100 });
|
||||
assert_eq!(
|
||||
out,
|
||||
Start {
|
||||
expr: 100
|
||||
}
|
||||
);
|
||||
assert_eq!("START 100", format!("{}", out));
|
||||
}
|
||||
|
||||
|
@ -47,7 +57,12 @@ mod tests {
|
|||
let res = start(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(out, Start { expr: 100 });
|
||||
assert_eq!(
|
||||
out,
|
||||
Start {
|
||||
expr: 100
|
||||
}
|
||||
);
|
||||
assert_eq!("START 100", format!("{}", out));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::{comment, mightbespace};
|
||||
use crate::sql::common::colons;
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::statements::begin::{begin, BeginStatement};
|
||||
use crate::sql::statements::cancel::{cancel, CancelStatement};
|
||||
use crate::sql::statements::commit::{commit, CommitStatement};
|
||||
|
@ -23,13 +29,13 @@ use crate::sql::statements::yuse::{yuse, UseStatement};
|
|||
use nom::branch::alt;
|
||||
use nom::combinator::map;
|
||||
use nom::multi::many0;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::sequence::delimited;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Statements(pub Vec<Statement>);
|
||||
|
||||
impl Statements {
|
||||
|
@ -45,12 +51,12 @@ impl fmt::Display for Statements {
|
|||
}
|
||||
|
||||
pub fn statements(i: &str) -> IResult<&str, Statements> {
|
||||
let (i, v) = separated_nonempty_list(colons, statement)(i)?;
|
||||
let (i, v) = separated_list1(colons, statement)(i)?;
|
||||
let (i, _) = many0(alt((colons, comment)))(i)?;
|
||||
Ok((i, Statements(v)))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Statement {
|
||||
Set(SetStatement),
|
||||
Use(UseStatement),
|
||||
|
@ -101,29 +107,32 @@ impl fmt::Display for Statement {
|
|||
}
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
pub fn execute(&self) -> String {
|
||||
impl dbs::Process for Statement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
match *self {
|
||||
Statement::Use(ref v) => format!("{}", v),
|
||||
Statement::Set(ref v) => format!("{}", v),
|
||||
Statement::Info(ref v) => format!("{}", v),
|
||||
Statement::Live(ref v) => format!("{}", v),
|
||||
Statement::Kill(ref v) => format!("{}", v),
|
||||
Statement::Begin(ref v) => format!("{}", v),
|
||||
Statement::Cancel(ref v) => format!("{}", v),
|
||||
Statement::Commit(ref v) => format!("{}", v),
|
||||
Statement::Output(ref v) => format!("{}", v),
|
||||
Statement::Ifelse(ref v) => format!("{}", v),
|
||||
Statement::Select(ref v) => format!("{}", v),
|
||||
Statement::Create(ref v) => format!("{}", v),
|
||||
Statement::Update(ref v) => format!("{}", v),
|
||||
Statement::Delete(ref v) => format!("{}", v),
|
||||
Statement::Relate(ref v) => format!("{}", v),
|
||||
Statement::Insert(ref v) => format!("{}", v),
|
||||
Statement::Upsert(ref v) => format!("{}", v),
|
||||
Statement::Define(ref v) => format!("{}", v),
|
||||
Statement::Remove(ref v) => format!("{}", v),
|
||||
Statement::Option(ref v) => format!("{}", v),
|
||||
Statement::Use(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Set(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Info(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Live(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Kill(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Output(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Ifelse(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Select(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Create(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Update(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Delete(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Relate(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Insert(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Upsert(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Define(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Remove(ref v) => v.process(ctx, exe, doc),
|
||||
Statement::Option(ref v) => v.process(ctx, exe, doc),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BeginStatement;
|
||||
|
||||
impl fmt::Display for BeginStatement {
|
||||
|
|
|
@ -7,7 +7,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CancelStatement;
|
||||
|
||||
impl fmt::Display for CancelStatement {
|
||||
|
|
|
@ -7,7 +7,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CommitStatement;
|
||||
|
||||
impl fmt::Display for CommitStatement {
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::data::{data, Data};
|
||||
use crate::sql::literal::{whats, Literal, Literals};
|
||||
use crate::sql::output::{output, Output};
|
||||
use crate::sql::timeout::{timeout, Timeout};
|
||||
use crate::sql::what::{whats, Whats};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::preceded;
|
||||
|
@ -10,9 +16,9 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CreateStatement {
|
||||
pub what: Whats,
|
||||
pub what: Literals,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Data>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -37,6 +43,43 @@ impl fmt::Display for CreateStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for CreateStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// Create a new iterator
|
||||
let i = Iterator::new();
|
||||
// Loop over the select targets
|
||||
for w in self.what.to_owned() {
|
||||
match w.process(ctx, exe, doc)? {
|
||||
Literal::Table(_) => {
|
||||
i.process_table(ctx, exe);
|
||||
}
|
||||
Literal::Thing(_) => {
|
||||
i.process_thing(ctx, exe);
|
||||
}
|
||||
Literal::Model(_) => {
|
||||
i.process_model(ctx, exe);
|
||||
}
|
||||
Literal::Array(_) => {
|
||||
i.process_array(ctx, exe);
|
||||
}
|
||||
Literal::Object(_) => {
|
||||
i.process_object(ctx, exe);
|
||||
}
|
||||
_ => {
|
||||
todo!() // Return error
|
||||
}
|
||||
};
|
||||
}
|
||||
// Output the results
|
||||
i.output(ctx, exe)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(i: &str) -> IResult<&str, CreateStatement> {
|
||||
let (i, _) = tag_no_case("CREATE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::algorithm::{algorithm, Algorithm};
|
||||
use crate::sql::base::{base, Base};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::take_u64;
|
||||
use crate::sql::duration::{duration, Duration};
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::idiom::{idiom, idioms, Idiom, Idioms};
|
||||
use crate::sql::kind::{kind, Kind};
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::permission::{permissions, Permissions};
|
||||
use crate::sql::statement::{statements, Statements};
|
||||
use crate::sql::strand::strand_raw;
|
||||
use crate::sql::view::{view, View};
|
||||
use crate::sql::{
|
||||
duration::{duration, Duration},
|
||||
kind::{kind, Kind},
|
||||
permission::{permissions, Permissions},
|
||||
};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::{map, opt};
|
||||
|
@ -20,7 +24,7 @@ use nom::{multi::many0, IResult};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DefineStatement {
|
||||
Namespace(DefineNamespaceStatement),
|
||||
Database(DefineDatabaseStatement),
|
||||
|
@ -49,6 +53,17 @@ impl fmt::Display for DefineStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for DefineStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define(i: &str) -> IResult<&str, DefineStatement> {
|
||||
alt((
|
||||
map(namespace, |v| DefineStatement::Namespace(v)),
|
||||
|
@ -67,7 +82,7 @@ pub fn define(i: &str) -> IResult<&str, DefineStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineNamespaceStatement {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -96,7 +111,7 @@ fn namespace(i: &str) -> IResult<&str, DefineNamespaceStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineDatabaseStatement {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -125,7 +140,7 @@ fn database(i: &str) -> IResult<&str, DefineDatabaseStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineLoginStatement {
|
||||
pub name: String,
|
||||
pub base: Base,
|
||||
|
@ -176,7 +191,7 @@ fn login(i: &str) -> IResult<&str, DefineLoginStatement> {
|
|||
))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DefineLoginOption {
|
||||
Password(String),
|
||||
Passhash(String),
|
||||
|
@ -206,7 +221,7 @@ fn login_hash(i: &str) -> IResult<&str, DefineLoginOption> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineTokenStatement {
|
||||
pub name: String,
|
||||
pub base: Base,
|
||||
|
@ -257,7 +272,7 @@ fn token(i: &str) -> IResult<&str, DefineTokenStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineScopeStatement {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -320,7 +335,7 @@ fn scope(i: &str) -> IResult<&str, DefineScopeStatement> {
|
|||
))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DefineScopeOption {
|
||||
Session(Duration),
|
||||
Signup(Expression),
|
||||
|
@ -368,7 +383,7 @@ fn scope_connect(i: &str) -> IResult<&str, DefineScopeOption> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineTableStatement {
|
||||
pub name: String,
|
||||
pub drop: bool,
|
||||
|
@ -390,9 +405,6 @@ impl fmt::Display for DefineTableStatement {
|
|||
if self.full == false {
|
||||
write!(f, " SCHEMALESS")?
|
||||
}
|
||||
if self.drop == true {
|
||||
write!(f, " DROP")?
|
||||
}
|
||||
if let Some(ref v) = self.view {
|
||||
write!(f, " {}", v)?
|
||||
}
|
||||
|
@ -442,7 +454,7 @@ fn table(i: &str) -> IResult<&str, DefineTableStatement> {
|
|||
))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DefineTableOption {
|
||||
Drop,
|
||||
View(View),
|
||||
|
@ -489,7 +501,7 @@ fn table_permissions(i: &str) -> IResult<&str, DefineTableOption> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineEventStatement {
|
||||
pub name: String,
|
||||
pub what: String,
|
||||
|
@ -540,7 +552,7 @@ fn event(i: &str) -> IResult<&str, DefineEventStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineFieldStatement {
|
||||
pub name: Idiom,
|
||||
pub what: String,
|
||||
|
@ -615,7 +627,7 @@ fn field(i: &str) -> IResult<&str, DefineFieldStatement> {
|
|||
))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DefineFieldOption {
|
||||
Kind(Kind),
|
||||
Value(Expression),
|
||||
|
@ -670,7 +682,7 @@ fn field_permissions(i: &str) -> IResult<&str, DefineFieldOption> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DefineIndexStatement {
|
||||
pub name: String,
|
||||
pub what: String,
|
||||
|
@ -702,7 +714,7 @@ fn index(i: &str) -> IResult<&str, DefineIndexStatement> {
|
|||
let (i, _) = tag_no_case("COLUMNS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, cols) = idioms(i)?;
|
||||
let (i, uniq) = opt(|i: &str| {
|
||||
let (i, uniq) = opt(|i| {
|
||||
shouldbespace(i)?;
|
||||
tag_no_case("UNIQUE")(i)?;
|
||||
Ok((i, true))
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
use crate::sql::literal::{whats, Literal, Literals};
|
||||
use crate::sql::output::{output, Output};
|
||||
use crate::sql::timeout::{timeout, Timeout};
|
||||
use crate::sql::what::{whats, Whats};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::preceded;
|
||||
|
@ -11,9 +17,9 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DeleteStatement {
|
||||
pub what: Whats,
|
||||
pub what: Literals,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cond: Option<Cond>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -38,6 +44,43 @@ impl fmt::Display for DeleteStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for DeleteStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// Create a new iterator
|
||||
let i = Iterator::new();
|
||||
// Loop over the select targets
|
||||
for w in self.what.to_owned() {
|
||||
match w.process(ctx, exe, doc)? {
|
||||
Literal::Table(_) => {
|
||||
i.process_table(ctx, exe);
|
||||
}
|
||||
Literal::Thing(_) => {
|
||||
i.process_thing(ctx, exe);
|
||||
}
|
||||
Literal::Model(_) => {
|
||||
i.process_model(ctx, exe);
|
||||
}
|
||||
Literal::Array(_) => {
|
||||
i.process_array(ctx, exe);
|
||||
}
|
||||
Literal::Object(_) => {
|
||||
i.process_object(ctx, exe);
|
||||
}
|
||||
_ => {
|
||||
todo!() // Return error
|
||||
}
|
||||
};
|
||||
}
|
||||
// Output the results
|
||||
i.output(ctx, exe)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(i: &str) -> IResult<&str, DeleteStatement> {
|
||||
let (i, _) = tag_no_case("DELETE")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("FROM"))))(i)?;
|
||||
|
|
|
@ -1,26 +1,36 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::many0;
|
||||
use nom::multi::separated_list0;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct IfelseStatement {
|
||||
pub first: (Expression, Expression),
|
||||
pub other: Vec<(Expression, Expression)>,
|
||||
pub exprs: Vec<(Expression, Expression)>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub close: Option<Expression>,
|
||||
}
|
||||
|
||||
impl fmt::Display for IfelseStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "IF {} THEN {}", self.first.0, self.first.1)?;
|
||||
for ref o in self.other.iter() {
|
||||
write!(f, " ELSE IF {} THEN {}", o.0, o.1)?
|
||||
}
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
self.exprs
|
||||
.iter()
|
||||
.map(|(ref cond, ref then)| format!("IF {} THEN {}", cond, then))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ELSE ")
|
||||
)?;
|
||||
if let Some(ref v) = self.close {
|
||||
write!(f, " ELSE {}", v)?
|
||||
}
|
||||
|
@ -29,36 +39,42 @@ impl fmt::Display for IfelseStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for IfelseStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
for (ref cond, ref then) in &self.exprs {
|
||||
let v = cond.process(ctx, exe, doc)?;
|
||||
if v.as_bool() {
|
||||
return then.process(ctx, exe, doc);
|
||||
}
|
||||
}
|
||||
match self.close {
|
||||
Some(ref v) => v.process(ctx, exe, doc),
|
||||
None => Ok(Literal::None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ifelse(i: &str) -> IResult<&str, IfelseStatement> {
|
||||
let (i, _) = tag_no_case("IF")(i)?;
|
||||
let (i, first) = first(i)?;
|
||||
let (i, other) = many0(other)(i)?;
|
||||
let (i, exprs) = separated_list0(split, exprs)(i)?;
|
||||
let (i, close) = opt(close)(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("END")(i)?;
|
||||
Ok((
|
||||
i,
|
||||
IfelseStatement {
|
||||
first,
|
||||
other,
|
||||
exprs,
|
||||
close,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn first(i: &str) -> IResult<&str, (Expression, Expression)> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, cond) = expression(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("THEN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, then) = expression(i)?;
|
||||
Ok((i, (cond, then)))
|
||||
}
|
||||
|
||||
fn other(i: &str) -> IResult<&str, (Expression, Expression)> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ELSE IF")(i)?;
|
||||
fn exprs(i: &str) -> IResult<&str, (Expression, Expression)> {
|
||||
let (i, _) = tag_no_case("IF")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, cond) = expression(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
@ -76,6 +92,13 @@ fn close(i: &str) -> IResult<&str, Expression> {
|
|||
Ok((i, then))
|
||||
}
|
||||
|
||||
fn split(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ELSE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum InfoStatement {
|
||||
Namespace,
|
||||
Database,
|
||||
|
@ -25,6 +31,17 @@ impl fmt::Display for InfoStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for InfoStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info(i: &str) -> IResult<&str, InfoStatement> {
|
||||
let (i, _) = tag_no_case("INFO")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::output::{output, Output};
|
||||
use crate::sql::table::{table, Table};
|
||||
use crate::sql::timeout::{timeout, Timeout};
|
||||
|
@ -11,7 +18,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct InsertStatement {
|
||||
pub data: Expression,
|
||||
pub into: Table,
|
||||
|
@ -34,6 +41,32 @@ impl fmt::Display for InsertStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for InsertStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// Create a new iterator
|
||||
let i = Iterator::new();
|
||||
// LooParse the expression
|
||||
match self.data.process(ctx, exe, doc)? {
|
||||
Literal::Object(_) => {
|
||||
i.process_object(ctx, exe);
|
||||
}
|
||||
Literal::Array(_) => {
|
||||
i.process_array(ctx, exe);
|
||||
}
|
||||
_ => {
|
||||
todo!() // Return error
|
||||
}
|
||||
};
|
||||
// Output the results
|
||||
i.output(ctx, exe)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(i: &str) -> IResult<&str, InsertStatement> {
|
||||
let (i, _) = tag_no_case("INSERT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct KillStatement {
|
||||
pub id: Ident,
|
||||
}
|
||||
|
@ -16,9 +22,25 @@ impl fmt::Display for KillStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for KillStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kill(i: &str) -> IResult<&str, KillStatement> {
|
||||
let (i, _) = tag_no_case("KILL")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = ident(i)?;
|
||||
Ok((i, KillStatement { id: v }))
|
||||
Ok((
|
||||
i,
|
||||
KillStatement {
|
||||
id: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
use crate::sql::fetch::{fetch, Fetchs};
|
||||
use crate::sql::field::{fields, Fields};
|
||||
use crate::sql::what::{whats, Whats};
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::literal::{whats, Literals};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::preceded;
|
||||
|
@ -10,10 +16,10 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct LiveStatement {
|
||||
pub expr: Fields,
|
||||
pub what: Whats,
|
||||
pub what: Literals,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cond: Option<Cond>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -33,6 +39,17 @@ impl fmt::Display for LiveStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for LiveStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn live(i: &str) -> IResult<&str, LiveStatement> {
|
||||
let (i, _) = tag_no_case("LIVE SELECT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
|
@ -10,7 +16,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct OptionStatement {
|
||||
pub name: Ident,
|
||||
pub what: bool,
|
||||
|
@ -26,19 +32,24 @@ impl fmt::Display for OptionStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for OptionStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn option(i: &str) -> IResult<&str, OptionStatement> {
|
||||
let (i, _) = tag_no_case("OPTION")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, n) = ident(i)?;
|
||||
let (i, v) = opt(alt((
|
||||
map(
|
||||
tuple((mightbespace, tag("="), mightbespace, tag_no_case("TRUE"))),
|
||||
|_| true,
|
||||
),
|
||||
map(
|
||||
tuple((mightbespace, tag("="), mightbespace, tag_no_case("FALSE"))),
|
||||
|_| false,
|
||||
),
|
||||
map(tuple((mightbespace, tag("="), mightbespace, tag_no_case("TRUE"))), |_| true),
|
||||
map(tuple((mightbespace, tag("="), mightbespace, tag_no_case("FALSE"))), |_| false),
|
||||
)))(i)?;
|
||||
Ok((
|
||||
i,
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct OutputStatement {
|
||||
pub what: Expression,
|
||||
}
|
||||
|
@ -16,11 +22,27 @@ impl fmt::Display for OutputStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for OutputStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(i: &str) -> IResult<&str, OutputStatement> {
|
||||
let (i, _) = tag_no_case("RETURN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = expression(i)?;
|
||||
Ok((i, OutputStatement { what: v }))
|
||||
Ok((
|
||||
i,
|
||||
OutputStatement {
|
||||
what: v,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::data::{data, Data};
|
||||
use crate::sql::literal::{whats, Literal, Literals};
|
||||
use crate::sql::output::{output, Output};
|
||||
use crate::sql::table::{table, Table};
|
||||
use crate::sql::timeout::{timeout, Timeout};
|
||||
use crate::sql::what::{whats, Whats};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
|
@ -15,11 +21,11 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RelateStatement {
|
||||
pub kind: Table,
|
||||
pub from: Whats,
|
||||
pub with: Whats,
|
||||
pub from: Literals,
|
||||
pub with: Literals,
|
||||
pub uniq: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Data>,
|
||||
|
@ -48,6 +54,43 @@ impl fmt::Display for RelateStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for RelateStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// Create a new iterator
|
||||
let i = Iterator::new();
|
||||
// Loop over the select targets
|
||||
for f in self.from.to_owned() {
|
||||
match f.process(ctx, exe, doc)? {
|
||||
Literal::Table(_) => {
|
||||
i.process_table(ctx, exe);
|
||||
}
|
||||
Literal::Thing(_) => {
|
||||
i.process_thing(ctx, exe);
|
||||
}
|
||||
Literal::Model(_) => {
|
||||
i.process_model(ctx, exe);
|
||||
}
|
||||
Literal::Array(_) => {
|
||||
i.process_array(ctx, exe);
|
||||
}
|
||||
Literal::Object(_) => {
|
||||
i.process_object(ctx, exe);
|
||||
}
|
||||
_ => {
|
||||
todo!() // Return error
|
||||
}
|
||||
};
|
||||
}
|
||||
// Output the results
|
||||
i.output(ctx, exe)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn relate(i: &str) -> IResult<&str, RelateStatement> {
|
||||
let (i, _) = tag_no_case("RELATE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
@ -70,7 +113,7 @@ pub fn relate(i: &str) -> IResult<&str, RelateStatement> {
|
|||
))
|
||||
}
|
||||
|
||||
fn relate_o(i: &str) -> IResult<&str, (Table, Whats, Whats)> {
|
||||
fn relate_o(i: &str) -> IResult<&str, (Table, Literals, Literals)> {
|
||||
let (i, from) = whats(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("->")(i)?;
|
||||
|
@ -83,7 +126,7 @@ fn relate_o(i: &str) -> IResult<&str, (Table, Whats, Whats)> {
|
|||
Ok((i, (kind, from, with)))
|
||||
}
|
||||
|
||||
fn relate_i(i: &str) -> IResult<&str, (Table, Whats, Whats)> {
|
||||
fn relate_i(i: &str) -> IResult<&str, (Table, Literals, Literals)> {
|
||||
let (i, with) = whats(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag("<-")(i)?;
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::base::{base, Base};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::map;
|
||||
|
@ -8,7 +14,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum RemoveStatement {
|
||||
Namespace(RemoveNamespaceStatement),
|
||||
Database(RemoveDatabaseStatement),
|
||||
|
@ -37,6 +43,17 @@ impl fmt::Display for RemoveStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for RemoveStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(i: &str) -> IResult<&str, RemoveStatement> {
|
||||
alt((
|
||||
map(namespace, |v| RemoveStatement::Namespace(v)),
|
||||
|
@ -55,7 +72,7 @@ pub fn remove(i: &str) -> IResult<&str, RemoveStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveNamespaceStatement {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -84,7 +101,7 @@ fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveDatabaseStatement {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -113,7 +130,7 @@ fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveLoginStatement {
|
||||
pub name: String,
|
||||
pub base: Base,
|
||||
|
@ -148,7 +165,7 @@ fn login(i: &str) -> IResult<&str, RemoveLoginStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveTokenStatement {
|
||||
pub name: String,
|
||||
pub base: Base,
|
||||
|
@ -183,7 +200,7 @@ fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveScopeStatement {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -212,7 +229,7 @@ fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveTableStatement {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -241,7 +258,7 @@ fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveEventStatement {
|
||||
pub name: String,
|
||||
pub what: String,
|
||||
|
@ -276,7 +293,7 @@ fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveFieldStatement {
|
||||
pub name: String,
|
||||
pub what: String,
|
||||
|
@ -311,7 +328,7 @@ fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RemoveIndexStatement {
|
||||
pub name: String,
|
||||
pub what: String,
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
use crate::sql::fetch::{fetch, Fetchs};
|
||||
use crate::sql::field::{fields, Fields};
|
||||
use crate::sql::group::{group, Groups};
|
||||
use crate::sql::limit::{limit, Limit};
|
||||
use crate::sql::literal::{literals, Literals};
|
||||
use crate::sql::literal::{literals, Literal, Literals};
|
||||
use crate::sql::order::{order, Orders};
|
||||
use crate::sql::split::{split, Splits};
|
||||
use crate::sql::start::{start, Start};
|
||||
|
@ -17,7 +23,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SelectStatement {
|
||||
pub expr: Fields,
|
||||
pub what: Literals,
|
||||
|
@ -75,6 +81,40 @@ impl fmt::Display for SelectStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for SelectStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// Create a new iterator
|
||||
let i = Iterator::new();
|
||||
// Loop over the select targets
|
||||
for w in self.what.to_owned() {
|
||||
match w.process(ctx, exe, doc)? {
|
||||
Literal::Table(_) => {
|
||||
i.process_table(ctx, exe);
|
||||
}
|
||||
Literal::Thing(_) => {
|
||||
i.process_thing(ctx, exe);
|
||||
}
|
||||
Literal::Model(_) => {
|
||||
i.process_model(ctx, exe);
|
||||
}
|
||||
Literal::Array(_) => {
|
||||
i.process_array(ctx, exe);
|
||||
}
|
||||
_ => {
|
||||
i.process_query(ctx, exe);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Output the results
|
||||
i.output(ctx, exe)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select(i: &str) -> IResult<&str, SelectStatement> {
|
||||
let (i, _) = tag_no_case("SELECT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::param::{param, Param};
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
|
@ -8,7 +14,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SetStatement {
|
||||
pub name: Param,
|
||||
pub what: Expression,
|
||||
|
@ -20,6 +26,17 @@ impl fmt::Display for SetStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for SetStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(i: &str) -> IResult<&str, SetStatement> {
|
||||
let (i, _) = tag_no_case("LET")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
@ -28,7 +45,13 @@ pub fn set(i: &str) -> IResult<&str, SetStatement> {
|
|||
let (i, _) = tag("=")(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, w) = expression(i)?;
|
||||
Ok((i, SetStatement { name: n, what: w }))
|
||||
Ok((
|
||||
i,
|
||||
SetStatement {
|
||||
name: n,
|
||||
what: w,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
use crate::sql::data::{data, Data};
|
||||
use crate::sql::literal::{whats, Literal, Literals};
|
||||
use crate::sql::output::{output, Output};
|
||||
use crate::sql::timeout::{timeout, Timeout};
|
||||
use crate::sql::what::{whats, Whats};
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::preceded;
|
||||
|
@ -11,9 +17,9 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UpdateStatement {
|
||||
pub what: Whats,
|
||||
pub what: Literals,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Data>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -43,6 +49,43 @@ impl fmt::Display for UpdateStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for UpdateStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// Create a new iterator
|
||||
let i = Iterator::new();
|
||||
// Loop over the select targets
|
||||
for w in self.what.to_owned() {
|
||||
match w.process(ctx, exe, doc)? {
|
||||
Literal::Table(_) => {
|
||||
i.process_table(ctx, exe);
|
||||
}
|
||||
Literal::Thing(_) => {
|
||||
i.process_thing(ctx, exe);
|
||||
}
|
||||
Literal::Model(_) => {
|
||||
i.process_model(ctx, exe);
|
||||
}
|
||||
Literal::Array(_) => {
|
||||
i.process_array(ctx, exe);
|
||||
}
|
||||
Literal::Object(_) => {
|
||||
i.process_object(ctx, exe);
|
||||
}
|
||||
_ => {
|
||||
todo!() // Return error
|
||||
}
|
||||
};
|
||||
}
|
||||
// Output the results
|
||||
i.output(ctx, exe)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(i: &str) -> IResult<&str, UpdateStatement> {
|
||||
let (i, _) = tag_no_case("UPDATE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::output::{output, Output};
|
||||
use crate::sql::table::{table, Table};
|
||||
use crate::sql::timeout::{timeout, Timeout};
|
||||
|
@ -11,7 +18,7 @@ use nom::IResult;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UpsertStatement {
|
||||
pub data: Expression,
|
||||
pub into: Table,
|
||||
|
@ -34,6 +41,32 @@ impl fmt::Display for UpsertStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for UpsertStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
// Create a new iterator
|
||||
let i = Iterator::new();
|
||||
// LooParse the expression
|
||||
match self.data.process(ctx, exe, doc)? {
|
||||
Literal::Object(_) => {
|
||||
i.process_object(ctx, exe);
|
||||
}
|
||||
Literal::Array(_) => {
|
||||
i.process_array(ctx, exe);
|
||||
}
|
||||
_ => {
|
||||
todo!() // Return error
|
||||
}
|
||||
};
|
||||
// Output the results
|
||||
i.output(ctx, exe)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upsert(i: &str) -> IResult<&str, UpsertStatement> {
|
||||
let (i, _) = tag_no_case("UPSERT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::ident::ident_raw;
|
||||
use crate::sql::literal::Literal;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UseStatement {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ns: Option<String>,
|
||||
|
@ -27,6 +33,17 @@ impl fmt::Display for UseStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for UseStatement {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn yuse(i: &str) -> IResult<&str, UseStatement> {
|
||||
alt((both, ns, db))(i)
|
||||
}
|
||||
|
|
|
@ -3,15 +3,24 @@ use nom::bytes::complete::is_not;
|
|||
use nom::bytes::complete::tag;
|
||||
use nom::sequence::delimited;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Strand {
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl From<String> for Strand {
|
||||
fn from(s: String) -> Self {
|
||||
Strand {
|
||||
value: s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Strand {
|
||||
fn from(s: &str) -> Self {
|
||||
Strand {
|
||||
|
@ -26,6 +35,21 @@ impl fmt::Display for Strand {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Strand {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_some(&self.value)
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct("Strand", 1)?;
|
||||
val.serialize_field("value", &self.value)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn strand(i: &str) -> IResult<&str, Strand> {
|
||||
let (i, v) = strand_raw(i)?;
|
||||
Ok((i, Strand::from(v)))
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::ctx::Parent;
|
||||
use crate::dbs;
|
||||
use crate::dbs::Executor;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::statements::create::{create, CreateStatement};
|
||||
use crate::sql::statements::delete::{delete, DeleteStatement};
|
||||
use crate::sql::statements::ifelse::{ifelse, IfelseStatement};
|
||||
|
@ -12,9 +19,10 @@ use nom::bytes::complete::tag;
|
|||
use nom::combinator::map;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Subquery {
|
||||
Expression(Expression),
|
||||
Select(SelectStatement),
|
||||
|
@ -27,6 +35,13 @@ pub enum Subquery {
|
|||
Ifelse(IfelseStatement),
|
||||
}
|
||||
|
||||
impl PartialOrd for Subquery {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Subquery {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -43,6 +58,83 @@ impl fmt::Display for Subquery {
|
|||
}
|
||||
}
|
||||
|
||||
impl dbs::Process for Subquery {
|
||||
fn process(
|
||||
&self,
|
||||
ctx: &Parent,
|
||||
exe: &Executor,
|
||||
doc: Option<&Document>,
|
||||
) -> Result<Literal, Error> {
|
||||
match self {
|
||||
Subquery::Expression(ref v) => v.process(ctx, exe, doc),
|
||||
Subquery::Ifelse(ref v) => v.process(ctx, exe, doc),
|
||||
Subquery::Select(ref v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if doc.is_some() {
|
||||
let doc = doc.unwrap().clone();
|
||||
ctx.add_value("parent", doc);
|
||||
}
|
||||
let ctx = ctx.freeze();
|
||||
v.process(&ctx, exe, doc)
|
||||
}
|
||||
Subquery::Create(ref v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if doc.is_some() {
|
||||
let doc = doc.unwrap().clone();
|
||||
ctx.add_value("parent", doc);
|
||||
}
|
||||
let ctx = ctx.freeze();
|
||||
v.process(&ctx, exe, doc)
|
||||
}
|
||||
Subquery::Update(ref v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if doc.is_some() {
|
||||
let doc = doc.unwrap().clone();
|
||||
ctx.add_value("parent", doc);
|
||||
}
|
||||
let ctx = ctx.freeze();
|
||||
v.process(&ctx, exe, doc)
|
||||
}
|
||||
Subquery::Delete(ref v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if doc.is_some() {
|
||||
let doc = doc.unwrap().clone();
|
||||
ctx.add_value("parent", doc);
|
||||
}
|
||||
let ctx = ctx.freeze();
|
||||
v.process(&ctx, exe, doc)
|
||||
}
|
||||
Subquery::Relate(ref v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if doc.is_some() {
|
||||
let doc = doc.unwrap().clone();
|
||||
ctx.add_value("parent", doc);
|
||||
}
|
||||
let ctx = ctx.freeze();
|
||||
v.process(&ctx, exe, doc)
|
||||
}
|
||||
Subquery::Insert(ref v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if doc.is_some() {
|
||||
let doc = doc.unwrap().clone();
|
||||
ctx.add_value("parent", doc);
|
||||
}
|
||||
let ctx = ctx.freeze();
|
||||
v.process(&ctx, exe, doc)
|
||||
}
|
||||
Subquery::Upsert(ref v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if doc.is_some() {
|
||||
let doc = doc.unwrap().clone();
|
||||
ctx.add_value("parent", doc);
|
||||
}
|
||||
let ctx = ctx.freeze();
|
||||
v.process(&ctx, exe, doc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subquery(i: &str) -> IResult<&str, Subquery> {
|
||||
alt((subquery_ifelse, subquery_others))(i)
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@ use crate::sql::common::commas;
|
|||
use crate::sql::common::escape;
|
||||
use crate::sql::common::val_char;
|
||||
use crate::sql::ident::ident_raw;
|
||||
use nom::multi::separated_nonempty_list;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::IResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Tables(Vec<Table>);
|
||||
|
||||
impl fmt::Display for Tables {
|
||||
|
@ -18,11 +18,11 @@ impl fmt::Display for Tables {
|
|||
}
|
||||
|
||||
pub fn tables(i: &str) -> IResult<&str, Tables> {
|
||||
let (i, v) = separated_nonempty_list(commas, table)(i)?;
|
||||
let (i, v) = separated_list1(commas, table)(i)?;
|
||||
Ok((i, Tables(v)))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct Table {
|
||||
pub name: String,
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ use crate::sql::common::val_char;
|
|||
use crate::sql::ident::ident_raw;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::IResult;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Thing {
|
||||
pub table: String,
|
||||
pub id: String,
|
||||
|
@ -14,12 +15,26 @@ pub struct Thing {
|
|||
|
||||
impl fmt::Display for Thing {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}",
|
||||
escape(&self.table, &val_char, "`"),
|
||||
escape(&self.id, &val_char, "`"),
|
||||
)
|
||||
let t = escape(&self.table, &val_char, "`");
|
||||
let i = escape(&self.id, &val_char, "`");
|
||||
write!(f, "{}:{}", t, i)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Thing {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
let output = format!("{}:{}", self.table, self.id);
|
||||
serializer.serialize_some(&output)
|
||||
} else {
|
||||
let mut val = serializer.serialize_struct("Thing", 2)?;
|
||||
val.serialize_field("table", &self.table)?;
|
||||
val.serialize_field("id", &self.id)?;
|
||||
val.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue