Skip to main content

flyer_orm/
lib.rs

1pub mod sqlite;
2pub mod postgres;
3pub mod mysql;
4pub mod query;
5
6use std::{collections::HashMap, marker::PhantomData, str, sync::LazyLock};
7
8use anyhow::{Ok, Result};
9use sqlx::{Arguments, Encode, FromRow, Pool, types::Type};
10
11use crate::query::{JoinQuery, JoinType, Order, OrderQuery, Pagination, Statement, Transaction, WhereQuery, WhereQueryGroup};
12
13pub(crate) static mut CONNECTIONS: LazyLock<HashMap<&str, String>> = LazyLock::new(|| HashMap::new());
14
15#[allow(async_fn_in_trait)]
16pub trait Executor {
17    type T: sqlx::Database;
18
19    async fn new(url: &str) -> Self where Self: Sized;
20
21    fn db<'q>(&'q self) -> &'q Pool<Self::T>; 
22
23    fn to_sql<'q>(&self, statement: &'q Statement<'q, Self::T>) -> Result<String>;
24
25    async fn execute<'q>(&self, sql: &'q str) -> Result<()>;
26
27    async fn insert<'q>(&self, statement: &'q Statement<'q, Self::T>) -> Result<()>;
28
29    async fn update<'q>(&self, statement: &'q Statement<'q, Self::T>) -> Result<()>;
30
31    async fn count<'q>(&self, statement: &'q Statement<'q, Self::T>) -> Result<u64>;
32
33    async fn delete<'q>(&self, statement: &'q Statement<'q, Self::T>) -> Result<()>;
34
35    async fn insert_as<'q, O>(&self, statement: &'q Statement<'q, Self::T>) -> Result<O>
36    where
37        O: for<'r> FromRow<'r, <Self::T as sqlx::Database>::Row> + Send + Unpin + Sized;
38
39    async fn query_all<'q, O, T: 'q + Encode<'q, Self::T> + Type<Self::T>>(&self, sql: &str, args: Vec<T>) -> Result<Vec<O>>
40    where
41        O: for<'r> FromRow<'r, <Self::T as sqlx::Database>::Row> + Send + Unpin + Sized;
42
43    async fn query_one<'q, O, T: 'q + Encode<'q, Self::T> + Type<Self::T>>(&self, sql: &str, args: Vec<T>) -> Result<O>
44    where
45        O: for<'r> FromRow<'r, <Self::T as sqlx::Database>::Row> + Send + Unpin + Sized;
46
47    async fn all<'q, O>(&self, statement: &'q Statement<'q, Self::T>) -> Result<Vec<O>>
48    where
49        O: for<'r> FromRow<'r, <Self::T as sqlx::Database>::Row> + Send + Unpin + Sized;
50
51    async fn first<'q, O>(&self, statement: &'q Statement<'q, Self::T>) -> Result<O>
52    where
53        O: for<'r> FromRow<'r, <Self::T as sqlx::Database>::Row> + Send + Unpin + Sized;
54
55    async fn paginate<'q, O>(&self, statement: &'q Statement<'q, Self::T>) -> Result<Pagination<O>>
56    where
57        O: for<'r> FromRow<'r, <Self::T as sqlx::Database>::Row> + Send + Unpin + Sized;
58}
59
60pub struct DB;
61
62impl DB {
63    #[allow(static_mut_refs)]
64    pub fn add(connection: &'static str, url: &str) {
65        unsafe { CONNECTIONS.insert(connection, url.to_string()); }
66    }
67
68    #[allow(static_mut_refs)]
69    pub fn remove(connection: &str) {
70        unsafe { CONNECTIONS.remove(connection); }
71    }
72
73    #[allow(static_mut_refs)]
74    pub async fn db<E: Executor>(connection: &str) -> Database::<E> {
75        return unsafe { Database::new(CONNECTIONS.get(connection).unwrap()).await };
76    }
77
78    pub async fn db_with_url<E: Executor>(url: &str) -> Database::<E> {
79        return Database::new(url).await;
80    }
81}
82
83#[derive(Debug)]
84pub struct Database<E: Executor> {
85    executor: E,
86}
87
88impl <E: Executor>Database<E> {
89    pub async fn new(url: &str) -> Self {
90        return Self {
91            executor: E::new(url).await,
92        }
93    }
94
95    pub async fn transaction<'q>(&self) -> Result<Transaction<'q, E::T>> {
96        return Ok(Transaction::new(self.executor.db().begin().await.unwrap()));
97    }
98
99    pub async fn execute(&self, sql: &str) -> Result<()> {
100        todo!();
101    }
102
103    pub fn query<'q>(&'q self, table: &str) -> Query<'q, E> {
104        return Query::new(table, &self.executor);
105    }
106
107    pub async fn close(&self) -> Result<()> {
108        return Ok(self.executor.db().close().await);
109    }
110}
111
112pub struct Query<'q, E: Executor> {
113    db: &'q E,
114    statement: Statement<'q, E::T>,
115    _marker: PhantomData<E>
116}
117
118impl <'q, E>Query<'q, E>
119where
120    E: Executor
121{
122    pub fn new(table: &str, exc: &'q E) -> Self {
123        return Self {
124            db: exc,
125            statement: Statement::<'q, E::T>::new(table),
126            _marker: PhantomData,
127        }
128    }
129
130    pub fn table(&mut self, name: &'q str) -> &mut Self {
131        self.statement.query.table = name.to_string();
132
133        return self;
134    }
135
136    pub fn select(&mut self, columns: Vec<&str>) -> &mut Self {
137        self.statement.query.select = columns.iter().map(|c| c.to_string()).collect();
138
139        return self;
140    }
141
142    pub fn r#where<T: 'q + Encode<'q, E::T> + Type<E::T>>(&mut self, column: &str, operator: &str, val: T) -> &mut Self {
143        if self.statement.query.where_queries.len() != 0 {
144            return self.and_where(column, operator, val);
145        }
146
147        // TODO: find better name...
148        self.statement.query.where_queries.push(WhereQuery {
149            column: Some(column.to_string()),
150            operator: Some(operator.to_string()),
151            position: None,
152            group: None
153        });
154
155        self.statement.arguments.add(val).unwrap();
156        
157        return self;
158    }
159
160    pub fn and_where<T: 'q + Encode<'q, E::T> + Type<E::T>>(&mut self, column: &str, operator: &str, val: T) -> &mut Self {
161        if self.statement.query.where_queries.len() == 0 {
162            return self.r#where(column, operator, val);
163        }
164
165        self.statement.query.where_queries.push(WhereQuery {
166            column: Some(column.to_string()),
167            operator: Some(operator.to_string()),
168            position: Some(query::QueryPosition::AND),
169            group: None
170        });
171
172        self.statement.arguments.add(val).unwrap();
173        
174        return self;
175    }
176
177    pub fn or_where<T: 'q + Encode<'q, E::T> + Type<E::T>>(&mut self, column: &str, operator: &str, val: T) -> &mut Self {
178        if self.statement.query.where_queries.len() == 0 {
179            return self.r#where(column, operator, val);
180        }
181
182        self.statement.query.where_queries.push(WhereQuery {
183            column: Some(column.to_string()),
184            operator: Some(operator.to_string()),
185            position: Some(query::QueryPosition::OR),
186            group: None
187        });
188
189        self.statement.arguments.add(val).unwrap();
190
191        return self;
192    }
193
194    pub fn where_group(&mut self, callback: fn(group: WhereQueryGroup<'q, E::T>) -> WhereQueryGroup<'q, E::T>) -> &mut Self {        
195        return self;
196    }
197
198    pub fn and_where_group(&mut self, callback: fn(group: WhereQueryGroup<'q, E::T>) -> WhereQueryGroup<'q, E::T>) -> &mut Self {        
199        return self;
200    }
201
202    pub fn or_where_group(&mut self, callback: fn(group: WhereQueryGroup<'q, E::T>) -> WhereQueryGroup<'q, E::T>) -> &mut Self {        
203        return self;
204    }
205
206    pub fn order_by(&mut self, column: &str, order: Order) -> &mut Self {
207        self.statement.query.order_by.push(OrderQuery {
208            column: column.to_string(),
209            order: order
210        });
211
212        return self;
213    }
214
215    pub fn join(&mut self, table: &str, column: &str, column_table: &str) -> &mut Self {
216        self.statement.query.join.push(JoinQuery {
217            table: table.to_string(),
218            column: column.to_string(),
219            operator: "=".to_string(),
220            column_table: column_table.to_string(),
221            join_type: JoinType::LeftJoin 
222        });
223
224        return self;
225    }
226
227    pub fn limit(&mut self, limit: u64) -> &mut Self {
228        self.statement.query.limit = Some(limit);
229
230        return self;
231    }
232
233    pub fn bind<T: 'q + Encode<'q, E::T> + Type<E::T>>(&'q mut self, value: T) -> &'q mut Self {
234        self.statement.arguments.add(value).unwrap();
235
236        return self;
237    }
238
239    pub async fn query<O, T: 'q + Encode<'q, E::T> + Type<E::T>>(&'q mut self, sql: &str, args: Vec<T>) -> Result<Vec<O>>
240    where
241        O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
242    {
243        return Ok(self.db.query_all::<O, T>(sql, args).await.unwrap());
244    }
245
246    // TODO: needs sub classes as insert_as to allow easy binding
247    pub async fn query_all<O, T: 'q + Encode<'q, E::T> + Type<E::T>>(&'q mut self, sql: &str, args: Vec<T>) -> Result<Vec<O>>
248    where
249        O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
250    {
251        return Ok(self.db.query_all::<O, T>(sql, args).await.unwrap());
252    }
253
254    // TODO: needs sub classes as insert_as to allow easy binding
255    pub async fn query_one<O, T: 'q + Encode<'q, E::T> + Type<E::T>>(&'q mut self, sql: &str, args: Vec<T>) -> Result<O>
256    where
257        O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
258    {
259        return Ok(self.db.query_one::<O, T>(sql, args).await.unwrap())
260    }
261
262    pub fn insert_as<O>(&'q mut self, columns: Vec<&str>) -> InsertAs<'q, E, O>
263    where
264        O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
265    {
266        self.statement.query.columns = Some(columns.iter().map(|c| c.to_string()).collect());
267
268        return InsertAs::new(self.db, &mut self.statement);
269    }
270
271    pub fn insert(&'q mut self, columns: Vec<&str>) -> Insert<'q, E> {
272        self.statement.query.columns = Some(columns.iter().map(|c| c.to_string()).collect());
273
274        return Insert::new(&self.db, &mut self.statement);
275    }
276
277    pub fn update(&'q mut self, columns: Vec<&str>) -> Update<'q, E> {
278        self.statement.query.columns = Some(columns.iter().map(|c| c.to_string()).collect());
279
280        return Update::new(&self.db, &mut self.statement);
281    }
282
283    pub async fn delete(&'q mut self) -> Result<()>
284    {
285        return Ok(self.db.delete(&self.statement).await.unwrap())
286    }
287
288    pub async fn first<O>(&'q mut self) -> Result<O>
289    where
290        O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
291    {
292        return Ok(self.db.first::<O>(&self.statement).await.unwrap())
293    }
294
295    pub async fn all<O>(&'q mut self) -> Result<Vec<O>>
296    where
297        O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
298    {
299        return Ok(self.db.all::<O>(&self.statement).await.unwrap())
300    }
301
302    pub async fn paginate<O>(&'q mut self, limit: u64, page: u64) -> Result<Pagination<O>>
303    where
304        O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
305    {
306        self.statement.query.limit = Some(limit);
307        self.statement.query.page = Some(page); // TODO: calc offset using offset
308
309        return Ok(self.db.paginate::<O>(&self.statement).await.unwrap());
310    }
311
312    pub fn to_sql(&'q mut self) -> Result<String> {
313        return Ok(self.db.to_sql(&self.statement).unwrap())
314    }
315}
316
317pub struct InsertAs<'q, E: Executor, O> {
318    db: &'q E,
319    statement: &'q mut Statement<'q, E::T>,
320    _marker: PhantomData<E>,
321    _type: PhantomData<O>
322}
323
324impl <'q, E, O>InsertAs<'q, E, O>
325where
326    E: Executor,
327    O: for<'r> FromRow<'r, <E::T as sqlx::Database>::Row> + Send + Unpin + Sized
328{
329    pub(crate) fn new(db: &'q E, statement: &'q mut Statement<'q, E::T>) -> Self {
330        return Self {
331            db: db,
332            statement: statement,
333            _marker: PhantomData,
334            _type: PhantomData
335        }
336    }
337
338    pub fn bind<T: 'q + Encode<'q, E::T> + Type<E::T>>(&'q mut self, value: T) -> &'q mut Self {
339        self.statement.arguments.add(value).unwrap();
340
341        return self;
342    }
343
344    pub async fn execute(&'q mut self) -> Result<O> {
345        return Ok(self.db.insert_as::<O>(self.statement).await.unwrap());
346    }
347}
348
349pub struct Insert<'q, E: Executor> {
350    db: &'q E,
351    statement: &'q mut Statement<'q, E::T>,
352    _marker: PhantomData<E>
353}
354
355impl <'q, E>Insert<'q, E>
356where
357    E: Executor
358{
359    pub(crate) fn new(db: &'q E, statement: &'q mut Statement<'q, E::T>) -> Self {
360        return Self {
361            db: db,
362            statement: statement,
363            _marker: PhantomData,
364        }
365    }
366
367    pub fn bind<T: 'q + Encode<'q, E::T> + Type<E::T>>(&'q mut self, value: T) -> &'q mut Self {
368        self.statement.arguments.add(value).unwrap();
369
370        return self;
371    }
372
373    pub async fn execute(&'q mut self) -> Result<()> {
374        return self.db.insert(self.statement).await;
375    }
376}
377
378pub struct Update<'q, E: Executor> {
379    db: &'q E,
380    statement: &'q mut Statement<'q, E::T>,
381    _marker: PhantomData<E>
382}
383
384impl <'q, E>Update<'q, E>
385where
386    E: Executor
387{
388    pub(crate) fn new(db: &'q E, statement: &'q mut Statement<'q, E::T>) -> Self {
389        return Self {
390            db: db,
391            statement: statement,
392            _marker: PhantomData,
393        }
394    }
395
396    pub fn bind<T: 'q + Encode<'q, E::T> + Type<E::T>>(&'q mut self, value: T) -> &'q mut Self {
397        self.statement.arguments.add(value).unwrap();
398
399        return self;
400    }
401
402
403    pub fn r#where<T: 'q + Encode<'q, E::T> + Type<E::T>>(&mut self, column: &str, operator: &str, val: T) -> &mut Self {
404        if self.statement.query.where_queries.len() != 0 {
405            return self.and_where(column, operator, val);
406        }
407
408        // TODO: find better name...
409        self.statement.query.where_queries.push(WhereQuery {
410            column: Some(column.to_string()),
411            operator: Some(operator.to_string()),
412            position: None,
413            group: None
414        });
415
416        self.statement.arguments.add(val).unwrap();
417        
418        return self;
419    }
420
421    pub fn and_where<T: 'q + Encode<'q, E::T> + Type<E::T>>(&mut self, column: &str, operator: &str, val: T) -> &mut Self {
422        if self.statement.query.where_queries.len() == 0 {
423            return self.r#where(column, operator, val);
424        }
425
426        self.statement.query.where_queries.push(WhereQuery {
427            column: Some(column.to_string()),
428            operator: Some(operator.to_string()),
429            position: Some(query::QueryPosition::AND),
430            group: None
431        });
432
433        self.statement.arguments.add(val).unwrap();
434        
435        return self;
436    }
437
438    pub fn or_where<T: 'q + Encode<'q, E::T> + Type<E::T>>(&mut self, column: &str, operator: &str, val: T) -> &mut Self {
439        if self.statement.query.where_queries.len() == 0 {
440            return self.r#where(column, operator, val);
441        }
442
443        self.statement.query.where_queries.push(WhereQuery {
444            column: Some(column.to_string()),
445            operator: Some(operator.to_string()),
446            position: Some(query::QueryPosition::OR),
447            group: None
448        });
449
450        self.statement.arguments.add(val).unwrap();
451
452        return self;
453    }
454
455    pub fn where_group(&mut self, callback: fn(group: WhereQueryGroup<'q, E::T>) -> WhereQueryGroup<'q, E::T>) -> &mut Self {        
456        return self;
457    }
458
459    pub fn and_where_group(&mut self, callback: fn(group: WhereQueryGroup<'q, E::T>) -> WhereQueryGroup<'q, E::T>) -> &mut Self {        
460        return self;
461    }
462
463    pub fn or_where_group(&mut self, callback: fn(group: WhereQueryGroup<'q, E::T>) -> WhereQueryGroup<'q, E::T>) -> &mut Self {        
464        return self;
465    }
466
467    pub async fn execute(&'q mut self) -> Result<()> {
468        return self.db.update(self.statement).await;
469    }
470}