use serde_json::{json, Value};
use rust_store_core::schema::{LoadConfig, Location, Registry, Role};
fn loc(source: &str, database: Option<&str>, schema: Option<&str>) -> Location {
Location {
source: source.to_string(),
database: database.map(String::from),
schema: schema.map(String::from),
role: None,
priority: None,
}
}
fn order_defn() -> Value {
json!({
"name": "Order", "collection": "orders", "timestamps": false,
"fields": { "code": { "type": "string" } },
"relations": {}
})
}
fn replica_defn() -> Value {
json!({ "name": "Order", "replica": true })
}
fn item_defn() -> Value {
json!({ "name": "Item", "collection": "items", "timestamps": false })
}
fn cfg(links: Value) -> LoadConfig {
LoadConfig::from_json(&json!({
"sources": {
"mongoMain": { "kind": "mongodb", "databases": ["sales_db"] },
"mongoAlt": { "kind": "mongodb", "databases": ["analytics_db"] },
"mongoCache": { "kind": "mongodb", "databases": ["cache_db"] }
},
"defs": ["schema"],
"links": links
}))
.expect("配置应可解析")
}
#[test]
fn apply_link_decls_attaches_and_appends() {
let mut r = Registry::new();
r.register_batch(
&[
(order_defn(), loc("mongoMain", Some("sales_db"), None)),
(replica_defn(), loc("mongoAlt", Some("analytics_db"), None)),
],
None,
)
.unwrap();
assert_eq!(r.links_of("Order").unwrap().len(), 2);
assert!(r
.links_of("Order")
.unwrap()
.iter()
.all(|l| l.role.is_none()));
let c = cfg(json!({
"Order": [
{ "source": "mongoCache", "database": "cache_db", "role": "cache", "priority": 5 },
{ "source": "mongoMain", "database": "sales_db", "role": "primary", "priority": 1 }
]
}));
r.apply_link_decls(&c).expect("装配应成功");
let links = r.links_of("Order").unwrap();
assert_eq!(links.len(), 3, "命中 2 条 + 追加 1 条");
assert_eq!(links[0].source, "mongoMain");
assert_eq!(links[0].database.as_deref(), Some("sales_db"));
assert_eq!(links[0].role, Some(Role::Primary));
assert_eq!(links[0].priority, Some(1));
assert_eq!(links[1].database.as_deref(), Some("analytics_db"));
assert_eq!(links[1].role, None);
assert_eq!(links[1].priority, None);
assert_eq!(links[2].source, "mongoCache");
assert_eq!(links[2].database.as_deref(), Some("cache_db"));
assert_eq!(links[2].role, Some(Role::Cache));
assert_eq!(links[2].priority, Some(5));
assert_eq!(r.links_of("OrderDeleted").unwrap(), links);
assert_eq!(r.version_of("Order").unwrap(), 1);
}
#[test]
fn apply_link_decls_leaves_undeclared_entries_untouched() {
let mut r = Registry::new();
r.register_batch(
&[
(order_defn(), loc("mongoMain", Some("sales_db"), None)),
(item_defn(), loc("mongoAlt", Some("analytics_db"), None)),
],
None,
)
.unwrap();
let c = cfg(json!({
"Order": [
{ "source": "mongoMain", "database": "sales_db", "role": "primary", "priority": 2 }
]
}));
r.apply_link_decls(&c).unwrap();
assert_eq!(r.links_of("Order").unwrap()[0].role, Some(Role::Primary));
assert_eq!(r.links_of("Order").unwrap()[0].priority, Some(2));
let item = r.links_of("Item").unwrap();
assert_eq!(item.len(), 1);
assert_eq!(item[0].database.as_deref(), Some("analytics_db"));
assert_eq!(item[0].role, None);
assert_eq!(item[0].priority, None);
assert_eq!(r.links_of("ItemDeleted").unwrap()[0].role, None);
}
#[test]
fn apply_link_decls_rejects_unknown_schema() {
let mut r = Registry::new();
r.register_batch(
&[(order_defn(), loc("mongoMain", Some("sales_db"), None))],
None,
)
.unwrap();
let c = cfg(json!({
"Ghost": [
{ "source": "mongoMain", "database": "sales_db", "role": "primary" }
]
}));
let err = r
.apply_link_decls(&c)
.expect_err("引用未注册 schema 应报错");
assert!(err.contains("未注册 schema"), "错误信息异常: {err}");
assert_eq!(r.links_of("Order").unwrap()[0].role, None);
assert!(!r.has("Ghost"));
}
#[test]
fn apply_link_decls_empty_is_noop() {
let mut r = Registry::new();
r.register_batch(
&[(order_defn(), loc("mongoMain", Some("sales_db"), None))],
None,
)
.unwrap();
let c = LoadConfig::from_json(&json!({
"sources": { "mongoMain": { "kind": "mongodb", "databases": ["sales_db"] } },
"defs": ["schema"]
}))
.unwrap();
r.apply_link_decls(&c).unwrap();
assert_eq!(r.links_of("Order").unwrap()[0].role, None);
}