Implements analyzer definition (#1705)
This commit is contained in:
parent
19b0920e15
commit
848be4dafb
28 changed files with 652 additions and 120 deletions
|
@ -234,6 +234,12 @@ pub enum Error {
|
|||
value: String,
|
||||
},
|
||||
|
||||
/// The requested analyzer does not exist
|
||||
#[error("The analyzer '{value}' does not exist")]
|
||||
AzNotFound {
|
||||
value: String,
|
||||
},
|
||||
|
||||
/// Unable to perform the realtime query
|
||||
#[error("Unable to perform the realtime query")]
|
||||
RealtimeDisabled,
|
||||
|
|
64
lib/src/key/az.rs
Normal file
64
lib/src/key/az.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use derive::Key;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Key)]
|
||||
pub struct Az<'a> {
|
||||
__: u8,
|
||||
_a: u8,
|
||||
pub ns: &'a str,
|
||||
_b: u8,
|
||||
pub db: &'a str,
|
||||
_c: u8,
|
||||
_d: u8,
|
||||
_e: u8,
|
||||
pub az: &'a str,
|
||||
}
|
||||
|
||||
pub fn new<'a>(ns: &'a str, db: &'a str, tb: &'a str) -> Az<'a> {
|
||||
Az::new(ns, db, tb)
|
||||
}
|
||||
|
||||
pub fn prefix(ns: &str, db: &str) -> Vec<u8> {
|
||||
let mut k = super::database::new(ns, db).encode().unwrap();
|
||||
k.extend_from_slice(&[0x21, 0x61, 0x7a, 0x00]);
|
||||
k
|
||||
}
|
||||
|
||||
pub fn suffix(ns: &str, db: &str) -> Vec<u8> {
|
||||
let mut k = super::database::new(ns, db).encode().unwrap();
|
||||
k.extend_from_slice(&[0x21, 0x61, 0x7a, 0xff]);
|
||||
k
|
||||
}
|
||||
|
||||
impl<'a> Az<'a> {
|
||||
pub fn new(ns: &'a str, db: &'a str, az: &'a str) -> Self {
|
||||
Self {
|
||||
__: 0x2f, // /
|
||||
_a: 0x2a, // *
|
||||
ns,
|
||||
_b: 0x2a, // *
|
||||
db,
|
||||
_c: 0x21, // !
|
||||
_d: 0x61, // a
|
||||
_e: 0x7a, // z
|
||||
az,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn key() {
|
||||
use super::*;
|
||||
#[rustfmt::skip]
|
||||
let val = Az::new(
|
||||
"ns",
|
||||
"db",
|
||||
"test",
|
||||
);
|
||||
let enc = Az::encode(&val).unwrap();
|
||||
let dec = Az::decode(&enc).unwrap();
|
||||
assert_eq!(val, dec);
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
/// DB /*{ns}!db{db}
|
||||
///
|
||||
/// Database /*{ns}*{db}
|
||||
/// AZ /*{ns}*{db}!az{az}
|
||||
/// DL /*{ns}*{db}!dl{us}
|
||||
/// DT /*{ns}*{db}!dt{tk}
|
||||
/// PA /*{ns}*{db}!pa{pa}
|
||||
|
@ -31,6 +32,7 @@
|
|||
///
|
||||
/// Index /*{ns}*{db}*{tb}¤{ix}{fd}{id}
|
||||
///
|
||||
pub mod az; // Stores a DEFINE ANALYZER config definition
|
||||
pub mod database; // Stores the key prefix for all keys under a database
|
||||
pub mod db; // Stores a DEFINE DATABASE config definition
|
||||
pub mod dl; // Stores a DEFINE LOGIN ON DATABASE config definition
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::kvs::kv::Key;
|
||||
use crate::sql::statements::DefineAnalyzerStatement;
|
||||
use crate::sql::statements::DefineDatabaseStatement;
|
||||
use crate::sql::statements::DefineEventStatement;
|
||||
use crate::sql::statements::DefineFieldStatement;
|
||||
|
@ -21,6 +22,7 @@ pub enum Entry {
|
|||
Ns(Arc<DefineNamespaceStatement>),
|
||||
Tb(Arc<DefineTableStatement>),
|
||||
// Multi definitions
|
||||
Azs(Arc<[DefineAnalyzerStatement]>),
|
||||
Dbs(Arc<[DefineDatabaseStatement]>),
|
||||
Dls(Arc<[DefineLoginStatement]>),
|
||||
Dts(Arc<[DefineTokenStatement]>),
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::sql::thing::Thing;
|
|||
use crate::sql::Value;
|
||||
use channel::Sender;
|
||||
use sql::permission::Permissions;
|
||||
use sql::statements::DefineAnalyzerStatement;
|
||||
use sql::statements::DefineDatabaseStatement;
|
||||
use sql::statements::DefineEventStatement;
|
||||
use sql::statements::DefineFieldStatement;
|
||||
|
@ -1086,6 +1087,28 @@ impl Transaction {
|
|||
val
|
||||
})
|
||||
}
|
||||
/// Retrieve all analyzer definitions for a specific database.
|
||||
pub async fn all_az(
|
||||
&mut self,
|
||||
ns: &str,
|
||||
db: &str,
|
||||
) -> Result<Arc<[DefineAnalyzerStatement]>, Error> {
|
||||
let key = crate::key::az::prefix(ns, db);
|
||||
Ok(if let Some(e) = self.cache.get(&key) {
|
||||
if let Entry::Azs(v) = e {
|
||||
v
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else {
|
||||
let beg = crate::key::az::prefix(ns, db);
|
||||
let end = crate::key::az::suffix(ns, db);
|
||||
let val = self.getr(beg..end, u32::MAX).await?;
|
||||
let val = val.convert().into();
|
||||
self.cache.set(key, Entry::Azs(Arc::clone(&val)));
|
||||
val
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieve a specific namespace definition.
|
||||
pub async fn get_ns(&mut self, ns: &str) -> Result<DefineNamespaceStatement, Error> {
|
||||
|
@ -1221,7 +1244,19 @@ impl Transaction {
|
|||
})?;
|
||||
Ok(val.into())
|
||||
}
|
||||
|
||||
/// Retrieve a specific analyzer definition.
|
||||
pub async fn get_az(
|
||||
&mut self,
|
||||
ns: &str,
|
||||
db: &str,
|
||||
az: &str,
|
||||
) -> Result<DefineAnalyzerStatement, Error> {
|
||||
let key = crate::key::az::new(ns, db, az);
|
||||
let val = self.get(key).await?.ok_or(Error::AzNotFound {
|
||||
value: az.to_owned(),
|
||||
})?;
|
||||
Ok(val.into())
|
||||
}
|
||||
/// Add a namespace with a default configuration, only if we are in dynamic mode.
|
||||
pub async fn add_ns(
|
||||
&mut self,
|
||||
|
@ -1610,6 +1645,20 @@ impl Transaction {
|
|||
chn.send(bytes!("")).await?;
|
||||
}
|
||||
}
|
||||
// Output ANALYZERS
|
||||
{
|
||||
let azs = self.all_az(ns, db).await?;
|
||||
if !azs.is_empty() {
|
||||
chn.send(bytes!("-- ------------------------------")).await?;
|
||||
chn.send(bytes!("-- ANALYZERS")).await?;
|
||||
chn.send(bytes!("-- ------------------------------")).await?;
|
||||
chn.send(bytes!("")).await?;
|
||||
for az in azs.iter() {
|
||||
chn.send(bytes!(format!("{az};"))).await?;
|
||||
}
|
||||
chn.send(bytes!("")).await?;
|
||||
}
|
||||
}
|
||||
// Output TABLES
|
||||
{
|
||||
let tbs = self.all_tb(ns, db).await?;
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::common::{closebracket, commas, openbracket};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::{pretty_indent, Fmt, Pretty};
|
||||
use crate::sql::number::Number;
|
||||
|
@ -355,13 +355,11 @@ impl Uniq<Array> for Array {
|
|||
// ------------------------------
|
||||
|
||||
pub fn array(i: &str) -> IResult<&str, Array> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = separated_list0(commas, value)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, Array(v)))
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::{comment, mightbespace};
|
||||
use crate::sql::common::colons;
|
||||
use crate::sql::common::{closebraces, colons, openbraces};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::{is_pretty, pretty_indent, Fmt, Pretty};
|
||||
use crate::sql::statements::create::{create, CreateStatement};
|
||||
|
@ -18,7 +18,6 @@ use crate::sql::statements::set::{set, SetStatement};
|
|||
use crate::sql::statements::update::{update, UpdateStatement};
|
||||
use crate::sql::value::{value, Value};
|
||||
use nom::branch::alt;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::map;
|
||||
use nom::multi::many0;
|
||||
use nom::multi::separated_list1;
|
||||
|
@ -159,12 +158,10 @@ impl Display for Block {
|
|||
}
|
||||
|
||||
pub fn block(i: &str) -> IResult<&str, Block> {
|
||||
let (i, _) = char('{')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbraces(i)?;
|
||||
let (i, v) = separated_list1(colons, entry)(i)?;
|
||||
let (i, _) = many0(alt((colons, comment)))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('}')(i)?;
|
||||
let (i, _) = closebraces(i)?;
|
||||
Ok((i, Block(v)))
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,54 @@ pub fn commasorspace(i: &str) -> IResult<&str, ()> {
|
|||
alt((commas, shouldbespace))(i)
|
||||
}
|
||||
|
||||
pub fn openparentheses(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
pub fn closeparentheses(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
pub fn openbraces(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = char('{')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
pub fn closebraces(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('}')(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
pub fn openbracket(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
pub fn closebracket(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
pub fn openchevron(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = char('<')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
pub fn closechevron(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('>')(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_hex(chr: char) -> bool {
|
||||
chr.is_ascii_hexdigit()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::{closeparentheses, openparentheses};
|
||||
use crate::sql::dir::{dir, Dir};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::table::{table, tables, Tables};
|
||||
|
@ -48,11 +48,9 @@ fn simple(i: &str) -> IResult<&str, Tables> {
|
|||
}
|
||||
|
||||
fn custom(i: &str) -> IResult<&str, Tables> {
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, w) = alt((any, tables))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, w))
|
||||
}
|
||||
|
||||
|
|
62
lib/src/sql/filter.rs
Normal file
62
lib/src/sql/filter.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::{closeparentheses, commas, openparentheses};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::language::{language, Language};
|
||||
use crate::sql::number::number;
|
||||
use crate::sql::Number;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::separated_list1;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
pub enum Filter {
|
||||
EdgeNgram(Number, Number),
|
||||
Lowercase,
|
||||
Snowball(Language),
|
||||
}
|
||||
|
||||
impl Display for Filter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::EdgeNgram(min, max) => write!(f, "EDGENGRAM({},{})", min, max),
|
||||
Self::Lowercase => f.write_str("LOWERCASE"),
|
||||
Self::Snowball(lang) => write!(f, "SNOWBALL({})", lang),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn edgengram(i: &str) -> IResult<&str, Filter> {
|
||||
let (i, _) = tag_no_case("EDGENGRAM")(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, min) = number(i)?;
|
||||
let (i, _) = commas(i)?;
|
||||
let (i, max) = number(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, Filter::EdgeNgram(min, max)))
|
||||
}
|
||||
|
||||
fn snowball(i: &str) -> IResult<&str, Filter> {
|
||||
let (i, _) = tag_no_case("SNOWBALL")(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, language) = language(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, Filter::Snowball(language)))
|
||||
}
|
||||
|
||||
fn lowercase(i: &str) -> IResult<&str, Filter> {
|
||||
let (i, _) = tag_no_case("LOWERCASE")(i)?;
|
||||
Ok((i, Filter::Lowercase))
|
||||
}
|
||||
|
||||
fn filter(i: &str) -> IResult<&str, Filter> {
|
||||
alt((edgengram, lowercase, snowball))(i)
|
||||
}
|
||||
|
||||
pub(super) fn filters(i: &str) -> IResult<&str, Vec<Filter>> {
|
||||
let (i, _) = tag_no_case("FILTERS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
separated_list1(commas, filter)(i)
|
||||
}
|
|
@ -4,8 +4,8 @@ use crate::dbs::Transaction;
|
|||
use crate::err::Error;
|
||||
use crate::fnc;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::common::val_char;
|
||||
use crate::sql::common::{closeparentheses, commas, openparentheses};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::idiom::Idiom;
|
||||
|
@ -229,11 +229,9 @@ pub fn function(i: &str) -> IResult<&str, Function> {
|
|||
|
||||
pub fn normal(i: &str) -> IResult<&str, Function> {
|
||||
let (i, s) = function_names(i)?;
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, a) = separated_list0(commas, value)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, Function::Normal(s.to_string(), a)))
|
||||
}
|
||||
|
||||
|
@ -250,11 +248,10 @@ pub fn custom(i: &str) -> IResult<&str, Function> {
|
|||
|
||||
fn script(i: &str) -> IResult<&str, Function> {
|
||||
let (i, _) = tag("function")(i)?;
|
||||
let (i, _) = tag("(")(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, a) = separated_list0(commas, value)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = tag(")")(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('{')(i)?;
|
||||
let (i, v) = func(i)?;
|
||||
|
|
|
@ -4,10 +4,10 @@ use crate::dbs::Transaction;
|
|||
use crate::err::Error;
|
||||
use crate::sql::block::{block, Block};
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::{closechevron, openchevron};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::value::Value;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::character::complete::char;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
|
@ -49,9 +49,9 @@ impl fmt::Display for Future {
|
|||
}
|
||||
|
||||
pub fn future(i: &str) -> IResult<&str, Future> {
|
||||
let (i, _) = char('<')(i)?;
|
||||
let (i, _) = openchevron(i)?;
|
||||
let (i, _) = tag("future")(i)?;
|
||||
let (i, _) = char('>')(i)?;
|
||||
let (i, _) = closechevron(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = block(i)?;
|
||||
Ok((i, Future(v)))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![allow(clippy::derived_hash_with_manual_eq)]
|
||||
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::common::{closebracket, closeparentheses, commas, openbracket, openparentheses};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use geo::algorithm::contains::Contains;
|
||||
|
@ -538,13 +538,11 @@ pub fn geometry(i: &str) -> IResult<&str, Geometry> {
|
|||
}
|
||||
|
||||
fn simple(i: &str) -> IResult<&str, Geometry> {
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, x) = double(i)?;
|
||||
let (i, _) = commas(i)?;
|
||||
let (i, y) = double(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, Geometry::Point((x, y).into())))
|
||||
}
|
||||
|
||||
|
@ -695,78 +693,64 @@ fn point_vals(i: &str) -> IResult<&str, Point<f64>> {
|
|||
}
|
||||
|
||||
fn line_vals(i: &str) -> IResult<&str, LineString<f64>> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = separated_list1(commas, coordinate)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, v.into()))
|
||||
}
|
||||
|
||||
fn polygon_vals(i: &str) -> IResult<&str, Polygon<f64>> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, e) = line_vals(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
let (i, v) = separated_list0(commas, |i| {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = line_vals(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, v))
|
||||
})(i)?;
|
||||
Ok((i, Polygon::new(e, v)))
|
||||
}
|
||||
|
||||
fn multipoint_vals(i: &str) -> IResult<&str, Vec<Point<f64>>> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = separated_list1(commas, point_vals)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, v))
|
||||
}
|
||||
|
||||
fn multiline_vals(i: &str) -> IResult<&str, Vec<LineString<f64>>> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = separated_list1(commas, line_vals)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, v))
|
||||
}
|
||||
|
||||
fn multipolygon_vals(i: &str) -> IResult<&str, Vec<Polygon<f64>>> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = separated_list1(commas, polygon_vals)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, v))
|
||||
}
|
||||
|
||||
fn collection_vals(i: &str) -> IResult<&str, Vec<Geometry>> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = separated_list1(commas, geometry)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = opt(char(','))(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, v))
|
||||
}
|
||||
|
||||
|
@ -775,15 +759,13 @@ fn collection_vals(i: &str) -> IResult<&str, Vec<Geometry>> {
|
|||
//
|
||||
|
||||
fn coordinate(i: &str) -> IResult<&str, (f64, f64)> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, x) = double(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(',')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, y) = double(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, (x, y)))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::{closeparentheses, openparentheses};
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
use crate::sql::dir::{dir, Dir};
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -106,8 +106,7 @@ fn simple(i: &str) -> IResult<&str, (Tables, Option<Cond>, Option<Idiom>)> {
|
|||
}
|
||||
|
||||
fn custom(i: &str) -> IResult<&str, (Tables, Option<Cond>, Option<Idiom>)> {
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, w) = alt((any, tables))(i)?;
|
||||
let (i, c) = opt(|i| {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
|
@ -121,8 +120,7 @@ fn custom(i: &str) -> IResult<&str, (Tables, Option<Cond>, Option<Idiom>)> {
|
|||
let (i, v) = idiom(i)?;
|
||||
Ok((i, v))
|
||||
})(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, (w, c, a)))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::common::verbar;
|
||||
use crate::sql::common::{closeparentheses, commas, openparentheses};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::table::{table, Table};
|
||||
|
@ -136,9 +136,9 @@ fn record(i: &str) -> IResult<&str, Kind> {
|
|||
let (i, v) = opt(alt((
|
||||
|i| {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, v) = separated_list1(commas, table)(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, v))
|
||||
},
|
||||
|i| {
|
||||
|
|
24
lib/src/sql/language.rs
Normal file
24
lib/src/sql/language.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use crate::sql::error::IResult;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::map;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
pub enum Language {
|
||||
English,
|
||||
}
|
||||
|
||||
impl Display for Language {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::English => "ENGLISH",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn language(i: &str) -> IResult<&str, Language> {
|
||||
alt((map(tag_no_case("ENGLISH"), |_| Language::English),))(i)
|
||||
}
|
|
@ -20,6 +20,7 @@ pub(crate) mod escape;
|
|||
pub(crate) mod expression;
|
||||
pub(crate) mod fetch;
|
||||
pub(crate) mod field;
|
||||
pub(crate) mod filter;
|
||||
pub(crate) mod fmt;
|
||||
pub(crate) mod function;
|
||||
pub(crate) mod future;
|
||||
|
@ -30,6 +31,7 @@ pub(crate) mod id;
|
|||
pub(crate) mod ident;
|
||||
pub(crate) mod idiom;
|
||||
pub(crate) mod kind;
|
||||
pub(crate) mod language;
|
||||
pub(crate) mod limit;
|
||||
pub(crate) mod model;
|
||||
pub(crate) mod number;
|
||||
|
@ -56,6 +58,7 @@ pub(crate) mod subquery;
|
|||
pub(crate) mod table;
|
||||
pub(crate) mod thing;
|
||||
pub(crate) mod timeout;
|
||||
pub(crate) mod tokenizer;
|
||||
pub(crate) mod uuid;
|
||||
pub(crate) mod value;
|
||||
pub(crate) mod version;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::{closebracket, openbracket};
|
||||
use crate::sql::ending::ident as ending;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
|
@ -159,9 +160,9 @@ pub fn all(i: &str) -> IResult<&str, Part> {
|
|||
Ok((i, ()))
|
||||
},
|
||||
|i| {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, _) = char('*')(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, ()))
|
||||
},
|
||||
))(i)?;
|
||||
|
@ -169,16 +170,16 @@ pub fn all(i: &str) -> IResult<&str, Part> {
|
|||
}
|
||||
|
||||
pub fn last(i: &str) -> IResult<&str, Part> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, _) = char('$')(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, Part::Last))
|
||||
}
|
||||
|
||||
pub fn index(i: &str) -> IResult<&str, Part> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, v) = number(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, Part::Index(v)))
|
||||
}
|
||||
|
||||
|
@ -190,11 +191,11 @@ pub fn field(i: &str) -> IResult<&str, Part> {
|
|||
}
|
||||
|
||||
pub fn filter(i: &str) -> IResult<&str, Part> {
|
||||
let (i, _) = char('[')(i)?;
|
||||
let (i, _) = openbracket(i)?;
|
||||
let (i, _) = alt((tag_no_case("WHERE"), tag("?")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value::value(i)?;
|
||||
let (i, _) = char(']')(i)?;
|
||||
let (i, _) = closebracket(i)?;
|
||||
Ok((i, Part::Where(v)))
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::sql::common::commas;
|
|||
use crate::sql::duration::{duration, Duration};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::escape_str;
|
||||
use crate::sql::filter::{filters, Filter};
|
||||
use crate::sql::fmt::is_pretty;
|
||||
use crate::sql::fmt::pretty_indent;
|
||||
use crate::sql::ident;
|
||||
|
@ -21,6 +22,7 @@ use crate::sql::kind::{kind, Kind};
|
|||
use crate::sql::permission::{permissions, Permissions};
|
||||
use crate::sql::statements::UpdateStatement;
|
||||
use crate::sql::strand::strand_raw;
|
||||
use crate::sql::tokenizer::{tokenizers, Tokenizer};
|
||||
use crate::sql::value::{value, values, Value, Values};
|
||||
use crate::sql::view::{view, View};
|
||||
use argon2::password_hash::{PasswordHasher, SaltString};
|
||||
|
@ -46,6 +48,7 @@ pub enum DefineStatement {
|
|||
Namespace(DefineNamespaceStatement),
|
||||
Database(DefineDatabaseStatement),
|
||||
Function(DefineFunctionStatement),
|
||||
Analyzer(DefineAnalyzerStatement),
|
||||
Login(DefineLoginStatement),
|
||||
Token(DefineTokenStatement),
|
||||
Scope(DefineScopeStatement),
|
||||
|
@ -77,11 +80,12 @@ impl DefineStatement {
|
|||
Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineStatement {
|
||||
impl Display for DefineStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Namespace(v) => Display::fmt(v, f),
|
||||
|
@ -95,6 +99,7 @@ impl fmt::Display for DefineStatement {
|
|||
Self::Event(v) => Display::fmt(v, f),
|
||||
Self::Field(v) => Display::fmt(v, f),
|
||||
Self::Index(v) => Display::fmt(v, f),
|
||||
Self::Analyzer(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +117,7 @@ pub fn define(i: &str) -> IResult<&str, DefineStatement> {
|
|||
map(event, DefineStatement::Event),
|
||||
map(field, DefineStatement::Field),
|
||||
map(index, DefineStatement::Index),
|
||||
map(analyzer, DefineStatement::Analyzer),
|
||||
))(i)
|
||||
}
|
||||
|
||||
|
@ -202,7 +208,7 @@ impl DefineDatabaseStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineDatabaseStatement {
|
||||
impl Display for DefineDatabaseStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE DATABASE {}", self.name)
|
||||
}
|
||||
|
@ -312,6 +318,80 @@ fn function(i: &str) -> IResult<&str, DefineFunctionStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
pub struct DefineAnalyzerStatement {
|
||||
pub name: Ident,
|
||||
pub tokenizers: Option<Vec<Tokenizer>>,
|
||||
pub filters: Option<Vec<Filter>>,
|
||||
}
|
||||
|
||||
impl DefineAnalyzerStatement {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&Value>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let run = txn.clone();
|
||||
// Claim transaction
|
||||
let mut run = run.lock().await;
|
||||
// Process the statement
|
||||
let key = crate::key::az::new(opt.ns(), opt.db(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Release the transaction
|
||||
drop(run);
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineAnalyzerStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE ANALYZER {}", self.name)?;
|
||||
if let Some(tokenizers) = &self.tokenizers {
|
||||
let tokens: Vec<String> = tokenizers.iter().map(|f| f.to_string()).collect();
|
||||
write!(f, " TOKENIZERS {}", tokens.join(","))?;
|
||||
}
|
||||
if let Some(filters) = &self.filters {
|
||||
let tokens: Vec<String> = filters.iter().map(|f| f.to_string()).collect();
|
||||
write!(f, " FILTERS {}", tokens.join(","))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn analyzer(i: &str) -> IResult<&str, DefineAnalyzerStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ANALYZER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, tokenizers) = opt(tokenizers)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, filters) = opt(filters)(i)?;
|
||||
Ok((
|
||||
i,
|
||||
DefineAnalyzerStatement {
|
||||
name,
|
||||
tokenizers,
|
||||
filters,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[format(Named)]
|
||||
pub struct DefineLoginStatement {
|
||||
|
@ -369,7 +449,7 @@ impl DefineLoginStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineLoginStatement {
|
||||
impl Display for DefineLoginStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE LOGIN {} ON {} PASSHASH {}", self.name, self.base, escape_str(&self.hash))
|
||||
}
|
||||
|
@ -512,7 +592,7 @@ impl DefineTokenStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineTokenStatement {
|
||||
impl Display for DefineTokenStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -595,7 +675,7 @@ impl DefineScopeStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineScopeStatement {
|
||||
impl Display for DefineScopeStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE SCOPE {}", self.name)?;
|
||||
if let Some(ref v) = self.session {
|
||||
|
@ -716,7 +796,7 @@ impl DefineParamStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineParamStatement {
|
||||
impl Display for DefineParamStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE PARAM ${} VALUE {}", self.name, self.value)
|
||||
}
|
||||
|
@ -816,7 +896,7 @@ impl DefineTableStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineTableStatement {
|
||||
impl Display for DefineTableStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE TABLE {}", self.name)?;
|
||||
if self.drop {
|
||||
|
@ -971,7 +1051,7 @@ impl DefineEventStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineEventStatement {
|
||||
impl Display for DefineEventStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -1059,7 +1139,7 @@ impl DefineFieldStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineFieldStatement {
|
||||
impl Display for DefineFieldStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE FIELD {} ON {}", self.name, self.what)?;
|
||||
if self.flex {
|
||||
|
|
|
@ -133,6 +133,12 @@ impl InfoStatement {
|
|||
tmp.insert(v.name.to_string(), v.to_string().into());
|
||||
}
|
||||
res.insert("tb".to_owned(), tmp.into());
|
||||
// Process the analyzers
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_az(opt.ns(), opt.db()).await?.iter() {
|
||||
tmp.insert(v.name.to_string(), v.to_string().into());
|
||||
}
|
||||
res.insert("az".to_owned(), tmp.into());
|
||||
// Ok all good
|
||||
Value::from(res).ok()
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ pub use self::set::SetStatement;
|
|||
pub use self::update::UpdateStatement;
|
||||
pub use self::yuse::UseStatement;
|
||||
|
||||
pub use self::define::DefineAnalyzerStatement;
|
||||
pub use self::define::DefineDatabaseStatement;
|
||||
pub use self::define::DefineEventStatement;
|
||||
pub use self::define::DefineFieldStatement;
|
||||
|
|
|
@ -27,6 +27,7 @@ pub enum RemoveStatement {
|
|||
Namespace(RemoveNamespaceStatement),
|
||||
Database(RemoveDatabaseStatement),
|
||||
Function(RemoveFunctionStatement),
|
||||
Analyzer(RemoveAnalyzerStatement),
|
||||
Login(RemoveLoginStatement),
|
||||
Token(RemoveTokenStatement),
|
||||
Scope(RemoveScopeStatement),
|
||||
|
@ -58,6 +59,7 @@ impl RemoveStatement {
|
|||
Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +78,7 @@ impl Display for RemoveStatement {
|
|||
Self::Event(v) => Display::fmt(v, f),
|
||||
Self::Field(v) => Display::fmt(v, f),
|
||||
Self::Index(v) => Display::fmt(v, f),
|
||||
Self::Analyzer(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +96,7 @@ pub fn remove(i: &str) -> IResult<&str, RemoveStatement> {
|
|||
map(event, RemoveStatement::Event),
|
||||
map(field, RemoveStatement::Field),
|
||||
map(index, RemoveStatement::Index),
|
||||
map(analyzer, RemoveStatement::Analyzer),
|
||||
))(i)
|
||||
}
|
||||
|
||||
|
@ -134,8 +138,8 @@ impl RemoveNamespaceStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveNamespaceStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveNamespaceStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE NAMESPACE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
@ -192,8 +196,8 @@ impl RemoveDatabaseStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveDatabaseStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveDatabaseStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE DATABASE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
@ -279,6 +283,60 @@ fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> {
|
|||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
pub struct RemoveAnalyzerStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveAnalyzerStatement {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&Value>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let run = txn.clone();
|
||||
// Claim transaction
|
||||
let mut run = run.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::az::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// TODO Check that the analyzer is not used in any schema
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveAnalyzerStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE ANALYZER {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn analyzer(i: &str) -> IResult<&str, RemoveAnalyzerStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ANALYZER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveAnalyzerStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[format(Named)]
|
||||
pub struct RemoveLoginStatement {
|
||||
|
@ -331,8 +389,8 @@ impl RemoveLoginStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveLoginStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveLoginStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE LOGIN {} ON {}", self.name, self.base)
|
||||
}
|
||||
}
|
||||
|
@ -427,8 +485,8 @@ impl RemoveTokenStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveTokenStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveTokenStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE TOKEN {} ON {}", self.name, self.base)
|
||||
}
|
||||
}
|
||||
|
@ -490,8 +548,8 @@ impl RemoveScopeStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveScopeStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveScopeStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE SCOPE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
@ -545,8 +603,8 @@ impl RemoveParamStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveParamStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveParamStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE PARAM {}", self.name)
|
||||
}
|
||||
}
|
||||
|
@ -604,8 +662,8 @@ impl RemoveTableStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveTableStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveTableStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE TABLE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
@ -663,8 +721,8 @@ impl RemoveEventStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveEventStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveEventStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE EVENT {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
@ -729,8 +787,8 @@ impl RemoveFieldStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveFieldStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveFieldStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE FIELD {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
@ -798,8 +856,8 @@ impl RemoveIndexStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoveIndexStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for RemoveIndexStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE INDEX {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::ctx::Context;
|
|||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::{closeparentheses, openparentheses};
|
||||
use crate::sql::ending::subquery as ending;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::statements::create::{create, CreateStatement};
|
||||
|
@ -15,7 +15,6 @@ use crate::sql::statements::select::{select, SelectStatement};
|
|||
use crate::sql::statements::update::{update, UpdateStatement};
|
||||
use crate::sql::value::{value, Value};
|
||||
use nom::branch::alt;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::map;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
|
@ -237,22 +236,18 @@ fn subquery_ifelse(i: &str) -> IResult<&str, Subquery> {
|
|||
}
|
||||
|
||||
fn subquery_value(i: &str) -> IResult<&str, Subquery> {
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, v) = map(value, Subquery::Value)(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, v))
|
||||
}
|
||||
|
||||
fn subquery_other(i: &str) -> IResult<&str, Subquery> {
|
||||
alt((
|
||||
|i| {
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = openparentheses(i)?;
|
||||
let (i, v) = subquery_inner(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = closeparentheses(i)?;
|
||||
Ok((i, v))
|
||||
},
|
||||
|i| {
|
||||
|
|
41
lib/src/sql/tokenizer.rs
Normal file
41
lib/src/sql/tokenizer.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::map;
|
||||
use nom::multi::separated_list1;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
pub enum Tokenizer {
|
||||
Case,
|
||||
Space,
|
||||
// Add new variants here
|
||||
}
|
||||
|
||||
impl Display for Tokenizer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::Case => "CASE",
|
||||
Self::Space => "SPACE",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn tokenizer(i: &str) -> IResult<&str, Tokenizer> {
|
||||
let (i, t) = alt((
|
||||
map(tag_no_case("CASE"), |_| Tokenizer::Case),
|
||||
map(tag_no_case("SPACE"), |_| Tokenizer::Space),
|
||||
))(i)?;
|
||||
Ok((i, t))
|
||||
}
|
||||
|
||||
pub(super) fn tokenizers(i: &str) -> IResult<&str, Vec<Tokenizer>> {
|
||||
let (i, _) = tag_no_case("TOKENIZERS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, t) = separated_list1(commas, tokenizer)(i)?;
|
||||
Ok((i, t))
|
||||
}
|
|
@ -76,6 +76,7 @@ async fn define_statement_function() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: { test: 'DEFINE FUNCTION fn::test($first: string, $last: string) { RETURN $first + $last; }' },
|
||||
|
@ -108,6 +109,7 @@ async fn define_statement_table_drop() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
|
@ -138,6 +140,7 @@ async fn define_statement_table_schemaless() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
|
@ -172,6 +175,7 @@ async fn define_statement_table_schemafull() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
|
@ -202,6 +206,7 @@ async fn define_statement_table_schemaful() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
|
@ -927,3 +932,41 @@ async fn define_statement_index_multiple_unique_existing() -> Result<(), Error>
|
|||
//
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn define_statement_analyzer() -> Result<(), Error> {
|
||||
let sql = "
|
||||
DEFINE ANALYZER english TOKENIZERS space,case FILTERS lowercase,snowball(english);
|
||||
DEFINE ANALYZER autocomplete FILTERS lowercase,edgengram(2,10);
|
||||
INFO FOR DB;
|
||||
";
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
|
||||
assert_eq!(res.len(), 3);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
//
|
||||
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {
|
||||
autocomplete: 'DEFINE ANALYZER autocomplete FILTERS LOWERCASE,EDGENGRAM(2,10)',
|
||||
english: 'DEFINE ANALYZER english TOKENIZERS SPACE,CASE FILTERS LOWERCASE,SNOWBALL(ENGLISH)',
|
||||
},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
pa: {},
|
||||
sc: {},
|
||||
tb: {}
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ async fn define_global_param() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
|
|
75
lib/tests/remove.rs
Normal file
75
lib/tests/remove.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
mod parse;
|
||||
|
||||
use parse::Parse;
|
||||
use surrealdb::dbs::Session;
|
||||
use surrealdb::err::Error;
|
||||
use surrealdb::kvs::Datastore;
|
||||
use surrealdb::sql::Value;
|
||||
|
||||
#[tokio::test]
|
||||
async fn remove_statement_table() -> Result<(), Error> {
|
||||
let sql = "
|
||||
DEFINE TABLE test SCHEMALESS;
|
||||
REMOVE TABLE test;
|
||||
INFO FOR DB;
|
||||
";
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
|
||||
assert_eq!(res.len(), 3);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
pa: {},
|
||||
sc: {},
|
||||
tb: {}
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remove_statement_analyzer() -> Result<(), Error> {
|
||||
let sql = "
|
||||
DEFINE ANALYZER english TOKENIZERS space,case FILTERS lowercase,snowball(english);
|
||||
REMOVE ANALYZER english;
|
||||
INFO FOR DB;
|
||||
";
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
|
||||
assert_eq!(res.len(), 3);
|
||||
// Analyzer is defined
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
// Analyzer is removed
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
// Check infos output
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
pa: {},
|
||||
sc: {},
|
||||
tb: {}
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
Ok(())
|
||||
}
|
|
@ -250,6 +250,7 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
|
|||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
az: {},
|
||||
dl: {},
|
||||
dt: {},
|
||||
fc: {},
|
||||
|
|
Loading…
Reference in a new issue