use serde_json::{json, Value};
use std::collections::HashMap;
#[test]
fn test_iterative_stitch_simple_path() {
let mut item = json!({
"id": "user1",
"name": "Test",
"profile": {
"avatar_id": "avatar123",
"bio": "Test bio"
}
});
let mut rel_map = HashMap::new();
rel_map.insert(
"table:avatar:avatar123".to_string(),
json!({
"id": "avatar123",
"url": "https://example.com/avatar.png"
})
);
stitch_test_helper(
&mut item,
&["profile", "avatar_id"],
&["profile", "avatar"],
&rel_map,
"avatar"
);
assert!(item["profile"]["avatar"].is_object());
assert_eq!(item["profile"]["avatar"]["url"], "https://example.com/avatar.png");
}
#[test]
fn test_iterative_stitch_deeply_nested() {
let mut item = json!({
"id": "user1",
"profile": {
"settings": {
"theme_id": "theme456",
"notifications": true
}
}
});
let mut rel_map = HashMap::new();
rel_map.insert(
"table:theme:theme456".to_string(),
json!({
"id": "theme456",
"name": "Dark Mode",
"colors": ["#000", "#FFF"]
})
);
stitch_test_helper(
&mut item,
&["profile", "settings", "theme_id"],
&["profile", "settings", "theme"],
&rel_map,
"theme"
);
assert!(item["profile"]["settings"]["theme"].is_object());
assert_eq!(item["profile"]["settings"]["theme"]["name"], "Dark Mode");
}
#[test]
fn test_iterative_stitch_array() {
let mut item = json!({
"id": "post1",
"title": "Test Post",
"tag_ids": ["tag1", "tag2", "tag3"]
});
let mut rel_map = HashMap::new();
rel_map.insert(
"table:tag:tag1".to_string(),
json!({"id": "tag1", "name": "rust"})
);
rel_map.insert(
"table:tag:tag2".to_string(),
json!({"id": "tag2", "name": "programming"})
);
rel_map.insert(
"table:tag:tag3".to_string(),
json!({"id": "tag3", "name": "tutorial"})
);
stitch_test_helper(
&mut item,
&["tag_ids"],
&["tags"],
&rel_map,
"tag"
);
assert!(item["tags"].is_array());
let tags = item["tags"].as_array().unwrap();
assert_eq!(tags.len(), 3);
assert_eq!(tags[0]["name"], "rust");
assert_eq!(tags[1]["name"], "programming");
assert_eq!(tags[2]["name"], "tutorial");
}
#[test]
fn test_iterative_stitch_nested_arrays() {
let mut item = json!({
"departments": [
{
"name": "Engineering",
"manager_id": "user1"
},
{
"name": "Sales",
"manager_id": "user2"
}
]
});
let mut rel_map = HashMap::new();
rel_map.insert(
"table:user:user1".to_string(),
json!({"id": "user1", "name": "Alice"})
);
rel_map.insert(
"table:user:user2".to_string(),
json!({"id": "user2", "name": "Bob"})
);
stitch_test_helper(
&mut item,
&["departments", "manager_id"],
&["departments", "manager"],
&rel_map,
"user"
);
assert!(item["departments"][0]["manager"].is_object());
assert_eq!(item["departments"][0]["manager"]["name"], "Alice");
assert!(item["departments"][1]["manager"].is_object());
assert_eq!(item["departments"][1]["manager"]["name"], "Bob");
}
#[test]
fn test_extremely_deep_nesting() {
let mut item = json!({
"level1": {
"level2": {
"level3": {
"level4": {
"level5": {
"level6": {
"level7": {
"level8": {
"level9": {
"deep_id": "deepvalue123"
}
}
}
}
}
}
}
}
}
});
let mut rel_map = HashMap::new();
rel_map.insert(
"table:deepmodel:deepvalue123".to_string(),
json!({
"id": "deepvalue123",
"data": "Successfully found at depth 9!"
})
);
stitch_test_helper(
&mut item,
&["level1", "level2", "level3", "level4", "level5", "level6", "level7", "level8", "level9", "deep_id"],
&["level1", "level2", "level3", "level4", "level5", "level6", "level7", "level8", "level9", "deep_obj"],
&rel_map,
"deepmodel"
);
assert!(item["level1"]["level2"]["level3"]["level4"]["level5"]["level6"]["level7"]["level8"]["level9"]["deep_obj"].is_object());
assert_eq!(
item["level1"]["level2"]["level3"]["level4"]["level5"]["level6"]["level7"]["level8"]["level9"]["deep_obj"]["data"],
"Successfully found at depth 9!"
);
}
#[test]
fn test_mixed_arrays_and_objects() {
let mut item = json!({
"company": {
"departments": [
{
"teams": [
{
"members": [
{"name": "John", "mentor_id": "senior1"},
{"name": "Jane", "mentor_id": "senior2"}
]
},
{
"members": [
{"name": "Bob", "mentor_id": "senior3"}
]
}
]
}
]
}
});
let mut rel_map = HashMap::new();
rel_map.insert("table:employee:senior1".to_string(), json!({"id": "senior1", "name": "Senior Dev 1"}));
rel_map.insert("table:employee:senior2".to_string(), json!({"id": "senior2", "name": "Senior Dev 2"}));
rel_map.insert("table:employee:senior3".to_string(), json!({"id": "senior3", "name": "Senior Dev 3"}));
stitch_test_helper(
&mut item,
&["company", "departments", "teams", "members", "mentor_id"],
&["company", "departments", "teams", "members", "mentor"],
&rel_map,
"employee"
);
let dept = &item["company"]["departments"][0];
assert_eq!(dept["teams"][0]["members"][0]["mentor"]["name"], "Senior Dev 1");
assert_eq!(dept["teams"][0]["members"][1]["mentor"]["name"], "Senior Dev 2");
assert_eq!(dept["teams"][1]["members"][0]["mentor"]["name"], "Senior Dev 3");
}
#[test]
fn test_no_matching_ids() {
let mut item = json!({
"user": {
"profile": {
"avatar_id": "nonexistent123"
}
}
});
let rel_map = HashMap::new();
stitch_test_helper(
&mut item,
&["user", "profile", "avatar_id"],
&["user", "profile", "avatar"],
&rel_map,
"avatar"
);
assert!(!item["user"]["profile"].get("avatar").is_some());
assert_eq!(item["user"]["profile"]["avatar_id"], "nonexistent123");
}
#[test]
fn test_partial_path_mismatch() {
let mut item = json!({
"user": {
"profile": {
"settings": {
"theme_id": "dark"
}
}
}
});
let mut rel_map = HashMap::new();
rel_map.insert("table:theme:dark".to_string(), json!({"id": "dark", "name": "Dark Theme"}));
stitch_test_helper(
&mut item,
&["user", "preferences", "theme_id"], &["user", "preferences", "theme"],
&rel_map,
"theme"
);
assert!(!item["user"]["preferences"].is_object());
}
#[test]
fn test_verify_stack_ordering() {
let mut item = json!({
"items": [
{"id": "1", "ref_id": "ref1"},
{"id": "2", "ref_id": "ref2"},
{"id": "3", "ref_id": "ref3"}
]
});
let mut rel_map = HashMap::new();
for i in 1..=3 {
rel_map.insert(
format!("table:ref:ref{}", i),
json!({"id": format!("ref{}", i), "order": i})
);
}
stitch_test_helper(
&mut item,
&["items", "ref_id"],
&["items", "ref"],
&rel_map,
"ref"
);
assert_eq!(item["items"][0]["ref"]["order"], 1);
assert_eq!(item["items"][1]["ref"]["order"], 2);
assert_eq!(item["items"][2]["ref"]["order"], 3);
}
#[test]
fn test_null_and_missing_values() {
let mut item = json!({
"items": [
{
"name": "item1",
"ref_id": null },
{
"name": "item2"
},
{
"name": "item3",
"ref_id": "valid123"
}
]
});
let mut rel_map = HashMap::new();
rel_map.insert(
"table:ref:valid123".to_string(),
json!({"id": "valid123", "data": "Valid reference"})
);
stitch_test_helper(
&mut item,
&["items", "ref_id"],
&["items", "ref"],
&rel_map,
"ref"
);
assert!(!item["items"][0].get("ref").is_some());
assert!(!item["items"][1].get("ref").is_some());
assert!(item["items"][2]["ref"].is_object());
assert_eq!(item["items"][2]["ref"]["data"], "Valid reference");
}
#[test]
fn test_multiple_arrays_at_different_depths() {
let mut item = json!({
"regions": [
{
"name": "North",
"stores": [
{
"departments": [
{"name": "Electronics", "manager_id": "mgr1"},
{"name": "Clothing", "manager_id": "mgr2"}
]
},
{
"departments": [
{"name": "Food", "manager_id": "mgr3"}
]
}
]
},
{
"name": "South",
"stores": [
{
"departments": [
{"name": "Books", "manager_id": "mgr4"}
]
}
]
}
]
});
let mut rel_map = HashMap::new();
for i in 1..=4 {
rel_map.insert(
format!("table:manager:mgr{}", i),
json!({"id": format!("mgr{}", i), "name": format!("Manager {}", i)})
);
}
stitch_test_helper(
&mut item,
&["regions", "stores", "departments", "manager_id"],
&["regions", "stores", "departments", "manager"],
&rel_map,
"manager"
);
assert_eq!(item["regions"][0]["stores"][0]["departments"][0]["manager"]["name"], "Manager 1");
assert_eq!(item["regions"][0]["stores"][0]["departments"][1]["manager"]["name"], "Manager 2");
assert_eq!(item["regions"][0]["stores"][1]["departments"][0]["manager"]["name"], "Manager 3");
assert_eq!(item["regions"][1]["stores"][0]["departments"][0]["manager"]["name"], "Manager 4");
}
fn stitch_test_helper(
root_node: &mut Value,
source_path: &[&str],
dest_path: &[&str],
rel_map: &HashMap<String, Value>,
model: &str,
) {
struct WorkItem {
source_path_idx: usize,
dest_path_idx: usize,
json_path: Vec<String>,
}
let mut stack = Vec::new();
stack.push(WorkItem {
source_path_idx: 0,
dest_path_idx: 0,
json_path: Vec::new(),
});
while let Some(work_item) = stack.pop() {
let source_remaining = source_path.len() - work_item.source_path_idx;
let dest_remaining = dest_path.len() - work_item.dest_path_idx;
if source_remaining == 1 && dest_remaining == 1 {
let source_key = source_path[work_item.source_path_idx];
let dest_key = dest_path[work_item.dest_path_idx];
if let Some(current_node) = get_mut_at_path(root_node, &work_item.json_path) {
if let Some(obj_to_modify) = current_node.as_object_mut() {
if let Some(id_val_at_source_key) = obj_to_modify.get(source_key) {
if let Some(id_str) = id_val_at_source_key.as_str() {
let rel_lookup_key = format!("table:{}:{}", model, id_str);
if let Some(related_data) = rel_map.get(&rel_lookup_key) {
obj_to_modify.insert(dest_key.to_string(), related_data.clone());
}
} else if let Some(ids_array) = id_val_at_source_key.as_array() {
let mut stitched_related_items_array = Vec::new();
for id_elem_in_array in ids_array {
if let Some(id_str_elem) = id_elem_in_array.as_str() {
let rel_lookup_key =
format!("table:{}:{}", model, id_str_elem);
if let Some(related_data) = rel_map.get(&rel_lookup_key) {
stitched_related_items_array.push(related_data.clone());
}
}
}
obj_to_modify.insert(
dest_key.to_string(),
Value::Array(stitched_related_items_array),
);
}
}
}
}
continue;
}
if source_remaining > 0
&& dest_remaining > 0
&& source_path[work_item.source_path_idx] == dest_path[work_item.dest_path_idx]
{
let common_key = source_path[work_item.source_path_idx];
if let Some(current_node) = get_mut_at_path(root_node, &work_item.json_path) {
if let Some(next_json_node_candidate) = current_node.get_mut(common_key) {
match next_json_node_candidate {
Value::Object(_) => {
let mut new_path = work_item.json_path.clone();
new_path.push(common_key.to_string());
stack.push(WorkItem {
source_path_idx: work_item.source_path_idx + 1,
dest_path_idx: work_item.dest_path_idx + 1,
json_path: new_path,
});
}
Value::Array(arr) => {
for (idx, _) in arr.iter().enumerate().rev() {
let mut new_path = work_item.json_path.clone();
new_path.push(common_key.to_string());
new_path.push(idx.to_string());
stack.push(WorkItem {
source_path_idx: work_item.source_path_idx + 1,
dest_path_idx: work_item.dest_path_idx + 1,
json_path: new_path,
});
}
}
_ => {}
}
}
}
}
}
}
fn get_mut_at_path<'a>(root: &'a mut Value, path: &[String]) -> Option<&'a mut Value> {
let mut current = root;
for segment in path {
if let Ok(index) = segment.parse::<usize>() {
current = current.get_mut(index)?;
} else {
current = current.get_mut(segment)?;
}
}
Some(current)
}