Skip to main content

spg_sqlx/
type_info.rs

1//! v7.16.0 — `sqlx::TypeInfo` for SPG column types.
2
3use std::fmt;
4
5use sqlx_core::type_info::TypeInfo;
6
7/// SPG column type info. Stores the concrete [`Kind`] so the
8/// adapter can drive PG-shape column metadata that
9/// `#[derive(FromRow)]` expects.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct SpgTypeInfo {
12    kind: Kind,
13}
14
15/// Identity tag for each column type the adapter currently
16/// understands. Matches the subset of `spg_storage::DataType`
17/// the adapter Encode/Decode coverage extends to.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[non_exhaustive]
20pub enum Kind {
21    /// `INT` / 4-byte signed integer.
22    Int,
23    /// `BIGINT` / 8-byte signed integer.
24    BigInt,
25    /// `SMALLINT` / 2-byte signed integer.
26    SmallInt,
27    /// `BOOLEAN`.
28    Bool,
29    /// `TEXT` / `VARCHAR` (text body — encoding agnostic).
30    Text,
31    /// `BYTEA` (raw bytes).
32    Bytes,
33    /// `FLOAT` (IEEE-754 double).
34    Float,
35    /// `DATE`.
36    Date,
37    /// `TIMESTAMP`.
38    Timestamp,
39    /// `TIMESTAMPTZ`.
40    Timestamptz,
41    /// `JSON` / `JSONB` (text-backed JSON).
42    Json,
43    /// Unknown / type-erased — used for parameters that the
44    /// adapter binds without a fixed column-side type yet (e.g.
45    /// the first bind of a fresh parameter index).
46    Null,
47}
48
49impl SpgTypeInfo {
50    /// Construct a TypeInfo for a known kind.
51    #[must_use]
52    pub const fn of(kind: Kind) -> Self {
53        Self { kind }
54    }
55
56    /// The concrete kind tag.
57    #[must_use]
58    pub const fn kind(&self) -> Kind {
59        self.kind
60    }
61
62    /// v7.16.0 — translate from the engine's [`DataType`] to
63    /// the adapter's typed `Kind`. Used by the fetch path to
64    /// build column metadata for `SpgRow`. Any DataType the
65    /// adapter hasn't bridged yet maps to `Kind::Null` —
66    /// downstream Decode calls then fail with a clear
67    /// "cannot decode" message identifying the column type.
68    #[must_use]
69    pub fn from_data_type(ty: spg_embedded::DataType) -> Self {
70        use spg_embedded::DataType;
71        let kind = match ty {
72            DataType::Int => Kind::Int,
73            DataType::BigInt => Kind::BigInt,
74            DataType::SmallInt => Kind::SmallInt,
75            DataType::Bool => Kind::Bool,
76            DataType::Text => Kind::Text,
77            DataType::Bytes => Kind::Bytes,
78            DataType::Float => Kind::Float,
79            DataType::Date => Kind::Date,
80            DataType::Timestamp => Kind::Timestamp,
81            DataType::Timestamptz => Kind::Timestamptz,
82            DataType::Json => Kind::Json,
83            // v7.16.0 — DataType is #[non_exhaustive]; any
84            // variant we haven't bridged yet decodes to Null
85            // (so Decode impls see "compatible? no" instead of
86            // a panic).
87            _ => Kind::Null,
88        };
89        Self { kind }
90    }
91}
92
93impl TypeInfo for SpgTypeInfo {
94    fn is_null(&self) -> bool {
95        matches!(self.kind, Kind::Null)
96    }
97
98    fn name(&self) -> &str {
99        match self.kind {
100            Kind::Int => "INT",
101            Kind::BigInt => "BIGINT",
102            Kind::SmallInt => "SMALLINT",
103            Kind::Bool => "BOOLEAN",
104            Kind::Text => "TEXT",
105            Kind::Bytes => "BYTEA",
106            Kind::Float => "FLOAT",
107            Kind::Date => "DATE",
108            Kind::Timestamp => "TIMESTAMP",
109            Kind::Timestamptz => "TIMESTAMPTZ",
110            Kind::Json => "JSON",
111            Kind::Null => "NULL",
112        }
113    }
114}
115
116impl fmt::Display for SpgTypeInfo {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        f.write_str(self.name())
119    }
120}