surrealdb-core 3.2.0

A scalable, distributed, collaborative, document-graph database, for the realtime web
Documentation
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};

/// This test is used to ensure that
#[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);
}