nautilus-orm-schema 0.1.5

Schema parsing and validation for Nautilus ORM
Documentation
use super::*;

impl SchemaValidator {
    pub(super) fn validate_defaults(&mut self) {
        let models: Vec<_> = self.schema.models().cloned().collect();
        for model in &models {
            for field in &model.fields {
                for attr in &field.attributes {
                    if let FieldAttribute::Default(expr, _) = attr {
                        self.validate_default_value(
                            &field.field_type,
                            expr,
                            &field.name.value,
                            &model.name.value,
                        );
                    }
                }
            }
        }
    }

    pub(super) fn validate_default_value(
        &mut self,
        field_type: &FieldType,
        expr: &Expr,
        field_name: &str,
        model_name: &str,
    ) {
        match expr {
            Expr::Literal(lit) => {
                self.validate_literal_default(field_type, lit, field_name, model_name);
            }
            Expr::Ident(ident) => {
                if let FieldType::UserType(type_name) = field_type {
                    if let Some(enum_decl) =
                        self.schema.enums().find(|e| e.name.value == *type_name)
                    {
                        let variant_exists = enum_decl
                            .variants
                            .iter()
                            .any(|v| v.name.value == ident.value);
                        if !variant_exists {
                            self.errors.push_back(SchemaError::Validation(
                                format!(
                                    "Enum variant '{}' does not exist in enum '{}' for field '{}' in model '{}'",
                                    ident.value, type_name, field_name, model_name
                                ),
                                ident.span,
                            ));
                        }
                    } else {
                        self.errors.push_back(SchemaError::Validation(
                            format!(
                                "Default value for field '{}' in model '{}' uses identifier '{}' but field type is not an enum",
                                field_name, model_name, ident.value
                            ),
                            ident.span,
                        ));
                    }
                } else {
                    self.errors.push_back(SchemaError::Validation(
                        format!(
                            "Default value for field '{}' in model '{}' uses identifier '{}' but field type is not an enum",
                            field_name, model_name, ident.value
                        ),
                        ident.span,
                    ));
                }
            }
            Expr::FunctionCall { name, args, span } => {
                self.validate_function_default(
                    field_type,
                    &name.value,
                    args,
                    *span,
                    field_name,
                    model_name,
                );
            }
            _ => {
                self.errors.push_back(SchemaError::Validation(
                    format!(
                        "Unsupported default value expression for field '{}' in model '{}'",
                        field_name, model_name
                    ),
                    expr.span(),
                ));
            }
        }
    }

    pub(super) fn validate_literal_default(
        &mut self,
        field_type: &FieldType,
        lit: &Literal,
        field_name: &str,
        model_name: &str,
    ) {
        match (field_type, lit) {
            (FieldType::String, Literal::String(_, _)) => {}
            (FieldType::Boolean, Literal::Boolean(_, _)) => {}
            (
                FieldType::Int | FieldType::BigInt | FieldType::Float | FieldType::Decimal { .. },
                Literal::Number(_, _),
            ) => {}
            _ => {
                self.errors.push_back(SchemaError::Validation(
                    format!(
                        "Type mismatch: field '{}' in model '{}' has type {:?} but default value is {:?}",
                        field_name, model_name, field_type, lit
                    ),
                    lit.span(),
                ));
            }
        }
    }

    pub(super) fn validate_function_default(
        &mut self,
        field_type: &FieldType,
        func_name: &str,
        _args: &[Expr],
        span: Span,
        field_name: &str,
        model_name: &str,
    ) {
        match func_name {
            "autoincrement" => {
                if !matches!(field_type, FieldType::Int | FieldType::BigInt) {
                    self.errors.push_back(SchemaError::Validation(
                        format!(
                            "autoincrement() can only be used with Int or BigInt fields, but field '{}' in model '{}' has type {:?}",
                            field_name, model_name, field_type
                        ),
                        span,
                    ));
                }
            }
            "uuid" => {
                if !matches!(field_type, FieldType::Uuid) {
                    self.errors.push_back(SchemaError::Validation(
                        format!(
                            "uuid() can only be used with Uuid fields, but field '{}' in model '{}' has type {:?}",
                            field_name, model_name, field_type
                        ),
                        span,
                    ));
                }
            }
            "now" => {
                if !matches!(field_type, FieldType::DateTime) {
                    self.errors.push_back(SchemaError::Validation(
                        format!(
                            "now() can only be used with DateTime fields, but field '{}' in model '{}' has type {:?}",
                            field_name, model_name, field_type
                        ),
                        span,
                    ));
                }
            }
            "env" => {}
            _ => {
                self.errors.push_back(SchemaError::Validation(
                    format!(
                        "Unknown function '{}' in default value for field '{}' in model '{}'",
                        func_name, field_name, model_name
                    ),
                    span,
                ));
            }
        }
    }
}