Skip to content

Commit

Permalink
CREATESTORE command inclusion
Browse files Browse the repository at this point in the history
  • Loading branch information
deven96 committed Sep 26, 2024
1 parent b365c20 commit e9cdde2
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 3 deletions.
54 changes: 52 additions & 2 deletions ahnlich/dsl/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::num::NonZeroUsize;
use std::{collections::HashSet, num::NonZeroUsize};

use crate::{
algorithm::{to_algorithm, to_non_linear},
Expand Down Expand Up @@ -44,10 +44,10 @@ fn parse_f32_array(pair: Pair<Rule>) -> StoreKey {
// DELKEY ((1.2, 3.0), (5.6, 7.8)) IN my_store
// GETPRED ((author = dickens) OR (country != Nigeria)) IN my_store
// GETSIMN 4 WITH (0.65, 2.78) USING cosinesimilarity IN my_store WHERE (author = dickens)
// CREATESTORE IF NOT EXISTS my_store DIMENSION 21 PREDICATES (author, country) NONLINEARALGORITHMINDEX (kdtree)
//
// #TODO
// SET
// CREATESTORE
pub fn parse_db_query(input: &str) -> Result<Vec<DBQuery>, DslError> {
let pairs = QueryParser::parse(Rule::db_query, input).map_err(Box::new)?;
let statements = pairs.into_iter().collect::<Vec<_>>();
Expand All @@ -60,6 +60,56 @@ pub fn parse_db_query(input: &str) -> Result<Vec<DBQuery>, DslError> {
Rule::list_clients => DBQuery::ListClients,
Rule::list_stores => DBQuery::ListStores,
Rule::info_server => DBQuery::InfoServer,
Rule::create_store => {
let mut inner_pairs = statement.into_inner().peekable();
let mut error_if_exists = true;
if let Some(next_pair) = inner_pairs.peek() {
if next_pair.as_rule() == Rule::if_not_exists {
inner_pairs.next(); // Consume rule
error_if_exists = false;
}
};
let store = inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?
.as_str();
let dimension = inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?
.as_str()
.parse::<NonZeroUsize>()?;
let mut create_predicates = HashSet::new();
if let Some(next_pair) = inner_pairs.peek() {
if next_pair.as_rule() == Rule::metadata_keys {
let index_name_pairs = inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?; // Consume rule
create_predicates = index_name_pairs
.into_inner()
.map(|index_pair| MetadataKey::new(index_pair.as_str().to_string()))
.collect();
}
};
let mut non_linear_indices = HashSet::new();
if let Some(next_pair) = inner_pairs.peek() {
if next_pair.as_rule() == Rule::non_linear_algorithms {
let index_name_pairs = inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?; // Consume rule
non_linear_indices = index_name_pairs
.into_inner()
.flat_map(|index_pair| to_non_linear(index_pair.as_str()))
.collect();
}
};
DBQuery::CreateStore {
store: StoreName(store.to_string()),
dimension,
create_predicates,
non_linear_indices,
error_if_exists,
}
}
Rule::get_sim_n => {
let mut inner_pairs = statement.into_inner();
let closest_n = inner_pairs
Expand Down
7 changes: 6 additions & 1 deletion ahnlich/dsl/src/syntax/syntax.pest
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ db_statement = _{
del_key |
get_pred |
get_sim_n |
create_store |
invalid_statement
}

Expand All @@ -33,15 +34,19 @@ del_key = { whitespace* ~ ^"delkey" ~ whitespace* ~ "(" ~ f32_arrays ~ ")" ~ in_
get_pred = { whitespace* ~ ^"getpred" ~ whitespace* ~ predicate_condition ~ in_ignored ~ store_name }
// GETSIMN 2 WITH store-key USING algorithm IN store (WHERE predicate_condition)
get_sim_n = { whitespace* ~ ^"getsimn" ~ whitespace* ~ non_zero ~ whitespace* ~ ^"with" ~ whitespace* ~ f32_array ~ whitespace* ~ ^"using" ~ whitespace* ~ algorithm ~ whitespace* ~ in_ignored ~ whitespace* ~ store_name ~ whitespace* ~ (^"where" ~ whitespace* ~ predicate_condition)? }
// CREATESTORE IF NOT EXISTS store-name DIMENSION non-zero-size PREDICATES (key1, key2) NONLINEARALGORITHMINDEX (kdtree)
create_store = { whitespace* ~ ^"createstore" ~ whitespace* ~ (if_not_exists)? ~ whitespace* ~ store_name ~ whitespace* ~ ^"dimension" ~ whitespace* ~ non_zero ~ whitespace* ~ (^"predicates" ~ whitespace* ~ "(" ~ whitespace* ~ metadata_keys ~ whitespace* ~ ")" )? ~ (whitespace* ~ ^"nonlinearalgorithmindex" ~ whitespace* ~ "(" ~ whitespace* ~ non_linear_algorithms ~ whitespace* ~ ")")? }

if_exists = { whitespace* ~ ^"if" ~ whitespace* ~ ^"exists" ~ whitespace* }
if_not_exists = { whitespace* ~ ^"if" ~ whitespace* ~ ^"not" ~ whitespace* ~ ^"exists" ~ whitespace* }

// stores and predicates can be alphanumeric
store_name = { (ASCII_ALPHANUMERIC | "_" | "-")+ }
index_name = { (ASCII_ALPHANUMERIC | "_" | "-")+ }
metadata_key = { (ASCII_ALPHANUMERIC | "_" | "-")+ }
metadata_keys = { metadata_key ~ (whitespace* ~ "," ~ whitespace* ~ metadata_key)* }
non_linear_algorithm = { ^"kdtree" }
algorithm = {
algorithm = {
^"kdtree" |
^"euclideandistance" |
^"cosinesimilarity" |
Expand Down
66 changes: 66 additions & 0 deletions ahnlich/dsl/src/tests/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,72 @@ fn test_no_valid_input_in_query() {
assert_eq!((start, end), (13, 20));
}

#[test]
fn test_create_store_parse() {
// simple syntax
let input = r#"CREATEstore storename DIMENSION 23"#;
assert_eq!(
parse_db_query(input).expect("Could not parse query input"),
vec![DBQuery::CreateStore {
store: StoreName("storename".to_string()),
dimension: NonZeroUsize::new(23).unwrap(),
create_predicates: HashSet::new(),
non_linear_indices: HashSet::new(),
error_if_exists: true
}]
);
let input = r#"CREATEstore IF NOT EXISTS testing DIMENSION 43"#;
assert_eq!(
parse_db_query(input).expect("Could not parse query input"),
vec![DBQuery::CreateStore {
store: StoreName("testing".to_string()),
dimension: NonZeroUsize::new(43).unwrap(),
create_predicates: HashSet::new(),
non_linear_indices: HashSet::new(),
error_if_exists: false
}]
);
let input = r#"CREATEstore IF NOT EXISTS school DIMENSION 39 PREDICATES (department, faculty)"#;
assert_eq!(
parse_db_query(input).expect("Could not parse query input"),
vec![DBQuery::CreateStore {
store: StoreName("school".to_string()),
dimension: NonZeroUsize::new(39).unwrap(),
create_predicates: HashSet::from_iter([
MetadataKey::new("department".to_string()),
MetadataKey::new("faculty".to_string()),
]),
non_linear_indices: HashSet::new(),
error_if_exists: false
}]
);
let input = r#"CREATEstore school DIMENSION 39 NONLINEARALGORITHMINDEX (kdtree)"#;
assert_eq!(
parse_db_query(input).expect("Could not parse query input"),
vec![DBQuery::CreateStore {
store: StoreName("school".to_string()),
dimension: NonZeroUsize::new(39).unwrap(),
create_predicates: HashSet::new(),
non_linear_indices: HashSet::from_iter([NonLinearAlgorithm::KDTree]),
error_if_exists: true
}]
);
let input = r#"CREATEstore school DIMENSION 77 PREDICATES(name, surname) NONLINEARALGORITHMINDEX (kdtree)"#;
assert_eq!(
parse_db_query(input).expect("Could not parse query input"),
vec![DBQuery::CreateStore {
store: StoreName("school".to_string()),
dimension: NonZeroUsize::new(77).unwrap(),
create_predicates: HashSet::from_iter([
MetadataKey::new("name".to_string()),
MetadataKey::new("surname".to_string()),
]),
non_linear_indices: HashSet::from_iter([NonLinearAlgorithm::KDTree]),
error_if_exists: true
}]
);
}

#[test]
fn test_drop_store_parse() {
let input = r#"DROPSTORE random"#;
Expand Down

0 comments on commit e9cdde2

Please sign in to comment.