Skip to main content

drizzle_postgres/
traits.rs

1//! Traits for `PostgreSQL` tables, columns, enums and custom column types,
2//! and for decoding values and driver rows.
3//!
4//! The macros implement most of these: `#[PostgresTable]` implements
5//! [`PostgresTable`] and [`PostgresColumn`], and `#[derive(PostgresEnum)]`
6//! implements [`DrizzlePostgresColumn`] (and [`PostgresEnum`] for native enums).
7//! Implement [`FromPostgresValue`] yourself to decode a custom type.
8
9mod column;
10mod table;
11mod value;
12
13#[cfg(not(feature = "std"))]
14use crate::prelude::*;
15pub use column::*;
16use core::any::Any;
17use drizzle_core::error::DrizzleError;
18pub use table::*;
19pub use value::*;
20
21use crate::values::{OwnedPostgresValue, PostgresValue};
22
23/// Object-safe view of a Rust enum stored as a `PostgreSQL` enum value.
24///
25/// `#[derive(PostgresEnum)]` implements it for enums stored as a native
26/// `PostgreSQL` enum type; integer-backed (`#[repr(...)]`) enums do not get it.
27/// It lets a [`PostgresValue`] hold any enum value as `dyn PostgresEnum` and
28/// bind it with its type name.
29#[allow(clippy::wrong_self_convention)]
30pub trait PostgresEnum: Send + Sync + Any {
31    /// Returns the `PostgreSQL` enum type name, such as `"mood"`.
32    fn enum_type_name(&self) -> &'static str;
33
34    /// Returns `self` as a trait object.
35    fn as_enum(&self) -> &dyn PostgresEnum;
36
37    /// Returns the variant's SQL label, such as `"happy"`.
38    fn variant_name(&self) -> &'static str;
39
40    /// Clones this value into a boxed trait object.
41    fn into_boxed(&self) -> Box<dyn PostgresEnum>;
42
43    /// Parses a variant from its SQL label.
44    ///
45    /// # Errors
46    ///
47    /// Returns [`DrizzleError::ConversionError`] when `value` is not a valid
48    /// variant name for this enum.
49    fn try_from_str(value: &str) -> Result<Self, DrizzleError>
50    where
51        Self: Sized;
52}
53
54impl core::fmt::Debug for &dyn PostgresEnum {
55    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56        f.debug_struct("PostgresSQLEnum")
57            .field("type", &self.enum_type_name())
58            .field("variant", &self.variant_name())
59            .finish()
60    }
61}
62
63impl PartialEq for &dyn PostgresEnum {
64    fn eq(&self, other: &Self) -> bool {
65        self.enum_type_name() == other.enum_type_name()
66            && self.variant_name() == other.variant_name()
67    }
68}
69
70impl core::fmt::Debug for Box<dyn PostgresEnum> {
71    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
72        f.debug_struct("PostgresSQLEnum")
73            .field("type", &self.enum_type_name())
74            .field("variant", &self.variant_name())
75            .finish()
76    }
77}
78
79impl Clone for Box<dyn PostgresEnum> {
80    fn clone(&self) -> Self {
81        self.into_boxed()
82    }
83}
84
85impl PartialEq for Box<dyn PostgresEnum> {
86    fn eq(&self, other: &Self) -> bool {
87        self.enum_type_name() == other.enum_type_name()
88            && self.variant_name() == other.variant_name()
89    }
90}
91
92/// A custom Rust type that can be used as a `PostgreSQL` column type.
93///
94/// `#[derive(PostgresEnum)]` implements it. The table macro uses this trait to
95/// detect enum fields, so they need no `#[column(ENUM)]` attribute.
96///
97/// The associated items say how the column is declared (`SQLType`,
98/// `SQL_TYPE`, `NEEDS_CREATE_TYPE`, `SCHEMA`) and how values are read
99/// (`decode`) and written (`encode`).
100///
101/// The blanket `From<Self> for PostgresValue` owns the encoded value because
102/// insert/update models may store SQL fragments after the source value is
103/// dropped. Call `encode()` directly when you need an immediate borrowed value.
104/// Override `encode_owned()` when consuming `self` can avoid cloning owned data.
105#[cfg(any(feature = "postgres-sync", feature = "tokio-postgres"))]
106#[diagnostic::on_unimplemented(
107    message = "`{Self}` cannot be used as a PostgreSQL column type",
108    note = "add #[derive(PostgresEnum)] for enum types, or use a supported primitive type"
109)]
110pub trait DrizzlePostgresColumn: Sized {
111    /// Drizzle SQL type marker for this column.
112    ///
113    /// Use one of the built-in PostgreSQL markers, such as `Text`, `Int4`,
114    /// `Bytea`, `Boolean`, `Numeric`, `Enum`, or `Any`.
115    type SQLType: drizzle_core::types::DataType;
116
117    /// Column type used in DDL: `"text"`, `"integer"`, or the native enum type name.
118    const SQL_TYPE: &'static str;
119
120    /// [`SQL_TYPE`](Self::SQL_TYPE) as `CREATE TABLE` writes it. Native
121    /// enums quote and schema-qualify their type (`"app"."Mood"`); other
122    /// types use `SQL_TYPE` unchanged.
123    const DDL_TYPE: &'static str = Self::SQL_TYPE;
124
125    /// Whether this requires a `CREATE TYPE` (native PG enum).
126    const NEEDS_CREATE_TYPE: bool = false;
127
128    /// Schema the custom type lives in (native PG enums with
129    /// `#[postgres_enum(schema = "...")]`). Defaults to `public`.
130    const SCHEMA: &'static str = "public";
131
132    /// Reads a value from column `idx` of a driver row.
133    ///
134    /// # Errors
135    ///
136    /// Returns [`DrizzleError::ConversionError`] when the column at `idx`
137    /// cannot be decoded into this type.
138    fn decode(row: &crate::Row, idx: usize) -> Result<Self, DrizzleError>;
139
140    /// Converts the value to a borrowed [`PostgresValue`] for binding.
141    fn encode(&self) -> PostgresValue<'_>;
142
143    /// Convert self to an owned `PostgreSQL` value for stored bind parameters.
144    ///
145    /// The default implementation owns the borrowed result of [`encode`](Self::encode).
146    /// Override this for wrappers that can move an internal string or byte buffer
147    /// directly into the SQL parameter.
148    fn encode_owned(self) -> OwnedPostgresValue {
149        self.encode().into_owned()
150    }
151}
152
153impl<'a, T> From<T> for PostgresValue<'a>
154where
155    T: DrizzlePostgresColumn,
156{
157    fn from(value: T) -> Self {
158        value.encode_owned().into()
159    }
160}
161
162/// A custom Rust type that can be used as a `PostgreSQL` column type
163/// (variant without a driver feature).
164///
165/// Without `postgres-sync` or `tokio-postgres` there is no row type, so this
166/// version has no `decode` method. Enum derives still compile, but the table
167/// macro does not generate row-decoding `TryFrom` impls.
168///
169/// The blanket `From<Self> for PostgresValue` owns the encoded value because
170/// insert/update models may store SQL fragments after the source value is
171/// dropped. Call `encode()` directly when you need an immediate borrowed value.
172/// Override `encode_owned()` when consuming `self` can avoid cloning owned data.
173#[cfg(not(any(feature = "postgres-sync", feature = "tokio-postgres")))]
174#[diagnostic::on_unimplemented(
175    message = "`{Self}` cannot be used as a PostgreSQL column type",
176    note = "add #[derive(PostgresEnum)] for enum types, or use a supported primitive type"
177)]
178pub trait DrizzlePostgresColumn: Sized {
179    /// Drizzle SQL type marker for this column.
180    ///
181    /// Use one of the built-in PostgreSQL markers, such as `Text`, `Int4`,
182    /// `Bytea`, `Boolean`, `Numeric`, `Enum`, or `Any`.
183    type SQLType: drizzle_core::types::DataType;
184
185    /// Column type used in DDL: `"text"`, `"integer"`, or the native enum type name.
186    const SQL_TYPE: &'static str;
187
188    /// [`SQL_TYPE`](Self::SQL_TYPE) as `CREATE TABLE` writes it. Native
189    /// enums quote and schema-qualify their type (`"app"."Mood"`); other
190    /// types use `SQL_TYPE` unchanged.
191    const DDL_TYPE: &'static str = Self::SQL_TYPE;
192
193    /// Whether this requires a `CREATE TYPE` (native PG enum).
194    const NEEDS_CREATE_TYPE: bool = false;
195
196    /// Schema the custom type lives in (native PG enums with
197    /// `#[postgres_enum(schema = "...")]`). Defaults to `public`.
198    const SCHEMA: &'static str = "public";
199
200    /// Converts the value to a borrowed [`PostgresValue`] for binding.
201    fn encode(&self) -> PostgresValue<'_>;
202
203    /// Convert self to an owned `PostgreSQL` value for stored bind parameters.
204    ///
205    /// The default implementation owns the borrowed result of [`encode`](Self::encode).
206    /// Override this for wrappers that can move an internal string or byte buffer
207    /// directly into the SQL parameter.
208    fn encode_owned(self) -> OwnedPostgresValue {
209        self.encode().into_owned()
210    }
211}