1use std::future::Future;
4use std::pin::Pin;
5
6use crate::error::QueryResult;
7use crate::filter::Filter;
8
9pub trait Model: Sized + Send + Sync {
11 const MODEL_NAME: &'static str;
13
14 const TABLE_NAME: &'static str;
16
17 const PRIMARY_KEY: &'static [&'static str];
19
20 const COLUMNS: &'static [&'static str];
22}
23
24pub trait View: Sized + Send + Sync {
29 const VIEW_NAME: &'static str;
31
32 const DB_VIEW_NAME: &'static str;
34
35 const COLUMNS: &'static [&'static str];
37
38 const IS_MATERIALIZED: bool;
40}
41
42pub trait MaterializedView: View {
44 const SUPPORTS_CONCURRENT_REFRESH: bool = true;
46}
47
48pub trait IntoFilter {
50 fn into_filter(self) -> Filter;
52}
53
54impl IntoFilter for Filter {
55 fn into_filter(self) -> Filter {
56 self
57 }
58}
59
60impl<F: FnOnce() -> Filter> IntoFilter for F {
61 fn into_filter(self) -> Filter {
62 self()
63 }
64}
65
66pub trait Executable {
68 type Output;
70
71 fn exec(self) -> impl Future<Output = QueryResult<Self::Output>> + Send;
73}
74
75pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
77
78pub trait QueryEngine: Send + Sync + Clone + 'static {
84 fn query_many<T: Model + Send + 'static>(
86 &self,
87 sql: &str,
88 params: Vec<crate::filter::FilterValue>,
89 ) -> BoxFuture<'_, QueryResult<Vec<T>>>;
90
91 fn query_one<T: Model + Send + 'static>(
93 &self,
94 sql: &str,
95 params: Vec<crate::filter::FilterValue>,
96 ) -> BoxFuture<'_, QueryResult<T>>;
97
98 fn query_optional<T: Model + Send + 'static>(
100 &self,
101 sql: &str,
102 params: Vec<crate::filter::FilterValue>,
103 ) -> BoxFuture<'_, QueryResult<Option<T>>>;
104
105 fn execute_insert<T: Model + Send + 'static>(
107 &self,
108 sql: &str,
109 params: Vec<crate::filter::FilterValue>,
110 ) -> BoxFuture<'_, QueryResult<T>>;
111
112 fn execute_update<T: Model + Send + 'static>(
114 &self,
115 sql: &str,
116 params: Vec<crate::filter::FilterValue>,
117 ) -> BoxFuture<'_, QueryResult<Vec<T>>>;
118
119 fn execute_delete(
121 &self,
122 sql: &str,
123 params: Vec<crate::filter::FilterValue>,
124 ) -> BoxFuture<'_, QueryResult<u64>>;
125
126 fn execute_raw(
128 &self,
129 sql: &str,
130 params: Vec<crate::filter::FilterValue>,
131 ) -> BoxFuture<'_, QueryResult<u64>>;
132
133 fn count(
135 &self,
136 sql: &str,
137 params: Vec<crate::filter::FilterValue>,
138 ) -> BoxFuture<'_, QueryResult<u64>>;
139
140 fn refresh_materialized_view(
146 &self,
147 view_name: &str,
148 concurrently: bool,
149 ) -> BoxFuture<'_, QueryResult<()>> {
150 let view_name = view_name.to_string();
151 Box::pin(async move {
152 let _ = (view_name, concurrently);
153 Err(crate::error::QueryError::unsupported(
154 "Materialized view refresh is not supported by this database",
155 ))
156 })
157 }
158}
159
160pub trait ViewQueryEngine: QueryEngine {
162 fn query_view_many<V: View + Send + 'static>(
164 &self,
165 sql: &str,
166 params: Vec<crate::filter::FilterValue>,
167 ) -> BoxFuture<'_, QueryResult<Vec<V>>>;
168
169 fn query_view_optional<V: View + Send + 'static>(
171 &self,
172 sql: &str,
173 params: Vec<crate::filter::FilterValue>,
174 ) -> BoxFuture<'_, QueryResult<Option<V>>>;
175
176 fn count_view(
178 &self,
179 sql: &str,
180 params: Vec<crate::filter::FilterValue>,
181 ) -> BoxFuture<'_, QueryResult<u64>> {
182 self.count(sql, params)
183 }
184}
185
186pub trait ModelAccessor<E: QueryEngine>: Send + Sync {
190 type Model: Model;
192
193 fn engine(&self) -> &E;
195
196 fn find_many(&self) -> crate::operations::FindManyOperation<E, Self::Model>;
198
199 fn find_unique(&self) -> crate::operations::FindUniqueOperation<E, Self::Model>;
201
202 fn find_first(&self) -> crate::operations::FindFirstOperation<E, Self::Model>;
204
205 fn create(
207 &self,
208 data: <Self::Model as CreateData>::Data,
209 ) -> crate::operations::CreateOperation<E, Self::Model>
210 where
211 Self::Model: CreateData;
212
213 fn update(&self) -> crate::operations::UpdateOperation<E, Self::Model>;
215
216 fn delete(&self) -> crate::operations::DeleteOperation<E, Self::Model>;
218
219 fn upsert(
221 &self,
222 create: <Self::Model as CreateData>::Data,
223 update: <Self::Model as UpdateData>::Data,
224 ) -> crate::operations::UpsertOperation<E, Self::Model>
225 where
226 Self::Model: CreateData + UpdateData;
227
228 fn count(&self) -> crate::operations::CountOperation<E, Self::Model>;
230}
231
232pub trait CreateData: Model {
234 type Data: Send + Sync;
236}
237
238pub trait UpdateData: Model {
240 type Data: Send + Sync;
242}
243
244pub trait UpsertData: CreateData + UpdateData {}
246
247impl<T: CreateData + UpdateData> UpsertData for T {}
248
249pub trait WithRelations: Model {
251 type Include;
253
254 type Select;
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 struct TestModel;
263
264 impl Model for TestModel {
265 const MODEL_NAME: &'static str = "TestModel";
266 const TABLE_NAME: &'static str = "test_models";
267 const PRIMARY_KEY: &'static [&'static str] = &["id"];
268 const COLUMNS: &'static [&'static str] = &["id", "name", "email"];
269 }
270
271 #[test]
272 fn test_model_trait() {
273 assert_eq!(TestModel::MODEL_NAME, "TestModel");
274 assert_eq!(TestModel::TABLE_NAME, "test_models");
275 assert_eq!(TestModel::PRIMARY_KEY, &["id"]);
276 }
277
278 #[test]
279 fn test_into_filter() {
280 let filter = Filter::Equals("id".into(), crate::filter::FilterValue::Int(1));
281 let converted = filter.clone().into_filter();
282 assert_eq!(converted, filter);
283 }
284}