2025-09-08 15:56:57 -07:00
|
|
|
use interim_pgtypes::pg_attribute::PgAttribute;
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2025-09-14 16:19:44 -04:00
|
|
|
use strum::{EnumIter, EnumString};
|
2025-09-08 15:56:57 -07:00
|
|
|
|
|
|
|
|
pub const RFC_3339_S: &str = "%Y-%m-%dT%H:%M:%S";
|
|
|
|
|
|
|
|
|
|
/// Struct defining how a field's is displayed and how it accepts input in UI.
|
2025-09-14 16:19:44 -04:00
|
|
|
#[derive(Clone, Debug, Deserialize, EnumIter, EnumString, PartialEq, Serialize, strum::Display)]
|
2025-09-08 15:56:57 -07:00
|
|
|
#[serde(tag = "t", content = "c")]
|
|
|
|
|
pub enum Presentation {
|
2025-10-21 18:58:09 +00:00
|
|
|
Dropdown {
|
|
|
|
|
allow_custom: bool,
|
|
|
|
|
options: Vec<DropdownOption>,
|
|
|
|
|
},
|
2025-11-11 01:26:48 +00:00
|
|
|
Numeric {},
|
2025-10-21 18:58:09 +00:00
|
|
|
Text {
|
|
|
|
|
input_mode: TextInputMode,
|
|
|
|
|
},
|
|
|
|
|
Timestamp {
|
|
|
|
|
format: String,
|
|
|
|
|
},
|
2025-09-08 15:56:57 -07:00
|
|
|
Uuid {},
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-21 18:58:09 +00:00
|
|
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
|
|
|
|
pub struct DropdownOption {
|
|
|
|
|
pub color: String,
|
|
|
|
|
pub value: String,
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 15:56:57 -07:00
|
|
|
impl Presentation {
|
|
|
|
|
/// Returns a SQL fragment for the default data type for creating or
|
|
|
|
|
/// altering a backing column, such as "integer", or "timestamptz".
|
2025-11-11 01:26:48 +00:00
|
|
|
pub fn attr_data_type_fragment(&self) -> &'static str {
|
2025-09-08 15:56:57 -07:00
|
|
|
match self {
|
2025-11-11 01:26:48 +00:00
|
|
|
Self::Dropdown { .. } | Self::Text { .. } => "text",
|
|
|
|
|
Self::Numeric { .. } => "numeric",
|
|
|
|
|
Self::Timestamp { .. } => "timestamptz",
|
|
|
|
|
Self::Uuid { .. } => "uuid",
|
2025-09-08 15:56:57 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Generate the default presentation based on an existing column's type.
|
|
|
|
|
/// Returns None if no default presentation exists.
|
|
|
|
|
pub fn default_from_attr(attr: &PgAttribute) -> Option<Self> {
|
|
|
|
|
match attr.regtype.to_lowercase().as_str() {
|
2025-11-11 01:26:48 +00:00
|
|
|
"numeric" => Some(Self::Numeric {}),
|
2025-09-08 15:56:57 -07:00
|
|
|
"text" => Some(Self::Text {
|
|
|
|
|
input_mode: TextInputMode::MultiLine {},
|
|
|
|
|
}),
|
|
|
|
|
"timestamp" => Some(Self::Timestamp {
|
|
|
|
|
format: RFC_3339_S.to_owned(),
|
|
|
|
|
}),
|
|
|
|
|
"uuid" => Some(Self::Uuid {}),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-14 16:19:44 -04:00
|
|
|
impl Default for Presentation {
|
|
|
|
|
/// Defaults to [`Self::Text`] as a reasonable fallback. The [`Default`]
|
|
|
|
|
/// trait is implemented for convenience, but in the vast majority of cases
|
|
|
|
|
/// the presentation value should be well defined and this should not be
|
|
|
|
|
/// called directly.
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::Text {
|
|
|
|
|
input_mode: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Deserialize, EnumString, EnumIter, PartialEq, Serialize, strum::Display)]
|
2025-09-08 15:56:57 -07:00
|
|
|
#[serde(tag = "t", content = "c")]
|
|
|
|
|
pub enum TextInputMode {
|
|
|
|
|
SingleLine {},
|
|
|
|
|
MultiLine {},
|
|
|
|
|
}
|
2025-09-14 16:19:44 -04:00
|
|
|
|
|
|
|
|
impl Default for TextInputMode {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::MultiLine {}
|
|
|
|
|
}
|
|
|
|
|
}
|