Skip to main content

data_modelling_core/import/
dbmv.rs

1//! Databricks Metric Views (DBMV) importer
2//!
3//! Parses DBMV YAML files (.dbmv.yaml) and converts them to DBMVDocument models.
4
5use super::ImportError;
6use crate::models::dbmv::{DBMVDocument, DBMVMetricView};
7
8/// DBMV importer for parsing Databricks Metric Views YAML files
9pub struct DBMVImporter;
10
11impl DBMVImporter {
12    /// Create a new DBMV importer instance
13    pub fn new() -> Self {
14        Self
15    }
16
17    /// Import a DBMV document from YAML content
18    ///
19    /// Optionally validates against the JSON schema if the `schema-validation` feature is enabled.
20    pub fn import(&self, yaml_content: &str) -> Result<DBMVDocument, ImportError> {
21        #[cfg(feature = "schema-validation")]
22        {
23            use crate::validation::schema::validate_dbmv_internal;
24            validate_dbmv_internal(yaml_content).map_err(ImportError::ValidationError)?;
25        }
26
27        DBMVDocument::from_yaml(yaml_content)
28            .map_err(|e| ImportError::ParseError(format!("Failed to parse DBMV YAML: {}", e)))
29    }
30
31    /// Import a DBMV document without schema validation
32    pub fn import_without_validation(
33        &self,
34        yaml_content: &str,
35    ) -> Result<DBMVDocument, ImportError> {
36        DBMVDocument::from_yaml(yaml_content)
37            .map_err(|e| ImportError::ParseError(format!("Failed to parse DBMV YAML: {}", e)))
38    }
39
40    /// Import a single standalone Databricks metric view from YAML content (no wrapper envelope)
41    pub fn import_single_view(&self, yaml_content: &str) -> Result<DBMVMetricView, ImportError> {
42        serde_yaml::from_str(yaml_content).map_err(|e| {
43            ImportError::ParseError(format!("Failed to parse metric view YAML: {}", e))
44        })
45    }
46}
47
48impl Default for DBMVImporter {
49    fn default() -> Self {
50        Self::new()
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_import_document() {
60        let importer = DBMVImporter::new();
61        let yaml = r#"
62apiVersion: v1.0.0
63kind: MetricViews
64system: test-system
65metricViews:
66  - name: orders_metrics
67    source: catalog.schema.orders
68    dimensions:
69      - name: order_date
70        expr: order_date
71    measures:
72      - name: total_revenue
73        expr: SUM(revenue)
74"#;
75        let result = importer.import_without_validation(yaml);
76        assert!(result.is_ok());
77        let doc = result.unwrap();
78        assert_eq!(doc.system, "test-system");
79        assert_eq!(doc.metric_views.len(), 1);
80        assert_eq!(doc.metric_views[0].name, "orders_metrics");
81    }
82
83    #[test]
84    fn test_import_single_view() {
85        let importer = DBMVImporter::new();
86        let yaml = r#"
87name: orders_metrics
88source: catalog.schema.orders
89dimensions:
90  - name: order_date
91    expr: order_date
92measures:
93  - name: total_revenue
94    expr: SUM(revenue)
95"#;
96        let result = importer.import_single_view(yaml);
97        assert!(result.is_ok());
98        let view = result.unwrap();
99        assert_eq!(view.name, "orders_metrics");
100        assert_eq!(view.dimensions.len(), 1);
101        assert_eq!(view.measures.len(), 1);
102    }
103
104    #[test]
105    fn test_import_invalid_yaml() {
106        let importer = DBMVImporter::new();
107        let result = importer.import_without_validation("not: valid: yaml: at: all");
108        assert!(result.is_err());
109    }
110}