Add info structure (#3876)

Co-authored-by: Micha de Vries <micha@devrie.sh>
This commit is contained in:
Raphael Darley 2024-04-16 10:05:07 +02:00 committed by GitHub
parent 77f1318152
commit e62bedf9bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 804 additions and 26 deletions

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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))]

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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))]

View file

@ -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(

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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::<Vec<Value>>()
.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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -21,6 +21,11 @@ pub enum InfoStatement {
Sc(Ident),
Tb(Ident),
User(Ident, Option<Base>),
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<Self, ()> {
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<T>(a: Arc<[T]>) -> Value
where
T: InfoStructure + Clone,
{
Value::Array(a.iter().cloned().map(InfoStructure::structure).collect())
}

View file

@ -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)
}
}

View file

@ -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::<Vec<_>>().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::<Vec<_>>()
}
#[derive(Debug, Default, Serialize, Deserialize, Hash, Clone, Eq, PartialEq, PartialOrd)]

View file

@ -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 {

View file

@ -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()
}
}

View file

@ -185,6 +185,7 @@ pub(crate) static KEYWORDS: phf::Map<UniCase<&'static str>, 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),

View file

@ -425,7 +425,7 @@ impl Parser<'_> {
/// Expects `INFO` to already be consumed.
pub(crate) fn parse_info_stmt(&mut self) -> ParseResult<InfoStatement> {
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)
}

View file

@ -144,6 +144,7 @@ keyword! {
Snowball => "SNOWBALL",
Split => "SPLIT",
Start => "START",
Structure => "STRUCTURE",
Table => "TABLE",
TermsCache => "TERMS_CACHE",
TermsOrder => "TERMS_ORDER",