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> Eq for TableRow<T> {}
51
52impl<T: Table> PartialOrd for TableRow<T> {
53    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
54        Some(self.cmp(other))
55    }
56}
57
58impl<T: Table> Ord for TableRow<T> {
59    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
60        self.inner.idx.cmp(&other.inner.idx)
61    }
62}
63
64pub(crate) struct TableRowInner<T> {
65    pub(crate) _p: PhantomData<T>,
66    pub(crate) idx: i64,
67}
68
69impl<T: Table> PartialEq for TableRow<T> {
70    fn eq(&self, other: &Self) -> bool {
71        self.inner.idx == other.inner.idx
72    }
73}
74
75impl<T: Table> Debug for TableRow<T> {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        write!(f, "db_{}", self.inner.idx)
78    }
79}
80
81impl<T: Table> Clone for TableRow<T> {
82    fn clone(&self) -> Self {
83        *self
84    }
85}
86
87impl<T: Table> Copy for TableRow<T> {}
88
89impl<T> Clone for TableRowInner<T> {
90    fn clone(&self) -> Self {
91        *self
92    }
93}
94impl<T> Copy for TableRowInner<T> {}
95
96impl<T: Table> From<TableRow<T>> for sea_query::Value {
97    fn from(value: TableRow<T>) -> Self {
98        value.inner.idx.into()
99    }
100}
101
102impl<T: Table> Typed for TableRowInner<T> {
103    type Typ = T;
104    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
105        sea_query::Expr::val(self.idx).into()
106    }
107    fn maybe_optional(&self) -> bool {
108        false
109    }
110}
111
112// works for any schema?
113impl<'column, S, T: Table> IntoExpr<'column, S> for TableRow<T> {
114    type Typ = T;
115    fn into_expr(self) -> Expr<'static, S, Self::Typ> {
116        Expr::new(self.inner)
117    }
118}
119
120/// This makes it possible to use TableRow as a parameter in
121/// rusqlite queries and statements.
122impl<T: Table> rusqlite::ToSql for TableRow<T> {
123    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
124        self.inner.idx.to_sql()
125    }
126}