cdl_openapi/
model.rs

1use anyhow::{bail, Result};
2use chrono::{DateTime, Utc};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use strum::{Display, EnumString};
6
7#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
8#[cfg_attr(feature = "k8s", derive(::kube::CustomResource))]
9#[cfg_attr(
10    feature = "k8s",
11    kube(
12        group = "cdl.ulagbulag.io",
13        version = "v1alpha1",
14        kind = "Model",
15        root = "ModelCrd",
16        status = "ModelStatus",
17        shortname = "m",
18        namespaced,
19        printcolumn = r#"{
20            "name": "state",
21            "type": "string",
22            "description": "state of the model",
23            "jsonPath": ".status.state"
24        }"#,
25        printcolumn = r#"{
26            "name": "created-at",
27            "type": "date",
28            "description": "created time",
29            "jsonPath": ".metadata.creationTimestamp"
30        }"#,
31        printcolumn = r#"{
32            "name": "updated-at",
33            "type": "date",
34            "description": "updated time",
35            "jsonPath": ".status.lastUpdated"
36        }"#,
37        printcolumn = r#"{
38            "name": "version",
39            "type": "integer",
40            "description": "model version",
41            "jsonPath": ".metadata.generation"
42        }"#,
43    )
44)]
45#[serde(rename_all = "camelCase")]
46pub enum ModelSpec {
47    Dynamic {},
48    Fields(ModelFieldsSpec),
49    CustomResourceDefinitionRef(ModelCustomResourceDefinitionRefSpec),
50}
51
52impl Default for ModelSpec {
53    fn default() -> Self {
54        Self::Dynamic {}
55    }
56}
57
58#[cfg(feature = "k8s")]
59impl ModelCrd {
60    pub const FINALIZER_NAME: &'static str = "cdl.ulagbulag.io/finalizer-models";
61
62    pub fn get_fields_unchecked(&self) -> &ModelFieldsNativeSpec {
63        self.status
64            .as_ref()
65            .and_then(|status| status.fields.as_ref())
66            .expect("fields should not be empty")
67    }
68
69    pub fn into_fields_unchecked(self) -> ModelFieldsNativeSpec {
70        self.status
71            .and_then(|status| status.fields)
72            .expect("fields should not be empty")
73    }
74}
75
76#[derive(
77    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
78)]
79#[serde(rename_all = "camelCase")]
80pub struct ModelStatus {
81    #[serde(default)]
82    pub state: ModelState,
83    pub fields: Option<ModelFieldsSpec<ModelFieldKindNativeSpec>>,
84    pub last_updated: DateTime<Utc>,
85}
86
87pub type ModelFieldsSpec<Kind = ModelFieldKindSpec> = Vec<ModelFieldSpec<Kind>>;
88pub type ModelFieldsNativeSpec = ModelFieldsSpec<ModelFieldKindNativeSpec>;
89
90pub type ModelFieldNativeSpec = ModelFieldSpec<ModelFieldKindNativeSpec>;
91pub type ModelFieldExtendedSpec = ModelFieldSpec<ModelFieldKindExtendedSpec>;
92
93#[derive(
94    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
95)]
96#[serde(rename_all = "camelCase")]
97pub struct ModelFieldSpec<Kind = ModelFieldKindSpec> {
98    pub name: String,
99    #[serde(flatten)]
100    pub kind: Kind,
101    #[serde(flatten)]
102    pub attribute: ModelFieldAttributeSpec,
103}
104
105impl ModelFieldSpec {
106    pub fn try_into_native(self) -> Result<ModelFieldNativeSpec> {
107        match self.kind {
108            ModelFieldKindSpec::Native(kind) => Ok(ModelFieldSpec {
109                name: self.name,
110                kind,
111                attribute: self.attribute,
112            }),
113            kind => {
114                let name = &self.name;
115                let type_ = kind.to_type();
116                bail!(
117                    "cannot infer field type {name:?}: expected Native types, but given {type_:?}"
118                )
119            }
120        }
121    }
122
123    pub fn try_into_extended(self) -> Result<ModelFieldExtendedSpec> {
124        match self.kind {
125            ModelFieldKindSpec::Extended(kind) => Ok(ModelFieldSpec {
126                name: self.name,
127                kind,
128                attribute: self.attribute,
129            }),
130            kind => {
131                let name = &self.name;
132                let type_ = kind.to_type();
133                bail!(
134                    "cannot infer field type {name:?}: expected Extended types, but given {type_:?}"
135                )
136            }
137        }
138    }
139}
140
141#[derive(
142    Copy,
143    Clone,
144    Debug,
145    Default,
146    PartialEq,
147    Eq,
148    PartialOrd,
149    Ord,
150    Hash,
151    Serialize,
152    Deserialize,
153    JsonSchema,
154)]
155#[serde(rename_all = "camelCase")]
156pub struct ModelFieldAttributeSpec {
157    #[serde(default)]
158    pub optional: bool,
159}
160
161#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
162pub enum ModelFieldKindSpec {
163    Native(ModelFieldKindNativeSpec),
164    Extended(ModelFieldKindExtendedSpec),
165}
166
167impl Default for ModelFieldKindSpec {
168    fn default() -> Self {
169        Self::Native(Default::default())
170    }
171}
172
173// NOTE: JsonSchema has no support for merging two enums
174mod _impl_jsonschema_for_model_field_kind_spec {
175    use super::*;
176
177    mod serialize {
178        #[allow(dead_code)]
179        #[derive(super::Serialize)]
180        #[serde(rename_all = "camelCase")]
181        enum ModelFieldKindSpec<'a> {
182            // BEGIN primitive types
183            None {},
184            Boolean {
185                #[serde(default)]
186                default: &'a Option<bool>,
187            },
188            Integer {
189                #[serde(default)]
190                default: &'a Option<super::Integer>,
191                #[serde(default)]
192                minimum: &'a Option<super::Integer>,
193                #[serde(default)]
194                maximum: &'a Option<super::Integer>,
195            },
196            Number {
197                #[serde(default)]
198                default: &'a Option<super::Number>,
199                #[serde(default)]
200                minimum: &'a Option<super::Number>,
201                #[serde(default)]
202                maximum: &'a Option<super::Number>,
203            },
204            String {
205                #[serde(default)]
206                default: &'a Option<String>,
207                #[serde(default, flatten)]
208                kind: &'a super::ModelFieldKindStringSpec,
209            },
210            OneOfStrings {
211                #[serde(default)]
212                default: &'a Option<String>,
213                choices: &'a Vec<String>,
214            },
215            // BEGIN string formats
216            DateTime {
217                #[serde(default)]
218                default: &'a Option<super::ModelFieldDateTimeDefaultType>,
219            },
220            Ip {},
221            Uuid {},
222            // BEGIN aggregation types
223            StringArray {},
224            Object {
225                #[serde(default)]
226                children: &'a Vec<String>,
227                #[serde(default)]
228                kind: &'a super::ModelFieldKindObjectSpec,
229            },
230            ObjectArray {
231                #[serde(default)]
232                children: &'a Vec<String>,
233            },
234            // BEGIN reference types
235            Model {
236                name: &'a String,
237            },
238        }
239
240        impl super::Serialize for super::ModelFieldKindSpec {
241            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
242            where
243                S: ::serde::Serializer,
244            {
245                let spec = match self {
246                    Self::Native(spec) => match spec {
247                        // BEGIN primitive types
248                        super::ModelFieldKindNativeSpec::None {} => ModelFieldKindSpec::None {},
249                        super::ModelFieldKindNativeSpec::Boolean { default } => {
250                            ModelFieldKindSpec::Boolean { default }
251                        }
252                        super::ModelFieldKindNativeSpec::Integer {
253                            default,
254                            minimum,
255                            maximum,
256                        } => ModelFieldKindSpec::Integer {
257                            default,
258                            minimum,
259                            maximum,
260                        },
261                        super::ModelFieldKindNativeSpec::Number {
262                            default,
263                            minimum,
264                            maximum,
265                        } => ModelFieldKindSpec::Number {
266                            default,
267                            minimum,
268                            maximum,
269                        },
270                        super::ModelFieldKindNativeSpec::String { default, kind } => {
271                            ModelFieldKindSpec::String { default, kind }
272                        }
273                        super::ModelFieldKindNativeSpec::OneOfStrings { default, choices } => {
274                            ModelFieldKindSpec::OneOfStrings { default, choices }
275                        }
276                        // BEGIN string formats
277                        super::ModelFieldKindNativeSpec::DateTime { default } => {
278                            ModelFieldKindSpec::DateTime { default }
279                        }
280                        super::ModelFieldKindNativeSpec::Ip {} => ModelFieldKindSpec::Ip {},
281                        super::ModelFieldKindNativeSpec::Uuid {} => ModelFieldKindSpec::Uuid {},
282                        // BEGIN aggregation types
283                        super::ModelFieldKindNativeSpec::StringArray {} => {
284                            ModelFieldKindSpec::StringArray {}
285                        }
286                        super::ModelFieldKindNativeSpec::Object { children, kind } => {
287                            ModelFieldKindSpec::Object { children, kind }
288                        }
289                        super::ModelFieldKindNativeSpec::ObjectArray { children } => {
290                            ModelFieldKindSpec::ObjectArray { children }
291                        }
292                    },
293                    Self::Extended(spec) => match spec {
294                        // BEGIN reference types
295                        super::ModelFieldKindExtendedSpec::Model { name } => {
296                            ModelFieldKindSpec::Model { name }
297                        }
298                    },
299                };
300
301                spec.serialize(serializer)
302            }
303        }
304    }
305
306    mod deserialize {
307        #[allow(dead_code)]
308        #[derive(super::Deserialize, super::JsonSchema)]
309        #[serde(rename_all = "camelCase")]
310        enum ModelFieldKindSpec {
311            // BEGIN primitive types
312            None {},
313            Boolean {
314                #[serde(default)]
315                default: Option<bool>,
316            },
317            Integer {
318                #[serde(default)]
319                default: Option<super::Integer>,
320                #[serde(default)]
321                minimum: Option<super::Integer>,
322                #[serde(default)]
323                maximum: Option<super::Integer>,
324            },
325            Number {
326                #[serde(default)]
327                default: Option<super::Number>,
328                #[serde(default)]
329                minimum: Option<super::Number>,
330                #[serde(default)]
331                maximum: Option<super::Number>,
332            },
333            String {
334                #[serde(default)]
335                default: Option<String>,
336                #[serde(default, flatten)]
337                kind: super::ModelFieldKindStringSpec,
338            },
339            OneOfStrings {
340                #[serde(default)]
341                default: Option<String>,
342                choices: Vec<String>,
343            },
344            // BEGIN string formats
345            DateTime {
346                #[serde(default)]
347                default: Option<super::ModelFieldDateTimeDefaultType>,
348            },
349            Ip {},
350            Uuid {},
351            // BEGIN aggregation types
352            Object {
353                #[serde(default)]
354                children: Vec<String>,
355                #[serde(default)]
356                kind: super::ModelFieldKindObjectSpec,
357            },
358            ObjectArray {
359                #[serde(default)]
360                children: Vec<String>,
361            },
362            // BEGIN reference types
363            Model {
364                name: String,
365            },
366        }
367
368        impl<'de> super::Deserialize<'de> for super::ModelFieldKindSpec {
369            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
370            where
371                D: ::serde::Deserializer<'de>,
372            {
373                <ModelFieldKindSpec as super::Deserialize<'de>>::deserialize(deserializer).map(
374                    |spec| {
375                        match spec {
376                            // BEGIN primitive types
377                            ModelFieldKindSpec::None {} => {
378                                Self::Native(super::ModelFieldKindNativeSpec::None {})
379                            }
380                            ModelFieldKindSpec::Boolean { default } => {
381                                Self::Native(super::ModelFieldKindNativeSpec::Boolean { default })
382                            }
383                            ModelFieldKindSpec::Integer {
384                                default,
385                                minimum,
386                                maximum,
387                            } => Self::Native(super::ModelFieldKindNativeSpec::Integer {
388                                default,
389                                minimum,
390                                maximum,
391                            }),
392                            ModelFieldKindSpec::Number {
393                                default,
394                                minimum,
395                                maximum,
396                            } => Self::Native(super::ModelFieldKindNativeSpec::Number {
397                                default,
398                                minimum,
399                                maximum,
400                            }),
401                            ModelFieldKindSpec::String { default, kind } => {
402                                Self::Native(super::ModelFieldKindNativeSpec::String {
403                                    default,
404                                    kind,
405                                })
406                            }
407                            ModelFieldKindSpec::OneOfStrings { default, choices } => {
408                                Self::Native(super::ModelFieldKindNativeSpec::OneOfStrings {
409                                    default,
410                                    choices,
411                                })
412                            }
413                            // BEGIN string formats
414                            ModelFieldKindSpec::DateTime { default } => {
415                                Self::Native(super::ModelFieldKindNativeSpec::DateTime { default })
416                            }
417                            ModelFieldKindSpec::Ip {} => {
418                                Self::Native(super::ModelFieldKindNativeSpec::Ip {})
419                            }
420                            ModelFieldKindSpec::Uuid {} => {
421                                Self::Native(super::ModelFieldKindNativeSpec::Uuid {})
422                            }
423                            // BEGIN aggregation types
424                            ModelFieldKindSpec::Object { children, kind } => {
425                                Self::Native(super::ModelFieldKindNativeSpec::Object {
426                                    children,
427                                    kind,
428                                })
429                            }
430                            ModelFieldKindSpec::ObjectArray { children } => {
431                                Self::Native(super::ModelFieldKindNativeSpec::ObjectArray {
432                                    children,
433                                })
434                            }
435                            // BEGIN reference types
436                            ModelFieldKindSpec::Model { name } => {
437                                Self::Extended(super::ModelFieldKindExtendedSpec::Model { name })
438                            }
439                        }
440                    },
441                )
442            }
443        }
444
445        impl super::JsonSchema for super::ModelFieldKindSpec {
446            fn is_referenceable() -> bool {
447                <ModelFieldKindSpec as super::JsonSchema>::is_referenceable()
448            }
449
450            fn schema_name() -> String {
451                <ModelFieldKindSpec as super::JsonSchema>::schema_name()
452            }
453
454            fn json_schema(
455                gen: &mut ::schemars::gen::SchemaGenerator,
456            ) -> ::schemars::schema::Schema {
457                <ModelFieldKindSpec as super::JsonSchema>::json_schema(gen)
458            }
459
460            fn _schemars_private_non_optional_json_schema(
461                gen: &mut ::schemars::gen::SchemaGenerator,
462            ) -> ::schemars::schema::Schema {
463                <ModelFieldKindSpec as super::JsonSchema>::_schemars_private_non_optional_json_schema(gen)
464            }
465
466            fn _schemars_private_is_option() -> bool {
467                <ModelFieldKindSpec as super::JsonSchema>::_schemars_private_is_option()
468            }
469        }
470    }
471}
472
473impl ModelFieldKindSpec {
474    pub fn get_children(&self) -> Option<&Vec<String>> {
475        match self {
476            Self::Native(spec) => spec.get_children(),
477            Self::Extended(spec) => spec.get_children(),
478        }
479    }
480
481    pub fn get_children_mut(&mut self) -> Option<&mut Vec<String>> {
482        match self {
483            Self::Native(spec) => spec.get_children_mut(),
484            Self::Extended(spec) => spec.get_children_mut(),
485        }
486    }
487
488    pub const fn to_type(&self) -> ModelFieldKindType {
489        match self {
490            Self::Native(spec) => ModelFieldKindType::Native(spec.to_type()),
491            Self::Extended(spec) => ModelFieldKindType::Extended(spec.to_type()),
492        }
493    }
494}
495
496#[derive(
497    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
498)]
499#[serde(rename_all = "camelCase")]
500pub enum ModelFieldKindNativeSpec {
501    // BEGIN primitive types
502    None {},
503    Boolean {
504        #[serde(default)]
505        default: Option<bool>,
506    },
507    Integer {
508        #[serde(default)]
509        default: Option<Integer>,
510        #[serde(default)]
511        minimum: Option<Integer>,
512        #[serde(default)]
513        maximum: Option<Integer>,
514    },
515    Number {
516        #[serde(default)]
517        default: Option<Number>,
518        #[serde(default)]
519        minimum: Option<Number>,
520        #[serde(default)]
521        maximum: Option<Number>,
522    },
523    String {
524        #[serde(default)]
525        default: Option<String>,
526        #[serde(default, flatten)]
527        kind: ModelFieldKindStringSpec,
528    },
529    OneOfStrings {
530        #[serde(default)]
531        default: Option<String>,
532        choices: Vec<String>,
533    },
534    // BEGIN string formats
535    DateTime {
536        #[serde(default)]
537        default: Option<ModelFieldDateTimeDefaultType>,
538    },
539    Ip {},
540    Uuid {},
541    // BEGIN aggregation types
542    StringArray {},
543    Object {
544        #[serde(default)]
545        children: Vec<String>,
546        #[serde(default)]
547        kind: ModelFieldKindObjectSpec,
548    },
549    ObjectArray {
550        #[serde(default)]
551        children: Vec<String>,
552    },
553}
554
555impl Default for ModelFieldKindNativeSpec {
556    fn default() -> Self {
557        Self::None {}
558    }
559}
560
561impl ModelFieldKindNativeSpec {
562    pub fn get_children(&self) -> Option<&Vec<String>> {
563        match self {
564            // BEGIN primitive types
565            Self::None {} => None,
566            Self::Boolean { .. } => None,
567            Self::Integer { .. } => None,
568            Self::Number { .. } => None,
569            Self::String { .. } => None,
570            Self::OneOfStrings { .. } => None,
571            // BEGIN string formats
572            Self::DateTime { .. } => None,
573            Self::Ip { .. } => None,
574            Self::Uuid { .. } => None,
575            // BEGIN aggregation types
576            Self::StringArray { .. } => None,
577            Self::Object { children, .. } | Self::ObjectArray { children, .. } => Some(children),
578        }
579    }
580
581    pub fn get_children_mut(&mut self) -> Option<&mut Vec<String>> {
582        match self {
583            // BEGIN primitive types
584            Self::None {} => None,
585            Self::Boolean { .. } => None,
586            Self::Integer { .. } => None,
587            Self::Number { .. } => None,
588            Self::String { .. } => None,
589            Self::OneOfStrings { .. } => None,
590            // BEGIN string formats
591            Self::DateTime { .. } => None,
592            Self::Ip { .. } => None,
593            Self::Uuid { .. } => None,
594            // BEGIN aggregation types
595            Self::StringArray { .. } => None,
596            Self::Object { children, .. } | Self::ObjectArray { children, .. } => Some(children),
597        }
598    }
599
600    pub const fn is_array(&self) -> bool {
601        self.to_type().is_array()
602    }
603
604    pub const fn to_type(&self) -> ModelFieldKindNativeType {
605        match self {
606            // BEGIN primitive types
607            Self::None {} => ModelFieldKindNativeType::None,
608            Self::Boolean { .. } => ModelFieldKindNativeType::Boolean,
609            Self::Integer { .. } => ModelFieldKindNativeType::Integer,
610            Self::Number { .. } => ModelFieldKindNativeType::Number,
611            Self::String { .. } => ModelFieldKindNativeType::String,
612            Self::OneOfStrings { .. } => ModelFieldKindNativeType::OneOfStrings,
613            // BEGIN string formats
614            Self::DateTime { .. } => ModelFieldKindNativeType::DateTime,
615            Self::Ip { .. } => ModelFieldKindNativeType::Ip,
616            Self::Uuid { .. } => ModelFieldKindNativeType::Uuid,
617            // BEGIN aggregation types
618            Self::StringArray { .. } => ModelFieldKindNativeType::StringArray,
619            Self::Object { .. } => ModelFieldKindNativeType::Object,
620            Self::ObjectArray { .. } => ModelFieldKindNativeType::ObjectArray,
621        }
622    }
623}
624
625#[derive(
626    Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
627)]
628#[serde(rename_all = "camelCase")]
629pub enum ModelFieldKindStringSpec {
630    Dynamic {},
631    Static {
632        length: u32,
633    },
634    Range {
635        #[serde(default)]
636        minimum: Option<u32>,
637        maximum: u32,
638    },
639}
640
641impl Default for ModelFieldKindStringSpec {
642    fn default() -> Self {
643        Self::Dynamic {}
644    }
645}
646
647#[derive(
648    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
649)]
650#[serde(rename_all = "camelCase")]
651pub enum ModelFieldKindObjectSpec {
652    Dynamic {},
653    Enumerate { choices: Vec<String> },
654    Static {},
655}
656
657impl Default for ModelFieldKindObjectSpec {
658    fn default() -> Self {
659        Self::Static {}
660    }
661}
662
663#[derive(
664    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
665)]
666#[serde(rename_all = "camelCase")]
667pub enum ModelFieldKindExtendedSpec {
668    // BEGIN reference types
669    Model { name: String },
670}
671
672impl ModelFieldKindExtendedSpec {
673    pub fn get_children(&self) -> Option<&Vec<String>> {
674        None
675    }
676
677    pub fn get_children_mut(&mut self) -> Option<&mut Vec<String>> {
678        None
679    }
680
681    pub const fn to_type(&self) -> ModelFieldKindExtendedType {
682        match self {
683            // BEGIN reference types
684            Self::Model { .. } => ModelFieldKindExtendedType::Model,
685        }
686    }
687}
688
689#[derive(
690    Copy,
691    Clone,
692    Debug,
693    Display,
694    PartialEq,
695    Eq,
696    PartialOrd,
697    Ord,
698    Hash,
699    Serialize,
700    Deserialize,
701    JsonSchema,
702)]
703#[serde(untagged)]
704pub enum ModelFieldKindType {
705    Native(ModelFieldKindNativeType),
706    Extended(ModelFieldKindExtendedType),
707}
708
709#[derive(
710    Copy,
711    Clone,
712    Debug,
713    Display,
714    EnumString,
715    PartialEq,
716    Eq,
717    PartialOrd,
718    Ord,
719    Hash,
720    Serialize,
721    Deserialize,
722    JsonSchema,
723)]
724pub enum ModelFieldKindNativeType {
725    // BEGIN primitive types
726    None,
727    Boolean,
728    Integer,
729    Number,
730    String,
731    OneOfStrings,
732    // BEGIN string formats
733    DateTime,
734    Ip,
735    Uuid,
736    // BEGIN aggregation types
737    StringArray,
738    Object,
739    ObjectArray,
740}
741
742impl ModelFieldKindNativeType {
743    pub const fn is_array(&self) -> bool {
744        // BEGIN aggregation types
745        matches!(self, Self::StringArray | Self::ObjectArray)
746    }
747
748    pub const fn to_natural(&self) -> &'static str {
749        match self {
750            // BEGIN primitive types
751            Self::None => "None",
752            Self::Boolean => "Boolean",
753            Self::Integer => "Integer",
754            Self::Number => "Number",
755            Self::String | Self::OneOfStrings => "String",
756            // BEGIN string formats
757            Self::DateTime => "DateTime",
758            Self::Ip => "Ip",
759            Self::Uuid => "Uuid",
760            // BEGIN aggregation types
761            Self::StringArray => "String[]",
762            Self::Object => "Object",
763            Self::ObjectArray => "Object[]",
764        }
765    }
766}
767
768#[derive(
769    Copy,
770    Clone,
771    Debug,
772    Display,
773    EnumString,
774    PartialEq,
775    Eq,
776    PartialOrd,
777    Ord,
778    Hash,
779    Serialize,
780    Deserialize,
781    JsonSchema,
782)]
783pub enum ModelFieldKindExtendedType {
784    // BEGIN reference types
785    Model,
786}
787
788#[derive(
789    Copy,
790    Clone,
791    Debug,
792    Display,
793    EnumString,
794    PartialEq,
795    Eq,
796    PartialOrd,
797    Ord,
798    Hash,
799    Serialize,
800    Deserialize,
801    JsonSchema,
802)]
803pub enum ModelFieldDateTimeDefaultType {
804    Now,
805}
806
807#[derive(
808    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
809)]
810#[serde(rename_all = "camelCase")]
811pub struct ModelCustomResourceDefinitionRefSpec {
812    pub name: String,
813}
814
815impl ModelCustomResourceDefinitionRefSpec {
816    pub fn plural(&self) -> &str {
817        self.name.split('.').next().unwrap()
818    }
819}
820
821#[derive(
822    Copy,
823    Clone,
824    Debug,
825    Display,
826    Default,
827    EnumString,
828    PartialEq,
829    Eq,
830    PartialOrd,
831    Ord,
832    Hash,
833    Serialize,
834    Deserialize,
835    JsonSchema,
836)]
837pub enum ModelState {
838    #[default]
839    Pending,
840    Ready,
841    Deleting,
842}
843
844pub type Integer = i64;
845
846pub type Number = ::ordered_float::OrderedFloat<f64>;