axion_db/types/
postgres.rs

1// axion-db/src/types/postgres.rs
2use crate::metadata::AxionDataType;
3use crate::types::TypeMapper;
4
5#[derive(Debug, Default, Clone, Copy)]
6pub struct PostgresTypeMapper;
7
8// A declarative macro to simplify the large match statement.
9macro_rules! map_sql_to_axion {
10    (
11        $lower_sql_type:expr,
12        { $( $sql:pat => $axion:expr ),* $(,)? }
13    ) => {
14        match $lower_sql_type {
15            $( $sql => $axion, )*
16            // Fallback for unmapped built-ins
17            _ => AxionDataType::Unsupported($lower_sql_type.to_string()),
18        }
19    };
20}
21
22impl TypeMapper for PostgresTypeMapper {
23    fn sql_to_axion(&self, sql_type: &str, udt_name: Option<&str>) -> AxionDataType {
24        // Handle Array types first, as they are a special case of `data_type`
25        if sql_type == "ARRAY" {
26            // For arrays, the element type is in the UDT name (e.g., "_int4", "_varchar").
27            // We strip the leading underscore to get the base type.
28            if let Some(udt) = udt_name.and_then(|u| u.strip_prefix('_')) {
29                return AxionDataType::Array(Box::new(self.sql_to_axion(udt, Some(udt))));
30            }
31        }
32
33        // Handle User-Defined types next (this is for custom enums)
34        if sql_type == "USER-DEFINED" {
35            if let Some(udt) = udt_name {
36                return AxionDataType::Enum(udt.to_string());
37            }
38        }
39
40        // Handle all other standard types
41        let lower_sql_type = sql_type.to_lowercase();
42
43        map_sql_to_axion!(lower_sql_type.as_str(), {
44            "uuid" => AxionDataType::Uuid,
45            "integer" | "int" | "int4" => AxionDataType::Integer(32),
46            "bigint" | "int8" => AxionDataType::Integer(64),
47            "smallint" | "int2" => AxionDataType::Integer(16),
48            "character varying" | "varchar" | "text" | "name" | "citext" | "char" | "bpchar" => AxionDataType::Text,
49            "boolean" | "bool" => AxionDataType::Boolean,
50            "date" => AxionDataType::Date,
51            "time without time zone" | "time" => AxionDataType::Time,
52            "timestamp without time zone" | "timestamp" => AxionDataType::Timestamp,
53            "timestamp with time zone" | "timestamptz" => AxionDataType::TimestampTz,
54            "numeric" | "decimal" => AxionDataType::Numeric,
55            "real" | "float4" => AxionDataType::Float(32),
56            "double precision" | "float8" => AxionDataType::Float(64),
57            "bytea" => AxionDataType::Bytes,
58            "json" => AxionDataType::Json,
59            "jsonb" => AxionDataType::JsonB,
60            "inet" | "cidr" => AxionDataType::Inet,
61        })
62    }
63}