Skip to main content

gatekeep_sqlx/fragment/
backend.rs

1use super::{SqlxDriver, SqlxValue};
2use sqlx::QueryBuilder;
3use std::fmt::Debug;
4
5/// `SQLx` backend supported by gatekeep lowering.
6pub trait GatekeepSqlxBackend: Clone + Copy + Debug + Send + Sync + 'static {
7    /// `SQLx` database driver for this backend.
8    type Database: sqlx::Database;
9
10    /// Database driver represented by this backend.
11    const DRIVER: SqlxDriver;
12
13    /// Stable backend name.
14    const NAME: &'static str;
15
16    /// Appends one bind placeholder to rendered SQL.
17    fn push_placeholder(sql: &mut String, index: usize);
18
19    /// Appends one typed bind value to a `SQLx` query builder.
20    fn push_bind(builder: &mut QueryBuilder<Self::Database>, value: &SqlxValue);
21
22    /// Name of the SQL function that returns the lower of two non-null grades.
23    const MIN_FUNCTION: &'static str;
24
25    /// Name of the SQL function that returns the higher of two non-null grades.
26    const MAX_FUNCTION: &'static str;
27
28    /// Whether the backend's grade functions return `NULL` when any input is
29    /// `NULL`.
30    const GRADE_FUNCTION_PROPAGATES_NULL: bool;
31}
32
33macro_rules! push_sqlx_bind {
34    ($builder:expr, $value:expr) => {
35        match $value {
36            SqlxValue::Bool(value) => {
37                $builder.push_bind(*value);
38            }
39            SqlxValue::I16(value) => {
40                $builder.push_bind(*value);
41            }
42            SqlxValue::I32(value) => {
43                $builder.push_bind(*value);
44            }
45            SqlxValue::I64(value) => {
46                $builder.push_bind(*value);
47            }
48            SqlxValue::Text(value) => {
49                $builder.push_bind(value.clone());
50            }
51            SqlxValue::Bytes(value) => {
52                $builder.push_bind(value.clone());
53            }
54            SqlxValue::Uuid(value) => {
55                $builder.push_bind(*value);
56            }
57            SqlxValue::Date(value) => {
58                $builder.push_bind(*value);
59            }
60            SqlxValue::Time(value) => {
61                $builder.push_bind(*value);
62            }
63            SqlxValue::Timestamp(value) => {
64                $builder.push_bind(*value);
65            }
66            SqlxValue::TimestampTz(value) => {
67                $builder.push_bind(*value);
68            }
69        }
70    };
71}
72
73/// Postgres backend marker.
74#[cfg(feature = "postgres")]
75#[derive(Clone, Copy, Debug)]
76pub struct PostgresBackend;
77
78#[cfg(feature = "postgres")]
79impl GatekeepSqlxBackend for PostgresBackend {
80    type Database = sqlx::Postgres;
81
82    const DRIVER: SqlxDriver = SqlxDriver::Postgres;
83    const NAME: &'static str = "postgres";
84    const MIN_FUNCTION: &'static str = "LEAST";
85    const MAX_FUNCTION: &'static str = "GREATEST";
86    const GRADE_FUNCTION_PROPAGATES_NULL: bool = false;
87
88    fn push_placeholder(sql: &mut String, index: usize) {
89        sql.push('$');
90        sql.push_str(&index.to_string());
91    }
92
93    fn push_bind(builder: &mut QueryBuilder<Self::Database>, value: &SqlxValue) {
94        push_sqlx_bind!(builder, value);
95    }
96}
97
98/// `SQLite` backend marker.
99#[cfg(feature = "sqlite")]
100#[derive(Clone, Copy, Debug)]
101pub struct SqliteBackend;
102
103#[cfg(feature = "sqlite")]
104impl GatekeepSqlxBackend for SqliteBackend {
105    type Database = sqlx::Sqlite;
106
107    const DRIVER: SqlxDriver = SqlxDriver::Sqlite;
108    const NAME: &'static str = "sqlite";
109    const MIN_FUNCTION: &'static str = "min";
110    const MAX_FUNCTION: &'static str = "max";
111    const GRADE_FUNCTION_PROPAGATES_NULL: bool = true;
112
113    fn push_placeholder(sql: &mut String, _index: usize) {
114        sql.push('?');
115    }
116
117    fn push_bind(builder: &mut QueryBuilder<Self::Database>, value: &SqlxValue) {
118        push_sqlx_bind!(builder, value);
119    }
120}
121
122/// `MySQL` backend marker.
123#[cfg(feature = "mysql")]
124#[derive(Clone, Copy, Debug)]
125pub struct MySqlBackend;
126
127#[cfg(feature = "mysql")]
128impl GatekeepSqlxBackend for MySqlBackend {
129    type Database = sqlx::MySql;
130
131    const DRIVER: SqlxDriver = SqlxDriver::MySql;
132    const NAME: &'static str = "mysql";
133    const MIN_FUNCTION: &'static str = "LEAST";
134    const MAX_FUNCTION: &'static str = "GREATEST";
135    const GRADE_FUNCTION_PROPAGATES_NULL: bool = true;
136
137    fn push_placeholder(sql: &mut String, _index: usize) {
138        sql.push('?');
139    }
140
141    fn push_bind(builder: &mut QueryBuilder<Self::Database>, value: &SqlxValue) {
142        push_sqlx_bind!(builder, value);
143    }
144}