Continue with initial code
This commit is contained in:
parent
ab0014ad02
commit
5d57c105b9
109 changed files with 4224 additions and 1814 deletions
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