use crate::{traits::FieldValueKind, types::EntityTag};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FieldStorageDecode {
ByKind,
Value,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ScalarCodec {
Blob,
Bool,
Date,
Duration,
Float32,
Float64,
Int64,
Principal,
Subaccount,
Text,
Timestamp,
Uint64,
Ulid,
Unit,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LeafCodec {
Scalar(ScalarCodec),
StructuralFallback,
}
#[derive(Clone, Copy, Debug)]
pub struct EnumVariantModel {
pub(crate) ident: &'static str,
pub(crate) payload_kind: Option<&'static FieldKind>,
pub(crate) payload_storage_decode: FieldStorageDecode,
}
impl EnumVariantModel {
#[must_use]
pub const fn new(
ident: &'static str,
payload_kind: Option<&'static FieldKind>,
payload_storage_decode: FieldStorageDecode,
) -> Self {
Self {
ident,
payload_kind,
payload_storage_decode,
}
}
#[must_use]
pub const fn ident(&self) -> &'static str {
self.ident
}
#[must_use]
pub const fn payload_kind(&self) -> Option<&'static FieldKind> {
self.payload_kind
}
#[must_use]
pub const fn payload_storage_decode(&self) -> FieldStorageDecode {
self.payload_storage_decode
}
}
#[derive(Debug)]
pub struct FieldModel {
pub(crate) name: &'static str,
pub(crate) kind: FieldKind,
pub(crate) nullable: bool,
pub(crate) storage_decode: FieldStorageDecode,
pub(crate) leaf_codec: LeafCodec,
pub(crate) insert_generation: Option<FieldInsertGeneration>,
pub(crate) write_management: Option<FieldWriteManagement>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FieldInsertGeneration {
Ulid,
Timestamp,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FieldWriteManagement {
CreatedAt,
UpdatedAt,
}
impl FieldModel {
#[must_use]
#[doc(hidden)]
pub const fn generated(name: &'static str, kind: FieldKind) -> Self {
Self::generated_with_storage_decode_and_nullability(
name,
kind,
FieldStorageDecode::ByKind,
false,
)
}
#[must_use]
#[doc(hidden)]
pub const fn generated_with_storage_decode(
name: &'static str,
kind: FieldKind,
storage_decode: FieldStorageDecode,
) -> Self {
Self::generated_with_storage_decode_and_nullability(name, kind, storage_decode, false)
}
#[must_use]
#[doc(hidden)]
pub const fn generated_with_storage_decode_and_nullability(
name: &'static str,
kind: FieldKind,
storage_decode: FieldStorageDecode,
nullable: bool,
) -> Self {
Self::generated_with_storage_decode_nullability_and_write_policies(
name,
kind,
storage_decode,
nullable,
None,
None,
)
}
#[must_use]
#[doc(hidden)]
pub const fn generated_with_storage_decode_nullability_and_insert_generation(
name: &'static str,
kind: FieldKind,
storage_decode: FieldStorageDecode,
nullable: bool,
insert_generation: Option<FieldInsertGeneration>,
) -> Self {
Self::generated_with_storage_decode_nullability_and_write_policies(
name,
kind,
storage_decode,
nullable,
insert_generation,
None,
)
}
#[must_use]
#[doc(hidden)]
pub const fn generated_with_storage_decode_nullability_and_write_policies(
name: &'static str,
kind: FieldKind,
storage_decode: FieldStorageDecode,
nullable: bool,
insert_generation: Option<FieldInsertGeneration>,
write_management: Option<FieldWriteManagement>,
) -> Self {
Self {
name,
kind,
nullable,
storage_decode,
leaf_codec: leaf_codec_for(kind, storage_decode),
insert_generation,
write_management,
}
}
#[must_use]
pub const fn name(&self) -> &'static str {
self.name
}
#[must_use]
pub const fn kind(&self) -> FieldKind {
self.kind
}
#[must_use]
pub const fn nullable(&self) -> bool {
self.nullable
}
#[must_use]
pub const fn storage_decode(&self) -> FieldStorageDecode {
self.storage_decode
}
#[must_use]
pub const fn leaf_codec(&self) -> LeafCodec {
self.leaf_codec
}
#[must_use]
pub const fn insert_generation(&self) -> Option<FieldInsertGeneration> {
self.insert_generation
}
#[must_use]
pub const fn write_management(&self) -> Option<FieldWriteManagement> {
self.write_management
}
}
const fn leaf_codec_for(kind: FieldKind, storage_decode: FieldStorageDecode) -> LeafCodec {
if matches!(storage_decode, FieldStorageDecode::Value) {
return LeafCodec::StructuralFallback;
}
match kind {
FieldKind::Blob => LeafCodec::Scalar(ScalarCodec::Blob),
FieldKind::Bool => LeafCodec::Scalar(ScalarCodec::Bool),
FieldKind::Date => LeafCodec::Scalar(ScalarCodec::Date),
FieldKind::Duration => LeafCodec::Scalar(ScalarCodec::Duration),
FieldKind::Float32 => LeafCodec::Scalar(ScalarCodec::Float32),
FieldKind::Float64 => LeafCodec::Scalar(ScalarCodec::Float64),
FieldKind::Int => LeafCodec::Scalar(ScalarCodec::Int64),
FieldKind::Principal => LeafCodec::Scalar(ScalarCodec::Principal),
FieldKind::Subaccount => LeafCodec::Scalar(ScalarCodec::Subaccount),
FieldKind::Text => LeafCodec::Scalar(ScalarCodec::Text),
FieldKind::Timestamp => LeafCodec::Scalar(ScalarCodec::Timestamp),
FieldKind::Uint => LeafCodec::Scalar(ScalarCodec::Uint64),
FieldKind::Ulid => LeafCodec::Scalar(ScalarCodec::Ulid),
FieldKind::Unit => LeafCodec::Scalar(ScalarCodec::Unit),
FieldKind::Relation { key_kind, .. } => leaf_codec_for(*key_kind, storage_decode),
FieldKind::Account
| FieldKind::Decimal { .. }
| FieldKind::Enum { .. }
| FieldKind::Int128
| FieldKind::IntBig
| FieldKind::List(_)
| FieldKind::Map { .. }
| FieldKind::Set(_)
| FieldKind::Structured { .. }
| FieldKind::Uint128
| FieldKind::UintBig => LeafCodec::StructuralFallback,
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RelationStrength {
Strong,
Weak,
}
#[derive(Clone, Copy, Debug)]
pub enum FieldKind {
Account,
Blob,
Bool,
Date,
Decimal {
scale: u32,
},
Duration,
Enum {
path: &'static str,
variants: &'static [EnumVariantModel],
},
Float32,
Float64,
Int,
Int128,
IntBig,
Principal,
Subaccount,
Text,
Timestamp,
Uint,
Uint128,
UintBig,
Ulid,
Unit,
Relation {
target_path: &'static str,
target_entity_name: &'static str,
target_entity_tag: EntityTag,
target_store_path: &'static str,
key_kind: &'static Self,
strength: RelationStrength,
},
List(&'static Self),
Set(&'static Self),
Map {
key: &'static Self,
value: &'static Self,
},
Structured {
queryable: bool,
},
}
impl FieldKind {
#[must_use]
pub const fn value_kind(&self) -> FieldValueKind {
match self {
Self::Account
| Self::Blob
| Self::Bool
| Self::Date
| Self::Duration
| Self::Enum { .. }
| Self::Float32
| Self::Float64
| Self::Int
| Self::Int128
| Self::IntBig
| Self::Principal
| Self::Subaccount
| Self::Text
| Self::Timestamp
| Self::Uint
| Self::Uint128
| Self::UintBig
| Self::Ulid
| Self::Unit
| Self::Decimal { .. }
| Self::Relation { .. } => FieldValueKind::Atomic,
Self::List(_) | Self::Set(_) => FieldValueKind::Structured { queryable: true },
Self::Map { .. } => FieldValueKind::Structured { queryable: false },
Self::Structured { queryable } => FieldValueKind::Structured {
queryable: *queryable,
},
}
}
#[must_use]
pub const fn is_deterministic_collection_shape(&self) -> bool {
match self {
Self::Relation { key_kind, .. } => key_kind.is_deterministic_collection_shape(),
Self::List(inner) | Self::Set(inner) => inner.is_deterministic_collection_shape(),
Self::Map { key, value } => {
key.is_deterministic_collection_shape() && value.is_deterministic_collection_shape()
}
_ => true,
}
}
}