Skip to main content

interstice_abi/schema/
module.rs

1use crate::{
2    ABI_VERSION, Authority, IntersticeType, ModuleDependency, NodeDependency, QuerySchema,
3    ReducerSchema, SubscriptionSchema, TableSchema, TableVisibility, Version,
4    interstice_type_def::IntersticeTypeDef,
5};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
10pub struct ReplicatedTableSchema {
11    pub node_name: String,
12    pub module_name: String,
13    pub table_name: String,
14}
15
16#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
17pub enum ModuleVisibility {
18    // Visible to all other nodes
19    Public,
20    // Only visible for local modules on the current node
21    Private,
22}
23
24#[derive(Debug, Clone, Deserialize, Serialize)]
25pub struct ModuleSchema {
26    pub abi_version: u16,
27    pub name: String,
28    pub version: Version,
29    pub visibility: ModuleVisibility,
30    pub reducers: Vec<ReducerSchema>,
31    pub queries: Vec<QuerySchema>,
32    pub tables: Vec<TableSchema>,
33    pub subscriptions: Vec<SubscriptionSchema>,
34    pub type_definitions: HashMap<String, IntersticeTypeDef>,
35    pub authorities: Vec<Authority>,
36    pub module_dependencies: Vec<ModuleDependency>,
37    pub node_dependencies: Vec<NodeDependency>,
38    pub replicated_tables: Vec<ReplicatedTableSchema>,
39}
40
41impl ModuleSchema {
42    pub fn empty() -> Self {
43        Self {
44            abi_version: 0,
45            name: "".into(),
46            version: Version {
47                major: 0,
48                minor: 0,
49                patch: 0,
50            },
51            visibility: ModuleVisibility::Private,
52            reducers: Vec::new(),
53            queries: Vec::new(),
54            tables: Vec::new(),
55            subscriptions: Vec::new(),
56            type_definitions: HashMap::new(),
57            authorities: Vec::new(),
58            module_dependencies: Vec::new(),
59            node_dependencies: Vec::new(),
60            replicated_tables: Vec::new(),
61        }
62    }
63
64    pub fn new(
65        name: impl Into<String>,
66        version: Version,
67        visibility: ModuleVisibility,
68        reducers: Vec<ReducerSchema>,
69        queries: Vec<QuerySchema>,
70        tables: Vec<TableSchema>,
71        subscriptions: Vec<SubscriptionSchema>,
72        type_definitions: HashMap<String, IntersticeTypeDef>,
73        authorities: Vec<Authority>,
74        module_dependencies: Vec<ModuleDependency>,
75        node_dependencies: Vec<NodeDependency>,
76        replicated_tables: Vec<ReplicatedTableSchema>,
77    ) -> Self {
78        Self {
79            abi_version: ABI_VERSION,
80            name: name.into(),
81            visibility,
82            version,
83            reducers,
84            queries,
85            tables,
86            subscriptions,
87            type_definitions,
88            authorities,
89            module_dependencies,
90            node_dependencies,
91            replicated_tables,
92        }
93    }
94
95    pub fn to_public(self) -> Self {
96        let mut type_definitions = HashMap::new();
97
98        // Helper to extract all Named type references from an IntersticeType
99        fn extract_named_types(it: &IntersticeType, names: &mut Vec<String>) {
100            match it {
101                IntersticeType::Named(name) => names.push(name.clone()),
102                IntersticeType::Vec(inner) | IntersticeType::Option(inner) => {
103                    extract_named_types(inner, names);
104                }
105                IntersticeType::Tuple(types) => {
106                    for ty in types {
107                        extract_named_types(ty, names);
108                    }
109                }
110                _ => {} // Primitive types
111            }
112        }
113
114        // Recursive helper to collect a type and all its nested dependencies
115        let collect_type_recursively =
116            |type_name: &str,
117             collected: &mut HashMap<String, IntersticeTypeDef>,
118             all_types: &HashMap<String, IntersticeTypeDef>| {
119                let mut stack = vec![type_name.to_string()];
120
121                while let Some(current_name) = stack.pop() {
122                    // Skip if already collected
123                    if collected.contains_key(&current_name) {
124                        continue;
125                    }
126
127                    // Get the type definition
128                    if let Some(type_def) = all_types.get(&current_name) {
129                        collected.insert(current_name.clone(), type_def.clone());
130
131                        // Extract nested type names from this type
132                        if let IntersticeTypeDef::Struct { fields, .. } = type_def {
133                            for field in fields {
134                                let mut nested_names = Vec::new();
135                                extract_named_types(&field.field_type, &mut nested_names);
136                                for nested_name in nested_names {
137                                    if !collected.contains_key(&nested_name) {
138                                        stack.push(nested_name);
139                                    }
140                                }
141                            }
142                        }
143                    }
144                }
145            };
146
147        // Collect types from public tables
148        let mut tables = Vec::new();
149        for table_schema in &self.tables {
150            if table_schema.visibility == TableVisibility::Public {
151                tables.push(table_schema.clone());
152
153                // Collect table type and all its dependencies
154                collect_type_recursively(
155                    &table_schema.type_name,
156                    &mut type_definitions,
157                    &self.type_definitions,
158                );
159
160                // Collect field types and their dependencies
161                for field in &table_schema.fields {
162                    let mut nested_names = Vec::new();
163                    extract_named_types(&field.field_type, &mut nested_names);
164                    for type_name in nested_names {
165                        collect_type_recursively(
166                            &type_name,
167                            &mut type_definitions,
168                            &self.type_definitions,
169                        );
170                    }
171                }
172            }
173        }
174
175        // Collect types from public reducers
176        let mut reducers = Vec::new();
177        for reducer_schema in &self.reducers {
178            let mut add_reducer = true;
179            for subscription in &self.subscriptions {
180                if subscription.reducer_name == reducer_schema.name {
181                    add_reducer = false;
182                    break;
183                }
184            }
185            if add_reducer {
186                reducers.push(reducer_schema.clone());
187
188                // Collect types from reducer arguments and their dependencies
189                for arg in &reducer_schema.arguments {
190                    let mut nested_names = Vec::new();
191                    extract_named_types(&arg.field_type, &mut nested_names);
192                    for type_name in nested_names {
193                        collect_type_recursively(
194                            &type_name,
195                            &mut type_definitions,
196                            &self.type_definitions,
197                        );
198                    }
199                }
200            }
201        }
202
203        // Collect types from queries
204        let queries = self.queries.clone();
205        for query_schema in &queries {
206            // Collect types from query arguments and their dependencies
207            for arg in &query_schema.arguments {
208                let mut nested_names = Vec::new();
209                extract_named_types(&arg.field_type, &mut nested_names);
210                for type_name in nested_names {
211                    collect_type_recursively(
212                        &type_name,
213                        &mut type_definitions,
214                        &self.type_definitions,
215                    );
216                }
217            }
218
219            // Collect type from query return type and its dependencies
220            let mut nested_names = Vec::new();
221            extract_named_types(&query_schema.return_type, &mut nested_names);
222            for type_name in nested_names {
223                collect_type_recursively(&type_name, &mut type_definitions, &self.type_definitions);
224            }
225        }
226
227        Self {
228            abi_version: self.abi_version,
229            name: self.name,
230            visibility: self.visibility,
231            version: self.version,
232            reducers,
233            queries,
234            tables,
235            subscriptions: Vec::new(),
236            type_definitions,
237            authorities: self.authorities,
238            module_dependencies: self.module_dependencies,
239            node_dependencies: self.node_dependencies,
240            replicated_tables: self.replicated_tables,
241        }
242    }
243
244    pub fn from_toml_string(toml_string: &str) -> Result<Self, toml::de::Error> {
245        toml::from_str(toml_string)
246    }
247
248    pub fn to_toml_string(&self) -> Result<String, toml::ser::Error> {
249        toml::to_string(&self)
250    }
251}