Skip to main content

drizzle_postgres/
traits.rs

1mod column;
2mod table;
3mod value;
4
5#[cfg(not(feature = "std"))]
6use crate::prelude::*;
7pub use column::*;
8use core::any::Any;
9use drizzle_core::error::DrizzleError;
10pub use table::*;
11pub use value::*;
12
13use crate::values::PostgresValue;
14
15/// Trait for `PostgreSQL` native enum types that can be used as dyn objects
16#[allow(clippy::wrong_self_convention)]
17pub trait PostgresEnum: Send + Sync + Any {
18    /// Get the enum type name for `PostgreSQL`
19    fn enum_type_name(&self) -> &'static str;
20
21    fn as_enum(&self) -> &dyn PostgresEnum;
22
23    /// Get the string representation of this enum variant
24    fn variant_name(&self) -> &'static str;
25
26    /// Clone this enum as a boxed trait object
27    fn into_boxed(&self) -> Box<dyn PostgresEnum>;
28
29    /// Try to create this enum from a string value
30    ///
31    /// # Errors
32    ///
33    /// Returns [`DrizzleError::ConversionError`] when `value` is not a valid
34    /// variant name for this enum.
35    fn try_from_str(value: &str) -> Result<Self, DrizzleError>
36    where
37        Self: Sized;
38}
39
40impl core::fmt::Debug for &dyn PostgresEnum {
41    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42        f.debug_struct("PostgresSQLEnum")
43            .field("type", &self.enum_type_name())
44            .field("variant", &self.variant_name())
45            .finish()
46    }
47}
48
49impl PartialEq for &dyn PostgresEnum {
50    fn eq(&self, other: &Self) -> bool {
51        self.enum_type_name() == other.enum_type_name()
52            && self.variant_name() == other.variant_name()
53    }
54}
55
56impl core::fmt::Debug for Box<dyn PostgresEnum> {
57    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58        f.debug_struct("PostgresSQLEnum")
59            .field("type", &self.enum_type_name())
60            .field("variant", &self.variant_name())
61            .finish()
62    }
63}
64
65impl Clone for Box<dyn PostgresEnum> {
66    fn clone(&self) -> Self {
67        self.into_boxed()
68    }
69}
70
71impl PartialEq for Box<dyn PostgresEnum> {
72    fn eq(&self, other: &Self) -> bool {
73        self.enum_type_name() == other.enum_type_name()
74            && self.variant_name() == other.variant_name()
75    }
76}
77
78/// Marker trait for custom Rust types that map to a `PostgreSQL` column.
79///
80/// Generated by `#[derive(PostgresEnum)]`. The table macro uses this trait to
81/// auto-detect enum types without requiring `#[column(ENUM)]`.
82///
83/// # Associated Constants
84///
85/// - `SQL_TYPE`: The `PostgreSQL` column type (e.g. `"text"`, `"integer"`, or the lowercased enum name)
86/// - `NEEDS_CREATE_TYPE`: Whether this requires a `CREATE TYPE` (native PG enum)
87///
88/// # Required Methods
89///
90/// - `from_postgres_row`: Read self from a postgres Row at the given index
91/// - `to_postgres_value`: Convert self to a `PostgresValue` for insertion/updates
92#[cfg(any(feature = "postgres-sync", feature = "tokio-postgres"))]
93#[diagnostic::on_unimplemented(
94    message = "`{Self}` cannot be used as a PostgreSQL column type",
95    note = "add #[derive(PostgresEnum)] for enum types, or use a supported primitive type"
96)]
97pub trait DrizzlePostgresColumn: Sized {
98    /// `PostgreSQL` column type: `"text"`, `"integer"`, or native enum type name
99    const SQL_TYPE: &'static str;
100
101    /// Whether this requires a `CREATE TYPE` (native PG enum).
102    const NEEDS_CREATE_TYPE: bool = false;
103
104    /// Read self from a postgres Row at the given index.
105    ///
106    /// # Errors
107    ///
108    /// Returns [`DrizzleError::ConversionError`] when the column at `idx`
109    /// cannot be decoded into this type.
110    fn from_postgres_row(row: &crate::Row, idx: usize) -> Result<Self, DrizzleError>;
111
112    /// Convert self to a `PostgresValue` for insertion/updates.
113    fn to_postgres_value(&self) -> PostgresValue<'static>;
114}
115
116/// Stub trait when no postgres driver is enabled — allows enum derives to compile
117/// without a driver feature, but the table macro's `TryFrom` impls won't be generated.
118#[cfg(not(any(feature = "postgres-sync", feature = "tokio-postgres")))]
119#[diagnostic::on_unimplemented(
120    message = "`{Self}` cannot be used as a PostgreSQL column type",
121    note = "add #[derive(PostgresEnum)] for enum types, or use a supported primitive type"
122)]
123pub trait DrizzlePostgresColumn: Sized {
124    /// `PostgreSQL` column type: `"text"`, `"integer"`, or native enum type name
125    const SQL_TYPE: &'static str;
126
127    /// Whether this requires a `CREATE TYPE` (native PG enum).
128    const NEEDS_CREATE_TYPE: bool = false;
129
130    /// Convert self to a `PostgresValue` for insertion/updates.
131    fn to_postgres_value(&self) -> PostgresValue<'static>;
132}