mirror of
https://github.com/eliasrenman/r-database.git
synced 2026-03-16 20:46:08 +01:00
feat: added test for recursive select parser
This commit is contained in:
@@ -1,14 +1,12 @@
|
|||||||
use std::{borrow::Borrow, collections::HashMap, str::FromStr};
|
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};
|
use super::{row::Row, table::Table, Database};
|
||||||
|
|
||||||
pub struct SelectProcessor {
|
pub struct SelectProcessor {}
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
{
|
{
|
||||||
select: [
|
select: [
|
||||||
@@ -27,53 +25,94 @@ pub struct SelectProcessor {
|
|||||||
//
|
//
|
||||||
*/
|
*/
|
||||||
impl SelectProcessor {
|
impl SelectProcessor {
|
||||||
// recursively select relations
|
// recursively select relations
|
||||||
|
|
||||||
pub fn selector(database: &Database, table_name: &String, row: &Row, select: Vec<String>, mut output: HashMap<String,Value>) -> HashMap<String,Value> {
|
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();
|
||||||
|
|
||||||
for value in select {
|
if (split.len() == 2 && split[1].eq("*")) {
|
||||||
let key = value.to_string();
|
let relation_rows =
|
||||||
if(key.eq("*")) {
|
SelectProcessor::resolve_relation(database, table_name, row, &split[0]);
|
||||||
return row.clone();// recursive call
|
output.insert(split[0].clone(), json!(relation_rows));
|
||||||
}
|
}
|
||||||
else if(key.contains(".")) {
|
// recursive call
|
||||||
let split: Vec<String> = key.split(".").map(|part| String::from_str(part).unwrap()).collect();
|
} else {
|
||||||
|
let value = row.get(&key);
|
||||||
if(split.len() == 2 && split[1].eq("*")) {
|
match value.is_some() {
|
||||||
let relation_rows = SelectProcessor::resolve_relation(database, table_name, row, &split[0]);
|
true => output.insert(key, value.unwrap().to_owned()),
|
||||||
output.insert(split[0].clone(), json!(relation_rows));
|
false => panic!("Failed to read key: {key} on table: {table_name}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// recursive call
|
return output;
|
||||||
} 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}"),
|
|
||||||
|
|
||||||
|
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> {
|
fn is_valid_key(key: &str) -> bool {
|
||||||
let table = database.get_table(table_name.clone()).unwrap();
|
key.chars().all(|c| c.is_ascii_lowercase() || c == '_')
|
||||||
|
}
|
||||||
println!("Attempting to find relation for '{key}' in table: '{table_name}'");
|
|
||||||
|
pub fn recursive_parse_select(node: Vec<&str>) -> Value {
|
||||||
|
let mut output = Map::new();
|
||||||
let value = row.get(key).unwrap();
|
|
||||||
let relation_name = match value.get("relation_name") {
|
for key in node {
|
||||||
Some(val) => String::from(val.as_str().unwrap()),
|
if let Some(dot_index) = key.find('.') {
|
||||||
None => panic!("Value was not a valid relation")
|
let next_key = key[..dot_index].to_string();
|
||||||
};
|
let next_node = key[dot_index + 1..].to_string();
|
||||||
let relation = table.get_relation(&relation_name).unwrap();
|
|
||||||
let relation_variation = relation.variation.as_str();
|
let mut nested_value = SelectProcessor::recursive_parse_select(vec![&next_node]);
|
||||||
return match relation_variation {
|
|
||||||
"one_to_one" => vec![OneToOne::from_value(value.to_owned()).get(table_name.clone(), database).unwrap()],
|
if output.contains_key(&next_key) {
|
||||||
"one_to_many" => OneToMany::from_value(value.to_owned()).get(table_name.clone(), database).unwrap(),
|
let deep_map = output.get_mut(&next_key).unwrap().as_object_mut().unwrap();
|
||||||
other => panic!("Unsupported relationship type: {other}")
|
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)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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": {
|
||||||
|
"*": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user