Improve structured output (#4217)
Co-authored-by: Gerard Guillemas Martos <gerard.guillemas@surrealdb.com> Co-authored-by: Gerard Guillemas Martos <gguillemas@users.noreply.github.com>
This commit is contained in:
parent
1810189f54
commit
af80c1ccce
28 changed files with 309 additions and 552 deletions
core/src
mac
sql
lib/tests
|
@ -11,10 +11,10 @@ macro_rules! bytes {
|
|||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! map {
|
||||
($($k:expr => $v:expr),* $(,)? $( => $x:expr )?) => {{
|
||||
($($k:expr $(, if let $grant:pat = $check:expr)? $(, if $guard:expr)? => $v:expr),* $(,)? $( => $x:expr )?) => {{
|
||||
let mut m = ::std::collections::BTreeMap::new();
|
||||
$(m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)?
|
||||
$(m.insert($k, $v);)+
|
||||
$(m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)?
|
||||
$( $(if let $grant = $check)? $(if $guard)? { m.insert($k, $v); };)+
|
||||
m
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use super::Value;
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::statements::DefineAccessStatement;
|
||||
use crate::sql::{escape::quote_str, Algorithm};
|
||||
|
@ -6,8 +7,6 @@ use serde::{Deserialize, Serialize};
|
|||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::{Object, Value};
|
||||
|
||||
/// The type of access methods available
|
||||
#[revisioned(revision = 1)]
|
||||
#[derive(Debug, Serialize, Deserialize, Hash, Clone, Eq, PartialEq, PartialOrd)]
|
||||
|
@ -27,9 +26,47 @@ impl Default for AccessType {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for AccessType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AccessType::Jwt(ac) => {
|
||||
write!(f, "JWT {}", ac)?;
|
||||
}
|
||||
AccessType::Record(ac) => {
|
||||
f.write_str("RECORD")?;
|
||||
if let Some(ref v) = ac.signup {
|
||||
write!(f, " SIGNUP {v}")?
|
||||
}
|
||||
if let Some(ref v) = ac.signin {
|
||||
write!(f, " SIGNIN {v}")?
|
||||
}
|
||||
write!(f, " WITH JWT {}", ac.jwt)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for AccessType {
|
||||
fn structure(self) -> Value {
|
||||
match self {
|
||||
AccessType::Jwt(v) => Value::from(map! {
|
||||
"kind".to_string() => "JWT".into(),
|
||||
"jwt".to_string() => v.structure(),
|
||||
}),
|
||||
AccessType::Record(v) => Value::from(map! {
|
||||
"kind".to_string() => "RECORD".into(),
|
||||
"jwt".to_string() => v.jwt.structure(),
|
||||
"signup".to_string(), if let Some(v) = v.signup => v.structure(),
|
||||
"signin".to_string(), if let Some(v) = v.signin => v.structure(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessType {
|
||||
// Returns whether or not the access method can issue non-token grants
|
||||
// In this context, token refers exclusively to JWT
|
||||
/// Returns whether or not the access method can issue non-token grants
|
||||
/// In this context, token refers exclusively to JWT
|
||||
#[allow(unreachable_patterns)]
|
||||
pub fn can_issue_grants(&self) -> bool {
|
||||
match self {
|
||||
|
@ -39,8 +76,8 @@ impl AccessType {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
// Returns whether or not the access method can issue tokens
|
||||
// In this context, tokens refers exclusively to JWT
|
||||
/// Returns whether or not the access method can issue tokens
|
||||
/// In this context, tokens refers exclusively to JWT
|
||||
pub fn can_issue_tokens(&self) -> bool {
|
||||
match self {
|
||||
// The JWT access method can only issue tokens if an issuer is set
|
||||
|
@ -80,7 +117,45 @@ impl Default for JwtAccess {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for JwtAccess {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.verify {
|
||||
JwtAccessVerify::Key(ref v) => {
|
||||
write!(f, "ALGORITHM {} KEY {}", v.alg, quote_str(&v.key))?;
|
||||
}
|
||||
JwtAccessVerify::Jwks(ref v) => {
|
||||
write!(f, "URL {}", quote_str(&v.url),)?;
|
||||
}
|
||||
}
|
||||
if let Some(iss) = &self.issue {
|
||||
write!(f, " WITH ISSUER KEY {}", quote_str(&iss.key))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for JwtAccess {
|
||||
fn structure(self) -> Value {
|
||||
Value::from(map! {
|
||||
"verify".to_string() => match self.verify {
|
||||
JwtAccessVerify::Jwks(v) => Value::from(map!{
|
||||
"url".to_string() => v.url.into(),
|
||||
}),
|
||||
JwtAccessVerify::Key(v) => Value::from(map!{
|
||||
"alg".to_string() => v.alg.structure(),
|
||||
"key".to_string() => v.key.into(),
|
||||
}),
|
||||
},
|
||||
"issuer".to_string(), if let Some(v) = self.issue => Value::from(map!{
|
||||
"alg".to_string() => v.alg.structure(),
|
||||
"key".to_string() => v.key.into(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl JwtAccess {
|
||||
/// Redacts certain parts of the definition for security on export.
|
||||
pub(crate) fn redacted(&self) -> JwtAccess {
|
||||
let mut jwt = self.clone();
|
||||
jwt.verify = match jwt.verify {
|
||||
|
@ -141,6 +216,20 @@ impl Default for JwtAccessVerify {
|
|||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for JwtAccessVerify {
|
||||
fn structure(self) -> Value {
|
||||
match self {
|
||||
JwtAccessVerify::Jwks(v) => Value::from(map! {
|
||||
"url".to_string() => v.url.into(),
|
||||
}),
|
||||
JwtAccessVerify::Key(v) => Value::from(map! {
|
||||
"alg".to_string() => v.alg.structure(),
|
||||
"key".to_string() => v.key.into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[derive(Debug, Serialize, Deserialize, Hash, Clone, Eq, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
|
@ -187,88 +276,3 @@ impl Default for RecordAccess {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AccessType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AccessType::Jwt(ac) => {
|
||||
write!(f, "JWT {}", ac)?;
|
||||
}
|
||||
AccessType::Record(ac) => {
|
||||
f.write_str("RECORD")?;
|
||||
if let Some(ref v) = ac.signup {
|
||||
write!(f, " SIGNUP {v}")?
|
||||
}
|
||||
if let Some(ref v) = ac.signin {
|
||||
write!(f, " SIGNIN {v}")?
|
||||
}
|
||||
write!(f, " WITH JWT {}", ac.jwt)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for AccessType {
|
||||
fn structure(self) -> Value {
|
||||
let mut acc = Object::default();
|
||||
|
||||
match self {
|
||||
AccessType::Jwt(ac) => {
|
||||
acc.insert("kind".to_string(), "JWT".into());
|
||||
acc.insert("jwt".to_string(), ac.structure());
|
||||
}
|
||||
AccessType::Record(ac) => {
|
||||
acc.insert("kind".to_string(), "RECORD".into());
|
||||
if let Some(signup) = ac.signup {
|
||||
acc.insert("signup".to_string(), signup.structure());
|
||||
}
|
||||
if let Some(signin) = ac.signin {
|
||||
acc.insert("signin".to_string(), signin.structure());
|
||||
}
|
||||
acc.insert("jwt".to_string(), ac.jwt.structure());
|
||||
}
|
||||
};
|
||||
|
||||
Value::Object(acc)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for JwtAccess {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.verify {
|
||||
JwtAccessVerify::Key(ref v) => {
|
||||
write!(f, "ALGORITHM {} KEY {}", v.alg, quote_str(&v.key))?;
|
||||
}
|
||||
JwtAccessVerify::Jwks(ref v) => {
|
||||
write!(f, "URL {}", quote_str(&v.url),)?;
|
||||
}
|
||||
}
|
||||
if let Some(iss) = &self.issue {
|
||||
write!(f, " WITH ISSUER KEY {}", quote_str(&iss.key))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for JwtAccess {
|
||||
fn structure(self) -> Value {
|
||||
let mut acc = Object::default();
|
||||
match self.verify {
|
||||
JwtAccessVerify::Key(v) => {
|
||||
acc.insert("alg".to_string(), v.alg.structure());
|
||||
acc.insert("key".to_string(), v.key.into());
|
||||
}
|
||||
JwtAccessVerify::Jwks(v) => {
|
||||
acc.insert("url".to_string(), v.url.into());
|
||||
}
|
||||
}
|
||||
if let Some(v) = self.issue {
|
||||
let mut iss = Object::default();
|
||||
iss.insert("alg".to_string(), v.alg.structure());
|
||||
iss.insert("key".to_string(), v.key.into());
|
||||
acc.insert("issuer".to_string(), iss.to_string().into());
|
||||
}
|
||||
Value::Object(acc)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ impl fmt::Display for Algorithm {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Algorithm {
|
||||
fn structure(self) -> Value {
|
||||
self.to_string().into()
|
||||
|
|
|
@ -33,6 +33,7 @@ impl fmt::Display for Base {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Base {
|
||||
fn structure(self) -> Value {
|
||||
self.to_string().into()
|
||||
|
|
|
@ -33,8 +33,12 @@ impl Default for ChangeFeed {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for ChangeFeed {
|
||||
fn structure(self) -> Value {
|
||||
self.to_string().into()
|
||||
Value::from(map! {
|
||||
"expiry".to_string() => Duration(self.expiry).structure(),
|
||||
"original".to_string() => self.store_diff.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ impl fmt::Display for Cond {
|
|||
write!(f, "WHERE {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Cond {
|
||||
fn structure(self) -> Value {
|
||||
self.0.structure()
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::sql::datetime::Datetime;
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::strand::Strand;
|
||||
use crate::sql::Value;
|
||||
use crate::syn;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -294,3 +296,9 @@ impl<'a> Sum<&'a Self> for Duration {
|
|||
iter.fold(Duration::default(), |a, b| &a + b)
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Duration {
|
||||
fn structure(self) -> Value {
|
||||
self.to_string().into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ 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())
|
||||
self.into_iter().map(Fetch::structure).collect::<Vec<_>>().into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,3 +58,9 @@ impl Display for Fetch {
|
|||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Fetch {
|
||||
fn structure(self) -> Value {
|
||||
self.to_string().into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ impl InfoStructure for Fields {
|
|||
self.to_string().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Fields {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
|
|
|
@ -62,6 +62,6 @@ impl Display for Ident {
|
|||
|
||||
impl InfoStructure for Ident {
|
||||
fn structure(self) -> Value {
|
||||
self.0.into()
|
||||
self.to_string().into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,12 @@ impl Display for Idioms {
|
|||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Idioms {
|
||||
fn structure(self) -> Value {
|
||||
self.to_string().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
#[serde(rename = "$surrealdb::private::sql::Idiom")]
|
||||
|
@ -202,12 +208,6 @@ 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()
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::sql::fmt::is_pretty;
|
|||
use crate::sql::fmt::pretty_indent;
|
||||
use crate::sql::fmt::pretty_sequence_item;
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{Object, Value};
|
||||
use crate::sql::Value;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Write;
|
||||
|
@ -113,6 +113,17 @@ impl Display for Permissions {
|
|||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Permissions {
|
||||
fn structure(self) -> Value {
|
||||
Value::from(map! {
|
||||
"select".to_string() => self.select.structure(),
|
||||
"create".to_string() => self.create.structure(),
|
||||
"update".to_string() => self.update.structure(),
|
||||
"delete".to_string() => self.delete.structure(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub(crate) enum PermissionKind {
|
||||
Select,
|
||||
|
@ -173,26 +184,7 @@ impl InfoStructure for Permission {
|
|||
match self {
|
||||
Permission::None => Value::Bool(false),
|
||||
Permission::Full => Value::Bool(true),
|
||||
Permission::Specific(v) => Value::Strand(v.to_string().into()),
|
||||
Permission::Specific(v) => 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::doc::CursorDoc;
|
|||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{access::AccessDuration, AccessType, Base, Ident, Object, Strand, Value};
|
||||
use crate::sql::{access::AccessDuration, AccessType, Base, Ident, Strand, Value};
|
||||
use derive::Store;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::Rng;
|
||||
|
@ -174,36 +174,16 @@ impl Display for DefineAccessStatement {
|
|||
|
||||
impl InfoStructure for DefineAccessStatement {
|
||||
fn structure(self) -> Value {
|
||||
let Self {
|
||||
name,
|
||||
base,
|
||||
kind,
|
||||
duration,
|
||||
comment,
|
||||
..
|
||||
} = self;
|
||||
let mut acc = Object::default();
|
||||
|
||||
acc.insert("name".to_string(), name.structure());
|
||||
|
||||
acc.insert("base".to_string(), base.structure());
|
||||
|
||||
let mut dur = Object::default();
|
||||
if kind.can_issue_grants() {
|
||||
dur.insert("grant".to_string(), duration.grant.into());
|
||||
}
|
||||
if kind.can_issue_tokens() {
|
||||
dur.insert("token".to_string(), duration.token.into());
|
||||
}
|
||||
dur.insert("session".to_string(), duration.session.into());
|
||||
acc.insert("duration".to_string(), dur.to_string().into());
|
||||
|
||||
acc.insert("kind".to_string(), kind.structure());
|
||||
|
||||
if let Some(comment) = comment {
|
||||
acc.insert("comment".to_string(), comment.into());
|
||||
}
|
||||
|
||||
Value::Object(acc)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"base".to_string() => self.base.structure(),
|
||||
"duration".to_string() => Value::from(map!{
|
||||
"session".to_string() => self.duration.session.into(),
|
||||
"grant".to_string(), if self.kind.can_issue_grants() => self.duration.grant.into(),
|
||||
"token".to_string(), if self.kind.can_issue_tokens() => self.duration.token.into(),
|
||||
}),
|
||||
"kind".to_string() => self.kind.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::doc::CursorDoc;
|
|||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{filter::Filter, tokenizer::Tokenizer, Base, Ident, Object, Strand, Value};
|
||||
use crate::sql::{filter::Filter, tokenizer::Tokenizer, Array, Base, Ident, Strand, Value};
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -96,40 +96,14 @@ impl Display for DefineAnalyzerStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"function".to_string(), if let Some(v) = self.function => v.structure(),
|
||||
"tokenizers".to_string(), if let Some(v) = self.tokenizers =>
|
||||
v.into_iter().map(|v| v.to_string().into()).collect::<Array>().into(),
|
||||
"filters".to_string(), if let Some(v) = self.filters =>
|
||||
v.into_iter().map(|v| v.to_string().into()).collect::<Array>().into(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::doc::CursorDoc;
|
|||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{changefeed::ChangeFeed, Base, Ident, Object, Strand, Value};
|
||||
use crate::sql::{changefeed::ChangeFeed, Base, Ident, Strand, Value};
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -94,19 +94,9 @@ impl Display for DefineDatabaseStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::doc::CursorDoc;
|
|||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{Base, Ident, Object, Strand, Value, Values};
|
||||
use crate::sql::{Base, Ident, Strand, Value, Values};
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -85,31 +85,12 @@ impl Display for DefineEventStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"what".to_string() => self.what.structure(),
|
||||
"when".to_string() => self.when.structure(),
|
||||
"then".to_string() => self.then.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,11 @@ use crate::dbs::Options;
|
|||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::fmt::{is_pretty, pretty_indent};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::statements::DefineTableStatement;
|
||||
use crate::sql::{
|
||||
fmt::is_pretty, fmt::pretty_indent, Base, Ident, Idiom, Kind, Permissions, Strand, Value,
|
||||
};
|
||||
use crate::sql::{Object, Part};
|
||||
use crate::sql::Part;
|
||||
use crate::sql::{Base, Ident, Idiom, Kind, Permissions, Strand, Value};
|
||||
use crate::sql::{Relation, TableType};
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
|
@ -210,51 +209,17 @@ impl Display for DefineFieldStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"what".to_string() => self.what.structure(),
|
||||
"flex".to_string() => self.flex.into(),
|
||||
"kind".to_string(), if let Some(v) = self.kind => v.structure(),
|
||||
"value".to_string(), if let Some(v) = self.value => v.structure(),
|
||||
"assert".to_string(), if let Some(v) = self.assert => v.structure(),
|
||||
"default".to_string(), if let Some(v) = self.default => v.structure(),
|
||||
"readonly".to_string() => self.readonly.into(),
|
||||
"permissions".to_string() => self.permissions.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,9 @@ use crate::dbs::Options;
|
|||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::fmt::{is_pretty, pretty_indent};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{
|
||||
fmt::{is_pretty, pretty_indent},
|
||||
Base, Block, Ident, Kind, Object, Permission, Strand, Value,
|
||||
};
|
||||
use crate::sql::{Base, Block, Ident, Kind, Permission, Strand, Value};
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -100,36 +98,16 @@ impl fmt::Display for DefineFunctionStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"args".to_string() => self.args
|
||||
.into_iter()
|
||||
.map(|(n, k)| vec![n.structure(), k.structure()].into())
|
||||
.collect::<Vec<Value>>()
|
||||
.into(),
|
||||
"block".to_string() => self.block.structure(),
|
||||
"permissions".to_string() => self.permissions.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::err::Error;
|
|||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{
|
||||
statements::UpdateStatement, Base, Ident, Idioms, Index, Object, Part, Strand, Value, Values,
|
||||
statements::UpdateStatement, Base, Ident, Idioms, Index, Part, Strand, Value, Values,
|
||||
};
|
||||
use derive::Store;
|
||||
use reblessive::tree::Stk;
|
||||
|
@ -130,28 +130,12 @@ impl Display for DefineIndexStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"what".to_string() => self.what.structure(),
|
||||
"cols".to_string() => self.cols.structure(),
|
||||
"index".to_string() => self.index.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,9 @@ use crate::dbs::Options;
|
|||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::fmt::{is_pretty, pretty_indent};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{
|
||||
fmt::{is_pretty, pretty_indent},
|
||||
Base, Ident, Object, Permission, Strand, Value,
|
||||
};
|
||||
use crate::sql::{Base, Ident, Permission, Strand, Value};
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -94,25 +92,11 @@ impl DefineModelStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"version".to_string() => self.version.into(),
|
||||
"permissions".to_string() => self.permissions.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::doc::CursorDoc;
|
|||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{Base, Ident, Object, Strand, Value};
|
||||
use crate::sql::{Base, Ident, Strand, Value};
|
||||
use derive::Store;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -87,19 +87,9 @@ impl Display for DefineNamespaceStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::err::Error;
|
|||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::fmt::{is_pretty, pretty_indent};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{Base, Ident, Object, Permission, Strand, Value};
|
||||
use crate::sql::{Base, Ident, Permission, Strand, Value};
|
||||
use derive::Store;
|
||||
use reblessive::tree::Stk;
|
||||
use revision::revisioned;
|
||||
|
@ -93,25 +93,11 @@ impl Display for DefineParamStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"value".to_string() => self.value.structure(),
|
||||
"permissions".to_string() => self.permissions.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
use super::DefineFieldStatement;
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::{Force, Options};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{
|
||||
changefeed::ChangeFeed,
|
||||
fmt::{is_pretty, pretty_indent},
|
||||
statements::UpdateStatement,
|
||||
Base, Ident, Object, Permissions, Strand, Value, Values, View,
|
||||
Base, Ident, Permissions, Strand, Value, Values, View,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{Idiom, Kind, Part, Table, TableType};
|
||||
use crate::sql::{Idiom, Kind, Part, TableType};
|
||||
use derive::Store;
|
||||
use reblessive::tree::Stk;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Write};
|
||||
|
||||
use super::DefineFieldStatement;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[revisioned(revision = 3)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
|
||||
|
@ -148,23 +146,20 @@ impl DefineTableStatement {
|
|||
}
|
||||
|
||||
impl DefineTableStatement {
|
||||
/// Checks if this is a TYPE RELATION table
|
||||
pub fn is_relation(&self) -> bool {
|
||||
matches!(self.kind, TableType::Relation(_))
|
||||
}
|
||||
|
||||
/// Checks if this table allows graph edges / relations
|
||||
pub fn allows_relation(&self) -> bool {
|
||||
matches!(self.kind, TableType::Relation(_) | TableType::Any)
|
||||
}
|
||||
|
||||
/// Checks if this table allows normal records / documents
|
||||
pub fn allows_normal(&self) -> bool {
|
||||
matches!(self.kind, TableType::Normal | TableType::Any)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_tables_from_kind(tables: &[Table]) -> String {
|
||||
tables.iter().map(|t| t.0.as_str()).collect::<Vec<_>>().join(" | ")
|
||||
}
|
||||
|
||||
impl Display for DefineTableStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE TABLE")?;
|
||||
|
@ -180,10 +175,18 @@ impl Display for DefineTableStatement {
|
|||
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 {}",
|
||||
kind.iter().map(|t| t.0.as_str()).collect::<Vec<_>>().join(" | ")
|
||||
)?;
|
||||
}
|
||||
if let Some(Kind::Record(kind)) = &rel.to {
|
||||
write!(f, " OUT {}", get_tables_from_kind(kind))?;
|
||||
write!(
|
||||
f,
|
||||
" OUT {}",
|
||||
kind.iter().map(|t| t.0.as_str()).collect::<Vec<_>>().join(" | ")
|
||||
)?;
|
||||
}
|
||||
}
|
||||
TableType::Any => {
|
||||
|
@ -220,40 +223,15 @@ impl Display for DefineTableStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"drop".to_string() => self.drop.into(),
|
||||
"full".to_string() => self.full.into(),
|
||||
"kind".to_string() => self.kind.structure(),
|
||||
"view".to_string(), if let Some(v) = self.view => v.structure(),
|
||||
"changefeed".to_string(), if let Some(v) = self.changefeed => v.structure(),
|
||||
"permissions".to_string() => self.permissions.structure(),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::err::Error;
|
|||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{
|
||||
escape::quote_str, fmt::Fmt, user::UserDuration, Base, Duration, Ident, Object, Strand, Value,
|
||||
escape::quote_str, fmt::Fmt, user::UserDuration, Base, Duration, Ident, Strand, Value,
|
||||
};
|
||||
use argon2::{
|
||||
password_hash::{PasswordHasher, SaltString},
|
||||
|
@ -251,37 +251,16 @@ impl Display for DefineUserStatement {
|
|||
|
||||
impl InfoStructure for DefineUserStatement {
|
||||
fn structure(self) -> Value {
|
||||
let Self {
|
||||
name,
|
||||
base,
|
||||
hash,
|
||||
roles,
|
||||
duration,
|
||||
comment,
|
||||
..
|
||||
} = self;
|
||||
let mut acc = Object::default();
|
||||
|
||||
acc.insert("name".to_string(), name.structure());
|
||||
|
||||
acc.insert("base".to_string(), base.structure());
|
||||
|
||||
acc.insert("passhash".to_string(), hash.into());
|
||||
|
||||
acc.insert(
|
||||
"roles".to_string(),
|
||||
Value::Array(roles.into_iter().map(|r| r.structure()).collect()),
|
||||
);
|
||||
|
||||
let mut dur = Object::default();
|
||||
dur.insert("token".to_string(), duration.token.into());
|
||||
dur.insert("session".to_string(), duration.session.into());
|
||||
acc.insert("duration".to_string(), dur.to_string().into());
|
||||
|
||||
if let Some(comment) = comment {
|
||||
acc.insert("comment".to_string(), comment.into());
|
||||
}
|
||||
|
||||
Value::Object(acc)
|
||||
Value::from(map! {
|
||||
"name".to_string() => self.name.structure(),
|
||||
"base".to_string() => self.base.structure(),
|
||||
"hash".to_string() => self.hash.into(),
|
||||
"roles".to_string() => self.roles.into_iter().map(Ident::structure).collect(),
|
||||
"duration".to_string() => Value::from(map! {
|
||||
"token".to_string() => self.duration.token.into(),
|
||||
"session".to_string() => self.duration.session.into(),
|
||||
}),
|
||||
"comment".to_string(), if let Some(v) = self.comment => v.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::fflags::FFLAGS;
|
|||
use crate::iam::Auth;
|
||||
use crate::kvs::lq_structs::{LqEntry, TrackedResult};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{Cond, Fetchs, Fields, Object, Table, Uuid, Value};
|
||||
use crate::sql::{Cond, Fetchs, Fields, Table, Uuid, Value};
|
||||
use derive::Store;
|
||||
use futures::lock::MutexGuard;
|
||||
use reblessive::tree::Stk;
|
||||
|
@ -202,27 +202,11 @@ impl fmt::Display for LiveStatement {
|
|||
|
||||
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)
|
||||
Value::from(map! {
|
||||
"expr".to_string() => self.expr.structure(),
|
||||
"what".to_string() => self.what.structure(),
|
||||
"cond".to_string(), if let Some(v) = self.cond => v.structure(),
|
||||
"fetch".to_string(), if let Some(v) = self.fetch => v.structure(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::Array;
|
||||
use crate::sql::{Kind, Value};
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::{Kind, Object, Table, Value};
|
||||
|
||||
/// The type of records stored by a table
|
||||
#[revisioned(revision = 1)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Hash, Clone, Eq, PartialEq, PartialOrd)]
|
||||
|
@ -27,11 +25,11 @@ 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).join(" | "))?;
|
||||
if let Some(kind) = &rel.from {
|
||||
write!(f, " IN {kind}")?;
|
||||
}
|
||||
if let Some(Kind::Record(kind)) = &rel.to {
|
||||
write!(f, " OUT {}", get_tables_from_kind(kind).join(" | "))?;
|
||||
if let Some(kind) = &rel.to {
|
||||
write!(f, " OUT {kind}")?;
|
||||
}
|
||||
}
|
||||
TableType::Any => {
|
||||
|
@ -44,42 +42,24 @@ impl Display for TableType {
|
|||
|
||||
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)
|
||||
match self {
|
||||
TableType::Any => Value::from(map! {
|
||||
"kind".to_string() => "ANY".into(),
|
||||
}),
|
||||
TableType::Normal => Value::from(map! {
|
||||
"kind".to_string() => "NORMAL".into(),
|
||||
}),
|
||||
TableType::Relation(rel) => Value::from(map! {
|
||||
"kind".to_string() => "RELATION".into(),
|
||||
"in".to_string(), if let Some(Kind::Record(tables)) = rel.from =>
|
||||
tables.into_iter().map(|t| t.0).collect::<Vec<_>>().into(),
|
||||
"out".to_string(), if let Some(Kind::Record(tables)) = rel.to =>
|
||||
tables.into_iter().map(|t| t.0).collect::<Vec<_>>().into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_tables_from_kind(tables: &[Table]) -> Vec<&str> {
|
||||
tables.iter().map(|t| t.0.as_str()).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Hash, Clone, Eq, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
|
|
|
@ -58,6 +58,12 @@ impl Display for Values {
|
|||
}
|
||||
}
|
||||
|
||||
impl InfoStructure for Values {
|
||||
fn structure(self) -> Value {
|
||||
self.into_iter().map(Value::structure).collect::<Vec<_>>().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Tables> for Values {
|
||||
fn from(tables: &Tables) -> Self {
|
||||
Self(tables.0.iter().map(|t| Value::Table(t.clone())).collect())
|
||||
|
|
|
@ -577,7 +577,7 @@ async fn access_info_redacted_structure() {
|
|||
assert!(out.is_ok(), "Unexpected error: {:?}", out);
|
||||
|
||||
let out_expected =
|
||||
r#"{ accesses: [{ base: 'NAMESPACE', duration: '{ session: 6h, token: 15m }', kind: { jwt: { alg: 'HS512', issuer: "{ alg: 'HS512', key: '[REDACTED]' }", key: '[REDACTED]' }, kind: 'JWT' }, name: 'access' }], databases: [], users: [] }"#.to_string();
|
||||
r#"{ accesses: [{ base: 'NAMESPACE', duration: { session: 6h, token: 15m }, kind: { jwt: { issuer: { alg: 'HS512', key: '[REDACTED]' }, verify: { alg: 'HS512', key: '[REDACTED]' } }, kind: 'JWT' }, name: 'access' }], databases: [], users: [] }"#.to_string();
|
||||
let out_str = out.unwrap().to_string();
|
||||
assert_eq!(
|
||||
out_str, out_expected,
|
||||
|
@ -600,7 +600,7 @@ async fn access_info_redacted_structure() {
|
|||
assert!(out.is_ok(), "Unexpected error: {:?}", out);
|
||||
|
||||
let out_expected =
|
||||
r#"{ accesses: [{ base: 'NAMESPACE', duration: '{ session: 6h, token: 15m }', kind: { jwt: { alg: 'PS512', issuer: "{ alg: 'PS512', key: '[REDACTED]' }", key: 'public' }, kind: 'JWT' }, name: 'access' }], databases: [], users: [] }"#.to_string();
|
||||
r#"{ accesses: [{ base: 'NAMESPACE', duration: { session: 6h, token: 15m }, kind: { jwt: { issuer: { alg: 'PS512', key: '[REDACTED]' }, verify: { alg: 'PS512', key: 'public' } }, kind: 'JWT' }, name: 'access' }], databases: [], users: [] }"#.to_string();
|
||||
let out_str = out.unwrap().to_string();
|
||||
assert_eq!(
|
||||
out_str, out_expected,
|
||||
|
@ -623,7 +623,7 @@ async fn access_info_redacted_structure() {
|
|||
assert!(out.is_ok(), "Unexpected error: {:?}", out);
|
||||
|
||||
let out_expected =
|
||||
r#"{ accesses: [{ base: 'NAMESPACE', duration: '{ session: 6h, token: 15m }', kind: { jwt: { alg: 'HS512', issuer: "{ alg: 'HS512', key: '[REDACTED]' }", key: '[REDACTED]' }, kind: 'RECORD' }, name: 'access' }], databases: [], users: [] }"#.to_string();
|
||||
r#"{ accesses: [{ base: 'NAMESPACE', duration: { session: 6h, token: 15m }, kind: { jwt: { issuer: { alg: 'HS512', key: '[REDACTED]' }, verify: { alg: 'HS512', key: '[REDACTED]' } }, kind: 'RECORD' }, name: 'access' }], databases: [], users: [] }"#.to_string();
|
||||
let out_str = out.unwrap().to_string();
|
||||
assert_eq!(
|
||||
out_str, out_expected,
|
||||
|
|
Loading…
Reference in a new issue