Skip to content

Commit

Permalink
SET command inclusion
Browse files Browse the repository at this point in the history
  • Loading branch information
deven96 committed Sep 26, 2024
1 parent 883ad6a commit 52fbb06
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 29 deletions.
17 changes: 17 additions & 0 deletions ahnlich/dsl/src/array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::parser::Rule;
use ahnlich_types::keyval::StoreKey;
use ndarray::Array1;
use pest::iterators::Pair;

pub(crate) fn parse_multi_f32_array(f32_arrays_pair: Pair<Rule>) -> Vec<StoreKey> {
f32_arrays_pair.into_inner().map(parse_f32_array).collect()
}

pub(crate) fn parse_f32_array(pair: Pair<Rule>) -> StoreKey {
StoreKey(Array1::from_iter(pair.into_inner().map(|f32_pair| {
f32_pair
.as_str()
.parse::<f32>()
.expect("Cannot parse single f32 num")
})))
}
42 changes: 19 additions & 23 deletions ahnlich/dsl/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,15 @@ use std::{collections::HashSet, num::NonZeroUsize};

use crate::{
algorithm::{to_algorithm, to_non_linear},
array::{parse_f32_array, parse_multi_f32_array},
metadata::parse_store_keys_to_store_value,
parser::{QueryParser, Rule},
};
use ahnlich_types::{
db::DBQuery,
keyval::{StoreKey, StoreName},
metadata::MetadataKey,
};
use ndarray::Array1;
use pest::iterators::Pair;
use ahnlich_types::{db::DBQuery, keyval::StoreName, metadata::MetadataKey};
use pest::Parser;

use crate::{error::DslError, predicate::parse_predicate_expression};

fn parse_multi_f32_array(f32_arrays_pair: Pair<Rule>) -> Vec<StoreKey> {
f32_arrays_pair.into_inner().map(parse_f32_array).collect()
}

fn parse_f32_array(pair: Pair<Rule>) -> StoreKey {
StoreKey(Array1::from_iter(pair.into_inner().map(|f32_pair| {
f32_pair
.as_str()
.parse::<f32>()
.expect("Cannot parse single f32 num")
})))
}

// Parse raw strings separated by ; into a Vec<DBQuery>. Examples include but are not restricted
// to
//
Expand All @@ -45,9 +28,7 @@ fn parse_f32_array(pair: Pair<Rule>) -> StoreKey {
// 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
// SET (([1.0, 2.1, 3.2], {name: Haks, category: dev}), ([3.1, 4.8, 5.0], {name: Deven, category: dev})) in store
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 +41,21 @@ 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::set_in_store => {
let mut inner_pairs = statement.into_inner();
let store_keys_to_store_values = inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?;
let store = inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?
.as_str();

DBQuery::Set {
store: StoreName(store.to_string()),
inputs: parse_store_keys_to_store_value(store_keys_to_store_values)?,
}
}
Rule::create_store => {
let mut inner_pairs = statement.into_inner().peekable();
let mut error_if_exists = true;
Expand Down
1 change: 1 addition & 0 deletions ahnlich/dsl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod algorithm;
mod array;
pub mod db;
pub mod error;
mod metadata;
Expand Down
49 changes: 47 additions & 2 deletions ahnlich/dsl/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::array::parse_f32_array;
use crate::error::DslError;
use crate::parser::Rule;
use ahnlich_types::metadata::MetadataValue;
use ahnlich_types::keyval::{StoreKey, StoreValue};
use ahnlich_types::metadata::{MetadataKey, MetadataValue};
use pest::iterators::Pair;
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};

pub(crate) fn parse_metadata_value(pair: Pair<Rule>) -> Result<MetadataValue, DslError> {
match pair.as_rule() {
Expand Down Expand Up @@ -34,3 +36,46 @@ pub(crate) fn parse_metadata_values(pair: Pair<Rule>) -> Result<HashSet<Metadata
}
Ok(values)
}

fn parse_into_store_key_and_value(pair: Pair<Rule>) -> Result<(StoreKey, StoreValue), DslError> {
let start_pos = pair.as_span().start_pos().pos();
let end_pos = pair.as_span().end_pos().pos();

let mut inner_pairs = pair.into_inner();
let f32_array = parse_f32_array(
inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?,
);
let store_value = inner_pairs
.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?;
let mut store_value_map = HashMap::new();
for store_value_single in store_value.into_inner() {
let start_pos = store_value_single.as_span().start_pos().pos();
let end_pos = store_value_single.as_span().end_pos().pos();
let mut v = store_value_single.into_inner();
let key = MetadataKey::new(
v.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?
.as_str()
.to_string(),
);
let value = parse_metadata_value(
v.next()
.ok_or(DslError::UnexpectedSpan((start_pos, end_pos)))?,
)?;
store_value_map.insert(key, value);
}
Ok((f32_array, store_value_map))
}

pub(crate) fn parse_store_keys_to_store_value(
pair: Pair<Rule>,
) -> Result<Vec<(StoreKey, StoreValue)>, DslError> {
let mut values = vec![];
for value_pair in pair.into_inner() {
values.push(parse_into_store_key_and_value(value_pair)?);
}
Ok(values)
}
12 changes: 9 additions & 3 deletions ahnlich/dsl/src/syntax/syntax.pest
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ db_statement = _{
get_pred |
get_sim_n |
create_store |
set_in_store |
invalid_statement
}

Expand All @@ -36,6 +37,7 @@ get_pred = { whitespace* ~ ^"getpred" ~ whitespace* ~ predicate_condition ~ in_i
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* ~ ")")? }
set_in_store = { whitespace* ~ ^"set" ~ whitespace* ~ store_keys_to_store_value ~ whitespace* ~ ^"in" ~ whitespace* ~ store_name }

