mirror of
https://github.com/eliasrenman/r-database.git
synced 2026-03-16 20:46:08 +01:00
feat: select processor
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
"*": "*",
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user