teaql_runtime/repository/
base.rs1use teaql_core::{
2 BatchInsertCommand, BatchUpdateCommand, DeleteCommand, Entity, InsertCommand, Record,
3 RecoverCommand, SelectQuery, SmartList, UpdateCommand,
4};
5use teaql_sql::{CompiledQuery, SqlDialect};
6
7use crate::{MetadataStore, RepositoryError, RuntimeError};
8
9use super::{QueryExecutor, Repository};
10
11impl<'a, D, M, E> Repository<'a, D, M, E>
12where
13 D: SqlDialect,
14 M: MetadataStore,
15 E: QueryExecutor,
16{
17 pub fn new(dialect: &'a D, metadata: &'a M, executor: &'a E) -> Self {
18 Self {
19 dialect,
20 metadata,
21 executor,
22 }
23 }
24
25 pub fn compile(&self, query: &SelectQuery) -> Result<CompiledQuery, RuntimeError> {
26 let entity = self
27 .metadata
28 .entity(&query.entity)
29 .ok_or_else(|| RuntimeError::MissingEntity(query.entity.clone()))?;
30 Ok(self.dialect.compile_select(entity, query)?)
31 }
32
33 pub fn compile_insert(&self, command: &InsertCommand) -> Result<CompiledQuery, RuntimeError> {
34 let entity = self
35 .metadata
36 .entity(&command.entity)
37 .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
38 Ok(self.dialect.compile_insert(entity, command)?)
39 }
40
41 pub fn compile_update(&self, command: &UpdateCommand) -> Result<CompiledQuery, RuntimeError> {
42 let entity = self
43 .metadata
44 .entity(&command.entity)
45 .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
46 Ok(self.dialect.compile_update(entity, command)?)
47 }
48
49 pub fn compile_batch_insert(
50 &self,
51 command: &BatchInsertCommand,
52 ) -> Result<CompiledQuery, RuntimeError> {
53 let entity = self
54 .metadata
55 .entity(&command.entity)
56 .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
57 Ok(self.dialect.compile_batch_insert(entity, command)?)
58 }
59
60 pub fn compile_batch_update(
61 &self,
62 command: &BatchUpdateCommand,
63 ) -> Result<CompiledQuery, RuntimeError> {
64 let entity = self
65 .metadata
66 .entity(&command.entity)
67 .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
68 Ok(self.dialect.compile_batch_update(entity, command)?)
69 }
70
71 pub fn compile_delete(&self, command: &DeleteCommand) -> Result<CompiledQuery, RuntimeError> {
72 let entity = self
73 .metadata
74 .entity(&command.entity)
75 .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
76 Ok(self.dialect.compile_delete(entity, command)?)
77 }
78
79 pub fn compile_recover(&self, command: &RecoverCommand) -> Result<CompiledQuery, RuntimeError> {
80 let entity = self
81 .metadata
82 .entity(&command.entity)
83 .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
84 Ok(self.dialect.compile_recover(entity, command)?)
85 }
86
87 pub fn fetch_all(&self, query: &SelectQuery) -> Result<Vec<Record>, RepositoryError<E::Error>> {
88 let compiled = self.compile(query).map_err(RepositoryError::Runtime)?;
89 self.executor
90 .fetch_all(&compiled)
91 .map_err(RepositoryError::Executor)
92 }
93
94 pub fn fetch_smart_list(
95 &self,
96 query: &SelectQuery,
97 ) -> Result<SmartList<Record>, RepositoryError<E::Error>> {
98 self.fetch_all(query).map(SmartList::from)
99 }
100
101 pub fn fetch_entities<T>(
102 &self,
103 query: &SelectQuery,
104 ) -> Result<SmartList<T>, RepositoryError<E::Error>>
105 where
106 T: Entity,
107 {
108 self.fetch_all(query)?
109 .into_iter()
110 .map(T::from_record)
111 .collect::<Result<Vec<_>, _>>()
112 .map(SmartList::from)
113 .map_err(RepositoryError::Entity)
114 }
115
116 pub fn fetch_enhanced_entities<T>(
117 &self,
118 query: &SelectQuery,
119 ) -> Result<SmartList<T>, RepositoryError<E::Error>>
120 where
121 T: Entity,
122 {
123 self.fetch_entities(query)
124 }
125
126 pub fn insert(&self, command: &InsertCommand) -> Result<u64, RepositoryError<E::Error>> {
127 let compiled = self
128 .compile_insert(command)
129 .map_err(RepositoryError::Runtime)?;
130 self.executor
131 .execute(&compiled)
132 .map_err(RepositoryError::Executor)
133 }
134
135 pub fn update(&self, command: &UpdateCommand) -> Result<u64, RepositoryError<E::Error>> {
136 let compiled = self
137 .compile_update(command)
138 .map_err(RepositoryError::Runtime)?;
139 let affected = self
140 .executor
141 .execute(&compiled)
142 .map_err(RepositoryError::Executor)?;
143
144 if command.expected_version.is_some() && affected == 0 {
145 return Err(RepositoryError::Runtime(
146 RuntimeError::OptimisticLockConflict {
147 entity: command.entity.clone(),
148 id: format!("{:?}", command.id),
149 },
150 ));
151 }
152
153 Ok(affected)
154 }
155
156 pub fn delete(&self, command: &DeleteCommand) -> Result<u64, RepositoryError<E::Error>> {
157 let compiled = self
158 .compile_delete(command)
159 .map_err(RepositoryError::Runtime)?;
160 let affected = self
161 .executor
162 .execute(&compiled)
163 .map_err(RepositoryError::Executor)?;
164
165 if command.expected_version.is_some() && affected == 0 {
166 return Err(RepositoryError::Runtime(
167 RuntimeError::OptimisticLockConflict {
168 entity: command.entity.clone(),
169 id: format!("{:?}", command.id),
170 },
171 ));
172 }
173
174 Ok(affected)
175 }
176
177 pub fn batch_insert(
178 &self,
179 command: &teaql_core::BatchInsertCommand,
180 ) -> Result<u64, RepositoryError<E::Error>> {
181 let compiled = self
182 .compile_batch_insert(command)
183 .map_err(RepositoryError::Runtime)?;
184 self.executor
185 .execute(&compiled)
186 .map_err(RepositoryError::Executor)
187 }
188
189 pub fn batch_update(
190 &self,
191 command: &teaql_core::BatchUpdateCommand,
192 ) -> Result<u64, RepositoryError<E::Error>> {
193 let compiled = self
194 .compile_batch_update(command)
195 .map_err(RepositoryError::Runtime)?;
196 let affected = self
197 .executor
198 .execute(&compiled)
199 .map_err(RepositoryError::Executor)?;
200
201 if command.batch_expected_versions.iter().any(|v| v.is_some()) {
202 if affected != command.batch_ids.len() as u64 {
203 return Err(RepositoryError::Runtime(
205 RuntimeError::OptimisticLockConflict {
206 entity: command.entity.clone(),
207 id: "BATCH".to_owned(),
208 },
209 ));
210 }
211 }
212
213 Ok(affected)
214 }
215
216 pub fn recover(&self, command: &RecoverCommand) -> Result<u64, RepositoryError<E::Error>> {
217 let compiled = self
218 .compile_recover(command)
219 .map_err(RepositoryError::Runtime)?;
220 let affected = self
221 .executor
222 .execute(&compiled)
223 .map_err(RepositoryError::Executor)?;
224
225 if affected == 0 {
226 return Err(RepositoryError::Runtime(
227 RuntimeError::OptimisticLockConflict {
228 entity: command.entity.clone(),
229 id: format!("{:?}", command.id),
230 },
231 ));
232 }
233
234 Ok(affected)
235 }
236
237 pub fn insert_many(
238 &self,
239 commands: &[InsertCommand],
240 ) -> Result<u64, RepositoryError<E::Error>> {
241 let mut total = 0;
242 for command in commands {
243 total += self.insert(command)?;
244 }
245 Ok(total)
246 }
247
248 pub fn update_many(
249 &self,
250 commands: &[UpdateCommand],
251 ) -> Result<u64, RepositoryError<E::Error>> {
252 let mut total = 0;
253 for command in commands {
254 total += self.update(command)?;
255 }
256 Ok(total)
257 }
258
259 pub fn delete_many(
260 &self,
261 commands: &[DeleteCommand],
262 ) -> Result<u64, RepositoryError<E::Error>> {
263 let mut total = 0;
264 for command in commands {
265 total += self.delete(command)?;
266 }
267 Ok(total)
268 }
269
270 pub fn recover_many(
271 &self,
272 commands: &[RecoverCommand],
273 ) -> Result<u64, RepositoryError<E::Error>> {
274 let mut total = 0;
275 for command in commands {
276 total += self.recover(command)?;
277 }
278 Ok(total)
279 }
280}