Implement exec for create model

next
Sayan Nandan 2 years ago
parent a88319b8b9
commit feac086edc
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -30,21 +30,61 @@ use crate::engine::{
core::model::cell::Datacell,
data::tag::{DataTag, FullTag, TagClass, TagSelector},
error::{DatabaseError, DatabaseResult},
idx::{IndexSTSeqCns, STIndex, STIndexSeq},
mem::VInline,
ql::ddl::syn::LayerSpec,
ql::ddl::{
crt::CreateModel,
syn::{FieldSpec, LayerSpec},
},
};
#[cfg(test)]
use std::cell::RefCell;
// FIXME(@ohsayan): update this!
#[derive(Debug)]
pub struct ModelView {}
#[derive(Debug, PartialEq)]
pub struct ModelView {
pub(super) p_key: Box<str>,
pub(super) p_tag: FullTag,
pub(super) fields: IndexSTSeqCns<Box<str>, Field>,
}
#[cfg(test)]
impl PartialEq for ModelView {
fn eq(&self, _: &Self) -> bool {
true
impl ModelView {
pub fn create(CreateModel { fields, props, .. }: CreateModel) -> DatabaseResult<Self> {
let mut okay = props.is_empty() & !fields.is_empty();
// validate fields
let mut field_spec = fields.into_iter();
let mut fields = IndexSTSeqCns::with_capacity(field_spec.len());
let mut last_pk = None;
let mut pk_cnt = 0;
while (field_spec.len() != 0) & okay {
let FieldSpec {
field_name,
layers,
null,
primary,
} = field_spec.next().unwrap();
if primary {
pk_cnt += 1usize;
last_pk = Some(field_name.as_str());
okay &= !null;
}
let layer = Field::parse_layers(layers, null)?;
okay &= fields.st_insert(field_name.as_str().to_string().into_boxed_str(), layer);
}
okay &= pk_cnt <= 1;
if okay {
let last_pk = last_pk.unwrap_or(fields.stseq_ord_key().next().unwrap());
let tag = fields.st_get(last_pk).unwrap().layers()[0].tag;
if tag.tag_unique().is_unique() {
return Ok(Self {
p_key: last_pk.into(),
p_tag: tag,
fields,
});
}
}
Err(DatabaseError::DdlModelBadDefinition)
}
}
@ -74,12 +114,16 @@ static LUT: [(&str, FullTag); 14] = [
];
#[derive(Debug, PartialEq, Clone)]
pub struct LayerView {
pub struct Field {
layers: VInline<1, Layer>,
nullable: bool,
}
impl LayerView {
impl Field {
#[cfg(test)]
pub fn new_test(layers: VInline<1, Layer>, nullable: bool) -> Self {
Self { layers, nullable }
}
pub fn layers(&self) -> &[Layer] {
&self.layers
}
@ -203,6 +247,10 @@ impl Layer {
}
impl Layer {
#[cfg(test)]
pub fn new_test(tag: FullTag, config: [usize; 2]) -> Self {
Self::new(tag, config)
}
#[inline(always)]
fn compute_index(&self, dc: &Datacell) -> usize {
self.tag.tag_class().word() * (dc.is_null() as usize)

@ -0,0 +1,115 @@
/*
* Created on Sat Mar 04 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 crate::engine::{
core::model::{Field, Layer, ModelView},
data::tag::{DataTag, FullTag},
error::{DatabaseError, DatabaseResult},
idx::STIndexSeq,
ql::{ast::parse_ast_node_full, tests::lex_insecure},
};
fn create(s: &str) -> DatabaseResult<ModelView> {
let tok = lex_insecure(s.as_bytes()).unwrap();
let create_model = parse_ast_node_full(&tok[2..]).unwrap();
ModelView::create(create_model)
}
#[test]
fn simple() {
let ModelView {
p_key,
p_tag,
fields,
} = create("create model mymodel(username: string, password: binary)").unwrap();
assert_eq!(p_key.as_ref(), "username");
assert_eq!(p_tag, FullTag::STR);
assert_eq!(
fields.stseq_ord_value().cloned().collect::<Vec<Field>>(),
[
Field::new_test([Layer::new_test(FullTag::STR, [0; 2])].into(), false),
Field::new_test([Layer::new_test(FullTag::BIN, [0; 2])].into(), false)
]
);
}
#[test]
fn idiotic_order() {
let ModelView {
p_key,
p_tag,
fields,
} = create("create model mymodel(password: binary, primary username: string)").unwrap();
assert_eq!(p_key.as_ref(), "username");
assert_eq!(p_tag, FullTag::STR);
assert_eq!(
fields.stseq_ord_value().cloned().collect::<Vec<Field>>(),
[
Field::new_test([Layer::new_test(FullTag::BIN, [0; 2])].into(), false),
Field::new_test([Layer::new_test(FullTag::STR, [0; 2])].into(), false),
]
);
}
#[test]
fn duplicate_primary_key() {
assert_eq!(
create("create model mymodel(primary username: string, primary contract_location: binary)")
.unwrap_err(),
DatabaseError::DdlModelBadDefinition
);
}
#[test]
fn duplicate_fields() {
assert_eq!(
create("create model mymodel(primary username: string, username: binary)").unwrap_err(),
DatabaseError::DdlModelBadDefinition
);
}
#[test]
fn illegal_props() {
assert_eq!(
create("create model mymodel(primary username: string, password: binary) with { lol_prop: false }").unwrap_err(),
DatabaseError::DdlModelBadDefinition
);
}
#[test]
fn illegal_pk() {
assert_eq!(
create(
"create model mymodel(primary username_bytes: list { type: uint8 }, password: binary)"
)
.unwrap_err(),
DatabaseError::DdlModelBadDefinition
);
assert_eq!(
create("create model mymodel(primary username: float32, password: binary)").unwrap_err(),
DatabaseError::DdlModelBadDefinition
);
}

@ -25,17 +25,17 @@
*/
use crate::engine::{
core::model::LayerView,
core::model::Field,
error::DatabaseResult,
ql::{ast::parse_ast_node_multiple_full, tests::lex_insecure},
};
fn layerview_nullable(layer_def: &str, nullable: bool) -> DatabaseResult<LayerView> {
fn layerview_nullable(layer_def: &str, nullable: bool) -> DatabaseResult<Field> {
let tok = lex_insecure(layer_def.as_bytes()).unwrap();
let spec = parse_ast_node_multiple_full(&tok).unwrap();
LayerView::parse_layers(spec, nullable)
Field::parse_layers(spec, nullable)
}
fn layerview(layer_def: &str) -> DatabaseResult<LayerView> {
fn layerview(layer_def: &str) -> DatabaseResult<Field> {
layerview_nullable(layer_def, false)
}

@ -24,4 +24,5 @@
*
*/
mod crt;
mod layer;

@ -65,8 +65,14 @@ pub enum TagUnique {
Illegal = 0xFF,
}
impl TagUnique {
pub const fn is_unique(&self) -> bool {
self.d() != 0xFF
}
}
macro_rules! d {
($($ty:ty),*) => {$(impl $ty { pub fn d(&self) -> u8 {unsafe{::core::mem::transmute_copy(self)}} pub fn word(&self) -> usize {Self::d(self) as usize} } )*}
($($ty:ty),*) => {$(impl $ty { pub const fn d(&self) -> u8 {unsafe{::core::mem::transmute(*self)}} pub const fn word(&self) -> usize {Self::d(self) as usize} } )*}
}
d!(TagClass, TagSelector, TagUnique);

@ -90,4 +90,6 @@ pub enum DatabaseError {
DdlSpaceNotFound,
/// bad definition for some typedef in a model
DdlModelInvalidTypeDefinition,
/// bad model definition; most likely an illegal primary key
DdlModelBadDefinition,
}

@ -100,7 +100,7 @@ pub struct DummyMetrics;
/// The base spec for any index. Iterators have meaningless order, and that is intentional and oftentimes
/// consequential. For more specialized impls, use the [`STIndex`], [`MTIndex`] or [`STIndexSeq`] traits
pub trait IndexBaseSpec<K, V>: Sized {
pub trait IndexBaseSpec<K: ?Sized, V: ?Sized>: Sized {
/// Index supports prealloc?
const PREALLOC: bool;
#[cfg(debug_assertions)]
@ -202,7 +202,7 @@ pub trait MTIndex<K, V>: IndexBaseSpec<K, V> {
}
/// An unordered STIndex
pub trait STIndex<K, V>: IndexBaseSpec<K, V> {
pub trait STIndex<K: ?Sized, V>: IndexBaseSpec<K, V> {
/// An iterator over the keys and values
type IterKV<'a>: Iterator<Item = (&'a K, &'a V)>
where
@ -284,7 +284,7 @@ pub trait STIndex<K, V>: IndexBaseSpec<K, V> {
fn st_iter_value<'a>(&'a self) -> Self::IterValue<'a>;
}
pub trait STIndexSeq<K, V>: STIndex<K, V> {
pub trait STIndexSeq<K: ?Sized, V>: STIndex<K, V> {
/// An ordered iterator over the keys and values
type IterOrdKV<'a>: Iterator<Item = (&'a K, &'a V)> + DoubleEndedIterator<Item = (&'a K, &'a V)>
where

@ -30,6 +30,7 @@ use {
std::{collections::hash_map::RandomState, marker::PhantomData, ptr},
};
#[derive(Debug)]
pub struct LiberalStrategy<K, V> {
f: *mut IndexSTSeqDllNode<K, V>,
}
@ -76,6 +77,7 @@ impl<K, V> AllocStrategy<K, V> for LiberalStrategy<K, V> {
}
}
#[derive(Debug)]
pub struct ConservativeStrategy<K, V> {
_d: PhantomData<IndexSTSeqDllNodePtr<K, V>>,
}
@ -113,6 +115,7 @@ pub trait Config<K, V> {
type AllocStrategy: AllocStrategy<K, V>;
}
#[derive(Debug)]
pub struct ConservativeConfig<K, V>(PhantomData<super::IndexSTSeqDll<K, V, Self>>);
impl<K, V> Config<K, V> for ConservativeConfig<K, V> {
@ -120,6 +123,7 @@ impl<K, V> Config<K, V> for ConservativeConfig<K, V> {
type AllocStrategy = ConservativeStrategy<K, V>;
}
#[derive(Debug)]
pub struct LiberalConfig<K, V>(PhantomData<super::IndexSTSeqDll<K, V, Self>>);
impl<K, V> Config<K, V> for LiberalConfig<K, V> {

@ -40,7 +40,7 @@ use {
alloc::{alloc as std_alloc, dealloc as std_dealloc, Layout},
borrow::Borrow,
collections::HashMap as StdMap,
fmt::Debug,
fmt::{self, Debug},
hash::{Hash, Hasher},
mem,
ptr::{self, NonNull},
@ -275,6 +275,15 @@ impl<K, V, C: Config<K, V>> IndexSTSeqDll<K, V, C> {
}
}
impl<K, V, C: Config<K, V>> IndexSTSeqDll<K, V, C> {
pub fn new() -> Self {
Self::with_hasher(C::Hasher::default())
}
pub fn with_capacity(cap: usize) -> Self {
Self::with_capacity_and_hasher(cap, C::Hasher::default())
}
}
impl<K, V, C: Config<K, V>> IndexSTSeqDll<K, V, C> {
#[inline(always)]
fn metrics_update_f_decr(&mut self) {
@ -709,3 +718,20 @@ impl<K: AsKeyClone, V: AsValueClone, C: Config<K, V>> Clone for IndexSTSeqDll<K,
unsafe impl<K: Send, V: Send, C: Config<K, V> + Send> Send for IndexSTSeqDll<K, V, C> {}
unsafe impl<K: Sync, V: Sync, C: Config<K, V> + Sync> Sync for IndexSTSeqDll<K, V, C> {}
impl<K: fmt::Debug, V: fmt::Debug, C: Config<K, V> + fmt::Debug> fmt::Debug
for IndexSTSeqDll<K, V, C>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self._iter_ord_kv()).finish()
}
}
impl<K: AsKey, V: AsValue + PartialEq, C: Config<K, V>> PartialEq for IndexSTSeqDll<K, V, C> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len()
&& self
._iter_unord_kv()
.all(|(k, v)| other._get(k).unwrap().eq(v))
}
}

@ -291,6 +291,13 @@ impl<T, const N: usize> Extend<T> for VInline<N, T> {
}
}
#[cfg(test)]
impl<T, const N: usize> From<[T; N]> for VInline<N, T> {
fn from(a: [T; N]) -> Self {
a.into_iter().collect()
}
}
impl<T: Clone, const N: usize> Clone for VInline<N, T> {
fn clone(&self) -> Self {
self.iter().cloned().collect()

@ -35,15 +35,3 @@ mod idx;
mod mem;
mod ql;
mod sync;
/*
A word on tests:
"Nature is not equal. That's the whole problem." - Freeman Dyson
Well, that applies to us for atleast all test cases since most of them are based on a quiescent
state than a chaotic state as in runtime. We do emulate such cases, but remember most assertions
that you'll make on most structures are just illusionary, and are only atomically correct at point
in time.
*/

@ -25,7 +25,7 @@
*/
use {
super::syn::{self, DictFoldState, Field},
super::syn::{self, DictFoldState, FieldSpec},
crate::{
engine::{
data::DictGeneric,
@ -82,11 +82,11 @@ impl<'a> CreateSpace<'a> {
/// A model definition
pub struct CreateModel<'a> {
/// the model name
model_name: Ident<'a>,
pub(in crate::engine) model_name: Ident<'a>,
/// the fields
fields: Vec<Field<'a>>,
pub(in crate::engine) fields: Vec<FieldSpec<'a>>,
/// properties
props: DictGeneric,
pub(in crate::engine) props: DictGeneric,
}
/*
@ -97,7 +97,7 @@ pub struct CreateModel<'a> {
*/
impl<'a> CreateModel<'a> {
pub fn new(model_name: Ident<'a>, fields: Vec<Field<'a>>, props: DictGeneric) -> Self {
pub fn new(model_name: Ident<'a>, fields: Vec<FieldSpec<'a>>, props: DictGeneric) -> Self {
Self {
model_name,
fields,
@ -118,7 +118,7 @@ impl<'a> CreateModel<'a> {
let mut stop = false;
let mut fields = Vec::with_capacity(2);
while state.loop_tt() && !stop {
fields.push(Field::parse(state)?);
fields.push(FieldSpec::parse(state)?);
let nx_close = state.cursor_rounded_eq(Token![() close]);
let nx_comma = state.cursor_rounded_eq(Token![,]);
state.poison_if_not(nx_close | nx_comma);

@ -307,18 +307,18 @@ fn rfold_layers<'a, Qd: QueryData<'a>>(
#[derive(Debug, PartialEq)]
/// A field definition
pub struct Field<'a> {
pub struct FieldSpec<'a> {
/// the field name
field_name: Ident<'a>,
pub(in crate::engine) field_name: Ident<'a>,
/// layers
layers: Vec<LayerSpec<'a>>,
pub(in crate::engine) layers: Vec<LayerSpec<'a>>,
/// is null
null: bool,
pub(in crate::engine) null: bool,
/// is primary
primary: bool,
pub(in crate::engine) primary: bool,
}
impl<'a> Field<'a> {
impl<'a> FieldSpec<'a> {
pub fn new(
field_name: Ident<'a>,
layers: Vec<LayerSpec<'a>>,
@ -353,7 +353,7 @@ impl<'a> Field<'a> {
let mut layers = Vec::new();
rfold_layers(LayerFoldState::BEGIN_IDENT, state, &mut layers);
if state.okay() {
Ok(Field {
Ok(FieldSpec {
field_name: field_name.clone(),
layers,
null: is_null,
@ -486,7 +486,7 @@ mod impls {
use {
super::{
rfold_dict, rfold_layers, rfold_tymeta, DictFoldState, DictGeneric, ExpandedField,
Field, LayerFoldState, LayerSpec,
FieldSpec, LayerFoldState, LayerSpec,
},
crate::engine::{
error::LangResult,
@ -553,7 +553,7 @@ mod impls {
Ok(Self(dict))
}
}
impl<'a> ASTNode<'a> for Field<'a> {
impl<'a> ASTNode<'a> for FieldSpec<'a> {
fn _from_state<Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> LangResult<Self> {
Self::parse(state)
}

@ -309,17 +309,17 @@ mod fields {
super::*,
crate::engine::ql::{
ast::parse_ast_node_full,
ddl::syn::{Field, LayerSpec},
ddl::syn::{FieldSpec, LayerSpec},
lex::Ident,
},
};
#[test]
fn field_mini() {
let tok = lex_insecure(b"username: string").unwrap();
let f = parse_ast_node_full::<Field>(&tok).unwrap();
let f = parse_ast_node_full::<FieldSpec>(&tok).unwrap();
assert_eq!(
f,
Field::new(
FieldSpec::new(
Ident::from("username"),
[LayerSpec::new(Ident::from("string"), null_dict! {})].into(),
false,
@ -330,10 +330,10 @@ mod fields {
#[test]
fn field() {
let tok = lex_insecure(b"primary username: string").unwrap();
let f = parse_ast_node_full::<Field>(&tok).unwrap();
let f = parse_ast_node_full::<FieldSpec>(&tok).unwrap();
assert_eq!(
f,
Field::new(
FieldSpec::new(
Ident::from("username"),
[LayerSpec::new(Ident::from("string"), null_dict! {})].into(),
false,
@ -352,10 +352,10 @@ mod fields {
",
)
.unwrap();
let f = parse_ast_node_full::<Field>(&tok).unwrap();
let f = parse_ast_node_full::<FieldSpec>(&tok).unwrap();
assert_eq!(
f,
Field::new(
FieldSpec::new(
Ident::from("username"),
[LayerSpec::new(
Ident::from("string"),
@ -384,10 +384,10 @@ mod fields {
",
)
.unwrap();
let f = parse_ast_node_full::<Field>(&tok).unwrap();
let f = parse_ast_node_full::<FieldSpec>(&tok).unwrap();
assert_eq!(
f,
Field::new(
FieldSpec::new(
Ident::from("notes"),
[
LayerSpec::new(
@ -417,7 +417,7 @@ mod schemas {
ast::parse_ast_node_full,
ddl::{
crt::CreateModel,
syn::{Field, LayerSpec},
syn::{FieldSpec, LayerSpec},
},
};
#[test]
@ -441,13 +441,13 @@ mod schemas {
CreateModel::new(
Ident::from("mymodel"),
vec![
Field::new(
FieldSpec::new(
Ident::from("username"),
vec![LayerSpec::new(Ident::from("string"), null_dict! {})],
false,
true,
),
Field::new(
FieldSpec::new(
Ident::from("password"),
vec![LayerSpec::new(Ident::from("binary"), null_dict! {})],
false,
@ -480,19 +480,19 @@ mod schemas {
CreateModel::new(
Ident::from("mymodel"),
vec![
Field::new(
FieldSpec::new(
Ident::from("username"),
vec![LayerSpec::new(Ident::from("string"), null_dict! {})],
false,
true,
),
Field::new(
FieldSpec::new(
Ident::from("password"),
vec![LayerSpec::new(Ident::from("binary"), null_dict! {})],
false,
false,
),
Field::new(
FieldSpec::new(
Ident::from("profile_pic"),
vec![LayerSpec::new(Ident::from("binary"), null_dict! {})],
true,
@ -530,25 +530,25 @@ mod schemas {
CreateModel::new(
Ident::from("mymodel"),
vec![
Field::new(
FieldSpec::new(
Ident::from("username"),
vec![LayerSpec::new(Ident::from("string"), null_dict! {})],
false,
true
),
Field::new(
FieldSpec::new(
Ident::from("password"),
vec![LayerSpec::new(Ident::from("binary"), null_dict! {})],
false,
false
),
Field::new(
FieldSpec::new(
Ident::from("profile_pic"),
vec![LayerSpec::new(Ident::from("binary"), null_dict! {})],
true,
false
),
Field::new(
FieldSpec::new(
Ident::from("notes"),
vec![
LayerSpec::new(Ident::from("string"), null_dict! {}),
@ -599,25 +599,25 @@ mod schemas {
CreateModel::new(
Ident::from("mymodel"),
vec![
Field::new(
FieldSpec::new(
Ident::from("username"),
vec![LayerSpec::new(Ident::from("string"), null_dict! {})],
false,
true
),
Field::new(
FieldSpec::new(
Ident::from("password"),
vec![LayerSpec::new(Ident::from("binary"), null_dict! {})],
false,
false
),
Field::new(
FieldSpec::new(
Ident::from("profile_pic"),
vec![LayerSpec::new(Ident::from("binary"), null_dict! {})],
true,
false
),
Field::new(
FieldSpec::new(
Ident::from("notes"),
vec![
LayerSpec::new(Ident::from("string"), null_dict! {}),

Loading…
Cancel
Save