type_bridge_server/crud/
types.rs1use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Deserialize)]
21pub struct EntityInsertRequest {
22 pub database: Option<String>,
24 pub attributes: HashMap<String, AttributeValueSpec>,
26}
27
28#[derive(Debug, Deserialize)]
32pub struct EntityFetchRequest {
33 pub database: Option<String>,
35 #[serde(default)]
37 pub filters: Vec<FilterSpec>,
38 #[serde(default)]
40 pub sort: Vec<SortSpec>,
41 pub limit: Option<u64>,
43 pub offset: Option<u64>,
45}
46
47#[derive(Debug, Deserialize)]
49pub struct EntityUpdateRequest {
50 pub database: Option<String>,
52 pub attributes: HashMap<String, AttributeValueSpec>,
54}
55
56#[derive(Debug, Deserialize)]
73pub struct RelationInsertRequest {
74 pub database: Option<String>,
76 pub role_players: Vec<RolePlayerSpec>,
78 #[serde(default)]
80 pub attributes: HashMap<String, AttributeValueSpec>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct AttributeValueSpec {
86 pub value: serde_json::Value,
88 pub value_type: String,
90}
91
92#[derive(Debug, Deserialize)]
94pub struct FilterSpec {
95 pub attr: String,
97 pub op: String,
99 pub value: AttributeValueSpec,
101}
102
103#[derive(Debug, Deserialize)]
105pub struct SortSpec {
106 pub attr: String,
108 #[serde(default = "default_sort_dir")]
110 pub dir: String,
111}
112
113fn default_sort_dir() -> String {
114 "asc".to_string()
115}
116
117#[derive(Debug, Deserialize)]
119pub struct RolePlayerSpec {
120 pub role: String,
122 pub entity_type: String,
124 pub iid: Option<String>,
126 pub key_attr: Option<String>,
128 pub key_value: Option<AttributeValueSpec>,
130}
131
132#[derive(Debug, Serialize)]
134pub struct CrudResponse {
135 pub status: String,
137 pub results: serde_json::Value,
139 pub metadata: CrudMetadata,
141}
142
143#[derive(Debug, Serialize)]
145pub struct CrudMetadata {
146 pub request_id: String,
148 pub execution_time_ms: u64,
150 pub typeql: String,
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn deserialize_entity_insert_request() {
160 let json = serde_json::json!({
161 "attributes": {
162 "name": { "value": "Alice", "value_type": "string" },
163 "age": { "value": 30, "value_type": "long" }
164 }
165 });
166 let req: EntityInsertRequest = serde_json::from_value(json).unwrap();
167 assert!(req.database.is_none());
168 assert_eq!(req.attributes.len(), 2);
169 assert_eq!(req.attributes["name"].value_type, "string");
170 }
171
172 #[test]
173 fn deserialize_entity_fetch_request_defaults() {
174 let json = serde_json::json!({});
175 let req: EntityFetchRequest = serde_json::from_value(json).unwrap();
176 assert!(req.filters.is_empty());
177 assert!(req.sort.is_empty());
178 assert!(req.limit.is_none());
179 }
180
181 #[test]
182 fn deserialize_relation_insert_request() {
183 let json = serde_json::json!({
184 "role_players": [
185 {
186 "role": "employee",
187 "entity_type": "person",
188 "key_attr": "name",
189 "key_value": { "value": "Alice", "value_type": "string" }
190 }
191 ],
192 "attributes": {}
193 });
194 let req: RelationInsertRequest = serde_json::from_value(json).unwrap();
195 assert_eq!(req.role_players.len(), 1);
196 assert_eq!(req.role_players[0].role, "employee");
197 }
198
199 #[test]
200 fn deserialize_filter_spec() {
201 let json = serde_json::json!({
202 "attr": "age",
203 "op": ">=",
204 "value": { "value": 18, "value_type": "long" }
205 });
206 let filter: FilterSpec = serde_json::from_value(json).unwrap();
207 assert_eq!(filter.attr, "age");
208 assert_eq!(filter.op, ">=");
209 }
210
211 #[test]
212 fn sort_spec_default_direction() {
213 let json = serde_json::json!({ "attr": "name" });
214 let sort: SortSpec = serde_json::from_value(json).unwrap();
215 assert_eq!(sort.dir, "asc");
216 }
217
218 #[test]
219 fn serialize_crud_response() {
220 let resp = CrudResponse {
221 status: "ok".to_string(),
222 results: serde_json::json!({"inserted": true}),
223 metadata: CrudMetadata {
224 request_id: "abc-123".to_string(),
225 execution_time_ms: 42,
226 typeql: "insert $e isa person;".to_string(),
227 },
228 };
229 let json = serde_json::to_value(&resp).unwrap();
230 assert_eq!(json["status"], "ok");
231 assert_eq!(json["metadata"]["execution_time_ms"], 42);
232 assert_eq!(json["metadata"]["typeql"], "insert $e isa person;");
233 }
234
235 #[test]
236 fn role_player_spec_with_iid() {
237 let json = serde_json::json!({
238 "role": "friend",
239 "entity_type": "person",
240 "iid": "0xabc123"
241 });
242 let rp: RolePlayerSpec = serde_json::from_value(json).unwrap();
243 assert_eq!(rp.iid.as_deref(), Some("0xabc123"));
244 assert!(rp.key_attr.is_none());
245 }
246
247 #[test]
248 fn attribute_value_spec_roundtrip() {
249 let spec = AttributeValueSpec {
250 value: serde_json::json!("hello"),
251 value_type: "string".to_string(),
252 };
253 let json = serde_json::to_value(&spec).unwrap();
254 let spec2: AttributeValueSpec = serde_json::from_value(json).unwrap();
255 assert_eq!(spec2.value, serde_json::json!("hello"));
256 assert_eq!(spec2.value_type, "string");
257 }
258}