Skip to main content

rust_store_core/dialect/
overlay.rs

1//! introspection 结果 ↔ 本地覆盖 合并(permission + compute)
2
3use serde_json::{Map, Value};
4
5/// 把 base(introspection 生成的 schemaJSON 数组)与 overlay(本地键控 schemaJSON 数组)
6/// 合并:相同 model 名的 def 做字段/关系并集,read/write 与 computes 由 overlay 覆盖。
7///
8/// overlay 中名字匹配到 base 的 def 才合并;未出现在 base 的新 model 也会保留(纯新增)。
9pub fn merge_schema(base: &Value, overlay: &Value) -> Result<Value, String> {
10    let base_arr = base.as_array().cloned().unwrap_or_default();
11    let overlay_arr = overlay.as_array().cloned().unwrap_or_default();
12
13    // base 按 model 名索引
14    let mut out: Vec<Value> = Vec::new();
15    for b in &base_arr {
16        let name = b
17            .get("name")
18            .and_then(|v| v.as_str())
19            .unwrap_or("")
20            .to_string();
21        let over = overlay_arr
22            .iter()
23            .find(|o| o.get("name").and_then(|v| v.as_str()) == Some(name.as_str()));
24        out.push(match over {
25            Some(o) => merge_one(b, o)?,
26            None => b.clone(),
27        });
28    }
29    // overlay 中 base 没有的新 model
30    for o in &overlay_arr {
31        let name = o
32            .get("name")
33            .and_then(|v| v.as_str())
34            .unwrap_or("")
35            .to_string();
36        let exists = base_arr
37            .iter()
38            .any(|b| b.get("name").and_then(|v| v.as_str()) == Some(name.as_str()));
39        if !exists {
40            out.push(o.clone());
41        }
42    }
43    Ok(Value::Array(out))
44}
45
46/// 合并单个 schema def:fields/relations 并集,read/write/computes/indexes overlay 覆盖
47fn merge_one(base: &Value, overlay: &Value) -> Result<Value, String> {
48    let mut out = base.clone();
49    let b = base.as_object().cloned().unwrap_or_default();
50    let b_fields = b
51        .get("fields")
52        .and_then(|f| f.as_object())
53        .cloned()
54        .unwrap_or_default();
55    let b_rels = b
56        .get("relations")
57        .and_then(|f| f.as_object())
58        .cloned()
59        .unwrap_or_default();
60
61    if let Some(o) = overlay.as_object() {
62        // 字段并集
63        let mut all_fields = b_fields;
64        if let Some(of) = o.get("fields").and_then(|f| f.as_object()) {
65            for (k, v) in of {
66                all_fields.insert(k.clone(), v.clone());
67            }
68        }
69        if let Some(rel_obj) = out.get_mut("fields") {
70            *rel_obj = Value::Object(all_fields);
71        }
72
73        // 关系并集
74        let mut all_rels = b_rels;
75        if let Some(or) = o.get("relations").and_then(|f| f.as_object()) {
76            for (k, v) in or {
77                all_rels.insert(k.clone(), v.clone());
78            }
79        }
80        if let Some(rel_obj) = out.get_mut("relations") {
81            *rel_obj = Value::Object(all_rels);
82        }
83
84        // 覆盖标量字段
85        for key in ["read", "write", "idPrefix", "collection"] {
86            if let Some(v) = o.get(key) {
87                if let Some(target) = out.get_mut(key) {
88                    *target = v.clone();
89                } else {
90                    out.as_object_mut()
91                        .map(|m| m.insert(key.to_string(), v.clone()));
92                }
93            }
94        }
95
96        // overlay 优先的 computes / indexes
97        if let Some(c) = o.get("computes") {
98            out.as_object_mut()
99                .map(|m| m.insert("computes".to_string(), c.clone()));
100        }
101        if let Some(i) = o.get("indexes") {
102            out.as_object_mut()
103                .map(|m| m.insert("indexes".to_string(), i.clone()));
104        }
105    }
106    Ok(out)
107}
108
109/// 简化单 def 合并(绑定层可能传单个 schema 而非数组)
110pub fn merge_one_schema_json(base: &Value, overlay: &Value) -> Result<Value, String> {
111    if base.get("name").is_some() && base.get("fields").is_some() {
112        merge_one(base, overlay)
113    } else {
114        Err("base 不是单个 schema def".to_string())
115    }
116}
117
118#[allow(dead_code)]
119fn _map_helper() -> Map<String, Value> {
120    Map::new()
121}