use serde_json::json;
use rust_store_core::schema::{Location, Registry};
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),
}
}
fn order_defn() -> serde_json::Value {
json!({
"name": "Order", "collection": "orders", "timestamps": false,
"fields": { "code": { "type": "string" } },
"relations": {}
})
}
fn replica_defn() -> serde_json::Value {
json!({ "name": "Order", "replica": true })
}
#[test]
fn a1_duplicate_primary_in_batch_errors() {
let mut r = Registry::new();
let items = vec![
(order_defn(), loc("mongo_main", Some("sales_db"), None)),
(order_defn(), loc("mongo_main", Some("analytics_db"), None)),
];
let err = r
.register_batch(&items, None)
.expect_err("同批两个同名主定义应报错");
assert!(err.contains("同名主定义重复"), "错误信息异常: {}", err);
assert!(!r.has("Order"));
assert!(r.list().is_empty());
}
#[test]
fn a1_cross_batch_reload_bumps_version() {
let mut r = Registry::new();
r.register_batch(
&[(order_defn(), loc("mongo_main", Some("sales_db"), None))],
None,
)
.unwrap();
assert_eq!(r.version_of("Order").unwrap(), 1);
r.register_batch(
&[(order_defn(), loc("mongo_main", Some("sales_db"), None))],
None,
)
.unwrap();
assert_eq!(r.version_of("Order").unwrap(), 2);
assert_eq!(
r.list(),
vec!["Order".to_string(), "OrderDeleted".to_string()]
);
}
#[test]
fn a3_primary_plus_replica_makes_links() {
let mut r = Registry::new();
let items = vec![
(order_defn(), loc("mongo_main", Some("sales_db"), None)),
(
replica_defn(),
loc("mongo_main", Some("analytics_db"), None),
),
];
r.register_batch(&items, None).unwrap();
let links = r.links_of("Order").unwrap();
assert_eq!(links.len(), 2, "主 + 从 = 两条链路");
assert_eq!(
links[0].database.as_deref(),
Some("sales_db"),
"links[0] 恒为主"
);
assert_eq!(links[1].database.as_deref(), Some("analytics_db"));
assert_eq!(
r.list(),
vec!["Order".to_string(), "OrderDeleted".to_string()]
);
assert_eq!(
r.primary_location("Order").unwrap().database.as_deref(),
Some("sales_db")
);
assert_eq!(r.get("Order").unwrap().database(), Some("sales_db"));
}
#[test]
fn a3_replica_without_primary_or_existing_errors() {
let mut r = Registry::new();
let err = r
.register_batch(
&[(
replica_defn(),
loc("mongo_main", Some("analytics_db"), None),
)],
None,
)
.expect_err("无主定义的从定义应报错");
assert!(err.contains("未找到主 schema"), "错误信息异常: {}", err);
}
#[test]
fn a3_replica_appends_link_to_existing_across_batch() {
let mut r = Registry::new();
r.register_batch(
&[(order_defn(), loc("mongo_main", Some("sales_db"), None))],
None,
)
.unwrap();
assert_eq!(r.links_of("Order").unwrap().len(), 1);
r.register_batch(
&[(
replica_defn(),
loc("mongo_main", Some("analytics_db"), None),
)],
None,
)
.unwrap();
assert_eq!(r.links_of("Order").unwrap().len(), 2);
assert_eq!(r.version_of("Order").unwrap(), 2);
}
#[test]
fn get_by_location_four_tuple_hits_any_link() {
let mut r = Registry::new();
r.register_batch(
&[
(order_defn(), loc("mongo_main", Some("sales_db"), None)),
(
replica_defn(),
loc("mongo_main", Some("analytics_db"), None),
),
],
None,
)
.unwrap();
assert!(r
.get_by_location("mongo_main", Some("sales_db"), None, "orders")
.is_ok());
assert!(r
.get_by_location("mongo_main", Some("analytics_db"), None, "orders")
.is_ok());
assert!(r
.get_by_location("mongo_main", Some("other_db"), None, "orders")
.is_err());
}
#[test]
fn location_conflict_across_names_errors() {
let mut r = Registry::new();
let items = vec![
(
json!({ "name": "A", "collection": "dup", "timestamps": false }),
loc("s", Some("db"), None),
),
(
json!({ "name": "B", "collection": "dup", "timestamps": false }),
loc("s", Some("db"), None),
),
];
let err = r
.register_batch(&items, None)
.expect_err("跨名占用同一四元组应报错");
assert!(err.contains("定位冲突"), "错误信息异常: {}", err);
assert!(!r.has("A") && !r.has("B"), "零副作用");
}
#[test]
fn default_source_is_none_and_pg_schema_layer_kept() {
let mut r = Registry::new();
r.register_batch(
&[
(
json!({ "name": "U", "collection": "u", "timestamps": false }),
Location::default(),
),
(
json!({ "name": "C", "collection": "c", "timestamps": false }),
loc("pg1", Some("app_db"), Some("app")),
),
],
None,
)
.unwrap();
assert_eq!(r.get("U").unwrap().source(), "default");
assert!(r.get("U").unwrap().source.is_none());
let c = r.get("C").unwrap();
assert_eq!(c.source(), "pg1");
assert_eq!(c.database(), Some("app_db"));
assert_eq!(c.schema(), Some("app"));
}