good_ormning/pg/schema/
field.rs

1use std::{
2    fmt::{
3        Debug,
4        Display,
5    },
6    rc::Rc,
7    ops::Deref,
8};
9use crate::{
10    pg::{
11        types::{
12            SimpleSimpleType,
13            SimpleType,
14            Type,
15        },
16        query::{
17            expr::{
18                Expr,
19            },
20        },
21    },
22};
23use super::table::{
24    Table,
25};
26
27#[derive(Clone, Debug)]
28pub struct FieldType {
29    pub type_: Type,
30    pub migration_default: Option<Expr>,
31}
32
33impl FieldType {
34    /// Create a field type from the specified value type.
35    pub fn with(t: &Type) -> Self {
36        Self {
37            type_: t.clone(),
38            migration_default: None,
39        }
40    }
41
42    /// Create a field type from the specified value type, and provide a migration fill
43    /// value.
44    pub fn with_migration(t: &Type, def: Option<Expr>) -> Self {
45        if t.opt {
46            panic!("Optional fields can't have defaults.");
47        }
48        Self {
49            type_: t.clone(),
50            migration_default: def,
51        }
52    }
53}
54
55pub struct FieldBuilder {
56    t: SimpleSimpleType,
57    default_: Option<Expr>,
58    opt: bool,
59    custom: Option<String>,
60}
61
62impl FieldBuilder {
63    fn new(t: SimpleSimpleType) -> FieldBuilder {
64        FieldBuilder {
65            t: t,
66            opt: false,
67            default_: None,
68            custom: None,
69        }
70    }
71
72    /// Make the field optional.
73    pub fn opt(mut self) -> FieldBuilder {
74        if self.default_.is_some() {
75            panic!("Optional fields can't have migration fill expressions.");
76        }
77        self.opt = true;
78        self
79    }
80
81    /// Specify an expression to use to populate the new column in existing rows. This
82    /// is must be specified (only) for non-opt fields in a new version of an existing
83    /// table.
84    pub fn migrate_fill(mut self, expr: Expr) -> FieldBuilder {
85        if self.opt {
86            panic!("Optional fields can't have migration fill expressions.");
87        }
88        self.default_ = Some(expr);
89        self
90    }
91
92    /// Use a custom Rust type for this field. This must be the full path to the type,
93    /// like `crate::abcdef::MyType`.
94    pub fn custom(mut self, type_: impl ToString) -> FieldBuilder {
95        self.custom = Some(type_.to_string());
96        self
97    }
98
99    pub fn build(self) -> FieldType {
100        FieldType {
101            type_: Type {
102                type_: SimpleType {
103                    custom: self.custom,
104                    type_: self.t,
105                },
106                opt: self.opt,
107            },
108            migration_default: self.default_,
109        }
110    }
111}
112
113pub fn field_auto() -> FieldBuilder {
114    FieldBuilder::new(SimpleSimpleType::Auto)
115}
116
117pub fn field_bool() -> FieldBuilder {
118    FieldBuilder::new(SimpleSimpleType::Bool)
119}
120
121pub fn field_i32() -> FieldBuilder {
122    FieldBuilder::new(SimpleSimpleType::I32)
123}
124
125pub fn field_i64() -> FieldBuilder {
126    FieldBuilder::new(SimpleSimpleType::I64)
127}
128
129pub fn field_f32() -> FieldBuilder {
130    FieldBuilder::new(SimpleSimpleType::F32)
131}
132
133pub fn field_f64() -> FieldBuilder {
134    FieldBuilder::new(SimpleSimpleType::F64)
135}
136
137pub fn field_str() -> FieldBuilder {
138    FieldBuilder::new(SimpleSimpleType::String)
139}
140
141pub fn field_bytes() -> FieldBuilder {
142    FieldBuilder::new(SimpleSimpleType::Bytes)
143}
144
145#[cfg(feature = "chrono")]
146pub fn field_utctime_chrono() -> FieldBuilder {
147    FieldBuilder::new(SimpleSimpleType::UtcTimeChrono)
148}
149
150#[cfg(feature = "chrono")]
151pub fn field_fixed_offset_time_chrono() -> FieldBuilder {
152    FieldBuilder::new(SimpleSimpleType::FixedOffsetTimeChrono)
153}
154
155#[cfg(feature = "jiff")]
156pub fn field_utctime_jiff() -> FieldBuilder {
157    FieldBuilder::new(SimpleSimpleType::UtcTimeJiff)
158}
159
160#[derive(Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
161pub struct SchemaFieldId(pub String);
162
163impl Display for SchemaFieldId {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        Display::fmt(&self.0, f)
166    }
167}
168
169#[derive(Debug)]
170pub struct Field_ {
171    pub table: Table,
172    pub schema_id: SchemaFieldId,
173    pub id: String,
174    pub type_: FieldType,
175}
176
177#[derive(Clone, Debug)]
178pub struct Field(pub Rc<Field_>);
179
180impl std::hash::Hash for Field {
181    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
182        self.0.schema_id.hash(state)
183    }
184}
185
186impl PartialEq for Field {
187    fn eq(&self, other: &Self) -> bool {
188        self.table == other.table && self.schema_id == other.schema_id
189    }
190}
191
192impl Eq for Field { }
193
194impl Deref for Field {
195    type Target = Field_;
196
197    fn deref(&self) -> &Self::Target {
198        self.0.as_ref()
199    }
200}
201
202impl Display for Field {
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        Display::fmt(&format!("{}.{} ({}.{})", self.table.id, self.id, self.table.schema_id.0, self.schema_id.0), f)
205    }
206}