1use crate::{
2 ColumnDef, Context, Dataset, Driver, DynQuery, Executor, Expression, Query, QueryBuilder,
3 RawQuery, Result, Row, RowValues, RowsAffected, TableRef, future::Either, stream::Stream,
4 truncate_long, writer::SqlWriter,
5};
6use anyhow::anyhow;
7use futures::{FutureExt, StreamExt};
8use log::Level;
9use std::{
10 future::{self, Future},
11 pin::pin,
12 sync::Arc,
13};
14
15pub trait AsEntity {
16 type Entity: Entity;
17 fn as_entity(&self) -> &Self::Entity;
18}
19
20pub trait Entity: AsEntity + Expression {
24 type PrimaryKey<'a>
26 where
27 Self: 'a;
28
29 fn table() -> &'static TableRef;
31
32 fn columns() -> &'static [ColumnDef];
34
35 fn primary_key_def() -> &'static [&'static ColumnDef];
37
38 fn primary_key(&self) -> Self::PrimaryKey<'_>;
40
41 fn primary_key_expr(&self) -> impl Expression;
43
44 fn unique_defs()
46 -> impl ExactSizeIterator<Item = impl ExactSizeIterator<Item = &'static ColumnDef>>;
47
48 fn row_values(&self) -> RowValues;
50
51 fn row(&self) -> Row {
53 Row {
54 labels: Self::columns()
55 .into_iter()
56 .map(|v| v.name().to_string())
57 .collect::<Arc<[String]>>(),
58 values: self.row_values(),
59 }
60 }
61
62 fn from_row(row: Row) -> Result<Self>
66 where
67 Self: Sized;
68
69 fn create_table(
74 executor: &mut impl Executor,
75 if_not_exists: bool,
76 create_schema: bool,
77 ) -> impl Future<Output = Result<()>> + Send
78 where
79 Self: Sized,
80 {
81 async move {
82 let mut query = DynQuery::with_capacity(2048);
83 let writer = executor.driver().sql_writer();
84 if create_schema && !Self::table().schema.is_empty() {
85 writer.write_create_schema::<Self>(&mut query, true);
86 }
87 if !executor.accepts_multiple_statements() && !query.is_empty() {
88 let mut q = query.into_query(executor.driver());
89 executor.execute(&mut q).await?;
90 query = q.into();
92 query.clear();
93 }
94 writer.write_create_table::<Self>(&mut query, if_not_exists);
95 executor.execute(query).await.map(|_| ())
96 }
97 }
98
99 fn drop_table(
104 executor: &mut impl Executor,
105 if_exists: bool,
106 drop_schema: bool,
107 ) -> impl Future<Output = Result<()>> + Send
108 where
109 Self: Sized,
110 {
111 async move {
112 let mut query = DynQuery::with_capacity(256);
113 let writer = executor.driver().sql_writer();
114 writer.write_drop_table::<Self>(&mut query, if_exists);
115 if drop_schema && !Self::table().schema.is_empty() {
116 if !executor.accepts_multiple_statements() {
117 let mut q = query.into_query(executor.driver());
118 executor.execute(&mut q).await?;
119 query = q.into();
121 query.clear();
122 }
123 writer.write_drop_schema::<Self>(&mut query, true);
124 }
125 executor.execute(query).await.map(|_| ())
126 }
127 }
128
129 fn insert_one(
131 executor: &mut impl Executor,
132 entity: impl AsEntity,
133 ) -> impl Future<Output = Result<RowsAffected>> + Send {
134 let mut query = DynQuery::with_capacity(128);
135 executor
136 .driver()
137 .sql_writer()
138 .write_insert(&mut query, [entity], false);
139 executor.execute(query)
140 }
141
142 fn insert_many<It>(
144 executor: &mut impl Executor,
145 items: It,
146 ) -> impl Future<Output = Result<RowsAffected>> + Send
147 where
148 Self: Sized,
149 It: IntoIterator + Send,
150 It::IntoIter: Send,
151 It::Item: AsEntity,
152 {
153 executor.append(items)
154 }
155
156 fn prepare_find<Exec: Executor>(
160 executor: &mut Exec,
161 condition: impl Expression,
162 limit: Option<u32>,
163 ) -> impl Future<Output = Result<Query<Exec::Driver>>> + Send {
164 let builder = QueryBuilder::new()
165 .select(Self::columns())
166 .from(Self::table())
167 .where_expr(condition)
168 .limit(limit);
169 let writer = executor.driver().sql_writer();
170 let mut query = DynQuery::default();
171 writer.write_select(&mut query, &builder);
172 async {
173 if let DynQuery::Raw(RawQuery(sql)) = query {
174 executor.prepare(sql).await
175 } else {
176 Ok(query.into())
177 }
178 }
179 }
180
181 fn find_one(
185 executor: &mut impl Executor,
186 condition: impl Expression,
187 ) -> impl Future<Output = Result<Option<Self>>> + Send
188 where
189 Self: Sized,
190 {
191 let stream = Self::find_many(executor, condition, Some(1));
192 async move { pin!(stream).into_future().map(|(v, _)| v).await.transpose() }
193 }
194
195 fn find_many(
200 executor: &mut impl Executor,
201 condition: impl Expression,
202 limit: Option<u32>,
203 ) -> impl Stream<Item = Result<Self>> + Send
204 where
205 Self: Sized,
206 {
207 let builder = QueryBuilder::new()
208 .select(Self::columns())
209 .from(Self::table())
210 .where_expr(condition)
211 .limit(limit);
212 executor
213 .fetch(builder.build(&executor.driver()))
214 .map(|result| result.and_then(Self::from_row))
215 }
216
217 fn delete_many(
221 executor: &mut impl Executor,
222 condition: impl Expression,
223 ) -> impl Future<Output = Result<RowsAffected>> + Send
224 where
225 Self: Sized,
226 {
227 let mut query = DynQuery::with_capacity(128);
228 executor
229 .driver()
230 .sql_writer()
231 .write_delete::<Self>(&mut query, condition);
232 executor.execute(query)
233 }
234
235 fn save(&self, executor: &mut impl Executor) -> impl Future<Output = Result<()>> + Send
241 where
242 Self: Sized,
243 for<'s> &'s Self: AsEntity,
244 {
245 if Self::primary_key_def().is_empty() {
246 let error = anyhow!(
247 "Cannot save an entity without a primary key, it would always result in an insert",
248 );
249 log::error!("{error:#}");
250 return Either::Left(future::ready(Err(error)));
251 }
252 let mut query = DynQuery::with_capacity(512);
253 executor
254 .driver()
255 .sql_writer()
256 .write_insert(&mut query, [self], true);
257 let sql = query.as_str();
258 let context = format!("While saving using the query {}", truncate_long!(sql));
259 Either::Right(executor.execute(query).map(|mut v| {
260 if let Ok(result) = v
261 && let Some(affected) = result.rows_affected
262 && affected > 2
263 {
264 v = Err(anyhow!(
265 "The driver returned affected rows: {affected} (expected <= 2)"
266 ));
267 }
268 match v {
269 Ok(_) => Ok(()),
270 Err(e) => Err(e.context(context)),
271 }
272 }))
273 }
274
275 fn delete(&self, executor: &mut impl Executor) -> impl Future<Output = Result<()>> + Send
282 where
283 Self: Sized,
284 {
285 if Self::primary_key_def().is_empty() {
286 let error =
287 anyhow!("Cannot delete an entity without a primary key, it would delete nothing",);
288 log::error!("{error:#}");
289 return Either::Left(future::ready(Err(error)));
290 }
291 Either::Right(
292 Self::delete_many(executor, self.primary_key_expr()).map(|v| {
293 v.and_then(|v| {
294 if let Some(affected) = v.rows_affected {
295 if affected != 1 {
296 let error = anyhow!(
297 "The query deleted {affected} rows instead of the expected 1"
298 );
299 log::log!(
300 if affected == 0 {
301 Level::Info
302 } else {
303 Level::Error
304 },
305 "{error}",
306 );
307 return Err(error);
308 }
309 }
310 Ok(())
311 })
312 }),
313 )
314 }
315}
316
317impl<E: Entity> Dataset for E {
318 fn qualified_columns() -> bool
322 where
323 Self: Sized,
324 {
325 false
326 }
327
328 fn write_table_name(&self, writer: &dyn SqlWriter, context: &mut Context, out: &mut DynQuery) {
330 Self::table().write_table_name(writer, context, out);
331 }
332
333 fn table_ref(&self) -> TableRef {
334 Self::table().clone()
335 }
336}