use std::collections::BTreeMap;
use std::str::FromStr;
use std::time::Duration;
use rstest::rstest;
use surrealdb_strand::Strand;
use uuid::Uuid;
use super::*;
use crate::catalog::auth::AuthLimit;
use crate::catalog::schema::base::Base;
use crate::expr::field::Selector;
use crate::expr::{
Block, ChangeFeed, Expr, Fetch, Fetchs, Field, Fields, Filter, Groups, Idiom, Kind, Literal,
Tokenizer,
};
use crate::iam::Auth;
use crate::kvs::KVValue;
use crate::kvs::version::MajorVersion;
use crate::val::{Datetime, TableName, Value};
#[rstest]
#[case::namespace(NamespaceDefinition {
namespace_id: NamespaceId(123),
name: "test".into(),
comment: Some("comment".to_string()),
}, 16)]
#[case::database(DatabaseDefinition {
namespace_id: NamespaceId(123),
database_id: DatabaseId(456),
name: "test".into(),
strict: false,
comment: Some("comment".to_string()),
changefeed: Some(ChangeFeed {
expiry: Duration::from_secs(123),
store_diff: false,
}),
}, 25)]
#[case::table(TableDefinition {
namespace_id: NamespaceId(123),
database_id: DatabaseId(456),
table_id: TableId(789),
name: TableName::from("test"),
drop: false,
schemafull: false,
view: Some(ViewDefinition::Select {
fields: Fields::Select(vec![Field::All, Field::Single (crate::expr::field::Selector{
expr: Expr::Literal(Literal::String(Strand::new_static("expr"))),
alias: Some(Idiom::from_str("field[0]").unwrap()),
})]),
tables: vec![TableName::from("what")],
condition: Some(Expr::Literal(Literal::String(Strand::new_static("cond")))),
groups: Some(Groups::default()),
}),
permissions: Permissions::default(),
changefeed: Some(ChangeFeed {
expiry: Duration::from_secs(123),
store_diff: false,
}),
comment: Some("comment".to_string()),
table_type: TableType::Normal,
cache_fields_ts: Uuid::default(),
cache_events_ts: Uuid::default(),
cache_tables_ts: Uuid::default(),
cache_indexes_ts: Uuid::default(),
graphql_alias: None,
graphql_deprecated: None,
}, 151)]
#[case::subscription(SubscriptionDefinition {
id: Uuid::default(),
node: Uuid::default(),
fields: SubscriptionFields::Select(Fields::Select(vec![Field::All, Field::Single(Selector{
expr: Expr::Literal(Literal::String(Strand::new_static("expr"))),
alias: Some(Idiom::from_str("field[0]").unwrap()),
})])),
what: Expr::Literal(Literal::String(Strand::new_static("what"))),
cond: Some(Expr::Literal(Literal::String(Strand::new_static("cond")))),
fetch: Some(Fetchs::new(vec![Fetch(Expr::Literal(Literal::String(Strand::new_static("fetch"))))])),
auth: Some(Auth::default()),
session: Some(Value::default()),
vars: BTreeMap::new(),
}, 101)]
#[case::access(AccessDefinition {
name: "access".into(),
access_type: AccessType::Bearer(BearerAccess {
kind: BearerAccessType::Bearer,
subject: BearerAccessSubject::Record,
jwt: JwtAccess {
verify: JwtAccessVerify::Key(JwtAccessVerifyKey {
alg: Algorithm::EdDSA,
key: "key".to_string(),
}),
issue: Some(JwtAccessIssue {
alg: Algorithm::Hs512,
key: "key".to_string(),
}),
},
}),
base: Base::Root,
authenticate: Some(Expr::Literal(Literal::String(Strand::new_static("expr")))),
grant_duration: Some(Duration::from_secs(123)),
token_duration: Some(Duration::from_secs(123)),
session_duration: Some(Duration::from_secs(123)),
comment: Some("comment".to_string()),
}, 61)]
#[case::access(AccessGrant {
id: "access".to_string(),
ac: "access".to_string(),
creation: Datetime::MAX_UTC,
expiration: Some(Datetime::MAX_UTC),
revocation: Some(Datetime::MAX_UTC),
subject: Subject::User("user".to_string()),
grant: Grant::Jwt(GrantJwt {
jti: Uuid::default(),
token: Some("token".to_string()),
}),
}, 95)]
#[case::analyzer(AnalyzerDefinition {
name: "analyzer".into(),
function: Some("function".into()),
tokenizers: Some(vec![Tokenizer::Camel]),
filters: Some(vec![Filter::Ascii]),
comment: Some("comment".to_string()),
}, 37)]
#[case::api(ApiDefinition {
path: "/test".parse().unwrap(),
actions: vec![
ApiActionDefinition {
methods: vec![ApiMethod::Get],
action: Expr::Literal(Literal::String(Strand::new_static("action"))),
config: ApiConfigDefinition::default(),
},
],
fallback: None,
config: ApiConfigDefinition {
middleware: vec![
MiddlewareDefinition {
name: "middleware".into(),
args: vec![],
},
],
permissions: Permission::Full,
},
comment: None,
auth_limit: AuthLimit::default(),
}, 48)]
#[case::bucket(BucketDefinition {
id: Some(BucketId(123)),
readonly: false,
name: "bucket".into(),
backend: Some("backend".into()),
comment: Some("comment".to_string()),
permissions: Permission::Full,
}, 32)]
#[case::config(ConfigDefinition::GraphQL(GraphQLConfig {
tables: GraphQLTablesConfig::default(),
functions: GraphQLFunctionsConfig::default(),
depth_limit: None,
complexity_limit: None,
introspection: GraphQLIntrospectionConfig::default(),
}), 11)]
#[case::event(EventDefinition {
name: "test".into(),
target_table: TableName::from("test"),
when: Expr::Literal(Literal::String(Strand::new_static("when"))),
then: vec![Expr::Literal(Literal::String(Strand::new_static("then")))],
comment: Some("comment".to_string()),
auth_limit: AuthLimit::default(),
kind: EventKind::Async {
retry: 1,
max_depth: 5,
},
}, 43)]
#[case::field(FieldDefinition {
name: Idiom::from_str("field[0]").unwrap(),
table: TableName::from("what"),
field_kind: None,
readonly: false,
flexible: false,
value: None,
assert: None,
computed: None,
default: DefineDefault::None,
select_permission: Permission::Full,
create_permission: Permission::Full,
update_permission: Permission::Full,
comment: Some("comment".to_string()),
reference: None,
auth_limit: AuthLimit::default(),
computed_deps: None,
graphql_alias: None,
graphql_deprecated: None,
}, 46)]
#[case::function(FunctionDefinition {
name: "function".into(),
args: vec![],
block: Block(vec![
Expr::Literal(Literal::String(Strand::new_static("expr"))),
]),
comment: Some("comment".to_string()),
permissions: Permission::Full,
returns: Some(Kind::Any),
auth_limit: AuthLimit::default(),
graphql_alias: None,
graphql_deprecated: None,
}, 42)]
#[case::index(IndexDefinition {
index_id: IndexId(123),
name: "test".into(),
table_name: TableName::from("what"),
cols: vec![Idiom::from_str("field[0]").unwrap()],
index: Index::Idx,
comment: Some("comment".to_string()),
prepare_remove: false,
}, 34)]
#[case::model(MlModelDefinition {
name: "model".into(),
hash: "hash".into(),
version: "1.0.0".into(),
comment: Some("comment".to_string()),
permissions: Permission::Full,
}, 29)]
#[case::param(ParamDefinition {
name: "param".into(),
value: Value::Bool(true),
comment: Some("comment".to_string()),
permissions: Permission::Full,
}, 21)]
#[case::sequence(SequenceDefinition {
name: "sequence".into(),
batch: 123,
start: 123,
timeout: Some(Duration::from_secs(123)),
}, 15)]
#[case::version(MajorVersion::from(1), 2)]
#[case::user(UserDefinition {
name: "tobie".into(),
hash: "hash".into(),
code: "code".to_string(),
roles: vec!["role".to_string()],
token_duration: Some(Duration::from_secs(123)),
session_duration: Some(Duration::from_secs(123)),
comment: Some("comment".to_string()),
base: crate::catalog::schema::base::Base::Root,
}, 40)]
fn test_serialize_deserialize<T>(#[case] original: T, #[case] expected_encoded_size: usize)
where
T: KVValue<KeyContext = ()> + std::fmt::Debug + PartialEq,
{
let encoded = original.kv_encode_value().unwrap();
assert_eq!(encoded.len(), expected_encoded_size);
let decoded = T::kv_decode_value(&encoded, ()).unwrap();
assert_eq!(decoded, original);
}