Basic DCL impls
parent
597a49a91b
commit
6a01d9d513
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Created on Thu Sep 21 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::{
|
||||||
|
data::{
|
||||||
|
tag::{DataTag, TagClass},
|
||||||
|
DictGeneric,
|
||||||
|
},
|
||||||
|
error::{Error, QueryResult},
|
||||||
|
ql::{
|
||||||
|
ast::{traits, QueryData, State},
|
||||||
|
ddl::syn,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parse<'a, Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> QueryResult<UserMeta<'a>> {
|
||||||
|
/*
|
||||||
|
user add [username] with { password: [password], ... }
|
||||||
|
^cursor
|
||||||
|
7 tokens
|
||||||
|
*/
|
||||||
|
if state.remaining() < 7 {
|
||||||
|
return Err(Error::QLInvalidSyntax);
|
||||||
|
}
|
||||||
|
let token_buffer = state.current();
|
||||||
|
// initial sig
|
||||||
|
let signature_okay = token_buffer[0].is_lit()
|
||||||
|
& token_buffer[1].eq(&Token![with])
|
||||||
|
& token_buffer[2].eq(&Token![open {}]);
|
||||||
|
// get props
|
||||||
|
state.poison_if_not(signature_okay);
|
||||||
|
state.cursor_ahead_by(2);
|
||||||
|
let Some(dict) = syn::parse_dict(state) else {
|
||||||
|
return Err(Error::QLInvalidCollectionSyntax);
|
||||||
|
};
|
||||||
|
let maybe_username = unsafe {
|
||||||
|
// UNSAFE(@ohsayan): the dict parse ensures state correctness
|
||||||
|
token_buffer[0].uck_read_lit()
|
||||||
|
};
|
||||||
|
state.poison_if_not(maybe_username.kind().tag_class() == TagClass::Str);
|
||||||
|
if state.not_exhausted() & !state.okay() {
|
||||||
|
// we shouldn't have more tokens
|
||||||
|
return Err(Error::QLInvalidSyntax);
|
||||||
|
}
|
||||||
|
Ok(UserMeta {
|
||||||
|
username: unsafe {
|
||||||
|
// UNSAFE(@ohsayan): +tagck in state
|
||||||
|
maybe_username.str()
|
||||||
|
},
|
||||||
|
options: dict,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UserMeta<'a> {
|
||||||
|
username: &'a str,
|
||||||
|
options: DictGeneric,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct UserAdd<'a> {
|
||||||
|
username: &'a str,
|
||||||
|
options: DictGeneric,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UserAdd<'a> {
|
||||||
|
pub(in crate::engine::ql) fn new(username: &'a str, options: DictGeneric) -> Self {
|
||||||
|
Self { username, options }
|
||||||
|
}
|
||||||
|
/// Parse a `user add` DCL command
|
||||||
|
///
|
||||||
|
/// MUSTENDSTREAM: YES
|
||||||
|
pub fn parse<Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> QueryResult<Self> {
|
||||||
|
parse(state).map(|UserMeta { username, options }: UserMeta| Self::new(username, options))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> traits::ASTNode<'a> for UserAdd<'a> {
|
||||||
|
fn _from_state<Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> QueryResult<Self> {
|
||||||
|
Self::parse(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct UserDel<'a> {
|
||||||
|
username: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UserDel<'a> {
|
||||||
|
pub(in crate::engine::ql) fn new(username: &'a str) -> Self {
|
||||||
|
Self { username }
|
||||||
|
}
|
||||||
|
/// Parse a `user del` DCL command
|
||||||
|
///
|
||||||
|
/// MUSTENDSTREAM: YES
|
||||||
|
pub fn parse<Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> QueryResult<Self> {
|
||||||
|
if state.can_read_lit_rounded() & (state.remaining() == 1) {
|
||||||
|
let lit = unsafe {
|
||||||
|
// UNSAFE(@ohsayan): +boundck
|
||||||
|
state.read_cursor_lit_unchecked()
|
||||||
|
};
|
||||||
|
state.cursor_ahead();
|
||||||
|
if lit.kind().tag_class() == TagClass::Str {
|
||||||
|
return Ok(Self::new(unsafe {
|
||||||
|
// UNSAFE(@ohsayan): +tagck
|
||||||
|
lit.str()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::QLInvalidSyntax)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> traits::ASTNode<'a> for UserDel<'a> {
|
||||||
|
fn _from_state<Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> QueryResult<Self> {
|
||||||
|
Self::parse(state)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Created on Fri Sep 22 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::ql::{ast, dcl, tests::lex_insecure};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_user_simple() {
|
||||||
|
let query = lex_insecure(b"create user 'sayan' with { password: 'mypass123' }").unwrap();
|
||||||
|
let q = ast::parse_ast_node_full::<dcl::UserAdd>(&query[2..]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
q,
|
||||||
|
dcl::UserAdd::new("sayan", into_dict!("password" => lit!("mypass123")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn delete_user_simple() {
|
||||||
|
let query = lex_insecure(b"delete user 'monster'").unwrap();
|
||||||
|
let q = ast::parse_ast_node_full::<dcl::UserDel>(&query[2..]).unwrap();
|
||||||
|
assert_eq!(q, dcl::UserDel::new("monster"))
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Created on Fri Sep 22 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::{
|
||||||
|
data::{cell::Datacell, DictEntryGeneric, DictGeneric},
|
||||||
|
fractal::SysConfig,
|
||||||
|
storage::v1::{
|
||||||
|
header_meta::{FileScope, FileSpecifier, FileSpecifierVersion},
|
||||||
|
RawFSInterface, SDSSError, SDSSFileIO, SDSSResult,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const SYSDB_PATH: &str = "sys.db";
|
||||||
|
const SYSDB_COW_PATH: &str = "sys.db.cow";
|
||||||
|
|
||||||
|
pub fn sync_system_database<Fs: RawFSInterface>(cfg: &SysConfig) -> SDSSResult<()> {
|
||||||
|
// get auth data
|
||||||
|
let auth_data = cfg.auth_data().read();
|
||||||
|
// prepare our flat file
|
||||||
|
let mut map: DictGeneric = into_dict!(
|
||||||
|
"host" => DictEntryGeneric::Map(into_dict!(
|
||||||
|
"settings_version" => Datacell::new_uint(cfg.host_data().settings_version() as _),
|
||||||
|
"startup_counter" => Datacell::new_uint(cfg.host_data().startup_counter() as _),
|
||||||
|
)),
|
||||||
|
"auth" => DictGeneric::new(),
|
||||||
|
);
|
||||||
|
let auth_key = map.get_mut("auth").unwrap();
|
||||||
|
match &*auth_data {
|
||||||
|
None => *auth_key = Datacell::null().into(),
|
||||||
|
Some(auth) => {
|
||||||
|
let auth_key = auth_key.as_dict_mut().unwrap();
|
||||||
|
auth_key.insert(
|
||||||
|
"root".into(),
|
||||||
|
DictEntryGeneric::Data(Datacell::new_bin(auth.root_key().into())),
|
||||||
|
);
|
||||||
|
auth_key.insert(
|
||||||
|
"users".into(),
|
||||||
|
DictEntryGeneric::Map(
|
||||||
|
auth.users()
|
||||||
|
.iter()
|
||||||
|
.map(|(username, user)| {
|
||||||
|
(
|
||||||
|
username.to_owned(),
|
||||||
|
DictEntryGeneric::Data(Datacell::new_list(vec![
|
||||||
|
Datacell::new_bin(user.key().into()),
|
||||||
|
])),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// open file
|
||||||
|
let mut file = SDSSFileIO::<Fs>::open_or_create_perm_rw::<false>(
|
||||||
|
SYSDB_COW_PATH,
|
||||||
|
FileScope::FlatmapData,
|
||||||
|
FileSpecifier::SysDB,
|
||||||
|
FileSpecifierVersion::__new(0),
|
||||||
|
cfg.host_data().settings_version(),
|
||||||
|
cfg.host_data().run_mode(),
|
||||||
|
cfg.host_data().startup_counter(),
|
||||||
|
)?
|
||||||
|
.into_created()
|
||||||
|
.ok_or(SDSSError::OtherError(
|
||||||
|
"sys.db.cow already exists. please remove this file.",
|
||||||
|
))?;
|
||||||
|
// write
|
||||||
|
let buf = super::inf::enc::enc_dict_full::<super::inf::map::GenericDictSpec>(&map);
|
||||||
|
file.fsynced_write(&buf)?;
|
||||||
|
// replace
|
||||||
|
Fs::fs_rename_file(SYSDB_COW_PATH, SYSDB_PATH)
|
||||||
|
}
|
Loading…
Reference in New Issue