rust_query/
db.rs

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