gears 0.1.7

Gears core implementation
Documentation
use crate::validation::common::{ValidationError, ValidationErrors};
use crate::structure::model::ModelDocument;

use uuid::Uuid;

use std::collections::HashSet;

#[derive(Debug)]
pub struct Validation {}

impl Validation {
    pub fn validate(model: &ModelDocument) -> ValidationErrors {
        let mut errors = Vec::<ValidationError>::new();

        errors.extend(Validation::all_locales_have_translation_docs(&model));
        errors.extend(Validation::all_translation_docs_have_locales(&model));
        errors.extend(
            Validation::all_page_xflow_references_point_to_existing_entities(&model),
        );
        errors.extend(Validation::all_doc_collections_have_correct_unique_keys(
            &model,
        ));

        errors
    }

    pub fn all_locales_have_translation_docs(model: &ModelDocument) -> ValidationErrors {
        debug!("all_locales_have_translation_docs");
        let mut errors = Vec::<ValidationError>::new();

        for locale in &model.body.config.body.locales {
            if !model.has_translation(&locale) {
                errors.push(ValidationError {
                    code: 1,
                    message: format!("Model: locale '{:?}' has no translation document", &locale),
                    paths: vec!["/config/locales".to_owned()],
                });
            }
        }

        errors
    }

    pub fn all_translation_docs_have_locales(model: &ModelDocument) -> Vec<ValidationError> {
        debug!("all_translation_docs_have_locales");
        let mut errors = Vec::<ValidationError>::new();

        for t in &model.body.translations {
            if !model.has_locale(&t.body.locale) {
                errors.push(ValidationError {
                                code: 1,
                                message: format!("Model: translation doc exists with locale '{:?}' but it is not listed as a supported locale",
                                                 &t.body.locale),
                                paths: vec!["/config/translations".to_owned()],
                            });
            }
        }

        errors
    }

    pub fn all_page_xflow_references_point_to_existing_entities(
        model: &ModelDocument,
    ) -> Vec<ValidationError> {
        debug!("all_page_xflow_references_point_to_existing_entities");
        let mut errors = Vec::<ValidationError>::new();
        let xflow_ids = model.all_xflow_ids();

        for page in &model.body.pages {
            for xflow_reference in &page.all_xflow_references() {
                if !xflow_ids.contains(xflow_reference) {
                    let message = format!(
                        "Page: Contains a reference to xflow id '{}', which does not exist in this model",
                        xflow_reference
                    );
                    errors.push(ValidationError {
                        code: 1,
                        message: message,
                        paths: vec![format!("/pages/{id}", id = page.id)],
                    });
                }
            }
        }

        errors
    }

    pub fn all_doc_collections_have_correct_unique_keys(
        model: &ModelDocument,
    ) -> Vec<ValidationError> {
        debug!("all_doc_collections_have_correct_unique_keys");
        let mut errors = Vec::<ValidationError>::new();

        let mut xflow_ids = HashSet::<&Uuid>::new();

        for doc in &model.body.xflows {
            if xflow_ids.contains(&doc.id) {
                let message = format!("xflow: Duplicate ID found in XFlow document '{}'", doc.id);
                errors.push(ValidationError {
                    code: 1,
                    message: message,
                    paths: vec![format!("/xflow/{id}", id = doc.id)],
                });
            } else {
                xflow_ids.insert(&doc.id);
            }
        }

        let mut page_ids = HashSet::<&Uuid>::new();

        for doc in &model.body.pages {
            if page_ids.contains(&doc.id) {
                let message = format!("page: Duplicate ID found in page document '{}'", doc.id);
                errors.push(ValidationError {
                    code: 1,
                    message: message,
                    paths: vec![format!("/page/{id}", id = doc.id)],
                });
            } else {
                page_ids.insert(&doc.id);
            }
        }

        let mut translation_ids = HashSet::<&Uuid>::new();

        for doc in &model.body.translations {
            if translation_ids.contains(&doc.id) {
                let message = format!(
                    "translation: Duplicate ID found in translation document '{}'",
                    doc.id
                );
                errors.push(ValidationError {
                    code: 1,
                    message: message,
                    paths: vec![format!("/translation/{id}", id = doc.id)],
                });
            } else {
                translation_ids.insert(&doc.id);
            }
        }

        errors
    }
}