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 super::{row::Row, table::Table, Database};
use super::{row::Row, Database};
pub struct SelectProcessor {}
/**
{
select: [
"id",
"name",
"relation.*"
]
}
{
select: [
"id",
"name",
"relation.id"
]
}
//
*/
impl SelectProcessor {
// recursively select relations
@@ -31,31 +15,56 @@ impl SelectProcessor {
database: &Database,
table_name: &String,
row: &Row,
select: Vec<String>,
mut output: HashMap<String, Value>,
select: Vec<&str>,
) -> 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();
let asd = SelectProcessor::parse_node(select);
println!("Debugging parsed selector {asd}");
SelectProcessor::recursive_traverse_resolver(database, table_name, row, &asd)
}
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));
fn recursive_traverse_resolver(
database: &Database,
table_name: &String,
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 {
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}"),
};
if value.as_str().unwrap() == "*" {
output = row.to_owned();
} else {
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;
@@ -66,7 +75,7 @@ impl SelectProcessor {
table_name: &String,
row: &Row,
key: &String,
) -> Vec<Row> {
) -> Value {
let table = database.get_table(table_name.clone()).unwrap();
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_variation = relation.variation.as_str();
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)
.unwrap()],
"one_to_many" => OneToMany::from_value(value.to_owned())
.unwrap()),
"one_to_many" => json!(OneToMany::from_value(value.to_owned())
.get(table_name.clone(), database)
.unwrap(),
.unwrap()),
other => panic!("Unsupported relationship type: {other}"),
};
}
@@ -93,7 +102,7 @@ impl SelectProcessor {
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();
for key in node {
@@ -101,14 +110,15 @@ impl SelectProcessor {
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]);
let mut nested_value = SelectProcessor::parse_node(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());
let current_value = output.get_mut(&next_key).unwrap().as_object_mut().unwrap();
current_value.append(nested_value.as_object_mut().unwrap());
} else {
output.insert(next_key, nested_value);
}
} else {
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 serde_json::json;
use std::collections::HashMap;
pub fn initialize() -> Database {
let cat_relations =
@@ -39,9 +38,8 @@ mod select_processor_test {
let cat_table = database.get_table("Cats".to_string()).unwrap();
let cat_1 = cat_table.find_by_pk(1u64).unwrap();
let select = vec!["id".to_string(), "name".to_string(), "foods.*".to_string()];
let output =
SelectProcessor::selector(&database, &cat_table.name, cat_1, select, HashMap::new());
let select = vec!["id", "name", "foods.*"];
let output = SelectProcessor::selector(&database, &cat_table.name, cat_1, select);
assert_json_include!(
actual: &output,
expected:
@@ -59,9 +57,8 @@ mod select_processor_test {
let cat_table = database.get_table("Cats".to_string()).unwrap();
let cat_1 = cat_table.find_by_pk(1u64).unwrap();
let select = vec!["id".to_string(), "name".to_string(), "breed".to_string()];
let output =
SelectProcessor::selector(&database, &cat_table.name, cat_1, select, HashMap::new());
let select = vec!["id", "name", "breed"];
let output = SelectProcessor::selector(&database, &cat_table.name, cat_1, select);
assert_json_include!(
actual: &output,
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_1 = cat_table.find_by_pk(1u64).unwrap();
let select = vec!["*".to_string()];
let output =
SelectProcessor::selector(&database, &cat_table.name, cat_1, select, HashMap::new());
let select = vec!["*"];
let output = SelectProcessor::selector(&database, &cat_table.name, cat_1, select);
assert_json_include!(
actual: &output,
@@ -91,22 +87,37 @@ 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": {
"*": "*"
}
}
})
let output =
SelectProcessor::parse_node(vec!["id", "food", "relation.*", "relation.food.*"]);
let json = serde_json::to_string_pretty(&output).unwrap();
assert_json_include!(
actual: &output,
expected: &json!({
"id": "id",
"food": "food",
"relation": {
"*": "*",
"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": {
"*": "*",
}
})
);
}
}