Skip to main content

teaql_runtime/repository/
base.rs

1use teaql_core::{
2    DeleteCommand, Entity, InsertCommand, Record, RecoverCommand, SelectQuery, SmartList,
3    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_delete(&self, command: &DeleteCommand) -> Result<CompiledQuery, RuntimeError> {
50        let entity = self
51            .metadata
52            .entity(&command.entity)
53            .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
54        Ok(self.dialect.compile_delete(entity, command)?)
55    }
56
57    pub fn compile_recover(&self, command: &RecoverCommand) -> Result<CompiledQuery, RuntimeError> {
58        let entity = self
59            .metadata
60            .entity(&command.entity)
61            .ok_or_else(|| RuntimeError::MissingEntity(command.entity.clone()))?;
62        Ok(self.dialect.compile_recover(entity, command)?)
63    }
64
65    pub fn fetch_all(&self, query: &SelectQuery) -> Result<Vec<Record>, RepositoryError<E::Error>> {
66        let compiled = self.compile(query).map_err(RepositoryError::Runtime)?;
67        self.executor
68            .fetch_all(&compiled)
69            .map_err(RepositoryError::Executor)
70    }
71
72    pub fn fetch_smart_list(
73        &self,
74        query: &SelectQuery,
75    ) -> Result<SmartList<Record>, RepositoryError<E::Error>> {
76        self.fetch_all(query).map(SmartList::from)
77    }
78
79    pub fn fetch_entities<T>(
80        &self,
81        query: &SelectQuery,
82    ) -> Result<SmartList<T>, RepositoryError<E::Error>>
83    where
84        T: Entity,
85    {
86        self.fetch_all(query)?
87            .into_iter()
88            .map(T::from_record)
89            .collect::<Result<Vec<_>, _>>()
90            .map(SmartList::from)
91            .map_err(RepositoryError::Entity)
92    }
93
94    pub fn fetch_enhanced_entities<T>(
95        &self,
96        query: &SelectQuery,
97    ) -> Result<SmartList<T>, RepositoryError<E::Error>>
98    where
99        T: Entity,
100    {
101        self.fetch_entities(query)
102    }
103
104    pub fn insert(&self, command: &InsertCommand) -> Result<u64, RepositoryError<E::Error>> {
105        let compiled = self
106            .compile_insert(command)
107            .map_err(RepositoryError::Runtime)?;
108        self.executor
109            .execute(&compiled)
110            .map_err(RepositoryError::Executor)
111    }
112
113    pub fn update(&self, command: &UpdateCommand) -> Result<u64, RepositoryError<E::Error>> {
114        let compiled = self
115            .compile_update(command)
116            .map_err(RepositoryError::Runtime)?;
117        let affected = self
118            .executor
119            .execute(&compiled)
120            .map_err(RepositoryError::Executor)?;
121
122        if command.expected_version.is_some() && affected == 0 {
123            return Err(RepositoryError::Runtime(
124                RuntimeError::OptimisticLockConflict {
125                    entity: command.entity.clone(),
126                    id: format!("{:?}", command.id),
127                },
128            ));
129        }
130
131        Ok(affected)
132    }
133
134    pub fn delete(&self, command: &DeleteCommand) -> Result<u64, RepositoryError<E::Error>> {
135        let compiled = self
136            .compile_delete(command)
137            .map_err(RepositoryError::Runtime)?;
138        let affected = self
139            .executor
140            .execute(&compiled)
141            .map_err(RepositoryError::Executor)?;
142
143        if command.expected_version.is_some() && affected == 0 {
144            return Err(RepositoryError::Runtime(
145                RuntimeError::OptimisticLockConflict {
146                    entity: command.entity.clone(),
147                    id: format!("{:?}", command.id),
148                },
149            ));
150        }
151
152        Ok(affected)
153    }
154
155    pub fn recover(&self, command: &RecoverCommand) -> Result<u64, RepositoryError<E::Error>> {
156        let compiled = self
157            .compile_recover(command)
158            .map_err(RepositoryError::Runtime)?;
159        let affected = self
160            .executor
161            .execute(&compiled)
162            .map_err(RepositoryError::Executor)?;
163
164        if affected == 0 {
165            return Err(RepositoryError::Runtime(
166                RuntimeError::OptimisticLockConflict {
167                    entity: command.entity.clone(),
168                    id: format!("{:?}", command.id),
169                },
170            ));
171        }
172
173        Ok(affected)
174    }
175
176    pub fn insert_many(
177        &self,
178        commands: &[InsertCommand],
179    ) -> Result<u64, RepositoryError<E::Error>> {
180        let mut total = 0;
181        for command in commands {
182            total += self.insert(command)?;
183        }
184        Ok(total)
185    }
186
187    pub fn update_many(
188        &self,
189        commands: &[UpdateCommand],
190    ) -> Result<u64, RepositoryError<E::Error>> {
191        let mut total = 0;
192        for command in commands {
193            total += self.update(command)?;
194        }
195        Ok(total)
196    }
197
198    pub fn delete_many(
199        &self,
200        commands: &[DeleteCommand],
201    ) -> Result<u64, RepositoryError<E::Error>> {
202        let mut total = 0;
203        for command in commands {
204            total += self.delete(command)?;
205        }
206        Ok(total)
207    }
208
209    pub fn recover_many(
210        &self,
211        commands: &[RecoverCommand],
212    ) -> Result<u64, RepositoryError<E::Error>> {
213        let mut total = 0;
214        for command in commands {
215            total += self.recover(command)?;
216        }
217        Ok(total)
218    }
219}