helix_dsl/
query_generator.rs1use serde::{Deserialize, Serialize};
2use std::collections::BTreeMap;
3use std::path::{Path, PathBuf};
4
5pub const QUERY_BUNDLE_VERSION: u32 = 4;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub enum QueryParamType {
11 Bool,
13 I64,
15 F64,
17 F32,
19 String,
21 DateTime,
23 Bytes,
25 Value,
27 Object,
29 Array(Box<QueryParamType>),
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct QueryParameter {
36 pub name: String,
38 pub ty: QueryParamType,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44pub struct QueryBundle {
45 pub version: u32,
47 pub read_routes: BTreeMap<String, crate::ReadBatch>,
49 pub write_routes: BTreeMap<String, crate::WriteBatch>,
51 pub read_parameters: BTreeMap<String, Vec<QueryParameter>>,
53 pub write_parameters: BTreeMap<String, Vec<QueryParameter>>,
55}
56
57impl Default for QueryBundle {
58 fn default() -> Self {
59 Self {
60 version: QUERY_BUNDLE_VERSION,
61 read_routes: BTreeMap::new(),
62 write_routes: BTreeMap::new(),
63 read_parameters: BTreeMap::new(),
64 write_parameters: BTreeMap::new(),
65 }
66 }
67}
68
69pub struct RegisteredReadQuery {
71 pub name: &'static str,
73 pub build: fn() -> crate::ReadBatch,
75 pub parameters: fn() -> Vec<QueryParameter>,
77}
78
79pub struct RegisteredWriteQuery {
81 pub name: &'static str,
83 pub build: fn() -> crate::WriteBatch,
85 pub parameters: fn() -> Vec<QueryParameter>,
87}
88
89inventory::collect!(RegisteredReadQuery);
90inventory::collect!(RegisteredWriteQuery);
91
92#[derive(Debug)]
94pub enum GenerateError {
95 DuplicateQueryName(String),
97 Io(std::io::Error),
99 Json(sonic_rs::Error),
101 UnsupportedVersion {
103 found: u32,
105 expected: u32,
107 },
108}
109
110impl std::fmt::Display for GenerateError {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 match self {
113 Self::DuplicateQueryName(name) => {
114 write!(f, "duplicate generated query name: {name}")
115 }
116 Self::Io(err) => write!(f, "io error: {err}"),
117 Self::Json(err) => write!(f, "json error: {err}"),
118 Self::UnsupportedVersion { found, expected } => {
119 write!(
120 f,
121 "unsupported query bundle version {found} (expected {expected})"
122 )
123 }
124 }
125 }
126}
127
128impl std::error::Error for GenerateError {}
129
130impl From<std::io::Error> for GenerateError {
131 fn from(value: std::io::Error) -> Self {
132 Self::Io(value)
133 }
134}
135
136impl From<sonic_rs::Error> for GenerateError {
137 fn from(value: sonic_rs::Error) -> Self {
138 Self::Json(value)
139 }
140}
141
142pub fn build_query_bundle() -> Result<QueryBundle, GenerateError> {
144 let mut bundle = QueryBundle::default();
145
146 for registered in inventory::iter::<RegisteredReadQuery> {
147 if bundle.read_routes.contains_key(registered.name)
148 || bundle.write_routes.contains_key(registered.name)
149 {
150 return Err(GenerateError::DuplicateQueryName(
151 registered.name.to_string(),
152 ));
153 }
154
155 bundle
156 .read_routes
157 .insert(registered.name.to_string(), (registered.build)());
158 bundle
159 .read_parameters
160 .insert(registered.name.to_string(), (registered.parameters)());
161 }
162
163 for registered in inventory::iter::<RegisteredWriteQuery> {
164 if bundle.read_routes.contains_key(registered.name)
165 || bundle.write_routes.contains_key(registered.name)
166 {
167 return Err(GenerateError::DuplicateQueryName(
168 registered.name.to_string(),
169 ));
170 }
171
172 bundle
173 .write_routes
174 .insert(registered.name.to_string(), (registered.build)());
175 bundle
176 .write_parameters
177 .insert(registered.name.to_string(), (registered.parameters)());
178 }
179
180 Ok(bundle)
181}
182
183pub fn serialize_query_bundle(bundle: &QueryBundle) -> Result<Vec<u8>, GenerateError> {
185 Ok(sonic_rs::to_vec_pretty(bundle)?)
186}
187
188pub fn deserialize_query_bundle(bytes: &[u8]) -> Result<QueryBundle, GenerateError> {
190 let bundle: QueryBundle = sonic_rs::from_slice(bytes)?;
191
192 if bundle.version != QUERY_BUNDLE_VERSION {
193 return Err(GenerateError::UnsupportedVersion {
194 found: bundle.version,
195 expected: QUERY_BUNDLE_VERSION,
196 });
197 }
198
199 Ok(bundle)
200}
201
202pub fn write_query_bundle_to_path<P: AsRef<Path>>(
204 bundle: &QueryBundle,
205 path: P,
206) -> Result<(), GenerateError> {
207 let bytes = serialize_query_bundle(bundle)?;
208 std::fs::write(path, bytes)?;
209 Ok(())
210}
211
212pub fn read_query_bundle_from_path<P: AsRef<Path>>(path: P) -> Result<QueryBundle, GenerateError> {
214 let bytes = std::fs::read(path)?;
215 deserialize_query_bundle(&bytes)
216}
217
218pub fn generate() -> Result<PathBuf, GenerateError> {
220 generate_to_path("queries.json")
221}
222
223pub fn generate_to_path<P: AsRef<Path>>(path: P) -> Result<PathBuf, GenerateError> {
225 let path = path.as_ref();
226 let bundle = build_query_bundle()?;
227 write_query_bundle_to_path(&bundle, path)?;
228 Ok(path.to_path_buf())
229}