Simplify global namespace handling

next
Sayan Nandan 1 year ago
parent 5cafc61231
commit 0d076dd1b3
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -25,15 +25,16 @@
*/
use crate::engine::{
core::{model::delta::DataDeltaKind, GlobalNS},
core::model::delta::DataDeltaKind,
error::{DatabaseError, DatabaseResult},
fractal::GlobalInstanceLike,
idx::MTIndex,
ql::dml::del::DeleteStatement,
sync,
};
pub fn delete(gns: &GlobalNS, mut delete: DeleteStatement) -> DatabaseResult<()> {
gns.with_model(delete.entity(), |model| {
pub fn delete(global: &impl GlobalInstanceLike, mut delete: DeleteStatement) -> DatabaseResult<()> {
global.namespace().with_model(delete.entity(), |model| {
let g = sync::atm::cpin();
let schema_version = model.delta_state().schema_current_version();
let delta_state = model.delta_state();

@ -28,16 +28,16 @@ use crate::engine::{
core::{
index::{DcFieldIndex, PrimaryIndexKey, Row},
model::{delta::DataDeltaKind, Fields, Model},
GlobalNS,
},
error::{DatabaseError, DatabaseResult},
fractal::GlobalInstanceLike,
idx::{IndexBaseSpec, MTIndex, STIndex, STIndexSeq},
ql::dml::ins::{InsertData, InsertStatement},
sync::atm::cpin,
};
pub fn insert(gns: &GlobalNS, insert: InsertStatement) -> DatabaseResult<()> {
gns.with_model(insert.entity(), |mdl| {
pub fn insert(gns: &impl GlobalInstanceLike, insert: InsertStatement) -> DatabaseResult<()> {
gns.namespace().with_model(insert.entity(), |mdl| {
let irmwd = mdl.intent_write_new_data();
let (pk, data) = prepare_insert(mdl, irmwd.fields(), insert.data())?;
let g = cpin();

@ -25,23 +25,24 @@
*/
use crate::engine::{
core::{index::DcFieldIndex, GlobalNS},
core::index::DcFieldIndex,
data::cell::{Datacell, VirtualDatacell},
error::{DatabaseError, DatabaseResult},
fractal::GlobalInstanceLike,
idx::{STIndex, STIndexSeq},
ql::dml::sel::SelectStatement,
sync,
};
pub fn select_custom<F>(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
mut select: SelectStatement,
mut cellfn: F,
) -> DatabaseResult<()>
where
F: FnMut(&Datacell),
{
gns.with_model(select.entity(), |mdl| {
global.namespace().with_model(select.entity(), |mdl| {
let irm = mdl.intent_read_model();
let target_key = mdl.resolve_where(select.clauses_mut())?;
let pkdc = VirtualDatacell::new(target_key.clone());

@ -30,7 +30,7 @@ use std::cell::RefCell;
use {
crate::{
engine::{
core::{model::delta::DataDeltaKind, query_meta::AssignmentOperator, GlobalNS},
core::{model::delta::DataDeltaKind, query_meta::AssignmentOperator},
data::{
cell::Datacell,
lit::LitIR,
@ -38,6 +38,7 @@ use {
tag::{DataTag, TagClass},
},
error::{DatabaseError, DatabaseResult},
fractal::GlobalInstanceLike,
idx::STIndex,
ql::dml::upd::{AssignmentExpression, UpdateStatement},
sync,
@ -232,8 +233,8 @@ pub fn collect_trace_path() -> Vec<&'static str> {
ROUTE_TRACE.with(|v| v.borrow().iter().cloned().collect())
}
pub fn update(gns: &GlobalNS, mut update: UpdateStatement) -> DatabaseResult<()> {
gns.with_model(update.entity(), |mdl| {
pub fn update(global: &impl GlobalInstanceLike, mut update: UpdateStatement) -> DatabaseResult<()> {
global.namespace().with_model(update.entity(), |mdl| {
let mut ret = Ok(());
// prepare row fetch
let key = mdl.resolve_where(update.clauses_mut())?;

@ -28,12 +28,13 @@ use {
super::{Field, IWModel, Layer, Model},
crate::{
engine::{
core::{util::EntityLocator, GlobalNS},
core::util::EntityLocator,
data::{
tag::{DataTag, TagClass},
DictEntryGeneric,
},
error::{DatabaseError, DatabaseResult},
fractal::GlobalInstanceLike,
idx::{IndexST, IndexSTSeqCns, STIndex, STIndexSeq},
ql::{
ast::Entity,
@ -249,12 +250,12 @@ impl<'a> AlterPlan<'a> {
impl Model {
pub fn transactional_exec_alter<GI: gnstxn::GNSTransactionDriverLLInterface>(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS<GI>,
alter: AlterModel,
) -> DatabaseResult<()> {
let (space_name, model_name) = EntityLocator::parse_entity(alter.model)?;
gns.with_space(space_name, |space| {
global.namespace().with_space(space_name, |space| {
space.with_model(model_name, |model| {
// make intent
let iwm = model.intent_write_model();
@ -303,9 +304,10 @@ impl Model {
txn_driver.try_commit(txn)?;
}
removed.iter().for_each(|field_id| {
model
.delta_state()
.schema_append_unresolved_wl_field_rem(&mut guard, field_id.as_str());
model.delta_state().schema_append_unresolved_wl_field_rem(
&mut guard,
field_id.as_str(),
);
iwm.fields_mut().st_delete(field_id.as_str());
});
}
@ -328,9 +330,9 @@ impl Model {
})
})
}
pub fn exec_alter(gns: &GlobalNS, stmt: AlterModel) -> DatabaseResult<()> {
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, |driver| {
Self::transactional_exec_alter(gns, driver, stmt)
pub fn exec_alter(global: &impl GlobalInstanceLike, stmt: AlterModel) -> DatabaseResult<()> {
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(global.namespace(), |driver| {
Self::transactional_exec_alter(global, driver, stmt)
})
}
}

@ -40,6 +40,7 @@ use {
uuid::Uuid,
},
error::{DatabaseError, DatabaseResult},
fractal::GlobalInstanceLike,
idx::{IndexBaseSpec, IndexSTSeqCns, STIndex, STIndexSeq},
mem::VInline,
ql::ddl::{
@ -204,13 +205,13 @@ impl Model {
impl Model {
pub fn transactional_exec_create<GI: gnstxn::GNSTransactionDriverLLInterface>(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS<GI>,
stmt: CreateModel,
) -> DatabaseResult<()> {
let (space_name, model_name) = stmt.model_name.parse_entity()?;
let model = Self::process_create(stmt)?;
gns.with_space(space_name, |space| {
global.namespace().with_space(space_name, |space| {
let mut w_space = space.models().write();
if w_space.st_contains(model_name) {
return Err(DatabaseError::DdlModelAlreadyExists);
@ -234,20 +235,20 @@ impl Model {
}
#[cfg(test)]
pub fn nontransactional_exec_create(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
stmt: CreateModel,
) -> DatabaseResult<()> {
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, |driver| {
Self::transactional_exec_create(gns, driver, stmt)
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(global.namespace(), |driver| {
Self::transactional_exec_create(global, driver, stmt)
})
}
pub fn transactional_exec_drop<GI: gnstxn::GNSTransactionDriverLLInterface>(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS<GI>,
stmt: DropModel,
) -> DatabaseResult<()> {
let (space_name, model_name) = stmt.entity.parse_entity()?;
gns.with_space(space_name, |space| {
global.namespace().with_space(space_name, |space| {
let mut w_space = space.models().write();
let Some(model) = w_space.get(model_name) else {
return Err(DatabaseError::DdlModelNotFound);
@ -270,11 +271,11 @@ impl Model {
}
#[cfg(test)]
pub fn nontransactional_exec_drop(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
stmt: DropModel,
) -> DatabaseResult<()> {
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, |driver| {
Self::transactional_exec_drop(gns, driver, stmt)
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(global.namespace(), |driver| {
Self::transactional_exec_drop(global, driver, stmt)
})
}
}

@ -29,6 +29,7 @@ use {
core::{model::Model, RWLIdx},
data::{dict, uuid::Uuid, DictEntryGeneric, DictGeneric},
error::{DatabaseError, DatabaseResult},
fractal::GlobalInstanceLike,
idx::{IndexST, STIndex},
ql::ddl::{alt::AlterSpace, crt::CreateSpace, drop::DropSpace},
txn::gns as gnstxn,
@ -189,14 +190,14 @@ impl Space {
impl Space {
pub fn transactional_exec_create<TI: gnstxn::GNSTransactionDriverLLInterface>(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS<TI>,
space: CreateSpace,
) -> DatabaseResult<()> {
// process create
let ProcedureCreate { space_name, space } = Self::process_create(space)?;
// acquire access
let mut wl = gns.spaces().write();
let mut wl = global.namespace().spaces().write();
if wl.st_contains(&space_name) {
return Err(DatabaseError::DdlSpaceAlreadyExists);
}
@ -213,22 +214,23 @@ impl Space {
/// Execute a `create` stmt
#[cfg(test)]
pub fn nontransactional_exec_create(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
space: CreateSpace,
) -> DatabaseResult<()> {
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, move |driver| {
Self::transactional_exec_create(gns, driver, space)
})
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(
global.namespace(),
move |driver| Self::transactional_exec_create(global, driver, space),
)
}
pub fn transactional_exec_alter<TI: gnstxn::GNSTransactionDriverLLInterface>(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS<TI>,
AlterSpace {
space_name,
updated_props,
}: AlterSpace,
) -> DatabaseResult<()> {
gns.with_space(&space_name, |space| {
global.namespace().with_space(&space_name, |space| {
match updated_props.get(SpaceMeta::KEY_ENV) {
Some(DictEntryGeneric::Map(_)) if updated_props.len() == 1 => {}
Some(DictEntryGeneric::Data(l)) if updated_props.len() == 1 && l.is_null() => {}
@ -262,22 +264,23 @@ impl Space {
#[cfg(test)]
/// Execute a `alter` stmt
pub fn nontransactional_exec_alter(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
alter: AlterSpace,
) -> DatabaseResult<()> {
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, move |driver| {
Self::transactional_exec_alter(gns, driver, alter)
})
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(
global.namespace(),
move |driver| Self::transactional_exec_alter(global, driver, alter),
)
}
pub fn transactional_exec_drop<TI: gnstxn::GNSTransactionDriverLLInterface>(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
txn_driver: &mut gnstxn::GNSTransactionDriverAnyFS<TI>,
DropSpace { space, force: _ }: DropSpace,
) -> DatabaseResult<()> {
// TODO(@ohsayan): force remove option
// TODO(@ohsayan): should a drop space block the entire global table?
let space_name = space;
let mut wgns = gns.spaces().write();
let mut wgns = global.namespace().spaces().write();
let space = match wgns.get(space_name.as_str()) {
Some(space) => space,
None => return Err(DatabaseError::DdlSpaceNotFound),
@ -298,12 +301,13 @@ impl Space {
}
#[cfg(test)]
pub fn nontransactional_exec_drop(
gns: &super::GlobalNS,
global: &impl GlobalInstanceLike,
drop_space: DropSpace,
) -> DatabaseResult<()> {
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(gns, move |driver| {
Self::transactional_exec_drop(gns, driver, drop_space)
})
gnstxn::GNSTransactionDriverNullZero::nullzero_create_exec(
global.namespace(),
move |driver| Self::transactional_exec_drop(global, driver, drop_space),
)
}
}

@ -28,9 +28,9 @@ use crate::engine::{
core::{
model::{alt::AlterPlan, Model},
tests::ddl_model::{create, exec_create},
GlobalNS,
},
error::DatabaseResult,
fractal::GlobalInstanceLike,
idx::STIndex,
ql::{ast::parse_ast_node_full, ddl::alt::AlterModel, tests::lex_insecure},
};
@ -47,15 +47,15 @@ fn plan(model: &str, plan: &str, f: impl Fn(AlterPlan)) {
with_plan(model, plan, f).unwrap()
}
fn exec_plan(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
new_space: bool,
model: &str,
plan: &str,
f: impl Fn(&Model),
) -> DatabaseResult<()> {
let mdl_name = exec_create(gns, model, new_space)?;
let mdl_name = exec_create(global, model, new_space)?;
let prev_uuid = {
let gns = gns.spaces().read();
let gns = global.namespace().spaces().read();
let space = gns.get("myspace").unwrap();
let space_read = space.models().read();
space_read.get(mdl_name.as_str()).unwrap().get_uuid()
@ -63,8 +63,8 @@ fn exec_plan(
let tok = lex_insecure(plan.as_bytes()).unwrap();
let alter = parse_ast_node_full::<AlterModel>(&tok[2..]).unwrap();
let (_space, model_name) = alter.model.into_full().unwrap();
Model::exec_alter(gns, alter)?;
let gns_read = gns.spaces().read();
Model::exec_alter(global, alter)?;
let gns_read = global.namespace().spaces().read();
let space = gns_read.st_get("myspace").unwrap();
let model = space.models().read();
let model = model.st_get(model_name.as_str()).unwrap();
@ -352,18 +352,16 @@ mod plan {
mod exec {
use crate::engine::{
core::{
model::{DeltaVersion, Field, Layer},
GlobalNS,
},
core::model::{DeltaVersion, Field, Layer},
error::DatabaseError,
fractal::test_utils::TestGlobal,
idx::{STIndex, STIndexSeq},
};
#[test]
fn simple_add() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_plan(
&gns,
&global,
true,
"create model myspace.mymodel(username: string, col1: uint64)",
"alter model myspace.mymodel add (col2 { type: uint32, nullable: true }, col3 { type: uint16, nullable: true })",
@ -392,9 +390,9 @@ mod exec {
}
#[test]
fn simple_remove() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_plan(
&gns,
&global,
true,
"create model myspace.mymodel(username: string, col1: uint64, col2: uint32, col3: uint16, col4: uint8)",
"alter model myspace.mymodel remove (col1, col2, col3, col4)",
@ -418,9 +416,9 @@ mod exec {
}
#[test]
fn simple_update() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_plan(
&gns,
&global,
true,
"create model myspace.mymodel(username: string, password: binary)",
"alter model myspace.mymodel update password { nullable: true }",
@ -437,10 +435,10 @@ mod exec {
}
#[test]
fn failing_alter_nullable_switch_need_lock() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_plan(
&gns,
&global,
true,
"create model myspace.mymodel(username: string, null gh_handle: string)",
"alter model myspace.mymodel update gh_handle { nullable: false }",

@ -135,9 +135,9 @@ mod exec {
core::{
model::{DeltaVersion, Field, Layer},
tests::ddl_model::{exec_create_new_space, with_model},
GlobalNS,
},
data::tag::{DataTag, FullTag},
fractal::test_utils::TestGlobal,
idx::STIndexSeq,
};
@ -145,13 +145,13 @@ mod exec {
#[test]
fn simple() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
exec_create_new_space(
&gns,
&global,
"create model myspace.mymodel(username: string, password: binary)",
)
.unwrap();
with_model(&gns, SPACE, "mymodel", |model| {
with_model(&global, SPACE, "mymodel", |model| {
let models: Vec<(String, Field)> = model
.intent_read_model()
.fields()

@ -29,8 +29,9 @@ mod crt;
mod layer;
use crate::engine::{
core::{model::Model, space::Space, GlobalNS},
core::{model::Model, space::Space},
error::DatabaseResult,
fractal::GlobalInstanceLike,
idx::STIndex,
ql::{
ast::{parse_ast_node_full, Entity},
@ -46,7 +47,7 @@ fn create(s: &str) -> DatabaseResult<Model> {
}
pub fn exec_create(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
create_stmt: &str,
create_new_space: bool,
) -> DatabaseResult<String> {
@ -56,27 +57,40 @@ pub fn exec_create(
Entity::Single(tbl) | Entity::Full(_, tbl) => tbl.to_string(),
};
if create_new_space {
gns.test_new_empty_space(&create_model.model_name.into_full().unwrap().0);
global
.namespace()
.test_new_empty_space(&create_model.model_name.into_full().unwrap().0);
}
Model::nontransactional_exec_create(gns, create_model).map(|_| name)
Model::nontransactional_exec_create(global, create_model).map(|_| name)
}
pub fn exec_create_new_space(gns: &GlobalNS, create_stmt: &str) -> DatabaseResult<()> {
exec_create(gns, create_stmt, true).map(|_| ())
pub fn exec_create_new_space(
global: &impl GlobalInstanceLike,
create_stmt: &str,
) -> DatabaseResult<()> {
exec_create(global, create_stmt, true).map(|_| ())
}
pub fn exec_create_no_create(gns: &GlobalNS, create_stmt: &str) -> DatabaseResult<()> {
exec_create(gns, create_stmt, false).map(|_| ())
pub fn exec_create_no_create(
global: &impl GlobalInstanceLike,
create_stmt: &str,
) -> DatabaseResult<()> {
exec_create(global, create_stmt, false).map(|_| ())
}
fn with_space(gns: &GlobalNS, space_name: &str, f: impl Fn(&Space)) {
let rl = gns.spaces().read();
fn with_space(global: &impl GlobalInstanceLike, space_name: &str, f: impl Fn(&Space)) {
let rl = global.namespace().spaces().read();
let space = rl.st_get(space_name).unwrap();
f(space);
}
fn with_model(gns: &GlobalNS, space_id: &str, model_name: &str, f: impl Fn(&Model)) {
with_space(gns, space_id, |space| {
fn with_model(
global: &impl GlobalInstanceLike,
space_id: &str,
model_name: &str,
f: impl Fn(&Model),
) {
with_space(global, space_id, |space| {
let space_rl = space.models().read();
let model = space_rl.st_get(model_name).unwrap();
f(model)

@ -25,19 +25,17 @@
*/
use crate::engine::{
core::{
space::{Space, SpaceMeta},
GlobalNS,
},
core::space::{Space, SpaceMeta},
data::cell::Datacell,
error::DatabaseError,
fractal::test_utils::TestGlobal,
};
#[test]
fn alter_add_prop_env_var() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_create_alter(
&gns,
&global,
"create space myspace",
"alter space myspace with { env: { MY_NEW_PROP: 100 } }",
|space| {
@ -56,9 +54,9 @@ fn alter_add_prop_env_var() {
#[test]
fn alter_update_prop_env_var() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
let uuid = super::exec_create(
&gns,
&global,
"create space myspace with { env: { MY_NEW_PROP: 100 } }",
|space| {
let rl = space.meta.dict().read();
@ -70,7 +68,7 @@ fn alter_update_prop_env_var() {
)
.unwrap();
super::exec_alter(
&gns,
&global,
"alter space myspace with { env: { MY_NEW_PROP: 200 } }",
|space| {
assert_eq!(
@ -88,9 +86,9 @@ fn alter_update_prop_env_var() {
#[test]
fn alter_remove_prop_env_var() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
let uuid = super::exec_create(
&gns,
&global,
"create space myspace with { env: { MY_NEW_PROP: 100 } }",
|space| {
let rl = space.meta.dict().read();
@ -102,7 +100,7 @@ fn alter_remove_prop_env_var() {
)
.unwrap();
super::exec_alter(
&gns,
&global,
"alter space myspace with { env: { MY_NEW_PROP: null } }",
|space| {
assert_eq!(
@ -116,10 +114,10 @@ fn alter_remove_prop_env_var() {
#[test]
fn alter_nx() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_alter(
&gns,
&global,
"alter space myspace with { env: { MY_NEW_PROP: 100 } }",
|_| {},
)
@ -130,9 +128,9 @@ fn alter_nx() {
#[test]
fn alter_remove_all_env() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
let uuid = super::exec_create(
&gns,
&global,
"create space myspace with { env: { MY_NEW_PROP: 100 } }",
|space| {
let rl = space.meta.dict().read();
@ -143,7 +141,7 @@ fn alter_remove_all_env() {
},
)
.unwrap();
super::exec_alter(&gns, "alter space myspace with { env: null }", |space| {
super::exec_alter(&global, "alter space myspace with { env: null }", |space| {
assert_eq!(space, &Space::empty_with_uuid(uuid))
})
.unwrap();

@ -25,18 +25,16 @@
*/
use crate::engine::{
core::{
space::{Space, SpaceMeta},
GlobalNS,
},
core::space::{Space, SpaceMeta},
data::cell::Datacell,
error::DatabaseError,
fractal::test_utils::TestGlobal,
};
#[test]
fn exec_create_space_simple() {
let gns = GlobalNS::empty();
super::exec_create(&gns, "create space myspace", |spc| {
let global = TestGlobal::empty();
super::exec_create(&global, "create space myspace", |spc| {
assert!(spc.models().read().is_empty())
})
.unwrap();
@ -44,9 +42,9 @@ fn exec_create_space_simple() {
#[test]
fn exec_create_space_with_env() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_create(
&gns,
&global,
r#"
create space myspace with {
env: {
@ -72,19 +70,19 @@ fn exec_create_space_with_env() {
#[test]
fn exec_create_space_with_bad_env_type() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_create(&gns, "create space myspace with { env: 100 }", |_| {}).unwrap_err(),
super::exec_create(&global, "create space myspace with { env: 100 }", |_| {}).unwrap_err(),
DatabaseError::DdlSpaceBadProperty
);
}
#[test]
fn exec_create_space_with_random_property() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_create(
&gns,
&global,
"create space myspace with { i_am_blue_da_ba_dee: 100 }",
|_| {}
)

@ -28,41 +28,50 @@ mod alter;
mod create;
use crate::engine::{
core::{space::Space, GlobalNS},
core::space::Space,
data::uuid::Uuid,
error::DatabaseResult,
fractal::GlobalInstanceLike,
ql::{
ast::{self},
tests::lex_insecure as lex,
},
};
fn exec_create(gns: &GlobalNS, create: &str, verify: impl Fn(&Space)) -> DatabaseResult<Uuid> {
fn exec_create(
gns: &impl GlobalInstanceLike,
create: &str,
verify: impl Fn(&Space),
) -> DatabaseResult<Uuid> {
let tok = lex(create.as_bytes()).unwrap();
let ast_node =
ast::parse_ast_node_full::<crate::engine::ql::ddl::crt::CreateSpace>(&tok[2..]).unwrap();
let name = ast_node.space_name;
Space::nontransactional_exec_create(gns, ast_node)?;
gns.with_space(&name, |space| {
gns.namespace().with_space(&name, |space| {
verify(space);
Ok(space.get_uuid())
})
}
fn exec_alter(gns: &GlobalNS, alter: &str, verify: impl Fn(&Space)) -> DatabaseResult<Uuid> {
fn exec_alter(
gns: &impl GlobalInstanceLike,
alter: &str,
verify: impl Fn(&Space),
) -> DatabaseResult<Uuid> {
let tok = lex(alter.as_bytes()).unwrap();
let ast_node =
ast::parse_ast_node_full::<crate::engine::ql::ddl::alt::AlterSpace>(&tok[2..]).unwrap();
let name = ast_node.space_name;
Space::nontransactional_exec_alter(gns, ast_node)?;
gns.with_space(&name, |space| {
gns.namespace().with_space(&name, |space| {
verify(space);
Ok(space.get_uuid())
})
}
fn exec_create_alter(
gns: &GlobalNS,
gns: &impl GlobalInstanceLike,
crt: &str,
alt: &str,
verify_post_alt: impl Fn(&Space),

@ -24,13 +24,13 @@
*
*/
use crate::engine::{core::GlobalNS, error::DatabaseError};
use crate::engine::{error::DatabaseError, fractal::test_utils::TestGlobal};
#[test]
fn simple_delete() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_delete(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string)",
Some("insert into myspace.mymodel('sayan', 'pass123')"),
"delete from myspace.mymodel where username = 'sayan'",
@ -41,10 +41,10 @@ fn simple_delete() {
#[test]
fn delete_nonexisting() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_delete(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string)",
None,
"delete from myspace.mymodel where username = 'sayan'",

@ -24,16 +24,16 @@
*
*/
use crate::engine::{core::GlobalNS, data::cell::Datacell, error::DatabaseError};
use crate::engine::{data::cell::Datacell, error::DatabaseError, fractal::test_utils::TestGlobal};
#[derive(sky_macros::Wrapper, Debug)]
struct Tuple(Vec<(Box<str>, Datacell)>);
#[test]
fn insert_simple() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_insert(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string)",
"insert into myspace.mymodel('sayan', 'pass123')",
"sayan",
@ -46,9 +46,9 @@ fn insert_simple() {
#[test]
fn insert_with_null() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_insert(
&gns,
&global,
"create model myspace.mymodel(username: string, null useless_password: string, null useless_email: string, null useless_random_column: uint64)",
"insert into myspace.mymodel('sayan', null, null, null)",
"sayan",
@ -69,9 +69,9 @@ fn insert_with_null() {
#[test]
fn insert_duplicate() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
super::exec_insert(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string)",
"insert into myspace.mymodel('sayan', 'pass123')",
"sayan",
@ -81,7 +81,7 @@ fn insert_duplicate() {
)
.unwrap();
assert_eq!(
super::exec_insert_only(&gns, "insert into myspace.mymodel('sayan', 'pass123')")
super::exec_insert_only(&global, "insert into myspace.mymodel('sayan', 'pass123')")
.unwrap_err(),
DatabaseError::DmlConstraintViolationDuplicate
);

@ -30,9 +30,10 @@ mod select;
mod update;
use crate::engine::{
core::{dml, index::Row, model::Model, GlobalNS},
core::{dml, index::Row, model::Model},
data::{cell::Datacell, lit::LitIR},
error::DatabaseResult,
fractal::GlobalInstanceLike,
ql::{
ast::{parse_ast_node_full, Entity},
dml::{del::DeleteStatement, ins::InsertStatement},
@ -41,36 +42,39 @@ use crate::engine::{
sync,
};
fn _exec_only_create_space_model(gns: &GlobalNS, model: &str) -> DatabaseResult<()> {
if !gns.spaces().read().contains_key("myspace") {
gns.test_new_empty_space("myspace");
fn _exec_only_create_space_model(
global: &impl GlobalInstanceLike,
model: &str,
) -> DatabaseResult<()> {
if !global.namespace().spaces().read().contains_key("myspace") {
global.namespace().test_new_empty_space("myspace");
}
let lex_create_model = lex_insecure(model.as_bytes()).unwrap();
let stmt_create_model = parse_ast_node_full(&lex_create_model[2..]).unwrap();
Model::nontransactional_exec_create(gns, stmt_create_model)
Model::nontransactional_exec_create(global, stmt_create_model)
}
fn _exec_only_insert<T>(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
insert: &str,
and_then: impl Fn(Entity) -> T,
) -> DatabaseResult<T> {
let lex_insert = lex_insecure(insert.as_bytes()).unwrap();
let stmt_insert = parse_ast_node_full::<InsertStatement>(&lex_insert[1..]).unwrap();
let entity = stmt_insert.entity();
dml::insert(gns, stmt_insert)?;
dml::insert(global, stmt_insert)?;
let r = and_then(entity);
Ok(r)
}
fn _exec_only_read_key_and_then<T>(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
entity: Entity,
key_name: &str,
and_then: impl Fn(Row) -> T,
) -> DatabaseResult<T> {
let guard = sync::atm::cpin();
gns.with_model(entity, |mdl| {
global.namespace().with_model(entity, |mdl| {
let _irm = mdl.intent_read_model();
let row = mdl
.primary_index()
@ -82,13 +86,17 @@ fn _exec_only_read_key_and_then<T>(
})
}
fn _exec_delete_only(gns: &GlobalNS, delete: &str, key: &str) -> DatabaseResult<()> {
fn _exec_delete_only(
global: &impl GlobalInstanceLike,
delete: &str,
key: &str,
) -> DatabaseResult<()> {
let lex_del = lex_insecure(delete.as_bytes()).unwrap();
let delete = parse_ast_node_full::<DeleteStatement>(&lex_del[1..]).unwrap();
let entity = delete.entity();
dml::delete(gns, delete)?;
dml::delete(global, delete)?;
assert_eq!(
gns.with_model(entity, |model| {
global.namespace().with_model(entity, |model| {
let _ = model.intent_read_model();
let g = sync::atm::cpin();
Ok(model.primary_index().select(key.into(), &g).is_none())
@ -98,75 +106,84 @@ fn _exec_delete_only(gns: &GlobalNS, delete: &str, key: &str) -> DatabaseResult<
Ok(())
}
fn _exec_only_select(gns: &GlobalNS, select: &str) -> DatabaseResult<Vec<Datacell>> {
fn _exec_only_select(
global: &impl GlobalInstanceLike,
select: &str,
) -> DatabaseResult<Vec<Datacell>> {
let lex_sel = lex_insecure(select.as_bytes()).unwrap();
let select = parse_ast_node_full(&lex_sel[1..]).unwrap();
let mut r = Vec::new();
dml::select_custom(gns, select, |cell| r.push(cell.clone()))?;
dml::select_custom(global, select, |cell| r.push(cell.clone()))?;
Ok(r)
}
fn _exec_only_update(gns: &GlobalNS, update: &str) -> DatabaseResult<()> {
fn _exec_only_update(global: &impl GlobalInstanceLike, update: &str) -> DatabaseResult<()> {
let lex_upd = lex_insecure(update.as_bytes()).unwrap();
let update = parse_ast_node_full(&lex_upd[1..]).unwrap();
dml::update(gns, update)
dml::update(global, update)
}
pub(self) fn exec_insert<T: Default>(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
model: &str,
insert: &str,
key_name: &str,
f: impl Fn(Row) -> T,
) -> DatabaseResult<T> {
_exec_only_create_space_model(gns, model)?;
_exec_only_insert(gns, insert, |entity| {
_exec_only_read_key_and_then(gns, entity, key_name, |row| f(row))
_exec_only_create_space_model(global, model)?;
_exec_only_insert(global, insert, |entity| {
_exec_only_read_key_and_then(global, entity, key_name, |row| f(row))
})?
}
pub(self) fn exec_insert_only(gns: &GlobalNS, insert: &str) -> DatabaseResult<()> {
_exec_only_insert(gns, insert, |_| {})
pub(self) fn exec_insert_only(
global: &impl GlobalInstanceLike,
insert: &str,
) -> DatabaseResult<()> {
_exec_only_insert(global, insert, |_| {})
}
pub(self) fn exec_delete(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
model: &str,
insert: Option<&str>,
delete: &str,
key: &str,
) -> DatabaseResult<()> {
_exec_only_create_space_model(gns, model)?;
_exec_only_create_space_model(global, model)?;
if let Some(insert) = insert {
_exec_only_insert(gns, insert, |_| {})?;
_exec_only_insert(global, insert, |_| {})?;
}
_exec_delete_only(gns, delete, key)
_exec_delete_only(global, delete, key)
}
pub(self) fn exec_select(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
model: &str,
insert: &str,
select: &str,
) -> DatabaseResult<Vec<Datacell>> {
_exec_only_create_space_model(gns, model)?;
_exec_only_insert(gns, insert, |_| {})?;
_exec_only_select(gns, select)
_exec_only_create_space_model(global, model)?;
_exec_only_insert(global, insert, |_| {})?;
_exec_only_select(global, select)
}
pub(self) fn exec_select_only(gns: &GlobalNS, select: &str) -> DatabaseResult<Vec<Datacell>> {
_exec_only_select(gns, select)
pub(self) fn exec_select_only(
global: &impl GlobalInstanceLike,
select: &str,
) -> DatabaseResult<Vec<Datacell>> {
_exec_only_select(global, select)
}
pub(self) fn exec_update(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
model: &str,
insert: &str,
update: &str,
select: &str,
) -> DatabaseResult<Vec<Datacell>> {
_exec_only_create_space_model(gns, model)?;
_exec_only_insert(gns, insert, |_| {})?;
_exec_only_update(gns, update)?;
_exec_only_select(gns, select)
_exec_only_create_space_model(global, model)?;
_exec_only_insert(global, insert, |_| {})?;
_exec_only_update(global, update)?;
_exec_only_select(global, select)
}

@ -24,14 +24,14 @@
*
*/
use crate::engine::{core::GlobalNS, data::cell::Datacell, error::DatabaseError};
use crate::engine::{data::cell::Datacell, error::DatabaseError, fractal::test_utils::TestGlobal};
#[test]
fn simple_select_wildcard() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_select(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string)",
"insert into myspace.mymodel('sayan', 'pass123')",
"select * from myspace.mymodel where username = 'sayan'",
@ -43,10 +43,10 @@ fn simple_select_wildcard() {
#[test]
fn simple_select_specified_same_order() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_select(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string)",
"insert into myspace.mymodel('sayan', 'pass123')",
"select username, password from myspace.mymodel where username = 'sayan'",
@ -58,10 +58,10 @@ fn simple_select_specified_same_order() {
#[test]
fn simple_select_specified_reversed_order() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_select(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string)",
"insert into myspace.mymodel('sayan', 'pass123')",
"select password, username from myspace.mymodel where username = 'sayan'",
@ -73,10 +73,10 @@ fn simple_select_specified_reversed_order() {
#[test]
fn select_null() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_select(
&gns,
&global,
"create model myspace.mymodel(username: string, null password: string)",
"insert into myspace.mymodel('sayan', null)",
"select username, password from myspace.mymodel where username = 'sayan'",
@ -88,10 +88,10 @@ fn select_null() {
#[test]
fn select_nonexisting() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_select(
&gns,
&global,
"create model myspace.mymodel(username: string, null password: string)",
"insert into myspace.mymodel('sayan', null)",
"select username, password from myspace.mymodel where username = 'notsayan'",

@ -25,17 +25,15 @@
*/
use crate::engine::{
core::{dml, GlobalNS},
data::cell::Datacell,
error::DatabaseError,
core::dml, data::cell::Datacell, error::DatabaseError, fractal::test_utils::TestGlobal,
};
#[test]
fn simple() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_update(
&gns,
&global,
"create model myspace.mymodel(username: string, email: string, followers: uint64, following: uint64)",
"insert into myspace.mymodel('sayan', 'sayan@example.com', 0, 100)",
"update myspace.mymodel set followers += 200000, following -= 15, email = 'sn@example.com' where username = 'sayan'",
@ -51,10 +49,10 @@ fn simple() {
#[test]
fn with_null() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_update(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string, null email: string)",
"insert into myspace.mymodel('sayan', 'pass123', null)",
"update myspace.mymodel set email = 'sayan@example.com' where username = 'sayan'",
@ -68,10 +66,10 @@ fn with_null() {
#[test]
fn with_list() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_update(
&gns,
&global,
"create model myspace.mymodel(link: string, click_ids: list { type: string })",
"insert into myspace.mymodel('example.com', [])",
"update myspace.mymodel set click_ids += 'ios_client_uuid' where link = 'example.com'",
@ -88,10 +86,10 @@ fn with_list() {
#[test]
fn fail_operation_on_null() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_update(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string, null email: string)",
"insert into myspace.mymodel('sayan', 'pass123', null)",
"update myspace.mymodel set email += '.com' where username = 'sayan'",
@ -108,10 +106,10 @@ fn fail_operation_on_null() {
#[test]
fn fail_unknown_fields() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_update(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string, null email: string)",
"insert into myspace.mymodel('sayan', 'pass123', null)",
"update myspace.mymodel set email2 = 'sayan@example.com', password += '4' where username = 'sayan'",
@ -123,18 +121,21 @@ fn fail_unknown_fields() {
assert_eq!(dml::update_flow_trace(), ["fieldnotfound", "rollback"]);
// verify integrity
assert_eq!(
super::exec_select_only(&gns, "select * from myspace.mymodel where username='sayan'")
.unwrap(),
super::exec_select_only(
&global,
"select * from myspace.mymodel where username='sayan'"
)
.unwrap(),
intovec!["sayan", "pass123", Datacell::null()]
);
}
#[test]
fn fail_typedef_violation() {
let gns = GlobalNS::empty();
let global = TestGlobal::empty();
assert_eq!(
super::exec_update(
&gns,
&global,
"create model myspace.mymodel(username: string, password: string, rank: uint8)",
"insert into myspace.mymodel('sayan', 'pass123', 1)",
"update myspace.mymodel set password = 'pass1234', rank = 'one' where username = 'sayan'",
@ -150,7 +151,7 @@ fn fail_typedef_violation() {
// verify integrity
assert_eq!(
super::exec_select_only(
&gns,
&global,
"select * from myspace.mymodel where username = 'sayan'"
)
.unwrap(),

@ -184,7 +184,7 @@ impl FractalMgr {
// was way behind in the queue
continue;
};
let res = global.namespace().with_model(
let res = global._namespace().with_model(
(model_id.space(), model_id.model()),
|model| {
if model.get_uuid() != model_id.uuid() {
@ -235,7 +235,7 @@ impl FractalMgr {
let mdl_drivers = global.get_state().get_mdl_drivers().read();
for (model_id, driver) in mdl_drivers.iter() {
let mut observed_len = 0;
let res = global.namespace().with_model((model_id.space(), model_id.model()), |model| {
let res = global._namespace().with_model((model_id.space(), model_id.model()), |model| {
if model.get_uuid() != model_id.uuid() {
// once again, throughput maximization will lead to, in extremely rare cases, this
// branch returning. but it is okay

@ -36,6 +36,8 @@ use {
mod config;
mod drivers;
mod mgr;
#[cfg(test)]
pub mod test_utils;
mod util;
pub use {
config::ServerConfig,
@ -94,35 +96,58 @@ pub unsafe fn enable_and_start_all(
global access
*/
/// Something that represents the global state
pub trait GlobalInstanceLike {
fn namespace(&self) -> &GlobalNS;
fn post_high_priority_task(&self, task: Task<CriticalTask>);
fn post_standard_priority_task(&self, task: Task<GenericTask>);
fn get_max_delta_size(&self) -> usize;
}
impl GlobalInstanceLike for Global {
fn namespace(&self) -> &GlobalNS {
self._namespace()
}
fn post_high_priority_task(&self, task: Task<CriticalTask>) {
self._post_high_priority_task(task)
}
fn post_standard_priority_task(&self, task: Task<GenericTask>) {
self._post_standard_priority_task(task)
}
fn get_max_delta_size(&self) -> usize {
self._get_max_delta_size()
}
}
#[derive(Debug, Clone, Copy)]
/// A handle to the global state
pub struct Global(());
impl Global {
fn new() -> Self {
unsafe fn new() -> Self {
Self(())
}
pub(self) fn get_state(&self) -> &'static GlobalState {
fn get_state(&self) -> &'static GlobalState {
unsafe { GLOBAL.assume_init_ref() }
}
/// Returns a handle to the [`GlobalNS`]
pub fn namespace(&self) -> &'static GlobalNS {
fn _namespace(&self) -> &'static GlobalNS {
&unsafe { GLOBAL.assume_init_ref() }.gns
}
/// Post an urgent task
pub fn post_high_priority_task(&self, task: Task<CriticalTask>) {
fn _post_high_priority_task(&self, task: Task<CriticalTask>) {
self.get_state().fractal_mgr().post_high_priority(task)
}
/// Post a task with normal priority
///
/// NB: It is not guaranteed that the task will remain as a low priority task because the scheduler can choose
/// to promote the task to a high priority task, if it deems necessary.
pub fn post_standard_priority_task(&self, task: Task<GenericTask>) {
fn _post_standard_priority_task(&self, task: Task<GenericTask>) {
self.get_state().fractal_mgr().post_low_priority(task)
}
/// Returns the maximum size a model's delta size can hit before it should immediately issue a batch write request
/// to avoid memory pressure
pub fn get_max_delta_size(&self) -> usize {
fn _get_max_delta_size(&self) -> usize {
self.get_state()
.fractal_mgr()
.get_rt_stat()

@ -0,0 +1,68 @@
/*
* Created on Wed Sep 13 2023
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2023, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use {
super::{CriticalTask, GenericTask, GlobalInstanceLike, Task},
crate::engine::core::GlobalNS,
parking_lot::RwLock,
};
/// A `test` mode global implementation
pub struct TestGlobal {
gns: GlobalNS,
hp_queue: RwLock<Vec<Task<CriticalTask>>>,
lp_queue: RwLock<Vec<Task<GenericTask>>>,
max_delta_size: usize,
}
impl TestGlobal {
pub fn empty() -> Self {
Self::with_max_delta_size(0)
}
pub fn with_max_delta_size(max_delta_size: usize) -> Self {
Self {
gns: GlobalNS::empty(),
hp_queue: RwLock::default(),
lp_queue: RwLock::default(),
max_delta_size,
}
}
}
impl GlobalInstanceLike for TestGlobal {
fn namespace(&self) -> &GlobalNS {
&self.gns
}
fn post_high_priority_task(&self, task: Task<CriticalTask>) {
self.hp_queue.write().push(task)
}
fn post_standard_priority_task(&self, task: Task<GenericTask>) {
self.lp_queue.write().push(task)
}
fn get_max_delta_size(&self) -> usize {
100
}
}

@ -28,10 +28,10 @@ use crate::engine::{
core::{
model::{Field, Layer, Model},
space::{Space, SpaceMeta},
GlobalNS,
},
data::{cell::Datacell, tag::TagSelector, uuid::Uuid, DictEntryGeneric},
error::DatabaseError,
fractal::{test_utils::TestGlobal, GlobalInstanceLike},
idx::STIndex,
ql::{
ast::parse_ast_node_full,
@ -52,13 +52,19 @@ fn with_variable<T>(var: T, f: impl FnOnce(T)) {
f(var);
}
fn init_txn_driver(gns: &GlobalNS, log_name: &str) -> GNSTransactionDriverVFS {
GNSTransactionDriverVFS::open_or_reinit_with_name(&gns, log_name, 0, HostRunMode::Prod, 0)
.unwrap()
fn init_txn_driver(global: &impl GlobalInstanceLike, log_name: &str) -> GNSTransactionDriverVFS {
GNSTransactionDriverVFS::open_or_reinit_with_name(
global.namespace(),
log_name,
0,
HostRunMode::Prod,
0,
)
.unwrap()
}
fn init_space(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
driver: &mut GNSTransactionDriverVFS,
space_name: &str,
env: &str,
@ -67,26 +73,32 @@ fn init_space(
let stmt = lex_insecure(query.as_bytes()).unwrap();
let stmt = parse_ast_node_full::<CreateSpace>(&stmt[2..]).unwrap();
let name = stmt.space_name;
Space::transactional_exec_create(&gns, driver, stmt).unwrap();
gns.spaces().read().get(name.as_str()).unwrap().get_uuid()
Space::transactional_exec_create(global, driver, stmt).unwrap();
global
.namespace()
.spaces()
.read()
.get(name.as_str())
.unwrap()
.get_uuid()
}
#[test]
fn create_space() {
with_variable("create_space_test.gns.db-tlog", |log_name| {
with_variable("create_space_test.global.db-tlog", |log_name| {
let uuid;
// start 1
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
uuid = init_space(&gns, &mut driver, "myspace", "{ SAYAN_MAX: 65536 }"); // good lord that doesn't sound like a good variable
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
uuid = init_space(&global, &mut driver, "myspace", "{ SAYAN_MAX: 65536 }"); // good lord that doesn't sound like a good variable
driver.close().unwrap();
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
assert_eq!(
gns.spaces().read().get("myspace").unwrap(),
global.namespace().spaces().read().get("myspace").unwrap(),
&Space::new_restore_empty(
SpaceMeta::with_env(
into_dict!("SAYAN_MAX" => DictEntryGeneric::Data(Datacell::new_uint(65536)))
@ -101,24 +113,24 @@ fn create_space() {
#[test]
fn alter_space() {
with_variable("alter_space_test.gns.db-tlog", |log_name| {
with_variable("alter_space_test.global.db-tlog", |log_name| {
let uuid;
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
uuid = init_space(&gns, &mut driver, "myspace", "{}");
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
uuid = init_space(&global, &mut driver, "myspace", "{}");
let stmt =
lex_insecure("alter space myspace with { env: { SAYAN_MAX: 65536 } }".as_bytes())
.unwrap();
let stmt = parse_ast_node_full(&stmt[2..]).unwrap();
Space::transactional_exec_alter(&gns, &mut driver, stmt).unwrap();
Space::transactional_exec_alter(&global, &mut driver, stmt).unwrap();
driver.close().unwrap();
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
assert_eq!(
gns.spaces().read().get("myspace").unwrap(),
global.namespace().spaces().read().get("myspace").unwrap(),
&Space::new_restore_empty(
SpaceMeta::with_env(
into_dict!("SAYAN_MAX" => DictEntryGeneric::Data(Datacell::new_uint(65536)))
@ -133,27 +145,27 @@ fn alter_space() {
#[test]
fn drop_space() {
with_variable("drop_space_test.gns.db-tlog", |log_name| {
with_variable("drop_space_test.global.db-tlog", |log_name| {
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
let _ = init_space(&gns, &mut driver, "myspace", "{}");
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
let _ = init_space(&global, &mut driver, "myspace", "{}");
let stmt = lex_insecure("drop space myspace".as_bytes()).unwrap();
let stmt = parse_ast_node_full(&stmt[2..]).unwrap();
Space::transactional_exec_drop(&gns, &mut driver, stmt).unwrap();
Space::transactional_exec_drop(&global, &mut driver, stmt).unwrap();
driver.close().unwrap();
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
assert_eq!(gns.spaces().read().get("myspace"), None);
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
assert_eq!(global.namespace().spaces().read().get("myspace"), None);
driver.close().unwrap();
})
})
}
fn init_model(
gns: &GlobalNS,
global: &impl GlobalInstanceLike,
txn_driver: &mut GNSTransactionDriverVFS,
space_name: &str,
model_name: &str,
@ -163,14 +175,19 @@ fn init_model(
let stmt = lex_insecure(query.as_bytes()).unwrap();
let stmt = parse_ast_node_full::<CreateModel>(&stmt[2..]).unwrap();
let model_name = stmt.model_name;
Model::transactional_exec_create(&gns, txn_driver, stmt).unwrap();
gns.with_model(model_name, |model| Ok(model.get_uuid()))
Model::transactional_exec_create(global, txn_driver, stmt).unwrap();
global
.namespace()
.with_model(model_name, |model| Ok(model.get_uuid()))
.unwrap()
}
fn init_default_model(gns: &GlobalNS, driver: &mut GNSTransactionDriverVFS) -> Uuid {
fn init_default_model(
global: &impl GlobalInstanceLike,
driver: &mut GNSTransactionDriverVFS,
) -> Uuid {
init_model(
gns,
global,
driver,
"myspace",
"mymodel",
@ -180,35 +197,37 @@ fn init_default_model(gns: &GlobalNS, driver: &mut GNSTransactionDriverVFS) -> U
#[test]
fn create_model() {
with_variable("create_model_test.gns.db-tlog", |log_name| {
with_variable("create_model_test.global.db-tlog", |log_name| {
let _uuid_space;
let uuid_model;
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
_uuid_space = init_space(&gns, &mut driver, "myspace", "{}");
uuid_model = init_default_model(&gns, &mut driver);
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
_uuid_space = init_space(&global, &mut driver, "myspace", "{}");
uuid_model = init_default_model(&global, &mut driver);
driver.close().unwrap();
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
gns.with_model(("myspace", "mymodel"), |model| {
assert_eq!(
model,
&Model::new_restore(
uuid_model,
"username".into(),
TagSelector::Str.into_full(),
into_dict! {
"username" => Field::new([Layer::str()].into(), false),
"password" => Field::new([Layer::bin()].into(), false),
}
)
);
Ok(())
})
.unwrap();
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
global
.namespace()
.with_model(("myspace", "mymodel"), |model| {
assert_eq!(
model,
&Model::new_restore(
uuid_model,
"username".into(),
TagSelector::Str.into_full(),
into_dict! {
"username" => Field::new([Layer::str()].into(), false),
"password" => Field::new([Layer::bin()].into(), false),
}
)
);
Ok(())
})
.unwrap();
driver.close().unwrap();
})
})
@ -216,35 +235,37 @@ fn create_model() {
#[test]
fn alter_model_add() {
with_variable("alter_model_add_test.gns.db-tlog", |log_name| {
with_variable("alter_model_add_test.global.db-tlog", |log_name| {
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
init_space(&gns, &mut driver, "myspace", "{}");
init_default_model(&gns, &mut driver);
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
init_space(&global, &mut driver, "myspace", "{}");
init_default_model(&global, &mut driver);
let stmt = lex_insecure(
b"alter model myspace.mymodel add profile_pic { type: binary, nullable: true }",
)
.unwrap();
let stmt = parse_ast_node_full(&stmt[2..]).unwrap();
Model::transactional_exec_alter(&gns, &mut driver, stmt).unwrap();
Model::transactional_exec_alter(&global, &mut driver, stmt).unwrap();
driver.close().unwrap();
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
gns.with_model(("myspace", "mymodel"), |model| {
assert_eq!(
model
.intent_read_model()
.fields()
.st_get("profile_pic")
.unwrap(),
&Field::new([Layer::bin()].into(), true)
);
Ok(())
})
.unwrap();
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
global
.namespace()
.with_model(("myspace", "mymodel"), |model| {
assert_eq!(
model
.intent_read_model()
.fields()
.st_get("profile_pic")
.unwrap(),
&Field::new([Layer::bin()].into(), true)
);
Ok(())
})
.unwrap();
driver.close().unwrap();
})
})
@ -252,13 +273,13 @@ fn alter_model_add() {
#[test]
fn alter_model_remove() {
with_variable("alter_model_remove_test.gns.db-tlog", |log_name| {
with_variable("alter_model_remove_test.global.db-tlog", |log_name| {
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
init_space(&gns, &mut driver, "myspace", "{}");
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
init_space(&global, &mut driver, "myspace", "{}");
init_model(
&gns,
&global,
&mut driver,
"myspace",
"mymodel",
@ -269,19 +290,21 @@ fn alter_model_remove() {
)
.unwrap();
let stmt = parse_ast_node_full(&stmt[2..]).unwrap();
Model::transactional_exec_alter(&gns, &mut driver, stmt).unwrap();
Model::transactional_exec_alter(&global, &mut driver, stmt).unwrap();
driver.close().unwrap()
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
gns.with_model(("myspace", "mymodel"), |model| {
let irm = model.intent_read_model();
assert!(irm.fields().st_get("has_secure_key").is_none());
assert!(irm.fields().st_get("is_dumb").is_none());
Ok(())
})
.unwrap();
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
global
.namespace()
.with_model(("myspace", "mymodel"), |model| {
let irm = model.intent_read_model();
assert!(irm.fields().st_get("has_secure_key").is_none());
assert!(irm.fields().st_get("is_dumb").is_none());
Ok(())
})
.unwrap();
driver.close().unwrap()
})
})
@ -289,13 +312,13 @@ fn alter_model_remove() {
#[test]
fn alter_model_update() {
with_variable("alter_model_update_test.gns.db-tlog", |log_name| {
with_variable("alter_model_update_test.global.db-tlog", |log_name| {
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
init_space(&gns, &mut driver, "myspace", "{}");
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
init_space(&global, &mut driver, "myspace", "{}");
init_model(
&gns,
&global,
&mut driver,
"myspace",
"mymodel",
@ -305,24 +328,26 @@ fn alter_model_update() {
lex_insecure(b"alter model myspace.mymodel update profile_pic { nullable: true }")
.unwrap();
let stmt = parse_ast_node_full(&stmt[2..]).unwrap();
Model::transactional_exec_alter(&gns, &mut driver, stmt).unwrap();
Model::transactional_exec_alter(&global, &mut driver, stmt).unwrap();
driver.close().unwrap();
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
gns.with_model(("myspace", "mymodel"), |model| {
assert_eq!(
model
.intent_read_model()
.fields()
.st_get("profile_pic")
.unwrap(),
&Field::new([Layer::bin()].into(), true)
);
Ok(())
})
.unwrap();
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
global
.namespace()
.with_model(("myspace", "mymodel"), |model| {
assert_eq!(
model
.intent_read_model()
.fields()
.st_get("profile_pic")
.unwrap(),
&Field::new([Layer::bin()].into(), true)
);
Ok(())
})
.unwrap();
driver.close().unwrap();
})
})
@ -330,22 +355,24 @@ fn alter_model_update() {
#[test]
fn drop_model() {
with_variable("drop_model_test.gns.db-tlog", |log_name| {
with_variable("drop_model_test.global.db-tlog", |log_name| {
{
let gns = GlobalNS::empty();
let mut driver = init_txn_driver(&gns, log_name);
init_space(&gns, &mut driver, "myspace", "{}");
init_default_model(&gns, &mut driver);
let global = TestGlobal::empty();
let mut driver = init_txn_driver(&global, log_name);
init_space(&global, &mut driver, "myspace", "{}");
init_default_model(&global, &mut driver);
let stmt = lex_insecure(b"drop model myspace.mymodel").unwrap();
let stmt = parse_ast_node_full(&stmt[2..]).unwrap();
Model::transactional_exec_drop(&gns, &mut driver, stmt).unwrap();
Model::transactional_exec_drop(&global, &mut driver, stmt).unwrap();
driver.close().unwrap();
}
multirun(|| {
let gns = GlobalNS::empty();
let driver = init_txn_driver(&gns, log_name);
let global = TestGlobal::empty();
let driver = init_txn_driver(&global, log_name);
assert_eq!(
gns.with_model(("myspace", "mymodel"), |_| { Ok(()) })
global
.namespace()
.with_model(("myspace", "mymodel"), |_| { Ok(()) })
.unwrap_err(),
DatabaseError::DdlModelNotFound
);

Loading…
Cancel
Save