feat: select processor

This commit is contained in:
Elias Renman
2023-11-23 22:07:16 +01:00
parent 9eb2a70593
commit 8d210c3da3
2 changed files with 97 additions and 76 deletions

View File

@@ -1,29 +1,13 @@
use std::{borrow::Borrow, collections::HashMap, str::FromStr}; use std::collections::HashMap;
use serde_json::{json, map::Values, Map, Value}; use serde_json::{json, Map, Value};
use crate::database::relation::{OneToMany, OneToOne}; use crate::database::relation::{OneToMany, OneToOne};
use super::{row::Row, table::Table, Database}; use super::{row::Row, Database};
pub struct SelectProcessor {} pub struct SelectProcessor {}
/**
{
select: [
"id",
"name",
"relation.*"
]
}
{
select: [
"id",
"name",
"relation.id"
]
}
//
*/
impl SelectProcessor { impl SelectProcessor {
// recursively select relations // recursively select relations
@@ -31,31 +15,56 @@ impl SelectProcessor {
database: &Database, database: &Database,
table_name: &String, table_name: &String,
row: &Row, row: &Row,
select: Vec<String>, select: Vec<&str>,
mut output: HashMap<String, Value>,
) -> HashMap<String, Value> { ) -> HashMap<String, Value> {
for value in select { let asd = SelectProcessor::parse_node(select);
let key = value.to_string(); println!("Debugging parsed selector {asd}");
if (key.eq("*")) { SelectProcessor::recursive_traverse_resolver(database, table_name, row, &asd)
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("*")) { fn recursive_traverse_resolver(
let relation_rows = database: &Database,
SelectProcessor::resolve_relation(database, table_name, row, &split[0]); table_name: &String,
output.insert(split[0].clone(), json!(relation_rows)); row: &Row,
selector: &Value,
) -> HashMap<String, Value> {
let object = selector.as_object().unwrap();
let mut output: HashMap<String, Value> = HashMap::new();
for (key, value) in object.into_iter() {
if value.is_object() {
let relation_rows: Value =
SelectProcessor::resolve_relation(database, table_name, row, key);
if relation_rows.is_array() {
let mut row_vec: Vec<HashMap<String, Value>> = vec![];
for row in relation_rows.as_array().unwrap() {
let asd = Row::from(row.as_object().unwrap());
let parsed_row = SelectProcessor::recursive_traverse_resolver(
database, table_name, &(row.as_object().unwrap()), &value,
);
row_vec.push(parsed_row);
}
output.insert(key.to_owned(), json!(row_vec));
} else {
let parsed_row = SelectProcessor::recursive_traverse_resolver(
database, table_name, &row, &value,
);
output.insert(key.to_owned(), json!(parsed_row));
} }
// recursive call
} else { } else {
let value = row.get(&key); if value.as_str().unwrap() == "*" {
match value.is_some() { output = row.to_owned();
true => output.insert(key, value.unwrap().to_owned()), } else {
false => panic!("Failed to read key: {key} on table: {table_name}"), let val = row.get(key);
}; if val.is_none() {
let pretty_json = serde_json::to_string_pretty(row).unwrap();
panic!(
"Value missing on key {key} in table {table_name} - row: {pretty_json}"
);
}
output.insert(key.to_owned(), json!(val.unwrap()));
}
} }
} }
return output; return output;
@@ -66,7 +75,7 @@ impl SelectProcessor {
table_name: &String, table_name: &String,
row: &Row, row: &Row,
key: &String, key: &String,
) -> Vec<Row> { ) -> Value {
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}'");
@@ -79,12 +88,12 @@ impl SelectProcessor {
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()) "one_to_one" => json!(OneToOne::from_value(value.to_owned())
.get(table_name.clone(), database) .get(table_name.clone(), database)
.unwrap()], .unwrap()),
"one_to_many" => OneToMany::from_value(value.to_owned()) "one_to_many" => json!(OneToMany::from_value(value.to_owned())
.get(table_name.clone(), database) .get(table_name.clone(), database)
.unwrap(), .unwrap()),
other => panic!("Unsupported relationship type: {other}"), other => panic!("Unsupported relationship type: {other}"),
}; };
} }
@@ -93,7 +102,7 @@ impl SelectProcessor {
key.chars().all(|c| c.is_ascii_lowercase() || c == '_') key.chars().all(|c| c.is_ascii_lowercase() || c == '_')
} }
pub fn recursive_parse_select(node: Vec<&str>) -> Value { pub fn parse_node(node: Vec<&str>) -> Value {
let mut output = Map::new(); let mut output = Map::new();
for key in node { for key in node {
@@ -101,14 +110,15 @@ impl SelectProcessor {
let next_key = key[..dot_index].to_string(); let next_key = key[..dot_index].to_string();
let next_node = key[dot_index + 1..].to_string(); let next_node = key[dot_index + 1..].to_string();
let mut nested_value = SelectProcessor::recursive_parse_select(vec![&next_node]); let mut nested_value = SelectProcessor::parse_node(vec![&next_node]);
if output.contains_key(&next_key) { if output.contains_key(&next_key) {
let deep_map = output.get_mut(&next_key).unwrap().as_object_mut().unwrap(); let current_value = output.get_mut(&next_key).unwrap().as_object_mut().unwrap();
deep_map.append(nested_value.as_object_mut().unwrap()); current_value.append(nested_value.as_object_mut().unwrap());
} else { } else {
output.insert(next_key, nested_value); output.insert(next_key, nested_value);
} }
} else {
output.insert(key.to_string(), json!(key)); output.insert(key.to_string(), json!(key));
} }
} }

View File

@@ -10,7 +10,6 @@ mod select_processor_test {
}; };
use assert_json_diff::assert_json_include; use assert_json_diff::assert_json_include;
use serde_json::json; use serde_json::json;
use std::collections::HashMap;
pub fn initialize() -> Database { pub fn initialize() -> Database {
let cat_relations = let cat_relations =
@@ -39,9 +38,8 @@ mod select_processor_test {
let cat_table = database.get_table("Cats".to_string()).unwrap(); let cat_table = database.get_table("Cats".to_string()).unwrap();
let cat_1 = cat_table.find_by_pk(1u64).unwrap(); let cat_1 = cat_table.find_by_pk(1u64).unwrap();
let select = vec!["id".to_string(), "name".to_string(), "foods.*".to_string()]; let select = vec!["id", "name", "foods.*"];
let output = let output = SelectProcessor::selector(&database, &cat_table.name, cat_1, select);
SelectProcessor::selector(&database, &cat_table.name, cat_1, select, HashMap::new());
assert_json_include!( assert_json_include!(
actual: &output, actual: &output,
expected: expected:
@@ -59,9 +57,8 @@ mod select_processor_test {
let cat_table = database.get_table("Cats".to_string()).unwrap(); let cat_table = database.get_table("Cats".to_string()).unwrap();
let cat_1 = cat_table.find_by_pk(1u64).unwrap(); let cat_1 = cat_table.find_by_pk(1u64).unwrap();
let select = vec!["id".to_string(), "name".to_string(), "breed".to_string()]; let select = vec!["id", "name", "breed"];
let output = let output = SelectProcessor::selector(&database, &cat_table.name, cat_1, select);
SelectProcessor::selector(&database, &cat_table.name, cat_1, select, HashMap::new());
assert_json_include!( assert_json_include!(
actual: &output, actual: &output,
expected: &row!["id" => 1, "name" =>"Ozzy", "breed" => "mixed"] expected: &row!["id" => 1, "name" =>"Ozzy", "breed" => "mixed"]
@@ -73,9 +70,8 @@ mod select_processor_test {
let cat_table = database.get_table("Cats".to_string()).unwrap(); let cat_table = database.get_table("Cats".to_string()).unwrap();
let cat_1 = cat_table.find_by_pk(1u64).unwrap(); let cat_1 = cat_table.find_by_pk(1u64).unwrap();
let select = vec!["*".to_string()]; let select = vec!["*"];
let output = let output = SelectProcessor::selector(&database, &cat_table.name, cat_1, select);
SelectProcessor::selector(&database, &cat_table.name, cat_1, select, HashMap::new());
assert_json_include!( assert_json_include!(
actual: &output, actual: &output,
@@ -91,22 +87,37 @@ mod select_processor_test {
#[test] #[test]
fn should_parse_node() { fn should_parse_node() {
let output = SelectProcessor::recursive_parse_select(vec!["id","food","relation.*","relation.food.*"]); let output =
let json = serde_json::to_string_pretty(&output).unwrap(); SelectProcessor::parse_node(vec!["id", "food", "relation.*", "relation.food.*"]);
println!("{json}"); let json = serde_json::to_string_pretty(&output).unwrap();
assert_json_include!( assert_json_include!(
actual: &output, actual: &output,
expected: expected: &json!({
&json!({ "id": "id",
"id": "id", "food": "food",
"food": "food", "relation": {
"relation": { "*": "*",
"*": "*", "food": {
"food": { "*": "*"
"*": "*" }
} }
} })
}) );
}
#[test]
fn should_parse_node_one_level() {
let output = SelectProcessor::parse_node(vec!["id", "name", "foods.*"]);
let json = serde_json::to_string_pretty(&output).unwrap();
println!("{json}");
assert_json_include!(
actual: &output,
expected: &json!({
"id": "id",
"name":"name",
"foods": {
"*": "*",
}
})
); );
} }
} }