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 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};
pub struct SelectProcessor {
}
pub struct SelectProcessor {}
/**
{
select: [
@@ -27,53 +25,94 @@ pub struct SelectProcessor {
//
*/
impl SelectProcessor {
// recursively select relations
pub fn selector(database: &Database, table_name: &String, row: &Row, select: Vec<String>, mut output: HashMap<String,Value>) -> HashMap<String,Value> {
// recursively select relations
for value in select {
let key = value.to_string();
if(key.eq("*")) {
return row.clone();// recursive call
}
else if(key.contains(".")) {
let split: Vec<String> = key.split(".").map(|part| String::from_str(part).unwrap()).collect();
if(split.len() == 2 && split[1].eq("*")) {
let relation_rows = SelectProcessor::resolve_relation(database, table_name, row, &split[0]);
output.insert(split[0].clone(), json!(relation_rows));
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 {
let key = value.to_string();
if (key.eq("*")) {
return row.clone(); // recursive call
} else if (key.contains(".")) {
let split: Vec<String> = key
.split(".")
.map(|part| String::from_str(part).unwrap())
.collect();
if (split.len() == 2 && split[1].eq("*")) {
let relation_rows =
SelectProcessor::resolve_relation(database, table_name, row, &split[0]);
output.insert(split[0].clone(), json!(relation_rows));
}
// recursive call
} else {
let value = row.get(&key);
match value.is_some() {
true => output.insert(key, value.unwrap().to_owned()),
false => panic!("Failed to read key: {key} on table: {table_name}"),
};
}
}
// recursive call
} else {
let value = row.get(&key);
match value.is_some() {
true => output.insert(key, value.unwrap().to_owned()),
false => panic!("Failed to read key: {key} on table: {table_name}"),
return output;
}
pub fn resolve_relation(
database: &Database,
table_name: &String,
row: &Row,
key: &String,
) -> Vec<Row> {
let table = database.get_table(table_name.clone()).unwrap();
println!("Attempting to find relation for '{key}' in table: '{table_name}'");
let value = row.get(key).unwrap();
let relation_name = match value.get("relation_name") {
Some(val) => String::from(val.as_str().unwrap()),
None => panic!("Value was not a valid relation"),
};
let relation = table.get_relation(&relation_name).unwrap();
let relation_variation = relation.variation.as_str();
return match relation_variation {
"one_to_one" => vec![OneToOne::from_value(value.to_owned())
.get(table_name.clone(), database)
.unwrap()],
"one_to_many" => OneToMany::from_value(value.to_owned())
.get(table_name.clone(), database)
.unwrap(),
other => panic!("Unsupported relationship type: {other}"),
};
}
}
return output;
}
pub fn resolve_relation(database: &Database, table_name: &String, row: &Row, key: &String) -> Vec<Row> {
let table = database.get_table(table_name.clone()).unwrap();
println!("Attempting to find relation for '{key}' in table: '{table_name}'");
let value = row.get(key).unwrap();
let relation_name = match value.get("relation_name") {
Some(val) => String::from(val.as_str().unwrap()),
None => panic!("Value was not a valid relation")
};
let relation = table.get_relation(&relation_name).unwrap();
let relation_variation = relation.variation.as_str();
return match relation_variation {
"one_to_one" => vec![OneToOne::from_value(value.to_owned()).get(table_name.clone(), database).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": {
"*": "*"
}
}
})
);
}
}