1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use dbui_core::database::column::Column;
use dbui_core::field_type::FieldType;
use dbui_core::Result;

use postgres::Row;

#[derive(Debug)]
pub(crate) struct ColumnDefinition {
  table_schema: String,
  table_name: String,
  column_name: String,
  ordinal_position: i32,
  column_default: Option<String>,
  is_nullable: bool,
  data_type: String,
  array_type: Option<String>,
  character_maximum_length: Option<i32>,
  character_octet_length: Option<i32>,
  numeric_precision: Option<i32>,
  numeric_precision_radix: Option<i32>,
  numeric_scale: Option<i32>,
  datetime_precision: Option<i32>,
  interval_type: Option<String>,
  domain_schema: Option<String>,
  domain_name: Option<String>,
  udt_schema: String,
  udt_name: String,
  dtd_identifier: String,
  is_updatable: bool
}

impl ColumnDefinition {
  pub(crate) fn from_row(row: &Row) -> Result<Self> {
    Ok(ColumnDefinition {
      table_schema: crate::get(&row, "table_schema")?,
      table_name: crate::get(&row, "table_name")?,
      column_name: crate::get(&row, "column_name")?,
      ordinal_position: crate::get(&row, "ordinal_position")?,
      column_default: crate::get(&row, "column_default")?,
      is_nullable: crate::get::<String>(&row, "is_nullable")? == "YES",
      data_type: crate::get(&row, "data_type")?,
      array_type: crate::get(&row, "array_type")?,
      character_maximum_length: crate::get(&row, "character_maximum_length")?,
      character_octet_length: crate::get(&row, "character_octet_length")?,
      numeric_precision: crate::get(&row, "numeric_precision")?,
      numeric_precision_radix: crate::get(&row, "numeric_precision_radix")?,
      numeric_scale: crate::get(&row, "numeric_scale")?,
      datetime_precision: crate::get(&row, "datetime_precision")?,
      interval_type: crate::get(&row, "interval_type")?,
      domain_schema: crate::get(&row, "domain_schema")?,
      domain_name: crate::get(&row, "domain_name")?,
      udt_schema: crate::get(&row, "udt_schema")?,
      udt_name: crate::get(&row, "udt_name")?,
      dtd_identifier: crate::get(&row, "dtd_identifier")?,
      is_updatable: crate::get::<String>(&row, "is_updatable")? == "YES"
    })
  }

  pub(crate) fn table_schema(&self) -> &String {
    &self.table_schema
  }

  pub(crate) fn table_name(&self) -> &String {
    &self.table_name
  }

  pub(crate) fn typ(&self) -> FieldType {
    match self.data_type.as_ref() {
      "text" | "character varying" => FieldType::String,
      "boolean" => FieldType::Boolean,
      "character" => FieldType::Char,
      "smallint" => FieldType::I16,
      "integer" | "serial" => FieldType::I32,
      "bigint" | "bigserial" | "int8" => FieldType::I64,
      "real" => FieldType::F32,
      "double precision" => FieldType::F64,
      "numeric" | "money" => FieldType::Numeric,

      "oid" => FieldType::U32,

      "date" => FieldType::Date,
      "time" | "time without time zone" => FieldType::Time,
      "timetz" | "time with time zone" => FieldType::TimeZoned,
      "timestamp" | "timestamp without time zone" => FieldType::Timestamp,
      "timestamptz" | "timestamp with time zone" => FieldType::TimestampZoned,

      "uuid" => FieldType::Uuid,
      "json" | "jsonb" => FieldType::Json,
      "xml" => FieldType::Xml,
      "hstore" => FieldType::StringMap,

      "bytea" => FieldType::ByteArray,
      "but" | "bit varying" => FieldType::BitArray,

      "cidr" => FieldType::Cidr,
      "inet" => FieldType::InetAddr,
      "macaddr" => FieldType::MacAddr,

      "box" => FieldType::Box,
      "circle" => FieldType::Circle,
      "path" => FieldType::Path,
      "polygon" => FieldType::Polygon,
      "point" => FieldType::Point,

      "tsquery" => FieldType::TsQuery,
      "tsvector" => FieldType::TsVector,

      /*

      */
      "USER-DEFINED" => match self.udt_name.as_ref() {
        "hstore" => FieldType::StringMap,
        _ => {
          println!("Unhandled UDT [{}]: {:?}", self.data_type, self);
          FieldType::Unknown { t: self.data_type.clone() }
        }
      },

      "ARRAY" => FieldType::List {
        t: Box::new(FieldType::String)
      },

      _ => {
        println!("Unhandled column type [{}]: {:?}", self.data_type, self);
        FieldType::Unknown { t: self.data_type.clone() }
      }
    }
  }

  pub(crate) fn column(&self) -> Column {
    Column::new(self.column_name.clone(), self.typ())
  }
}