1use pylon_kernel::{AppManifest, ManifestField, ManifestQuery};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct QueryDescriptor {
12 pub name: String,
13 pub input: Vec<InputField>,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct InputField {
19 pub name: String,
20 pub field_type: String,
21 pub optional: bool,
22}
23
24impl InputField {
25 pub fn from_manifest_field(f: &ManifestField) -> Self {
26 Self {
27 name: f.name.clone(),
28 field_type: f.field_type.clone(),
29 optional: f.optional,
30 }
31 }
32}
33
34impl QueryDescriptor {
35 pub fn from_manifest(mq: &ManifestQuery) -> Self {
36 Self {
37 name: mq.name.clone(),
38 input: mq
39 .input
40 .iter()
41 .map(InputField::from_manifest_field)
42 .collect(),
43 }
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct QueryRegistry {
54 pub queries: Vec<QueryDescriptor>,
55}
56
57impl QueryRegistry {
58 pub fn from_manifest(manifest: &AppManifest) -> Self {
59 Self {
60 queries: manifest
61 .queries
62 .iter()
63 .map(QueryDescriptor::from_manifest)
64 .collect(),
65 }
66 }
67
68 pub fn get(&self, name: &str) -> Option<&QueryDescriptor> {
69 self.queries.iter().find(|q| q.name == name)
70 }
71
72 pub fn names(&self) -> Vec<&str> {
73 self.queries.iter().map(|q| q.name.as_str()).collect()
74 }
75}
76
77#[cfg(test)]
82mod tests {
83 use super::*;
84 use pylon_kernel::ManifestField;
85
86 fn test_manifest() -> AppManifest {
92 fn f(name: &str, ty: &str, optional: bool) -> ManifestField {
93 ManifestField {
94 name: name.into(),
95 field_type: ty.into(),
96 optional,
97 unique: false,
98 crdt: None,
99 }
100 }
101 AppManifest {
102 manifest_version: 1,
103 name: "test".into(),
104 version: "0.0.0".into(),
105 entities: vec![],
106 routes: vec![],
107 actions: vec![],
108 policies: vec![],
109 queries: vec![
110 ManifestQuery {
111 name: "todosByAuthor".into(),
112 input: vec![f("authorId", "id(User)", false)],
113 },
114 ManifestQuery {
115 name: "allTodos".into(),
116 input: vec![f("done", "bool", true)],
117 },
118 ManifestQuery {
119 name: "todoById".into(),
120 input: vec![f("id", "id(Todo)", false)],
121 },
122 ],
123 auth: Default::default(),
124 }
125 }
126
127 #[test]
128 fn registry_from_manifest() {
129 let reg = QueryRegistry::from_manifest(&test_manifest());
130 assert_eq!(reg.queries.len(), 3);
131 assert_eq!(reg.names(), vec!["todosByAuthor", "allTodos", "todoById"]);
132 }
133
134 #[test]
135 fn get_query_by_name() {
136 let reg = QueryRegistry::from_manifest(&test_manifest());
137 let q = reg.get("todosByAuthor").unwrap();
138 assert_eq!(q.name, "todosByAuthor");
139 assert_eq!(q.input.len(), 1);
140 assert_eq!(q.input[0].name, "authorId");
141 assert_eq!(q.input[0].field_type, "id(User)");
142 assert!(!q.input[0].optional);
143 }
144
145 #[test]
146 fn get_query_with_optional_input() {
147 let reg = QueryRegistry::from_manifest(&test_manifest());
148 let q = reg.get("allTodos").unwrap();
149 assert_eq!(q.input.len(), 1);
150 assert_eq!(q.input[0].name, "done");
151 assert!(q.input[0].optional);
152 }
153
154 #[test]
155 fn get_missing_query_returns_none() {
156 let reg = QueryRegistry::from_manifest(&test_manifest());
157 assert!(reg.get("nonexistent").is_none());
158 }
159
160 #[test]
161 fn descriptor_from_manifest_query() {
162 let mq = ManifestQuery {
163 name: "test".into(),
164 input: vec![ManifestField {
165 name: "id".into(),
166 field_type: "string".into(),
167 optional: false,
168 unique: false,
169 crdt: None,
170 }],
171 };
172 let desc = QueryDescriptor::from_manifest(&mq);
173 assert_eq!(desc.name, "test");
174 assert_eq!(desc.input.len(), 1);
175 assert_eq!(desc.input[0].name, "id");
176 }
177}