Skip to main content

drizzle_core/
dialect.rs

1//! Dialect type re-exported from drizzle-types with core-specific extensions.
2
3/// Re-export the unified Dialect enum from drizzle-types
4pub use drizzle_types::Dialect;
5
6// =============================================================================
7// Type-level dialect markers
8// =============================================================================
9
10/// Type-level marker for `SQLite`.
11///
12/// Used by [`crate::row::SQLTypeToRust`] to provide SQLite-specific type mappings.
13/// `SQLite` stores UUIDs as BLOB by default and uses TEXT for date/time and JSON values.
14#[derive(Debug, Clone, Copy)]
15pub struct SQLiteDialect;
16
17/// Type-level marker for `PostgreSQL`.
18///
19/// Used by [`crate::row::SQLTypeToRust`] to provide PostgreSQL-specific type mappings.
20/// `PostgreSQL` uses native binary formats for dates, UUIDs, and JSON, so the corresponding
21/// feature flags (`chrono`, `uuid`, `serde`) must be enabled.
22#[derive(Debug, Clone, Copy)]
23pub struct PostgresDialect;
24
25/// Type-level marker for `MySQL`.
26///
27/// MySQL keeps signed and unsigned integer markers distinct, uses backtick
28/// identifiers, and has one native JSON type. It has no native UUID or
29/// time-zone-bearing datetime type: UUIDs use `BINARY(16)`, while
30/// `TimestampTz` maps to session-time-zone-aware `TIMESTAMP`. Concrete
31/// wire-driver behavior remains outside this marker.
32#[derive(Debug, Clone, Copy)]
33pub struct MySQLDialect;
34
35// =============================================================================
36// DialectTypes — maps conceptual SQL types to dialect-native markers
37// =============================================================================
38
39use crate::types::{Binary, BooleanLike, DataType, Floating, Integral, Temporal, Textual};
40
41/// Maps conceptual SQL types (Int, Text, Bool, ...) to dialect-native markers.
42///
43/// Implemented for [`SQLiteDialect`], [`PostgresDialect`], and
44/// [`MySQLDialect`] so that
45/// expressions like `i32` can resolve to `sqlite::types::Integer` or
46/// `postgres::types::Int4` depending on the value type `V`.
47pub trait DialectTypes {
48    type SmallInt: DataType + Integral;
49    type Int: DataType + Integral;
50    type BigInt: DataType + Integral;
51    type Float: DataType + Floating;
52    type Double: DataType + Floating;
53    type Text: DataType + Textual;
54    type Bool: DataType + BooleanLike;
55    type Bytes: DataType + Binary;
56    type Date: DataType + Temporal;
57    type Time: DataType + Temporal;
58    type Timestamp: DataType + Temporal;
59    type TimestampTz: DataType + Temporal;
60    type Uuid: DataType;
61    type Json: DataType;
62    type Jsonb: DataType;
63    type Any: DataType;
64}
65
66impl DialectTypes for SQLiteDialect {
67    type SmallInt = drizzle_types::sqlite::types::Integer;
68    type Int = drizzle_types::sqlite::types::Integer;
69    type BigInt = drizzle_types::sqlite::types::Integer;
70    type Float = drizzle_types::sqlite::types::Real;
71    type Double = drizzle_types::sqlite::types::Real;
72    type Text = drizzle_types::sqlite::types::Text;
73    type Bool = drizzle_types::sqlite::types::Integer;
74    type Bytes = drizzle_types::sqlite::types::Blob;
75    type Date = drizzle_types::sqlite::types::Text;
76    type Time = drizzle_types::sqlite::types::Text;
77    type Timestamp = drizzle_types::sqlite::types::Text;
78    type TimestampTz = drizzle_types::sqlite::types::Text;
79    type Uuid = drizzle_types::sqlite::types::Blob;
80    type Json = drizzle_types::sqlite::types::Text;
81    type Jsonb = drizzle_types::sqlite::types::Text;
82    type Any = drizzle_types::sqlite::types::Any;
83}
84
85impl DialectTypes for PostgresDialect {
86    type SmallInt = drizzle_types::postgres::types::Int2;
87    type Int = drizzle_types::postgres::types::Int4;
88    type BigInt = drizzle_types::postgres::types::Int8;
89    type Float = drizzle_types::postgres::types::Float4;
90    type Double = drizzle_types::postgres::types::Float8;
91    type Text = drizzle_types::postgres::types::Text;
92    type Bool = drizzle_types::postgres::types::Boolean;
93    type Bytes = drizzle_types::postgres::types::Bytea;
94    type Date = drizzle_types::postgres::types::Date;
95    type Time = drizzle_types::postgres::types::Time;
96    type Timestamp = drizzle_types::postgres::types::Timestamp;
97    type TimestampTz = drizzle_types::postgres::types::Timestamptz;
98    type Uuid = drizzle_types::postgres::types::Uuid;
99    type Json = drizzle_types::postgres::types::Json;
100    type Jsonb = drizzle_types::postgres::types::Jsonb;
101    type Any = drizzle_types::postgres::types::Any;
102}
103
104impl DialectTypes for MySQLDialect {
105    type SmallInt = drizzle_types::mysql::types::SmallInt;
106    type Int = drizzle_types::mysql::types::Int;
107    type BigInt = drizzle_types::mysql::types::BigInt;
108    type Float = drizzle_types::mysql::types::Float;
109    type Double = drizzle_types::mysql::types::Double;
110    type Text = drizzle_types::mysql::types::Text;
111    type Bool = drizzle_types::mysql::types::Boolean;
112    type Bytes = drizzle_types::mysql::types::Blob;
113    type Date = drizzle_types::mysql::types::Date;
114    type Time = drizzle_types::mysql::types::Time;
115    type Timestamp = drizzle_types::mysql::types::DateTime;
116    type TimestampTz = drizzle_types::mysql::types::Timestamp;
117    type Uuid = drizzle_types::mysql::types::Binary;
118    type Json = drizzle_types::mysql::types::Json;
119    type Jsonb = drizzle_types::mysql::types::Json;
120    type Any = drizzle_types::mysql::types::Any;
121}
122
123/// Parameter placeholder rendering style.
124///
125/// Decouples placeholder syntax from [`Dialect`] so drivers that speak a
126/// given SQL dialect but bind parameters differently (e.g. AWS Aurora Data
127/// API — Postgres SQL, named `:N` parameters) can request a non-default
128/// style without duplicating the whole dialect plumbing.
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum ParamStyle {
131    /// `$1, $2, ...` — `PostgreSQL` native wire protocol.
132    DollarNumbered,
133    /// `?` — `SQLite` / `MySQL` positional.
134    Question,
135    /// `:1, :2, ...` — AWS Aurora Data API named parameters.
136    ///
137    /// Names are stringified 1-indexed ordinals, matching the
138    /// `SqlParameter { name: "1", ... }` encoding the Data API expects.
139    ColonNumbered,
140}
141
142impl ParamStyle {
143    /// Default placeholder style for a given dialect when the driver hasn't
144    /// overridden it.
145    #[inline]
146    #[must_use]
147    pub const fn for_dialect(dialect: Dialect) -> Self {
148        match dialect {
149            Dialect::PostgreSQL => Self::DollarNumbered,
150            Dialect::SQLite | Dialect::MySQL => Self::Question,
151        }
152    }
153
154    /// Write the placeholder for `index` (1-indexed) to the buffer.
155    #[inline]
156    pub fn write(self, index: usize, buf: &mut impl core::fmt::Write) {
157        match self {
158            Self::DollarNumbered => {
159                let _ = buf.write_char('$');
160                let _ = write!(buf, "{index}");
161            }
162            Self::ColonNumbered => {
163                let _ = buf.write_char(':');
164                let _ = write!(buf, "{index}");
165            }
166            Self::Question => {
167                let _ = buf.write_char('?');
168            }
169        }
170    }
171}
172
173/// Writes a dialect-appropriate placeholder directly to a buffer.
174///
175/// Equivalent to `ParamStyle::for_dialect(dialect).write(index, buf)`. Kept
176/// as a free function for existing call sites that don't need a style override.
177#[inline]
178pub fn write_placeholder(dialect: Dialect, index: usize, buf: &mut impl core::fmt::Write) {
179    ParamStyle::for_dialect(dialect).write(index, buf);
180}