From e62bedf9bb4ea52de034d3a93f70998b420b7970 Mon Sep 17 00:00:00 2001 From: Raphael Darley Date: Tue, 16 Apr 2024 10:05:07 +0200 Subject: [PATCH] Add info structure (#3876) Co-authored-by: Micha de Vries --- core/src/sql/algorithm.rs | 7 + core/src/sql/base.rs | 8 +- core/src/sql/block.rs | 6 + core/src/sql/changefeed.rs | 7 + core/src/sql/cond.rs | 6 + core/src/sql/fetch.rs | 7 + core/src/sql/field.rs | 6 + core/src/sql/ident.rs | 9 +- core/src/sql/idiom.rs | 13 ++ core/src/sql/index.rs | 9 +- core/src/sql/kind.rs | 9 +- core/src/sql/permission.rs | 32 +++- core/src/sql/statements/define/analyzer.rs | 43 +++++- core/src/sql/statements/define/database.rs | 22 ++- core/src/sql/statements/define/event.rs | 34 ++++- core/src/sql/statements/define/field.rs | 54 ++++++- core/src/sql/statements/define/function.rs | 39 ++++- core/src/sql/statements/define/index.rs | 33 +++- core/src/sql/statements/define/model.rs | 28 +++- core/src/sql/statements/define/namespace.rs | 22 ++- core/src/sql/statements/define/param.rs | 28 +++- core/src/sql/statements/define/scope.rs | 32 +++- core/src/sql/statements/define/table.rs | 43 +++++- core/src/sql/statements/define/token.rs | 31 +++- core/src/sql/statements/define/user.rs | 34 ++++- core/src/sql/statements/info.rs | 161 ++++++++++++++++++++ core/src/sql/statements/live.rs | 30 +++- core/src/sql/table_type.rs | 46 +++++- core/src/sql/value/value.rs | 7 + core/src/sql/view.rs | 8 +- core/src/syn/lexer/keywords.rs | 1 + core/src/syn/parser/stmt/mod.rs | 14 +- core/src/syn/token/keyword.rs | 1 + 33 files changed, 804 insertions(+), 26 deletions(-) diff --git a/core/src/sql/algorithm.rs b/core/src/sql/algorithm.rs index 80c13a7e..59b33a18 100644 --- a/core/src/sql/algorithm.rs +++ b/core/src/sql/algorithm.rs @@ -1,3 +1,5 @@ +use crate::sql::statements::info::InfoStructure; +use crate::sql::Value; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt; @@ -49,3 +51,8 @@ impl fmt::Display for Algorithm { }) } } +impl InfoStructure for Algorithm { + fn structure(self) -> Value { + self.to_string().into() + } +} diff --git a/core/src/sql/base.rs b/core/src/sql/base.rs index 834f0680..38da1872 100644 --- a/core/src/sql/base.rs +++ b/core/src/sql/base.rs @@ -1,4 +1,5 @@ -use crate::sql::Ident; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Ident, Value}; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt; @@ -30,3 +31,8 @@ impl fmt::Display for Base { } } } +impl InfoStructure for Base { + fn structure(self) -> Value { + self.to_string().into() + } +} diff --git a/core/src/sql/block.rs b/core/src/sql/block.rs index f5eb45f8..b24141f6 100644 --- a/core/src/sql/block.rs +++ b/core/src/sql/block.rs @@ -3,6 +3,7 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::fmt::{is_pretty, pretty_indent, Fmt, Pretty}; +use crate::sql::statements::info::InfoStructure; use crate::sql::statements::{ BreakStatement, ContinueStatement, CreateStatement, DefineStatement, DeleteStatement, ForeachStatement, IfelseStatement, InsertStatement, OutputStatement, RelateStatement, @@ -166,6 +167,11 @@ impl Display for Block { } } +impl InfoStructure for Block { + fn structure(self) -> Value { + self.to_string().into() + } +} #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] #[revisioned(revision = 1)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] diff --git a/core/src/sql/changefeed.rs b/core/src/sql/changefeed.rs index a839e683..5ba3c3b3 100644 --- a/core/src/sql/changefeed.rs +++ b/core/src/sql/changefeed.rs @@ -1,4 +1,6 @@ use crate::sql::duration::Duration; +use crate::sql::statements::info::InfoStructure; +use crate::sql::Value; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt::{self, Display, Formatter}; @@ -31,3 +33,8 @@ impl Default for ChangeFeed { } } } +impl InfoStructure for ChangeFeed { + fn structure(self) -> Value { + self.to_string().into() + } +} diff --git a/core/src/sql/cond.rs b/core/src/sql/cond.rs index 2564156b..e2211ae9 100644 --- a/core/src/sql/cond.rs +++ b/core/src/sql/cond.rs @@ -1,3 +1,4 @@ +use crate::sql::statements::info::InfoStructure; use crate::sql::value::Value; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -22,3 +23,8 @@ impl fmt::Display for Cond { write!(f, "WHERE {}", self.0) } } +impl InfoStructure for Cond { + fn structure(self) -> Value { + self.0.structure() + } +} diff --git a/core/src/sql/fetch.rs b/core/src/sql/fetch.rs index 349005c9..8c58cdd9 100644 --- a/core/src/sql/fetch.rs +++ b/core/src/sql/fetch.rs @@ -1,5 +1,7 @@ use crate::sql::fmt::Fmt; use crate::sql::idiom::Idiom; +use crate::sql::statements::info::InfoStructure; +use crate::sql::Value; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt::{self, Display, Formatter}; @@ -32,6 +34,11 @@ impl fmt::Display for Fetchs { } } +impl InfoStructure for Fetchs { + fn structure(self) -> Value { + Value::Array(self.0.into_iter().map(|f| f.0.structure()).collect()) + } +} #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] #[revisioned(revision = 1)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] diff --git a/core/src/sql/field.rs b/core/src/sql/field.rs index 8ca920f7..5f1f9514 100644 --- a/core/src/sql/field.rs +++ b/core/src/sql/field.rs @@ -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::info::InfoStructure; use crate::sql::{fmt::Fmt, Idiom, Part, Value}; use crate::syn; use revision::revisioned; @@ -65,6 +66,11 @@ impl Display for Fields { } } +impl InfoStructure for Fields { + fn structure(self) -> Value { + self.to_string().into() + } +} impl Fields { /// Process this type returning a computed simple Value pub(crate) async fn compute( diff --git a/core/src/sql/ident.rs b/core/src/sql/ident.rs index 13a1d389..8f36c88f 100644 --- a/core/src/sql/ident.rs +++ b/core/src/sql/ident.rs @@ -1,4 +1,5 @@ -use crate::sql::{escape::escape_ident, strand::no_nul_bytes}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{escape::escape_ident, strand::no_nul_bytes, Value}; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt::{self, Display, Formatter}; @@ -58,3 +59,9 @@ impl Display for Ident { Display::fmt(&escape_ident(&self.0), f) } } + +impl InfoStructure for Ident { + fn structure(self) -> Value { + self.0.into() + } +} diff --git a/core/src/sql/idiom.rs b/core/src/sql/idiom.rs index 9bd6d841..8c244a8c 100644 --- a/core/src/sql/idiom.rs +++ b/core/src/sql/idiom.rs @@ -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::info::InfoStructure; use crate::sql::{ fmt::{fmt_separated_by, Fmt}, part::Next, @@ -199,3 +200,15 @@ impl Display for Idiom { ) } } + +impl InfoStructure for Idioms { + fn structure(self) -> Value { + self.to_string().into() + } +} + +impl InfoStructure for Idiom { + fn structure(self) -> Value { + self.to_string().into() + } +} diff --git a/core/src/sql/index.rs b/core/src/sql/index.rs index 0d999846..0c48b09e 100644 --- a/core/src/sql/index.rs +++ b/core/src/sql/index.rs @@ -5,7 +5,8 @@ use crate::fnc::util::math::vector::{ }; use crate::sql::ident::Ident; use crate::sql::scoring::Scoring; -use crate::sql::Number; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Number, Value}; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt; @@ -204,3 +205,9 @@ impl Display for Index { } } } + +impl InfoStructure for Index { + fn structure(self) -> Value { + self.to_string().into() + } +} diff --git a/core/src/sql/kind.rs b/core/src/sql/kind.rs index 30c594d2..cb2cb377 100644 --- a/core/src/sql/kind.rs +++ b/core/src/sql/kind.rs @@ -1,4 +1,5 @@ -use crate::sql::{fmt::Fmt, Table}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{fmt::Fmt, Table, Value}; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt::{self, Display, Formatter}; @@ -130,3 +131,9 @@ impl Display for Kind { } } } + +impl InfoStructure for Kind { + fn structure(self) -> Value { + self.to_string().into() + } +} diff --git a/core/src/sql/permission.rs b/core/src/sql/permission.rs index 46710aae..980bb695 100644 --- a/core/src/sql/permission.rs +++ b/core/src/sql/permission.rs @@ -1,7 +1,8 @@ use crate::sql::fmt::is_pretty; use crate::sql::fmt::pretty_indent; use crate::sql::fmt::pretty_sequence_item; -use crate::sql::Value; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Object, Value}; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt::Write; @@ -166,3 +167,32 @@ impl Display for Permission { } } } + +impl InfoStructure for Permission { + fn structure(self) -> Value { + match self { + Permission::None => Value::Bool(false), + Permission::Full => Value::Bool(true), + Permission::Specific(v) => Value::Strand(v.to_string().into()), + } + } +} + +impl InfoStructure for Permissions { + fn structure(self) -> Value { + let Self { + select, + create, + update, + delete, + } = self; + let mut acc = Object::default(); + + acc.insert("select".to_string(), select.structure()); + acc.insert("create".to_string(), create.structure()); + acc.insert("update".to_string(), update.structure()); + acc.insert("delete".to_string(), delete.structure()); + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/analyzer.rs b/core/src/sql/statements/define/analyzer.rs index 4c7688bd..dfa9154b 100644 --- a/core/src/sql/statements/define/analyzer.rs +++ b/core/src/sql/statements/define/analyzer.rs @@ -3,7 +3,8 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{filter::Filter, tokenizer::Tokenizer, Base, Ident, Strand, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{filter::Filter, tokenizer::Tokenizer, Base, Ident, Object, Strand, Value}; use derive::Store; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -89,3 +90,43 @@ impl Display for DefineAnalyzerStatement { Ok(()) } } + +impl InfoStructure for DefineAnalyzerStatement { + fn structure(self) -> Value { + let Self { + name, + function, + tokenizers, + filters, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + if let Some(function) = function { + acc.insert("function".to_string(), function.structure()); + } + + if let Some(tokenizers) = tokenizers { + acc.insert( + "tokenizers".to_string(), + Value::Array(tokenizers.into_iter().map(|t| t.to_string().into()).collect()), + ); + } + + if let Some(filters) = filters { + acc.insert( + "filters".to_string(), + Value::Array(filters.into_iter().map(|f| f.to_string().into()).collect()), + ); + } + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/database.rs b/core/src/sql/statements/define/database.rs index fd736303..99c45311 100644 --- a/core/src/sql/statements/define/database.rs +++ b/core/src/sql/statements/define/database.rs @@ -3,7 +3,8 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{changefeed::ChangeFeed, Base, Ident, Strand, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{changefeed::ChangeFeed, Base, Ident, Object, Strand, Value}; use derive::Store; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -87,3 +88,22 @@ impl Display for DefineDatabaseStatement { Ok(()) } } + +impl InfoStructure for DefineDatabaseStatement { + fn structure(self) -> Value { + let Self { + name, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/event.rs b/core/src/sql/statements/define/event.rs index e709d09a..f8d856fe 100644 --- a/core/src/sql/statements/define/event.rs +++ b/core/src/sql/statements/define/event.rs @@ -3,7 +3,8 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Strand, Value, Values}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Base, Ident, Object, Strand, Value, Values}; use derive::Store; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -80,3 +81,34 @@ impl Display for DefineEventStatement { Ok(()) } } + +impl InfoStructure for DefineEventStatement { + fn structure(self) -> Value { + let Self { + name, + what, + when, + then, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("what".to_string(), what.structure()); + + acc.insert("when".to_string(), when.structure()); + + acc.insert( + "then".to_string(), + Value::Array(then.0.iter().map(|v| v.to_string().into()).collect()), + ); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/field.rs b/core/src/sql/statements/define/field.rs index 927f2ad5..a37ac422 100644 --- a/core/src/sql/statements/define/field.rs +++ b/core/src/sql/statements/define/field.rs @@ -3,11 +3,12 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; +use crate::sql::statements::info::InfoStructure; use crate::sql::statements::DefineTableStatement; -use crate::sql::Part; use crate::sql::{ fmt::is_pretty, fmt::pretty_indent, Base, Ident, Idiom, Kind, Permissions, Strand, Value, }; +use crate::sql::{Object, Part}; use crate::sql::{Relation, TableType}; use derive::Store; use revision::revisioned; @@ -204,3 +205,54 @@ impl Display for DefineFieldStatement { Ok(()) } } + +impl InfoStructure for DefineFieldStatement { + fn structure(self) -> Value { + let Self { + name, + what, + flex, + kind, + readonly, + value, + assert, + default, + permissions, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("what".to_string(), what.structure()); + + acc.insert("flex".to_string(), flex.into()); + + if let Some(kind) = kind { + acc.insert("kind".to_string(), kind.structure()); + } + + acc.insert("readonly".to_string(), readonly.into()); + + if let Some(value) = value { + acc.insert("value".to_string(), value.structure()); + } + + if let Some(assert) = assert { + acc.insert("assert".to_string(), assert.structure()); + } + + if let Some(default) = default { + acc.insert("default".to_string(), default.structure()); + } + + acc.insert("permissions".to_string(), permissions.structure()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/function.rs b/core/src/sql/statements/define/function.rs index b5d8ccc9..7e8b35c9 100644 --- a/core/src/sql/statements/define/function.rs +++ b/core/src/sql/statements/define/function.rs @@ -3,9 +3,10 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; +use crate::sql::statements::info::InfoStructure; use crate::sql::{ fmt::{is_pretty, pretty_indent}, - Base, Block, Ident, Kind, Permission, Strand, Value, + Base, Block, Ident, Kind, Object, Permission, Strand, Value, }; use derive::Store; use revision::revisioned; @@ -93,3 +94,39 @@ impl fmt::Display for DefineFunctionStatement { Ok(()) } } + +impl InfoStructure for DefineFunctionStatement { + fn structure(self) -> Value { + let Self { + name, + args, + block, + comment, + permissions, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert( + "args".to_string(), + Value::Array( + args.into_iter() + .map(|(n, k)| Value::Array(vec![n.structure(), k.structure()].into())) + .collect::>() + .into(), + ), + ); + + acc.insert("block".to_string(), block.structure()); + + acc.insert("permissions".to_string(), permissions.structure()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/index.rs b/core/src/sql/statements/define/index.rs index 41ab91af..d86e7dff 100644 --- a/core/src/sql/statements/define/index.rs +++ b/core/src/sql/statements/define/index.rs @@ -3,7 +3,10 @@ use crate::dbs::{Force, Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{statements::UpdateStatement, Base, Ident, Idioms, Index, Strand, Value, Values}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{ + statements::UpdateStatement, Base, Ident, Idioms, Index, Object, Strand, Value, Values, +}; use derive::Store; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -98,3 +101,31 @@ impl Display for DefineIndexStatement { Ok(()) } } + +impl InfoStructure for DefineIndexStatement { + fn structure(self) -> Value { + let Self { + name, + what, + cols, + index, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("what".to_string(), what.structure()); + + acc.insert("cols".to_string(), cols.structure()); + + acc.insert("index".to_string(), index.structure()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/model.rs b/core/src/sql/statements/define/model.rs index 4a783f12..20a7d2c4 100644 --- a/core/src/sql/statements/define/model.rs +++ b/core/src/sql/statements/define/model.rs @@ -3,9 +3,10 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; +use crate::sql::statements::info::InfoStructure; use crate::sql::{ fmt::{is_pretty, pretty_indent}, - Base, Ident, Permission, Strand, Value, + Base, Ident, Object, Permission, Strand, Value, }; use derive::Store; use revision::revisioned; @@ -89,3 +90,28 @@ impl DefineModelStatement { Ok(Value::None) } } + +impl InfoStructure for DefineModelStatement { + fn structure(self) -> Value { + let Self { + name, + version, + comment, + permissions, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("version".to_string(), version.into()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + acc.insert("permissions".to_string(), permissions.structure()); + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/namespace.rs b/core/src/sql/statements/define/namespace.rs index d4263655..89b04295 100644 --- a/core/src/sql/statements/define/namespace.rs +++ b/core/src/sql/statements/define/namespace.rs @@ -3,7 +3,8 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Ident, Strand, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Base, Ident, Object, Strand, Value}; use derive::Store; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -80,3 +81,22 @@ impl Display for DefineNamespaceStatement { Ok(()) } } + +impl InfoStructure for DefineNamespaceStatement { + fn structure(self) -> Value { + let Self { + name, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/param.rs b/core/src/sql/statements/define/param.rs index 76cea9e4..dc4923e2 100644 --- a/core/src/sql/statements/define/param.rs +++ b/core/src/sql/statements/define/param.rs @@ -4,7 +4,8 @@ use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; use crate::sql::fmt::{is_pretty, pretty_indent}; -use crate::sql::{Base, Ident, Permission, Strand, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Base, Ident, Object, Permission, Strand, Value}; use derive::Store; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -84,3 +85,28 @@ impl Display for DefineParamStatement { Ok(()) } } + +impl InfoStructure for DefineParamStatement { + fn structure(self) -> Value { + let Self { + name, + value, + comment, + permissions, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("value".to_string(), value.structure()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + acc.insert("permissions".to_string(), permissions.structure()); + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/scope.rs b/core/src/sql/statements/define/scope.rs index e399ae37..f571eb88 100644 --- a/core/src/sql/statements/define/scope.rs +++ b/core/src/sql/statements/define/scope.rs @@ -3,7 +3,8 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{Base, Duration, Ident, Strand, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Base, Duration, Ident, Object, Strand, Value}; use derive::Store; use rand::distributions::Alphanumeric; use rand::Rng; @@ -93,3 +94,32 @@ impl Display for DefineScopeStatement { Ok(()) } } + +impl InfoStructure for DefineScopeStatement { + fn structure(self) -> Value { + let Self { + name, + signup, + signin, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + if let Some(signup) = signup { + acc.insert("signup".to_string(), signup.structure()); + } + + if let Some(signin) = signin { + acc.insert("signin".to_string(), signin.structure()); + } + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/table.rs b/core/src/sql/statements/define/table.rs index 4c2ee10a..11eb3436 100644 --- a/core/src/sql/statements/define/table.rs +++ b/core/src/sql/statements/define/table.rs @@ -7,10 +7,11 @@ use crate::sql::{ changefeed::ChangeFeed, fmt::{is_pretty, pretty_indent}, statements::UpdateStatement, - Base, Ident, Permissions, Strand, Value, Values, View, + Base, Ident, Object, Permissions, Strand, Value, Values, View, }; use std::sync::Arc; +use crate::sql::statements::info::InfoStructure; use crate::sql::{Idiom, Kind, Part, Table, TableType}; use derive::Store; use revision::revisioned; @@ -211,3 +212,43 @@ impl Display for DefineTableStatement { Ok(()) } } + +impl InfoStructure for DefineTableStatement { + fn structure(self) -> Value { + let Self { + name, + drop, + full, + view, + permissions, + changefeed, + comment, + kind, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("drop".to_string(), drop.into()); + acc.insert("full".to_string(), full.into()); + + if let Some(view) = view { + acc.insert("view".to_string(), view.structure()); + } + + acc.insert("permissions".to_string(), permissions.structure()); + + if let Some(changefeed) = changefeed { + acc.insert("changefeed".to_string(), changefeed.structure()); + } + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + acc.insert("kind".to_string(), kind.structure()); + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/token.rs b/core/src/sql/statements/define/token.rs index 5e845672..5b22394e 100644 --- a/core/src/sql/statements/define/token.rs +++ b/core/src/sql/statements/define/token.rs @@ -3,7 +3,8 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{escape::quote_str, Algorithm, Base, Ident, Strand, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{escape::quote_str, Algorithm, Base, Ident, Object, Strand, Value}; use derive::Store; use revision::revisioned; use serde::{Deserialize, Serialize}; @@ -143,3 +144,31 @@ impl Display for DefineTokenStatement { Ok(()) } } + +impl InfoStructure for DefineTokenStatement { + fn structure(self) -> Value { + let Self { + name, + base, + kind, + code, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("base".to_string(), base.structure()); + + acc.insert("kind".to_string(), kind.structure()); + + acc.insert("code".to_string(), code.into()); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/define/user.rs b/core/src/sql/statements/define/user.rs index 9341a93f..210bd991 100644 --- a/core/src/sql/statements/define/user.rs +++ b/core/src/sql/statements/define/user.rs @@ -3,7 +3,8 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::iam::{Action, ResourceKind}; -use crate::sql::{escape::quote_str, fmt::Fmt, Base, Ident, Strand, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{escape::quote_str, fmt::Fmt, Base, Ident, Object, Strand, Value}; use argon2::{ password_hash::{PasswordHasher, SaltString}, Argon2, @@ -199,3 +200,34 @@ impl Display for DefineUserStatement { Ok(()) } } + +impl InfoStructure for DefineUserStatement { + fn structure(self) -> Value { + let Self { + name, + base, + code, + roles, + comment, + .. + } = self; + let mut acc = Object::default(); + + acc.insert("name".to_string(), name.structure()); + + acc.insert("base".to_string(), base.structure()); + + acc.insert("code".to_string(), code.into()); + + acc.insert( + "roles".to_string(), + Value::Array(roles.into_iter().map(|r| r.structure()).collect()), + ); + + if let Some(comment) = comment { + acc.insert("comment".to_string(), comment.into()); + } + + Value::Object(acc) + } +} diff --git a/core/src/sql/statements/info.rs b/core/src/sql/statements/info.rs index 27452832..4edab4d5 100644 --- a/core/src/sql/statements/info.rs +++ b/core/src/sql/statements/info.rs @@ -21,6 +21,11 @@ pub enum InfoStatement { Sc(Ident), Tb(Ident), User(Ident, Option), + RootStructure, + NsStructure, + DbStructure, + ScStructure(Ident), + TbStructure(Ident), } impl InfoStatement { @@ -215,6 +220,130 @@ impl InfoStatement { // Ok all good Value::from(res.to_string()).ok() } + InfoStatement::RootStructure => { + // Allowed to run? + opt.is_allowed(Action::View, ResourceKind::Any, &Base::Root)?; + // Claim transaction + let mut run = txn.lock().await; + // Create the result set + let mut res = Object::default(); + // Process the namespaces + res.insert("namespaces".to_owned(), process_arr(run.all_ns().await?)); + // Process the users + res.insert("users".to_owned(), process_arr(run.all_root_users().await?)); + // Ok all good + Value::from(res).ok() + } + InfoStatement::NsStructure => { + // Allowed to run? + opt.is_allowed(Action::View, ResourceKind::Any, &Base::Ns)?; + // Claim transaction + let mut run = txn.lock().await; + // Create the result set + let mut res = Object::default(); + // Process the databases + res.insert("databases".to_owned(), process_arr(run.all_db(opt.ns()).await?)); + // Process the users + res.insert("users".to_owned(), process_arr(run.all_ns_users(opt.ns()).await?)); + // Process the tokens + res.insert("tokens".to_owned(), process_arr(run.all_ns_tokens(opt.ns()).await?)); + // Ok all good + Value::from(res).ok() + } + InfoStatement::DbStructure => { + // Allowed to run? + opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?; + // Claim transaction + let mut run = txn.lock().await; + // Create the result set + let mut res = Object::default(); + // Process the users + res.insert( + "users".to_owned(), + process_arr(run.all_db_users(opt.ns(), opt.db()).await?), + ); + // Process the tokens + res.insert( + "tokens".to_owned(), + process_arr(run.all_db_tokens(opt.ns(), opt.db()).await?), + ); + // Process the functions + res.insert( + "functions".to_owned(), + process_arr(run.all_db_functions(opt.ns(), opt.db()).await?), + ); + // Process the models + res.insert( + "models".to_owned(), + process_arr(run.all_db_models(opt.ns(), opt.db()).await?), + ); + // Process the params + res.insert( + "params".to_owned(), + process_arr(run.all_db_params(opt.ns(), opt.db()).await?), + ); + // Process the scopes + res.insert("scopes".to_owned(), process_arr(run.all_sc(opt.ns(), opt.db()).await?)); + // Process the tables + res.insert("tables".to_owned(), process_arr(run.all_tb(opt.ns(), opt.db()).await?)); + // Process the analyzers + res.insert( + "analyzers".to_owned(), + process_arr(run.all_db_analyzers(opt.ns(), opt.db()).await?), + ); + // Ok all good + Value::from(res).ok() + } + InfoStatement::ScStructure(sc) => { + // Allowed to run? + opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?; + // Claim transaction + let mut run = txn.lock().await; + // Create the result set + let mut res = Object::default(); + // Process the tokens + res.insert( + "tokens".to_owned(), + process_arr(run.all_sc_tokens(opt.ns(), opt.db(), sc).await?), + ); + // Ok all good + Value::from(res).ok() + } + InfoStatement::TbStructure(tb) => { + // Allowed to run? + opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?; + // Claim transaction + let mut run = txn.lock().await; + // Create the result set + let mut res = Object::default(); + // Process the events + res.insert( + "events".to_owned(), + process_arr(run.all_tb_events(opt.ns(), opt.db(), tb).await?), + ); + // Process the fields + res.insert( + "fields".to_owned(), + process_arr(run.all_tb_fields(opt.ns(), opt.db(), tb).await?), + ); + // Process the tables + res.insert( + "tables".to_owned(), + process_arr(run.all_tb_views(opt.ns(), opt.db(), tb).await?), + ); + // Process the indexes + res.insert( + "indexes".to_owned(), + process_arr(run.all_tb_indexes(opt.ns(), opt.db(), tb).await?), + ); + // Process the live queries + res.insert( + "lives".to_owned(), + process_arr(run.all_tb_lives(opt.ns(), opt.db(), tb).await?), + ); + // Ok all good + Value::from(res).ok() + } } } } @@ -223,10 +352,15 @@ impl fmt::Display for InfoStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Root => f.write_str("INFO FOR ROOT"), + Self::RootStructure => f.write_str("INFO FOR ROOT STRUCTURE"), Self::Ns => f.write_str("INFO FOR NAMESPACE"), + Self::NsStructure => f.write_str("INFO FOR NAMESPACE STRUCTURE"), Self::Db => f.write_str("INFO FOR DATABASE"), + Self::DbStructure => f.write_str("INFO FOR DATABASE STRUCTURE"), Self::Sc(ref s) => write!(f, "INFO FOR SCOPE {s}"), + Self::ScStructure(ref s) => write!(f, "INFO FOR SCOPE {s} STRUCTURE"), Self::Tb(ref t) => write!(f, "INFO FOR TABLE {t}"), + Self::TbStructure(ref t) => write!(f, "INFO FOR TABLE {t} STRUCTURE"), Self::User(ref u, ref b) => match b { Some(ref b) => write!(f, "INFO FOR USER {u} ON {b}"), None => write!(f, "INFO FOR USER {u}"), @@ -234,3 +368,30 @@ impl fmt::Display for InfoStatement { } } } + +use std::sync::Arc; + +pub(crate) trait InfoStructure { + fn structure(self) -> Value; +} + +impl InfoStatement { + pub(crate) fn structurize(self) -> Result { + let out = match self { + InfoStatement::Root => InfoStatement::RootStructure, + InfoStatement::Ns => InfoStatement::NsStructure, + InfoStatement::Db => InfoStatement::DbStructure, + InfoStatement::Sc(s) => InfoStatement::ScStructure(s), + InfoStatement::Tb(t) => InfoStatement::TbStructure(t), + _ => return Err(()), + }; + Ok(out) + } +} + +fn process_arr(a: Arc<[T]>) -> Value +where + T: InfoStructure + Clone, +{ + Value::Array(a.iter().cloned().map(InfoStructure::structure).collect()) +} diff --git a/core/src/sql/statements/live.rs b/core/src/sql/statements/live.rs index f709cf19..394b1dea 100644 --- a/core/src/sql/statements/live.rs +++ b/core/src/sql/statements/live.rs @@ -5,7 +5,8 @@ use crate::err::{Error, LiveQueryCause}; use crate::fflags::FFLAGS; use crate::iam::Auth; use crate::kvs::lq_structs::{LqEntry, TrackedResult}; -use crate::sql::{Cond, Fetchs, Fields, Table, Uuid, Value}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{Cond, Fetchs, Fields, Object, Table, Uuid, Value}; use derive::Store; use futures::lock::MutexGuard; use revision::revisioned; @@ -191,3 +192,30 @@ impl fmt::Display for LiveStatement { Ok(()) } } + +impl InfoStructure for LiveStatement { + fn structure(self) -> Value { + let Self { + expr, + what, + cond, + fetch, + .. + } = self; + + let mut acc = Object::default(); + + acc.insert("expr".to_string(), expr.structure()); + + acc.insert("what".to_string(), what.structure()); + + if let Some(cond) = cond { + acc.insert("cond".to_string(), cond.structure()); + } + + if let Some(fetch) = fetch { + acc.insert("fetch".to_string(), fetch.structure()); + } + Value::Object(acc) + } +} diff --git a/core/src/sql/table_type.rs b/core/src/sql/table_type.rs index bcb3887f..f883130d 100644 --- a/core/src/sql/table_type.rs +++ b/core/src/sql/table_type.rs @@ -1,9 +1,11 @@ +use crate::sql::statements::info::InfoStructure; +use crate::sql::Array; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt; use std::fmt::Display; -use super::{Kind, Table}; +use super::{Kind, Object, Table, Value}; /// The type of records stored by a table #[derive(Debug, Default, Serialize, Deserialize, Hash, Clone, Eq, PartialEq, PartialOrd)] @@ -26,10 +28,10 @@ impl Display for TableType { TableType::Relation(rel) => { f.write_str(" RELATION")?; if let Some(Kind::Record(kind)) = &rel.from { - write!(f, " IN {}", get_tables_from_kind(kind))?; + write!(f, " IN {}", get_tables_from_kind(kind).join(" | "))?; } if let Some(Kind::Record(kind)) = &rel.to { - write!(f, " OUT {}", get_tables_from_kind(kind))?; + write!(f, " OUT {}", get_tables_from_kind(kind).join(" | "))?; } } TableType::Any => { @@ -40,8 +42,42 @@ impl Display for TableType { } } -fn get_tables_from_kind(tables: &[Table]) -> String { - tables.iter().map(|t| t.0.as_str()).collect::>().join(" | ") +impl InfoStructure for TableType { + fn structure(self) -> Value { + let mut acc = Object::default(); + + match &self { + TableType::Any => { + acc.insert("kind".to_string(), "ANY".into()); + } + TableType::Normal => { + acc.insert("kind".to_string(), "NORMAL".into()); + } + TableType::Relation(rel) => { + acc.insert("kind".to_string(), "RELATION".into()); + + if let Some(Kind::Record(tables)) = &rel.from { + acc.insert( + "in".to_string(), + Value::Array(Array::from(get_tables_from_kind(tables))), + ); + } + + if let Some(Kind::Record(tables)) = &rel.to { + acc.insert( + "out".to_string(), + Value::Array(Array::from(get_tables_from_kind(tables))), + ); + } + } + }; + + Value::Object(acc) + } +} + +fn get_tables_from_kind(tables: &[Table]) -> Vec<&str> { + tables.iter().map(|t| t.0.as_str()).collect::>() } #[derive(Debug, Default, Serialize, Deserialize, Hash, Clone, Eq, PartialEq, PartialOrd)] diff --git a/core/src/sql/value/value.rs b/core/src/sql/value/value.rs index 2ca75ac9..93608266 100644 --- a/core/src/sql/value/value.rs +++ b/core/src/sql/value/value.rs @@ -5,6 +5,7 @@ use crate::dbs::{Options, Transaction}; use crate::doc::CursorDoc; use crate::err::Error; use crate::fnc::util::string::fuzzy::Fuzzy; +use crate::sql::statements::info::InfoStructure; use crate::sql::{ array::Uniq, fmt::{Fmt, Pretty}, @@ -2594,6 +2595,12 @@ impl fmt::Display for Value { } } +impl InfoStructure for Value { + fn structure(self) -> Value { + self.to_string().into() + } +} + impl Value { /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { diff --git a/core/src/sql/view.rs b/core/src/sql/view.rs index c9ed33e2..91bf2143 100644 --- a/core/src/sql/view.rs +++ b/core/src/sql/view.rs @@ -1,4 +1,5 @@ -use crate::sql::{cond::Cond, field::Fields, group::Groups, table::Tables}; +use crate::sql::statements::info::InfoStructure; +use crate::sql::{cond::Cond, field::Fields, group::Groups, table::Tables, Value}; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt; @@ -26,3 +27,8 @@ impl fmt::Display for View { Ok(()) } } +impl InfoStructure for View { + fn structure(self) -> Value { + self.to_string().into() + } +} diff --git a/core/src/syn/lexer/keywords.rs b/core/src/syn/lexer/keywords.rs index 509c7671..99070071 100644 --- a/core/src/syn/lexer/keywords.rs +++ b/core/src/syn/lexer/keywords.rs @@ -185,6 +185,7 @@ pub(crate) static KEYWORDS: phf::Map, TokenKind> = phf_map UniCase::ascii("SNOWBALL") => TokenKind::Keyword(Keyword::Snowball), UniCase::ascii("SPLIT") => TokenKind::Keyword(Keyword::Split), UniCase::ascii("START") => TokenKind::Keyword(Keyword::Start), + UniCase::ascii("STRUCTURE") => TokenKind::Keyword(Keyword::Structure), UniCase::ascii("TABLE") => TokenKind::Keyword(Keyword::Table), UniCase::ascii("TB") => TokenKind::Keyword(Keyword::Table), UniCase::ascii("TERMS_CACHE") => TokenKind::Keyword(Keyword::TermsCache), diff --git a/core/src/syn/parser/stmt/mod.rs b/core/src/syn/parser/stmt/mod.rs index bbbae2e9..7bdd668a 100644 --- a/core/src/syn/parser/stmt/mod.rs +++ b/core/src/syn/parser/stmt/mod.rs @@ -425,7 +425,7 @@ impl Parser<'_> { /// Expects `INFO` to already be consumed. pub(crate) fn parse_info_stmt(&mut self) -> ParseResult { expected!(self, t!("FOR")); - let stmt = match self.next().kind { + let mut stmt = match self.next().kind { t!("ROOT") => InfoStatement::Root, t!("NAMESPACE") => InfoStatement::Ns, t!("DATABASE") => InfoStatement::Db, @@ -444,6 +444,18 @@ impl Parser<'_> { } x => unexpected!(self, x, "an info target"), }; + + if self.peek_kind() == t!("STRUCTURE") { + stmt = match stmt.structurize() { + Ok(s) => { + self.pop_peek(); + s + } + Err(_) => { + unexpected!(self, t!("STRUCTURE"), "not STRUCTURE") + } + } + }; Ok(stmt) } diff --git a/core/src/syn/token/keyword.rs b/core/src/syn/token/keyword.rs index 3f2af948..ab36d2ce 100644 --- a/core/src/syn/token/keyword.rs +++ b/core/src/syn/token/keyword.rs @@ -144,6 +144,7 @@ keyword! { Snowball => "SNOWBALL", Split => "SPLIT", Start => "START", + Structure => "STRUCTURE", Table => "TABLE", TermsCache => "TERMS_CACHE", TermsOrder => "TERMS_ORDER",