diff --git a/src/database/select_processor.rs b/src/database/select_processor.rs index d6222ad..043b4d6 100644 --- a/src/database/select_processor.rs +++ b/src/database/select_processor.rs @@ -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, mut output: HashMap) -> HashMap { + // 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 = 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, + mut output: HashMap, + ) -> HashMap { + for value in select { + let key = value.to_string(); + if (key.eq("*")) { + return row.clone(); // recursive call + } else if (key.contains(".")) { + let split: Vec = 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 { + 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 { - 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 == '_') } - } -} \ No newline at end of file + + 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) + } +} diff --git a/src/tests/select_processor_test.rs b/src/tests/select_processor_test.rs index a369349..d1e4bd7 100644 --- a/src/tests/select_processor_test.rs +++ b/src/tests/select_processor_test.rs @@ -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": { + "*": "*" + } + } + }) + ); + } }