mirror of
https://github.com/eliasrenman/r-database.git
synced 2026-03-16 20:46:08 +01:00
chore: cleanup
This commit is contained in:
@@ -8,8 +8,8 @@ pub mod index;
|
|||||||
pub mod relation;
|
pub mod relation;
|
||||||
pub mod row;
|
pub mod row;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
pub mod select_processor;
|
pub mod query;
|
||||||
pub mod query_builder;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
|
|||||||
3
src/database/query/mod.rs
Normal file
3
src/database/query/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod select_processor;
|
||||||
|
pub mod query_builder;
|
||||||
|
pub mod select_parser;
|
||||||
28
src/database/query/select_parser.rs
Normal file
28
src/database/query/select_parser.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use serde_json::{Map, Value, json};
|
||||||
|
|
||||||
|
pub struct SelectParser {}
|
||||||
|
impl SelectParser {
|
||||||
|
pub fn parse_selector_recursive(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 = SelectParser::parse_selector_recursive(vec![&next_node]);
|
||||||
|
|
||||||
|
if output.contains_key(&next_key) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json!(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::database::relation::{OneToMany, OneToOne};
|
use crate::database::{relation::{OneToMany, OneToOne}, Database, row::Row, query::select_parser::SelectParser};
|
||||||
|
|
||||||
use super::{row::Row, Database};
|
|
||||||
|
|
||||||
pub struct SelectProcessor {}
|
pub struct SelectProcessor {}
|
||||||
|
|
||||||
@@ -17,7 +14,7 @@ impl SelectProcessor {
|
|||||||
row: &Row,
|
row: &Row,
|
||||||
select: Vec<&str>,
|
select: Vec<&str>,
|
||||||
) -> Map<String, Value> {
|
) -> Map<String, Value> {
|
||||||
let asd = SelectProcessor::parse_node(select);
|
let asd = SelectParser::parse_selector_recursive(select);
|
||||||
println!("Debugging parsed selector {asd}");
|
println!("Debugging parsed selector {asd}");
|
||||||
SelectProcessor::recursive_traverse_resolver(database, table_name, row, &asd)
|
SelectProcessor::recursive_traverse_resolver(database, table_name, row, &asd)
|
||||||
}
|
}
|
||||||
@@ -46,8 +43,9 @@ impl SelectProcessor {
|
|||||||
}
|
}
|
||||||
output.insert(key.to_owned(), json!(row_vec));
|
output.insert(key.to_owned(), json!(row_vec));
|
||||||
} else {
|
} else {
|
||||||
|
let foreign_row = relation_rows.as_object().unwrap();
|
||||||
let parsed_row = SelectProcessor::recursive_traverse_resolver(
|
let parsed_row = SelectProcessor::recursive_traverse_resolver(
|
||||||
database, table_name, &row, &value,
|
database, table_name, foreign_row, &value,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.insert(key.to_owned(), json!(parsed_row));
|
output.insert(key.to_owned(), json!(parsed_row));
|
||||||
@@ -101,28 +99,4 @@ impl SelectProcessor {
|
|||||||
fn is_valid_key(key: &str) -> bool {
|
fn is_valid_key(key: &str) -> bool {
|
||||||
key.chars().all(|c| c.is_ascii_lowercase() || c == '_')
|
key.chars().all(|c| c.is_ascii_lowercase() || c == '_')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_node(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::parse_node(vec![&next_node]);
|
|
||||||
|
|
||||||
if output.contains_key(&next_key) {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
json!(output)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,4 +2,5 @@ mod database_test;
|
|||||||
mod index_test;
|
mod index_test;
|
||||||
mod relation_test;
|
mod relation_test;
|
||||||
mod table_test;
|
mod table_test;
|
||||||
mod select_processor_test;
|
mod select_processor_test;
|
||||||
|
mod select_parser_test;
|
||||||
43
src/tests/select_parser_test.rs
Normal file
43
src/tests/select_parser_test.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod select_parser_test {
|
||||||
|
use crate::database::{
|
||||||
|
query::select_parser::SelectParser
|
||||||
|
};
|
||||||
|
use assert_json_diff::assert_json_include;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_selector_recursive() {
|
||||||
|
let output =
|
||||||
|
SelectParser::parse_selector_recursive(vec!["id", "food", "relation.*", "relation.food.*"]);
|
||||||
|
assert_json_include!(
|
||||||
|
actual: &output,
|
||||||
|
expected: &json!({
|
||||||
|
"id": "id",
|
||||||
|
"food": "food",
|
||||||
|
"relation": {
|
||||||
|
"*": "*",
|
||||||
|
"food": {
|
||||||
|
"*": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn should_parse_selector_recursive_one_level() {
|
||||||
|
let output = SelectParser::parse_selector_recursive(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": {
|
||||||
|
"*": "*",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,22 +3,23 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod select_processor_test {
|
mod select_processor_test {
|
||||||
use crate::database::{
|
use crate::database::{
|
||||||
relation::{OneToMany, Relation},
|
relation::{OneToMany, Relation, OneToOne},
|
||||||
select_processor::SelectProcessor,
|
|
||||||
table::Table,
|
table::Table,
|
||||||
Database,
|
Database, query::select_processor::SelectProcessor,
|
||||||
};
|
};
|
||||||
use assert_json_diff::assert_json_include;
|
use assert_json_diff::assert_json_include;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
pub fn initialize() -> Database {
|
pub fn initialize() -> Database {
|
||||||
let cat_relations =
|
let cat_relations =
|
||||||
hashmap!["cat_food" => Relation::new("Food".to_string(), "one_to_many".to_string())];
|
hashmap!["cat_food" => Relation::new("Food".to_string(), "one_to_many".to_string()),
|
||||||
|
"cat_age_group" => Relation::new("AgeGroup".to_string(), "one_to_one".to_string())];
|
||||||
let cat_table: Table = Table::new("Cats", "id", None, Some(cat_relations));
|
let cat_table: Table = Table::new("Cats", "id", None, Some(cat_relations));
|
||||||
|
|
||||||
let food_table: Table = Table::new("Food", "id", None, None);
|
let food_table: Table = Table::new("Food", "id", None, None);
|
||||||
|
let age_table: Table = Table::new("AgeGroup", "id", None, None);
|
||||||
|
|
||||||
let mut database: Database = Database::new(vec![cat_table, food_table]);
|
let mut database: Database = Database::new(vec![cat_table, food_table,age_table]);
|
||||||
|
|
||||||
_ = database
|
_ = database
|
||||||
.get_table_mut("Food".to_string())
|
.get_table_mut("Food".to_string())
|
||||||
@@ -28,7 +29,16 @@ mod select_processor_test {
|
|||||||
.get_table_mut("Food".to_string())
|
.get_table_mut("Food".to_string())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert_row(row!["id" => 12, "name" => "Dry Feed"]);
|
.insert_row(row!["id" => 12, "name" => "Dry Feed"]);
|
||||||
_ = database.get_table_mut("Cats".to_string()).unwrap().insert_row(row!["id" => 1, "name" => "Ozzy", "breed" => "mixed", "foods" => OneToMany::new(vec![123u64,12u64], "cat_food".to_string())]);
|
_ = database
|
||||||
|
.get_table_mut("AgeGroup".to_string())
|
||||||
|
.unwrap()
|
||||||
|
.insert_row(row!["id" => 99, "age" => "Young"]);
|
||||||
|
_ = database.get_table_mut("Cats".to_string()).unwrap().insert_row(row![
|
||||||
|
"id" => 1,
|
||||||
|
"name" => "Ozzy",
|
||||||
|
"breed" => "mixed",
|
||||||
|
"foods" => OneToMany::new(vec![123u64,12u64], "cat_food".to_string()),
|
||||||
|
"group" => OneToOne::new(99,"cat_age_group".to_string())]);
|
||||||
|
|
||||||
return database;
|
return database;
|
||||||
}
|
}
|
||||||
@@ -51,6 +61,22 @@ mod select_processor_test {
|
|||||||
]]
|
]]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn should_succed_select_processor_one_level_resolved_onetoone() {
|
||||||
|
let database = initialize();
|
||||||
|
|
||||||
|
let cat_table = database.get_table("Cats".to_string()).unwrap();
|
||||||
|
let cat_1 = cat_table.find_by_pk(1u64).unwrap();
|
||||||
|
let select = vec!["id", "name", "group.age"];
|
||||||
|
let output = SelectProcessor::selector(&database, &cat_table.name, cat_1, select);
|
||||||
|
assert_json_include!(
|
||||||
|
actual: &output,
|
||||||
|
expected:
|
||||||
|
&row!["id" => 1, "name" =>"Ozzy", "group"=> row![
|
||||||
|
"age" => "Young"
|
||||||
|
]]
|
||||||
|
);
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_succed_select_processor_zero_level_resolved() {
|
fn should_succed_select_processor_zero_level_resolved() {
|
||||||
let database = initialize();
|
let database = initialize();
|
||||||
@@ -84,40 +110,4 @@ mod select_processor_test {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_parse_node() {
|
|
||||||
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