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// =============================================================================
26// DialectTypes — maps conceptual SQL types to dialect-native markers
27// =============================================================================
28
29use crate::types::{Binary, BooleanLike, DataType, Floating, Integral, Temporal, Textual};
30
31/// Maps conceptual SQL types (Int, Text, Bool, ...) to dialect-native markers.
32///
33/// Implemented for [`SQLiteDialect`] and [`PostgresDialect`] so that
34/// expressions like `i32` can resolve to `sqlite::types::Integer` or
35/// `postgres::types::Int4` depending on the value type `V`.
36pub trait DialectTypes {
37    type SmallInt: DataType + Integral;
38    type Int: DataType + Integral;
39    type BigInt: DataType + Integral;
40    type Float: DataType + Floating;
41    type Double: DataType + Floating;
42    type Text: DataType + Textual;
43    type Bool: DataType + BooleanLike;
44    type Bytes: DataType + Binary;
45    type Date: DataType + Temporal;
46    type Time: DataType + Temporal;
47    type Timestamp: DataType + Temporal;
48    type TimestampTz: DataType + Temporal;
49    type Uuid: DataType;
50    type Json: DataType;
51    type Jsonb: DataType;
52    type Any: DataType;
53}
54
55impl DialectTypes for SQLiteDialect {
56    type SmallInt = drizzle_types::sqlite::types::Integer;
57    type Int = drizzle_types::sqlite::types::Integer;
58    type BigInt = drizzle_types::sqlite::types::Integer;
59    type Float = drizzle_types::sqlite::types::Real;
60    type Double = drizzle_types::sqlite::types::Real;
61    type Text = drizzle_types::sqlite::types::Text;
62    type Bool = drizzle_types::sqlite::types::Integer;
63    type Bytes = drizzle_types::sqlite::types::Blob;
64    type Date = drizzle_types::sqlite::types::Text;
65    type Time = drizzle_types::sqlite::types::Text;
66    type Timestamp = drizzle_types::sqlite::types::Text;
67    type TimestampTz = drizzle_types::sqlite::types::Text;
68    type Uuid = drizzle_types::sqlite::types::Blob;
69    type Json = drizzle_types::sqlite::types::Text;
70    type Jsonb = drizzle_types::sqlite::types::Text;
71    type Any = drizzle_types::sqlite::types::Any;
72}
73
74impl DialectTypes for PostgresDialect {
75    type SmallInt = drizzle_types::postgres::types::Int2;
76    type Int = drizzle_types::postgres::types::Int4;
77    type BigInt = drizzle_types::postgres::types::Int8;
78    type Float = drizzle_types::postgres::types::Float4;
79    type Double = drizzle_types::postgres::types::Float8;
80    type Text = drizzle_types::postgres::types::Text;
81    type Bool = drizzle_types::postgres::types::Boolean;
82    type Bytes = drizzle_types::postgres::types::Bytea;
83    type Date = drizzle_types::postgres::types::Date;
84    type Time = drizzle_types::postgres::types::Time;
85    type Timestamp = drizzle_types::postgres::types::Timestamp;
86    type TimestampTz = drizzle_types::postgres::types::Timestamptz;
87    type Uuid = drizzle_types::postgres::types::Uuid;
88    type Json = drizzle_types::postgres::types::Json;
89    type Jsonb = drizzle_types::postgres::types::Jsonb;
90    type Any = drizzle_types::postgres::types::Any;
91}
92
93/// Parameter placeholder rendering style.
94///
95/// Decouples placeholder syntax from [`Dialect`] so drivers that speak a
96/// given SQL dialect but bind parameters differently (e.g. AWS Aurora Data
97/// API — Postgres SQL, named `:N` parameters) can request a non-default
98/// style without duplicating the whole dialect plumbing.
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub enum ParamStyle {
101    /// `$1, $2, ...` — `PostgreSQL` native wire protocol.
102    DollarNumbered,
103    /// `?` — `SQLite` / `MySQL` positional.
104    Question,
105    /// `:1, :2, ...` — AWS Aurora Data API named parameters.
106    ///
107    /// Names are stringified 1-indexed ordinals, matching the
108    /// `SqlParameter { name: "1", ... }` encoding the Data API expects.
109    ColonNumbered,
110}
111
112impl ParamStyle {
113    /// Default placeholder style for a given dialect when the driver hasn't
114    /// overridden it.
115    #[inline]
116    #[must_use]
117    pub const fn for_dialect(dialect: Dialect) -> Self {
118        match dialect {
119            Dialect::PostgreSQL => Self::DollarNumbered,
120            Dialect::SQLite | Dialect::MySQL => Self::Question,
121        }
122    }
123
124    /// Write the placeholder for `index` (1-indexed) to the buffer.
125    #[inline]
126    pub fn write(self, index: usize, buf: &mut impl core::fmt::Write) {
127        match self {
128            Self::DollarNumbered => {
129                let _ = buf.write_char('$');
130                let _ = write!(buf, "{index}");
131            }
132            Self::ColonNumbered => {
133                let _ = buf.write_char(':');
134                let _ = write!(buf, "{index}");
135            }
136            Self::Question => {
137                let _ = buf.write_char('?');
138            }
139        }
140    }
141}
142
143/// Writes a dialect-appropriate placeholder directly to a buffer.
144///
145/// Equivalent to `ParamStyle::for_dialect(dialect).write(index, buf)`. Kept
146/// as a free function for existing call sites that don't need a style override.
147#[inline]
148pub fn write_placeholder(dialect: Dialect, index: usize, buf: &mut impl core::fmt::Write) {
149    ParamStyle::for_dialect(dialect).write(index, buf);
150}