if_exists = { whitespace* ~ ^"if" ~ whitespace* ~ ^"exists" ~ whitespace* }
if_not_exists = { whitespace* ~ ^"if" ~ whitespace* ~ ^"not" ~ whitespace* ~ ^"exists" ~ whitespace* }
Expand All @@ -45,6 +47,10 @@ store_name = { (ASCII_ALPHANUMERIC | "_" | "-")+ }
index_name = { (ASCII_ALPHANUMERIC | "_" | "-")+ }
metadata_key = { (ASCII_ALPHANUMERIC | "_" | "-")+ }
metadata_keys = { metadata_key ~ (whitespace* ~ "," ~ whitespace* ~ metadata_key)* }
store_value_single = { metadata_key ~ whitespace* ~ ":" ~ whitespace* ~ metadata_value }
store_value = { "{" ~ whitespace* ~ store_value_single ~ (whitespace* ~ "," ~ whitespace* ~ store_value_single)* ~ whitespace* ~ "}" }
store_key_to_store_value = { "(" ~ whitespace* ~ f32_array ~ whitespace* ~ "," ~ whitespace* ~ store_value ~ whitespace* ~ ")" }
store_keys_to_store_value = { "(" ~ whitespace* ~ store_key_to_store_value ~ (whitespace* ~ "," ~ whitespace* ~ store_key_to_store_value)* ~ whitespace* ~ ")" }
non_linear_algorithm = { ^"kdtree" }
algorithm = {
^"kdtree" |
Expand All @@ -59,14 +65,14 @@ index_names = { index_name ~ (whitespace* ~ "," ~ whitespace* ~ index_name)* }
non_zero = { '1'..'9' ~ ASCII_DIGIT* }
f32 = { ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
// Array of floating-point numbers
f32_array = { "[" ~ f32 ~ (whitespace* ~ "," ~ whitespace* ~ f32)* ~ "]"}
f32_array = { "[" ~ whitespace* ~ f32 ~ (whitespace* ~ "," ~ whitespace* ~ f32)* ~ whitespace* ~ "]"}

// List of f32 arrays (comma-separated)
f32_arrays = { f32_array ~ (whitespace* ~ "," ~ whitespace* ~ f32_array)* }


// raw string. For simplicity no quotes in the string
raw_string = { (!("," | ")") ~ ANY)+ }
// raw string. For simplicity no quotes, commas or closing braces in the string
raw_string = { (!("," | ")" | "}" ) ~ ANY)+ }
ASCII_HEX = { '0'..'9' | 'A'..'F' | 'a'..'f' }
// image contains all possible ascii hex
image = { "/x" ~ ASCII_HEX+ }
Expand Down
43 changes: 42 additions & 1 deletion ahnlich/dsl/src/tests/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use ahnlich_types::{
metadata::MetadataKey,
};
use ndarray::Array1;
use std::{collections::HashSet, num::NonZeroUsize};
use std::{
collections::{HashMap, HashSet},
num::NonZeroUsize,
};

use ahnlich_types::{
metadata::MetadataValue,
Expand Down Expand Up @@ -298,6 +301,44 @@ fn test_get_key_parse() {
);
}

#[test]
fn test_set_in_store_parse() {
let input = r#"set 2134 in store"#;
let DslError::UnexpectedSpan((start, end)) = parse_db_query(input).unwrap_err() else {
panic!("Unexpected error pattern found")
};
assert_eq!((start, end), (0, 17));
let input = r#"SET (([1,2,3], {state: Munich, country: Germany}), ([3.2, 4.5, 9.4], {country: USA})) in geo"#;
assert_eq!(
parse_db_query(input).expect("Could not parse query input"),
vec![DBQuery::Set {
store: StoreName("geo".to_string()),
inputs: vec![
(
StoreKey(Array1::from_iter([1.0, 2.0, 3.0])),
HashMap::from_iter([
(
MetadataKey::new("state".to_string()),
MetadataValue::RawString("Munich".to_string())
),
(
MetadataKey::new("country".to_string()),
MetadataValue::RawString("Germany".to_string())
),
])
),
(
StoreKey(Array1::from_iter([3.2, 4.5, 9.4])),
HashMap::from_iter([(
MetadataKey::new("country".to_string()),
MetadataValue::RawString("USA".to_string())
),])
)
],
}]
);
}

#[test]
fn test_del_key_parse() {
let input = r#"DELKEY ([a, b, c], [3.0, 4.0]) in 1234"#;
Expand Down

0 comments on commit 52fbb06

Please sign in to comment.