Feat: Introduce Rebuild command (#3933)
This commit is contained in:
parent
8f6af53de6
commit
8172753ac4
16 changed files with 441 additions and 14 deletions
|
@ -157,9 +157,9 @@ async fn process_change_set_for_notifications(
|
|||
"There are {} table mutations being prepared for notifications",
|
||||
table_mutations.1.len()
|
||||
);
|
||||
for (i, mutation) in table_mutations.1.iter().enumerate() {
|
||||
for (_i, mutation) in table_mutations.1.iter().enumerate() {
|
||||
#[cfg(debug_assertions)]
|
||||
trace!("[{} @ {:?}] Processing table mutation: {:?} Constructing document from mutation", i, change_vs, mutation);
|
||||
trace!("[{} @ {:?}] Processing table mutation: {:?} Constructing document from mutation", _i, change_vs, mutation);
|
||||
if let Some(doc) = construct_document(mutation)? {
|
||||
// We know we are only processing a single LQ at a time, so we can limit notifications to 1
|
||||
let notification_capacity = 1;
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::doc::CursorDoc;
|
|||
use crate::err::Error;
|
||||
use crate::sql::fmt::{is_pretty, pretty_indent, Fmt, Pretty};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::statements::rebuild::RebuildStatement;
|
||||
use crate::sql::statements::{
|
||||
BreakStatement, ContinueStatement, CreateStatement, DefineStatement, DeleteStatement,
|
||||
ForeachStatement, IfelseStatement, InsertStatement, OutputStatement, RelateStatement,
|
||||
|
@ -101,6 +102,9 @@ impl Block {
|
|||
Entry::Define(v) => {
|
||||
v.compute(stk, &ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Rebuild(v) => {
|
||||
v.compute(stk, &ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Remove(v) => {
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
|
@ -175,7 +179,7 @@ impl InfoStructure for Block {
|
|||
}
|
||||
}
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[revisioned(revision = 2)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[non_exhaustive]
|
||||
|
@ -196,6 +200,8 @@ pub enum Entry {
|
|||
Break(BreakStatement),
|
||||
Continue(ContinueStatement),
|
||||
Foreach(ForeachStatement),
|
||||
#[revision(start = 2)]
|
||||
Rebuild(RebuildStatement),
|
||||
}
|
||||
|
||||
impl PartialOrd for Entry {
|
||||
|
@ -220,6 +226,7 @@ impl Entry {
|
|||
Self::Insert(v) => v.writeable(),
|
||||
Self::Output(v) => v.writeable(),
|
||||
Self::Define(v) => v.writeable(),
|
||||
Self::Rebuild(v) => v.writeable(),
|
||||
Self::Remove(v) => v.writeable(),
|
||||
Self::Throw(v) => v.writeable(),
|
||||
Self::Break(v) => v.writeable(),
|
||||
|
@ -243,6 +250,7 @@ impl Display for Entry {
|
|||
Self::Insert(v) => write!(f, "{v}"),
|
||||
Self::Output(v) => write!(f, "{v}"),
|
||||
Self::Define(v) => write!(f, "{v}"),
|
||||
Self::Rebuild(v) => write!(f, "{v}"),
|
||||
Self::Remove(v) => write!(f, "{v}"),
|
||||
Self::Throw(v) => write!(f, "{v}"),
|
||||
Self::Break(v) => write!(f, "{v}"),
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::ctx::Context;
|
|||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::statements::rebuild::RebuildStatement;
|
||||
use crate::sql::{
|
||||
fmt::{Fmt, Pretty},
|
||||
statements::{
|
||||
|
@ -53,7 +54,7 @@ impl Display for Statements {
|
|||
}
|
||||
}
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[revisioned(revision = 2)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[non_exhaustive]
|
||||
|
@ -85,6 +86,8 @@ pub enum Statement {
|
|||
Update(UpdateStatement),
|
||||
Throw(ThrowStatement),
|
||||
Use(UseStatement),
|
||||
#[revision(start = 2)]
|
||||
Rebuild(RebuildStatement),
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
|
@ -118,6 +121,7 @@ impl Statement {
|
|||
Self::Live(_) => true,
|
||||
Self::Output(v) => v.writeable(),
|
||||
Self::Option(_) => false,
|
||||
Self::Rebuild(_) => true,
|
||||
Self::Relate(v) => v.writeable(),
|
||||
Self::Remove(_) => true,
|
||||
Self::Select(v) => v.writeable(),
|
||||
|
@ -154,6 +158,7 @@ impl Statement {
|
|||
Self::Live(v) => v.compute(stk, ctx, opt, txn, doc).await,
|
||||
Self::Output(v) => v.compute(stk, ctx, opt, txn, doc).await,
|
||||
Self::Relate(v) => v.compute(stk, ctx, opt, txn, doc).await,
|
||||
Self::Rebuild(v) => v.compute(stk, ctx, opt, txn, doc).await,
|
||||
Self::Remove(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Select(v) => v.compute(stk, ctx, opt, txn, doc).await,
|
||||
Self::Set(v) => v.compute(stk, ctx, opt, txn, doc).await,
|
||||
|
@ -193,6 +198,7 @@ impl Display for Statement {
|
|||
Self::Live(v) => write!(Pretty::from(f), "{v}"),
|
||||
Self::Option(v) => write!(Pretty::from(f), "{v}"),
|
||||
Self::Output(v) => write!(Pretty::from(f), "{v}"),
|
||||
Self::Rebuild(v) => write!(Pretty::from(f), "{v}"),
|
||||
Self::Relate(v) => write!(Pretty::from(f), "{v}"),
|
||||
Self::Remove(v) => write!(Pretty::from(f), "{v}"),
|
||||
Self::Select(v) => write!(Pretty::from(f), "{v}"),
|
||||
|
|
|
@ -86,6 +86,7 @@ impl ForeachStatement {
|
|||
stk.run(|stk| v.compute(stk, &ctx, opt, txn, doc)).await
|
||||
}
|
||||
Entry::Define(v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
Entry::Rebuild(v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
Entry::Remove(v) => v.compute(&ctx, opt, txn, doc).await,
|
||||
Entry::Output(v) => {
|
||||
return stk.run(|stk| v.compute(stk, &ctx, opt, txn, doc)).await;
|
||||
|
|
|
@ -15,6 +15,7 @@ pub(crate) mod kill;
|
|||
pub(crate) mod live;
|
||||
pub(crate) mod option;
|
||||
pub(crate) mod output;
|
||||
pub(crate) mod rebuild;
|
||||
pub(crate) mod relate;
|
||||
pub(crate) mod remove;
|
||||
pub(crate) mod select;
|
||||
|
|
118
core/src/sql/statements/rebuild.rs
Normal file
118
core/src/sql/statements/rebuild.rs
Normal file
|
@ -0,0 +1,118 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::ident::Ident;
|
||||
use crate::sql::statements::RemoveIndexStatement;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Base;
|
||||
use derive::Store;
|
||||
use reblessive::tree::Stk;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[non_exhaustive]
|
||||
pub enum RebuildStatement {
|
||||
Index(RebuildIndexStatement),
|
||||
}
|
||||
|
||||
impl RebuildStatement {
|
||||
/// Check if we require a writeable transaction
|
||||
pub(crate) fn writeable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
stk: &mut Stk,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Index(s) => s.compute(stk, ctx, opt, txn, doc).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RebuildStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Index(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[non_exhaustive]
|
||||
pub struct RebuildIndexStatement {
|
||||
pub name: Ident,
|
||||
pub what: Ident,
|
||||
pub if_exists: bool,
|
||||
}
|
||||
|
||||
impl RebuildIndexStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
stk: &mut Stk,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
let future = async {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?;
|
||||
|
||||
// Get the index definition
|
||||
let ix = txn
|
||||
.lock()
|
||||
.await
|
||||
.get_and_cache_tb_index(opt.ns(), opt.db(), self.what.as_str(), self.name.as_str())
|
||||
.await?;
|
||||
|
||||
// Remove the index
|
||||
let remove = RemoveIndexStatement {
|
||||
name: self.name.clone(),
|
||||
what: self.what.clone(),
|
||||
if_exists: false,
|
||||
};
|
||||
remove.compute(ctx, opt, txn).await?;
|
||||
|
||||
// Rebuild the index
|
||||
ix.compute(stk, ctx, opt, txn, doc).await?;
|
||||
|
||||
// Return the result object
|
||||
Ok(Value::None)
|
||||
}
|
||||
.await;
|
||||
match future {
|
||||
Err(Error::IxNotFound {
|
||||
..
|
||||
}) if self.if_exists => Ok(Value::None),
|
||||
v => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RebuildIndexStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REBUILD INDEX")?;
|
||||
if self.if_exists {
|
||||
write!(f, " IF EXISTS")?
|
||||
}
|
||||
write!(f, " {} ON {}", self.name, self.what)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ use crate::ctx::Context;
|
|||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::statements::rebuild::RebuildStatement;
|
||||
use crate::sql::statements::{
|
||||
CreateStatement, DefineStatement, DeleteStatement, IfelseStatement, InsertStatement,
|
||||
OutputStatement, RelateStatement, RemoveStatement, SelectStatement, UpdateStatement,
|
||||
|
@ -15,7 +16,7 @@ use std::fmt::{self, Display, Formatter};
|
|||
|
||||
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Subquery";
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[revisioned(revision = 2)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[serde(rename = "$surrealdb::private::sql::Subquery")]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
|
@ -32,6 +33,8 @@ pub enum Subquery {
|
|||
Insert(InsertStatement),
|
||||
Define(DefineStatement),
|
||||
Remove(RemoveStatement),
|
||||
#[revision(start = 2)]
|
||||
Rebuild(RebuildStatement),
|
||||
// Add new variants here
|
||||
}
|
||||
|
||||
|
@ -57,6 +60,7 @@ impl Subquery {
|
|||
Self::Insert(v) => v.writeable(),
|
||||
Self::Define(v) => v.writeable(),
|
||||
Self::Remove(v) => v.writeable(),
|
||||
Self::Rebuild(v) => v.writeable(),
|
||||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
|
@ -80,6 +84,7 @@ impl Subquery {
|
|||
Self::Ifelse(ref v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
Self::Output(ref v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
Self::Define(ref v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
Self::Rebuild(ref v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
Self::Remove(ref v) => v.compute(&ctx, opt, txn, doc).await,
|
||||
Self::Select(ref v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
Self::Create(ref v) => v.compute(stk, &ctx, opt, txn, doc).await,
|
||||
|
@ -104,6 +109,7 @@ impl Display for Subquery {
|
|||
Self::Insert(v) => write!(f, "({v})"),
|
||||
Self::Define(v) => write!(f, "({v})"),
|
||||
Self::Remove(v) => write!(f, "({v})"),
|
||||
Self::Rebuild(v) => write!(f, "({v})"),
|
||||
Self::Ifelse(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ pub mod kill;
|
|||
pub mod live;
|
||||
pub mod option;
|
||||
pub mod output;
|
||||
pub mod rebuild;
|
||||
pub mod relate;
|
||||
pub mod remove;
|
||||
pub mod select;
|
||||
|
@ -76,6 +77,7 @@ impl ser::Serializer for Serializer {
|
|||
"Live" => Ok(Statement::Live(value.serialize(live::Serializer.wrap())?)),
|
||||
"Option" => Ok(Statement::Option(value.serialize(option::Serializer.wrap())?)),
|
||||
"Output" => Ok(Statement::Output(value.serialize(output::Serializer.wrap())?)),
|
||||
"Rebuild" => Ok(Statement::Rebuild(value.serialize(rebuild::Serializer.wrap())?)),
|
||||
"Relate" => Ok(Statement::Relate(value.serialize(relate::Serializer.wrap())?)),
|
||||
"Remove" => Ok(Statement::Remove(value.serialize(remove::Serializer.wrap())?)),
|
||||
"Select" => Ok(Statement::Select(value.serialize(select::Serializer.wrap())?)),
|
||||
|
|
91
core/src/sql/value/serde/ser/statement/rebuild/index.rs
Normal file
91
core/src/sql/value/serde/ser/statement/rebuild/index.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::statements::rebuild::RebuildIndexStatement;
|
||||
use crate::sql::value::serde::ser;
|
||||
use crate::sql::Ident;
|
||||
use ser::Serializer as _;
|
||||
use serde::ser::Error as _;
|
||||
use serde::ser::Impossible;
|
||||
use serde::ser::Serialize;
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct Serializer;
|
||||
|
||||
impl ser::Serializer for Serializer {
|
||||
type Ok = RebuildIndexStatement;
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = Impossible<RebuildIndexStatement, Error>;
|
||||
type SerializeTuple = Impossible<RebuildIndexStatement, Error>;
|
||||
type SerializeTupleStruct = Impossible<RebuildIndexStatement, Error>;
|
||||
type SerializeTupleVariant = Impossible<RebuildIndexStatement, Error>;
|
||||
type SerializeMap = Impossible<RebuildIndexStatement, Error>;
|
||||
type SerializeStruct = SerializeRebuildIndexStatement;
|
||||
type SerializeStructVariant = Impossible<RebuildIndexStatement, Error>;
|
||||
|
||||
const EXPECTED: &'static str = "a struct `RebuildIndexStatement`";
|
||||
|
||||
#[inline]
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Error> {
|
||||
Ok(SerializeRebuildIndexStatement::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct SerializeRebuildIndexStatement {
|
||||
name: Ident,
|
||||
what: Ident,
|
||||
if_exists: bool,
|
||||
}
|
||||
|
||||
impl serde::ser::SerializeStruct for SerializeRebuildIndexStatement {
|
||||
type Ok = RebuildIndexStatement;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
match key {
|
||||
"name" => {
|
||||
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
|
||||
}
|
||||
"what" => {
|
||||
self.what = Ident(value.serialize(ser::string::Serializer.wrap())?);
|
||||
}
|
||||
"if_exists" => {
|
||||
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
|
||||
}
|
||||
key => {
|
||||
return Err(Error::custom(format!(
|
||||
"unexpected field `RebuildIndexStatement::{key}`"
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Error> {
|
||||
Ok(RebuildIndexStatement {
|
||||
name: self.name,
|
||||
what: self.what,
|
||||
if_exists: self.if_exists,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let stmt = RebuildIndexStatement::default();
|
||||
let value: RebuildIndexStatement = stmt.serialize(Serializer.wrap()).unwrap();
|
||||
assert_eq!(value, stmt);
|
||||
}
|
||||
}
|
59
core/src/sql/value/serde/ser/statement/rebuild/mod.rs
Normal file
59
core/src/sql/value/serde/ser/statement/rebuild/mod.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
mod index;
|
||||
|
||||
use crate::err::Error;
|
||||
use crate::sql::statements::rebuild::RebuildStatement;
|
||||
use crate::sql::value::serde::ser;
|
||||
use serde::ser::Error as _;
|
||||
use serde::ser::Impossible;
|
||||
use serde::ser::Serialize;
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct Serializer;
|
||||
|
||||
impl ser::Serializer for Serializer {
|
||||
type Ok = RebuildStatement;
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = Impossible<RebuildStatement, Error>;
|
||||
type SerializeTuple = Impossible<RebuildStatement, Error>;
|
||||
type SerializeTupleStruct = Impossible<RebuildStatement, Error>;
|
||||
type SerializeTupleVariant = Impossible<RebuildStatement, Error>;
|
||||
type SerializeMap = Impossible<RebuildStatement, Error>;
|
||||
type SerializeStruct = Impossible<RebuildStatement, Error>;
|
||||
type SerializeStructVariant = Impossible<RebuildStatement, Error>;
|
||||
|
||||
const EXPECTED: &'static str = "an enum `RebuildStatement`";
|
||||
|
||||
#[inline]
|
||||
fn serialize_newtype_variant<T>(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Error>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
match variant {
|
||||
"Index" => Ok(RebuildStatement::Index(value.serialize(index::Serializer.wrap())?)),
|
||||
variant => {
|
||||
Err(Error::custom(format!("unexpected newtype variant `{name}::{variant}`")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::sql::statements::rebuild::RebuildStatement;
|
||||
use ser::Serializer as _;
|
||||
|
||||
#[test]
|
||||
fn index() {
|
||||
let stmt = RebuildStatement::Index(Default::default());
|
||||
let serialized = stmt.serialize(Serializer.wrap()).unwrap();
|
||||
assert_eq!(stmt, serialized);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ pub static RESERVED_KEYWORD: phf::Set<UniCase<&'static str>> = phf_set! {
|
|||
UniCase::ascii("KILL"),
|
||||
UniCase::ascii("LIVE"),
|
||||
UniCase::ascii("OPTION"),
|
||||
UniCase::ascii("REBUILD"),
|
||||
UniCase::ascii("RETURN"),
|
||||
UniCase::ascii("RELATE"),
|
||||
UniCase::ascii("REMOVE"),
|
||||
|
@ -162,6 +163,7 @@ pub(crate) static KEYWORDS: phf::Map<UniCase<&'static str>, TokenKind> = phf_map
|
|||
UniCase::ascii("READONLY") => TokenKind::Keyword(Keyword::Readonly),
|
||||
UniCase::ascii("RELATE") => TokenKind::Keyword(Keyword::Relate),
|
||||
UniCase::ascii("RELATION") => TokenKind::Keyword(Keyword::Relation),
|
||||
UniCase::ascii("REBUILD") => TokenKind::Keyword(Keyword::Rebuild),
|
||||
UniCase::ascii("REMOVE") => TokenKind::Keyword(Keyword::Remove),
|
||||
UniCase::ascii("REPLACE") => TokenKind::Keyword(Keyword::Replace),
|
||||
UniCase::ascii("RETURN") => TokenKind::Keyword(Keyword::Return),
|
||||
|
|
|
@ -85,7 +85,8 @@ impl Parser<'_> {
|
|||
| t!("DELETE")
|
||||
| t!("RELATE")
|
||||
| t!("DEFINE")
|
||||
| t!("REMOVE") => {
|
||||
| t!("REMOVE")
|
||||
| t!("REBUILD") => {
|
||||
self.parse_inner_subquery(ctx, None).await.map(|x| Value::Subquery(Box::new(x)))
|
||||
}
|
||||
t!("fn") => self.parse_custom_function(ctx).await.map(|x| Value::Function(Box::new(x))),
|
||||
|
@ -244,7 +245,8 @@ impl Parser<'_> {
|
|||
| t!("DELETE")
|
||||
| t!("RELATE")
|
||||
| t!("DEFINE")
|
||||
| t!("REMOVE") => {
|
||||
| t!("REMOVE")
|
||||
| t!("REBUILD") => {
|
||||
self.parse_inner_subquery(ctx, None).await.map(|x| Value::Subquery(Box::new(x)))?
|
||||
}
|
||||
t!("fn") => {
|
||||
|
@ -411,6 +413,11 @@ impl Parser<'_> {
|
|||
let stmt = self.parse_remove_stmt()?;
|
||||
Subquery::Remove(stmt)
|
||||
}
|
||||
t!("REBUILD") => {
|
||||
self.pop_peek();
|
||||
let stmt = self.parse_rebuild_stmt()?;
|
||||
Subquery::Rebuild(stmt)
|
||||
}
|
||||
t!("+") | t!("-") => {
|
||||
// handle possible coordinate in the shape of ([-+]?number,[-+]?number)
|
||||
if let TokenKind::Number(kind) = self.peek_token_at(1).kind {
|
||||
|
@ -557,6 +564,11 @@ impl Parser<'_> {
|
|||
let stmt = self.parse_remove_stmt()?;
|
||||
Subquery::Remove(stmt)
|
||||
}
|
||||
t!("REBUILD") => {
|
||||
self.pop_peek();
|
||||
let stmt = self.parse_rebuild_stmt()?;
|
||||
Subquery::Rebuild(stmt)
|
||||
}
|
||||
_ => {
|
||||
let value = ctx.run(|ctx| self.parse_value_field(ctx)).await?;
|
||||
Subquery::Value(value)
|
||||
|
|
|
@ -2,6 +2,7 @@ use reblessive::Stk;
|
|||
|
||||
use crate::enter_query_recursion;
|
||||
use crate::sql::block::Entry;
|
||||
use crate::sql::statements::rebuild::{RebuildIndexStatement, RebuildStatement};
|
||||
use crate::sql::statements::show::{ShowSince, ShowStatement};
|
||||
use crate::sql::statements::sleep::SleepStatement;
|
||||
use crate::sql::statements::{
|
||||
|
@ -83,12 +84,12 @@ impl Parser<'_> {
|
|||
| t!("FOR") | t!("IF")
|
||||
| t!("INFO") | t!("INSERT")
|
||||
| t!("KILL") | t!("LIVE")
|
||||
| t!("OPTION") | t!("RETURN")
|
||||
| t!("RELATE") | t!("REMOVE")
|
||||
| t!("SELECT") | t!("LET")
|
||||
| t!("SHOW") | t!("SLEEP")
|
||||
| t!("THROW") | t!("UPDATE")
|
||||
| t!("USE")
|
||||
| t!("OPTION") | t!("REBUILD")
|
||||
| t!("RETURN") | t!("RELATE")
|
||||
| t!("REMOVE") | t!("SELECT")
|
||||
| t!("LET") | t!("SHOW")
|
||||
| t!("SLEEP") | t!("THROW")
|
||||
| t!("UPDATE") | t!("USE")
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -165,6 +166,10 @@ impl Parser<'_> {
|
|||
self.pop_peek();
|
||||
self.parse_option_stmt().map(Statement::Option)
|
||||
}
|
||||
t!("REBUILD") => {
|
||||
self.pop_peek();
|
||||
self.parse_rebuild_stmt().map(Statement::Rebuild)
|
||||
}
|
||||
t!("RETURN") => {
|
||||
self.pop_peek();
|
||||
ctx.run(|ctx| self.parse_return_stmt(ctx)).await.map(Statement::Output)
|
||||
|
@ -254,6 +259,10 @@ impl Parser<'_> {
|
|||
self.pop_peek();
|
||||
self.parse_insert_stmt(ctx).await.map(Entry::Insert)
|
||||
}
|
||||
t!("REBUILD") => {
|
||||
self.pop_peek();
|
||||
self.parse_rebuild_stmt().map(Entry::Rebuild)
|
||||
}
|
||||
t!("RETURN") => {
|
||||
self.pop_peek();
|
||||
self.parse_return_stmt(ctx).await.map(Entry::Output)
|
||||
|
@ -517,6 +526,31 @@ impl Parser<'_> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn parse_rebuild_stmt(&mut self) -> ParseResult<RebuildStatement> {
|
||||
let res = match self.next().kind {
|
||||
t!("INDEX") => {
|
||||
let if_exists = if self.eat(t!("IF")) {
|
||||
expected!(self, t!("EXISTS"));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let name = self.next_token_value()?;
|
||||
expected!(self, t!("ON"));
|
||||
self.eat(t!("TABLE"));
|
||||
let what = self.next_token_value()?;
|
||||
|
||||
RebuildStatement::Index(RebuildIndexStatement {
|
||||
what,
|
||||
name,
|
||||
if_exists,
|
||||
})
|
||||
}
|
||||
x => unexpected!(self, x, "a rebuild statement keyword"),
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Parsers a RETURN statement.
|
||||
///
|
||||
/// # Parser State
|
||||
|
|
|
@ -83,7 +83,8 @@ impl Parser<'_> {
|
|||
| t!("DELETE")
|
||||
| t!("RELATE")
|
||||
| t!("DEFINE")
|
||||
| t!("REMOVE") => {
|
||||
| t!("REMOVE")
|
||||
| t!("REBUILD") => {
|
||||
self.parse_inner_subquery(ctx, None).await.map(|x| Value::Subquery(Box::new(x)))
|
||||
}
|
||||
t!("IF") => {
|
||||
|
|
|
@ -122,6 +122,7 @@ keyword! {
|
|||
PostingsOrder => "POSTINGS_ORDER",
|
||||
Punct => "PUNCT",
|
||||
Readonly => "READONLY",
|
||||
Rebuild => "REBUILD",
|
||||
Relate => "RELATE",
|
||||
Relation => "RELATION",
|
||||
Remove => "REMOVE",
|
||||
|
|
85
lib/tests/rebuild.rs
Normal file
85
lib/tests/rebuild.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
mod parse;
|
||||
use parse::Parse;
|
||||
|
||||
mod helpers;
|
||||
use helpers::*;
|
||||
|
||||
use surrealdb::dbs::Session;
|
||||
use surrealdb::err::Error;
|
||||
use surrealdb::sql::Value;
|
||||
|
||||
#[tokio::test]
|
||||
async fn rebuild_index_statement() -> Result<(), Error> {
|
||||
let sql = "
|
||||
CREATE book:1 SET title = 'Rust Web Programming', isbn = '978-1803234694', author = 'Maxwell Flitton';
|
||||
DEFINE INDEX uniq_isbn ON book FIELDS isbn UNIQUE;
|
||||
REBUILD INDEX IF EXISTS uniq_isbn ON book;
|
||||
INFO FOR TABLE book;
|
||||
REBUILD INDEX IF EXISTS idx_author ON book;
|
||||
REBUILD INDEX IF EXISTS ft_title ON book;
|
||||
DEFINE INDEX idx_author ON book FIELDS author;
|
||||
DEFINE ANALYZER simple TOKENIZERS blank,class FILTERS lowercase;
|
||||
DEFINE INDEX ft_title ON book FIELDS title SEARCH ANALYZER simple BM25 HIGHLIGHTS;
|
||||
REBUILD INDEX uniq_isbn ON book;
|
||||
REBUILD INDEX idx_author ON book;
|
||||
REBUILD INDEX ft_title ON book;
|
||||
INFO FOR TABLE book;
|
||||
SELECT * FROM book WHERE title @@ 'Rust';
|
||||
";
|
||||
let dbs = new_ds().await?;
|
||||
let ses = Session::owner().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(sql, &ses, None).await?;
|
||||
assert_eq!(res.len(), 14);
|
||||
for _ in 0..3 {
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
}
|
||||
// Check infos output
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
events: {},
|
||||
fields: {},
|
||||
indexes: {
|
||||
uniq_isbn: 'DEFINE INDEX uniq_isbn ON book FIELDS isbn UNIQUE'
|
||||
},
|
||||
lives: {},
|
||||
tables: {}
|
||||
}",
|
||||
);
|
||||
assert_eq!(format!("{tmp:#}"), format!("{val:#}"));
|
||||
for _ in 0..8 {
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
}
|
||||
// Check infos output
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
events: {},
|
||||
fields: {},
|
||||
indexes: {
|
||||
ft_title: 'DEFINE INDEX ft_title ON book FIELDS title SEARCH ANALYZER simple BM25(1.2,0.75) DOC_IDS_ORDER 100 DOC_LENGTHS_ORDER 100 POSTINGS_ORDER 100 TERMS_ORDER 100 DOC_IDS_CACHE 100 DOC_LENGTHS_CACHE 100 POSTINGS_CACHE 100 TERMS_CACHE 100 HIGHLIGHTS',
|
||||
idx_author: 'DEFINE INDEX idx_author ON book FIELDS author',
|
||||
uniq_isbn: 'DEFINE INDEX uniq_isbn ON book FIELDS isbn UNIQUE'
|
||||
},
|
||||
lives: {},
|
||||
tables: {}
|
||||
}",
|
||||
);
|
||||
assert_eq!(format!("{tmp:#}"), format!("{val:#}"));
|
||||
// Check record is found
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"[
|
||||
{
|
||||
author: 'Maxwell Flitton',
|
||||
id: book:1,
|
||||
isbn: '978-1803234694',
|
||||
title: 'Rust Web Programming'
|
||||
}
|
||||
]",
|
||||
);
|
||||
assert_eq!(format!("{tmp:#}"), format!("{val:#}"));
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue