diesel/pg/
backend.rs

1//! The PostgreSQL backend
2
3use super::query_builder::PgQueryBuilder;
4use super::{PgMetadataLookup, PgValue};
5use crate::backend::*;
6use crate::deserialize::Queryable;
7use crate::expression::operators::LikeIsAllowedForType;
8use crate::pg::metadata_lookup::PgMetadataCacheKey;
9use crate::query_builder::bind_collector::RawBytesBindCollector;
10use crate::sql_types::TypeMetadata;
11
12/// The PostgreSQL backend
13#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
14pub struct Pg;
15
16#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Queryable)]
17pub struct InnerPgTypeMetadata {
18    pub(in crate::pg) oid: u32,
19    pub(in crate::pg) array_oid: u32,
20}
21
22impl From<(u32, u32)> for InnerPgTypeMetadata {
23    fn from((oid, array_oid): (u32, u32)) -> Self {
24        Self { oid, array_oid }
25    }
26}
27
28/// This error indicates that a type lookup for a custom
29/// postgres type failed
30#[derive(Clone, Debug, Hash, PartialEq, Eq)]
31#[cfg_attr(
32    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
33    cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
34)]
35#[allow(unreachable_pub)]
36pub struct FailedToLookupTypeError(Box<PgMetadataCacheKey<'static>>);
37
38impl FailedToLookupTypeError {
39    /// Construct a new instance of this error type
40    /// containing information about which type lookup failed
41    #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
42    pub fn new(cache_key: PgMetadataCacheKey<'static>) -> Self {
43        Self::new_internal(cache_key)
44    }
45
46    pub(in crate::pg) fn new_internal(cache_key: PgMetadataCacheKey<'static>) -> Self {
47        Self(Box::new(cache_key))
48    }
49}
50
51impl std::error::Error for FailedToLookupTypeError {}
52
53impl std::fmt::Display for FailedToLookupTypeError {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        if let Some(schema) = self.0.schema.as_ref() {
56            write!(
57                f,
58                "Failed to find a type oid for `{}`.`{}`",
59                schema, self.0.type_name
60            )
61        } else {
62            write!(f, "Failed to find a type oid for `{}`", self.0.type_name)
63        }
64    }
65}
66
67/// The [OIDs] for a SQL type
68///
69/// [OIDs]: https://www.postgresql.org/docs/current/static/datatype-oid.html
70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71#[must_use]
72pub struct PgTypeMetadata(pub(in crate::pg) Result<InnerPgTypeMetadata, FailedToLookupTypeError>);
73
74impl PgTypeMetadata {
75    /// Create a new instance of this type based on known constant [OIDs].
76    ///
77    /// Please refer to [PgMetadataLookup] for a way to query [OIDs]
78    /// of custom types at run time
79    ///
80    /// [OIDs]: https://www.postgresql.org/docs/current/static/datatype-oid.html
81    /// [PgMetadataLookup]: struct.PgMetadataLookup.html
82    pub fn new(type_oid: u32, array_oid: u32) -> Self {
83        Self(Ok(InnerPgTypeMetadata {
84            oid: type_oid,
85            array_oid,
86        }))
87    }
88
89    /// Create a new instance of this type based on dynamically lookup information
90    ///
91    /// This function is useful for third party crates that may implement a custom
92    /// postgres connection type and want to bring their own lookup mechanism.
93    ///
94    /// Otherwise refer to [PgMetadataLookup] for a way to automatically
95    /// implement the corresponding lookup functionality
96    #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
97    pub fn from_result(r: Result<(u32, u32), FailedToLookupTypeError>) -> Self {
98        Self(r.map(|(oid, array_oid)| InnerPgTypeMetadata { oid, array_oid }))
99    }
100
101    /// The [OID] of `T`
102    ///
103    /// [OID]: https://www.postgresql.org/docs/current/static/datatype-oid.html
104    pub fn oid(&self) -> Result<u32, impl std::error::Error + Send + Sync> {
105        self.0.as_ref().map(|i| i.oid).map_err(Clone::clone)
106    }
107
108    /// The [OID] of `T[]`
109    ///
110    /// [OID]: https://www.postgresql.org/docs/current/static/datatype-oid.html
111    pub fn array_oid(&self) -> Result<u32, impl std::error::Error + Send + Sync> {
112        self.0.as_ref().map(|i| i.array_oid).map_err(Clone::clone)
113    }
114}
115
116impl Backend for Pg {
117    type QueryBuilder = PgQueryBuilder;
118    type RawValue<'a> = PgValue<'a>;
119    type BindCollector<'a> = RawBytesBindCollector<Pg>;
120}
121
122impl TypeMetadata for Pg {
123    type TypeMetadata = PgTypeMetadata;
124    type MetadataLookup = dyn PgMetadataLookup;
125}
126
127impl SqlDialect for Pg {
128    type ReturningClause = sql_dialect::returning_clause::PgLikeReturningClause;
129
130    type OnConflictClause = PgOnConflictClause;
131
132    type InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword;
133    type BatchInsertSupport = sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport;
134    type ConcatClause = sql_dialect::concat_clause::ConcatWithPipesClause;
135
136    type DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause;
137
138    type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
139    type SelectStatementSyntax = sql_dialect::select_statement_syntax::AnsiSqlSelectStatement;
140
141    type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
142    type ArrayComparison = PgStyleArrayComparison;
143    type AliasSyntax = sql_dialect::alias_syntax::AsAliasSyntax;
144}
145
146impl DieselReserveSpecialization for Pg {}
147impl TrustedBackend for Pg {}
148
149#[derive(Debug, Copy, Clone)]
150pub struct PgOnConflictClause;
151
152impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for PgOnConflictClause {}
153impl sql_dialect::on_conflict_clause::SupportsOnConflictClauseWhere for PgOnConflictClause {}
154impl sql_dialect::on_conflict_clause::PgLikeOnConflictClause for PgOnConflictClause {}
155
156#[derive(Debug, Copy, Clone)]
157pub struct PgStyleArrayComparison;
158
159impl LikeIsAllowedForType<crate::sql_types::Binary> for Pg {}
160
161// Using the same field names as tokio-postgres
162/// See Postgres documentation for SQL Commands NOTIFY and LISTEN
163#[derive(Clone, Debug)]
164pub struct PgNotification {
165    /// process ID of notifying server process
166    pub process_id: i32,
167    /// Name of the notification channel
168    pub channel: String,
169    /// optional data that was submitted with the notification,
170    ///
171    /// This is set to an empty string if no data was submitted
172    ///
173    /// (Postgres unfortunally does not provide a way to differentiate between
174    /// not set and empty here)
175    pub payload: String,
176}