feat: added test for recursive select parser

This commit is contained in:
Elias Renman
2023-11-22 00:28:44 +01:00
parent 26bc065a00
commit 9eb2a70593
2 changed files with 110 additions and 50 deletions

View File

@@ -1,14 +1,12 @@
use std::{borrow::Borrow, collections::HashMap, str::FromStr}; use std::{borrow::Borrow, collections::HashMap, str::FromStr};
use serde_json::{map::Values, Value, json}; use serde_json::{json, map::Values, Map, Value};
use crate::database::relation::{OneToOne, OneToMany}; use crate::database::relation::{OneToMany, OneToOne};
use super::{row::Row, table::Table, Database}; use super::{row::Row, table::Table, Database};
pub struct SelectProcessor { pub struct SelectProcessor {}
}
/** /**
{ {
select: [ select: [
@@ -29,18 +27,26 @@ pub struct SelectProcessor {
impl SelectProcessor { impl SelectProcessor {
// recursively select relations // recursively select relations
pub fn selector(database: &Database, table_name: &String, row: &Row, select: Vec<String>, mut output: HashMap<String,Value>) -> HashMap<String,Value> { pub fn selector(
database: &Database,
table_name: &String,
row: &Row,
select: Vec<String>,
mut output: HashMap<String, Value>,
) -> HashMap<String, Value> {
for value in select { for value in select {
let key = value.to_string(); let key = value.to_string();
if (key.eq("*")) { if (key.eq("*")) {
return row.clone(); // recursive call return row.clone(); // recursive call
} } else if (key.contains(".")) {
else if(key.contains(".")) { let split: Vec<String> = key
let split: Vec<String> = key.split(".").map(|part| String::from_str(part).unwrap()).collect(); .split(".")
.map(|part| String::from_str(part).unwrap())
.collect();
if (split.len() == 2 && split[1].eq("*")) { if (split.len() == 2 && split[1].eq("*")) {
let relation_rows = SelectProcessor::resolve_relation(database, table_name, row, &split[0]); let relation_rows =
SelectProcessor::resolve_relation(database, table_name, row, &split[0]);
output.insert(split[0].clone(), json!(relation_rows)); output.insert(split[0].clone(), json!(relation_rows));
} }
// recursive call // recursive call
@@ -49,31 +55,64 @@ impl SelectProcessor {
match value.is_some() { match value.is_some() {
true => output.insert(key, value.unwrap().to_owned()), true => output.insert(key, value.unwrap().to_owned()),
false => panic!("Failed to read key: {key} on table: {table_name}"), false => panic!("Failed to read key: {key} on table: {table_name}"),
}; };
} }
} }
return output; return output;
} }
pub fn resolve_relation(database: &Database, table_name: &String, row: &Row, key: &String) -> Vec<Row> { pub fn resolve_relation(
database: &Database,
table_name: &String,
row: &Row,
key: &String,
) -> Vec<Row> {
let table = database.get_table(table_name.clone()).unwrap(); let table = database.get_table(table_name.clone()).unwrap();
println!("Attempting to find relation for '{key}' in table: '{table_name}'"); println!("Attempting to find relation for '{key}' in table: '{table_name}'");
let value = row.get(key).unwrap(); let value = row.get(key).unwrap();
let relation_name = match value.get("relation_name") { let relation_name = match value.get("relation_name") {
Some(val) => String::from(val.as_str().unwrap()), Some(val) => String::from(val.as_str().unwrap()),
None => panic!("Value was not a valid relation") None => panic!("Value was not a valid relation"),
}; };
let relation = table.get_relation(&relation_name).unwrap(); let relation = table.get_relation(&relation_name).unwrap();
let relation_variation = relation.variation.as_str(); let relation_variation = relation.variation.as_str();
return match relation_variation { return match relation_variation {
"one_to_one" => vec![OneToOne::from_value(value.to_owned()).get(table_name.clone(), database).unwrap()], "one_to_one" => vec![OneToOne::from_value(value.to_owned())
"one_to_many" => OneToMany::from_value(value.to_owned()).get(table_name.clone(), database).unwrap(), .get(table_name.clone(), database)
other => panic!("Unsupported relationship type: {other}") .unwrap()],
"one_to_many" => OneToMany::from_value(value.to_owned())
.get(table_name.clone(), database)
.unwrap(),
other => panic!("Unsupported relationship type: {other}"),
};
}
fn is_valid_key(key: &str) -> bool {
key.chars().all(|c| c.is_ascii_lowercase() || c == '_')
}
pub fn recursive_parse_select(node: Vec<&str>) -> Value {
let mut output = Map::new();
for key in node {
if let Some(dot_index) = key.find('.') {
let next_key = key[..dot_index].to_string();
let next_node = key[dot_index + 1..].to_string();
let mut nested_value = SelectProcessor::recursive_parse_select(vec![&next_node]);
if output.contains_key(&next_key) {
let deep_map = output.get_mut(&next_key).unwrap().as_object_mut().unwrap();
deep_map.append(nested_value.as_object_mut().unwrap());
} else {
output.insert(next_key, nested_value);
}
output.insert(key.to_string(), json!(key));
} }
} }
json!(output)
}
} }

View File

@@ -88,4 +88,25 @@ mod select_processor_test {
}) })
); );
} }
#[test]
fn should_parse_node() {
let output = SelectProcessor::recursive_parse_select(vec!["id","food","relation.*","relation.food.*"]);
let json = serde_json::to_string_pretty(&output).unwrap();
println!("{json}");
assert_json_include!(
actual: &output,
expected:
&json!({
"id": "id",
"food": "food",
"relation": {
"*": "*",
"food": {
"*": "*"
}
}
})
);
}
} }