use super::mixins::FieldCacheMixin;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GeneratedFieldType {
Stored,
Virtual,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GeneratedField {
pub expression: String,
pub output_field_type: String,
pub generated_type: GeneratedFieldType,
pub db_persist: bool,
}
impl Default for GeneratedField {
fn default() -> Self {
Self {
expression: String::new(),
output_field_type: "TEXT".to_string(),
generated_type: GeneratedFieldType::Stored,
db_persist: true,
}
}
}
impl GeneratedField {
#[must_use]
pub fn new(expression: impl Into<String>, output_field_type: impl Into<String>) -> Self {
Self {
expression: expression.into(),
output_field_type: output_field_type.into(),
..Self::default()
}
}
#[must_use]
pub fn stored(mut self) -> Self {
self.generated_type = GeneratedFieldType::Stored;
self.db_persist = true;
self
}
#[must_use]
pub fn virtual_column(mut self) -> Self {
self.generated_type = GeneratedFieldType::Virtual;
self.db_persist = false;
self
}
#[must_use]
pub fn expression(&self) -> &str {
&self.expression
}
#[must_use]
pub fn output_field_type(&self) -> &str {
&self.output_field_type
}
#[must_use]
pub fn is_stored(&self) -> bool {
matches!(self.generated_type, GeneratedFieldType::Stored)
}
}
impl FieldCacheMixin for GeneratedField {
fn get_cache_name(&self) -> String {
"generated_field".to_string()
}
fn is_cached(&self) -> bool {
self.db_persist
}
}
#[cfg(test)]
mod tests {
use super::{GeneratedField, GeneratedFieldType};
#[test]
fn generated_field_defaults_to_stored_column() {
let field = GeneratedField::default();
assert_eq!(field.generated_type, GeneratedFieldType::Stored);
assert!(field.db_persist);
assert!(field.expression.is_empty());
}
#[test]
fn generated_field_virtual_column_disables_persistence() {
let field = GeneratedField::new("LOWER(name)", "TEXT").virtual_column();
assert_eq!(field.generated_type, GeneratedFieldType::Virtual);
assert!(!field.db_persist);
assert!(!field.is_stored());
}
#[test]
fn generated_field_exposes_expression() {
let field = GeneratedField::new("price * quantity", "DECIMAL");
assert_eq!(field.expression(), "price * quantity");
assert_eq!(field.output_field_type(), "DECIMAL");
}
}