rust_query/
db.rs

1use std::{fmt::Debug, marker::PhantomData, ops::Deref};
2
3use ref_cast::RefCast;
4use sea_query::{Alias, SimpleExpr};
5
6use crate::{
7    Expr, IntoExpr, LocalClient, Table,
8    alias::MyAlias,
9    value::{MyTableRef, Typed, ValueBuilder},
10};
11
12/// Table reference that is the result of a join.
13/// It can only be used in the query where it was created.
14/// Invariant in `'t`.
15pub(crate) struct Join<T> {
16    pub(crate) table_idx: MyTableRef,
17    pub(crate) _p: PhantomData<T>,
18}
19
20impl<T> Join<T> {
21    pub(crate) fn new(table_idx: MyTableRef) -> Self {
22        Self {
23            table_idx,
24            _p: PhantomData,
25        }
26    }
27}
28
29impl<T: Table> Typed for Join<T> {
30    type Typ = T;
31    fn build_expr(&self, b: &mut ValueBuilder) -> SimpleExpr {
32        sea_query::Expr::col((self.build_table(b), Alias::new(T::ID))).into()
33    }
34    fn build_table(&self, b: &mut ValueBuilder) -> MyAlias {
35        b.get_table::<T>(self.table_idx.clone())
36    }
37}
38
39/// Row reference that can be used in any query in the same transaction.
40///
41/// [TableRow] is covariant in `'t` and restricted to a single thread to prevent it from being used in a different transaction.
42pub struct TableRow<'t, T> {
43    pub(crate) _p: PhantomData<&'t ()>,
44    pub(crate) _local: PhantomData<LocalClient>,
45    pub(crate) inner: TableRowInner<T>,
46}
47impl<T> TableRow<'_, T> {
48    pub(crate) fn new(idx: i64) -> Self {
49        Self {
50            _p: PhantomData,
51            _local: PhantomData,
52            inner: TableRowInner {
53                _p: PhantomData,
54                idx,
55            },
56        }
57    }
58}
59
60impl<T> Eq for TableRow<'_, T> {}
61
62impl<T> PartialOrd for TableRow<'_, T> {
63    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
64        Some(self.cmp(other))
65    }
66}
67
68impl<T> Ord for TableRow<'_, T> {
69    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
70        self.inner.idx.cmp(&other.inner.idx)
71    }
72}
73
74pub(crate) struct TableRowInner<T> {
75    pub(crate) _p: PhantomData<T>,
76    pub(crate) idx: i64,
77}
78
79impl<T> PartialEq for TableRow<'_, T> {
80    fn eq(&self, other: &Self) -> bool {
81        self.inner.idx == other.inner.idx
82    }
83}
84
85impl<T> Debug for TableRow<'_, T> {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        write!(f, "db_{}", self.inner.idx)
88    }
89}
90
91impl<T> Clone for TableRow<'_, T> {
92    fn clone(&self) -> Self {
93        *self
94    }
95}
96impl<T> Copy for TableRow<'_, T> {}
97
98impl<T> Clone for TableRowInner<T> {
99    fn clone(&self) -> Self {
100        *self
101    }
102}
103impl<T> Copy for TableRowInner<T> {}
104
105impl<T: Table> Deref for TableRow<'_, T> {
106    type Target = T::Ext<Self>;
107
108    fn deref(&self) -> &Self::Target {
109        RefCast::ref_cast(self)
110    }
111}
112
113impl<T> From<TableRow<'_, T>> for sea_query::Value {
114    fn from(value: TableRow<T>) -> Self {
115        value.inner.idx.into()
116    }
117}
118
119impl<T: Table> Typed for TableRowInner<T> {
120    type Typ = T;
121    fn build_expr(&self, _: &mut ValueBuilder) -> SimpleExpr {
122        sea_query::Expr::val(self.idx).into()
123    }
124}
125
126impl<'t, S, T: Table> IntoExpr<'t, S> for TableRow<'t, T> {
127    type Typ = T;
128    fn into_expr(self) -> Expr<'t, S, Self::Typ> {
129        Expr::new(self.inner)
130    }
131}
132
133/// This makes it possible to use TableRow as a parameter in
134/// rusqlite queries and statements.
135impl<T> rusqlite::ToSql for TableRow<'_, T> {
136    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
137        self.inner.idx.to_sql()
138    }
139}