Skip to main content

mig_assembly/
service.rs

1//! High-level conversion service that orchestrates the full pipeline.
2//!
3//! Loads a MIG schema once and provides methods for converting EDIFACT
4//! input to assembled trees (as JSON) or performing roundtrip conversion.
5
6use std::path::Path;
7
8use crate::assembler::{Assembler, AssemblerConfig};
9use crate::parsing::parse_mig;
10use crate::tokenize::parse_to_segments;
11use crate::AssemblyError;
12use mig_types::schema::mig::MigSchema;
13
14/// High-level service that holds a parsed MIG schema and provides
15/// convenient methods for EDIFACT conversion.
16pub struct ConversionService {
17    mig: MigSchema,
18}
19
20impl ConversionService {
21    /// Create a new `ConversionService` by loading a MIG XML file.
22    pub fn new(
23        mig_path: &Path,
24        message_type: &str,
25        variant: Option<&str>,
26        format_version: &str,
27    ) -> Result<Self, AssemblyError> {
28        let mig = parse_mig(mig_path, message_type, variant, format_version)
29            .map_err(|e| AssemblyError::ParseError(e.to_string()))?;
30        Ok(Self { mig })
31    }
32
33    /// Create a `ConversionService` from an already-parsed MIG schema.
34    pub fn from_mig(mig: MigSchema) -> Self {
35        Self { mig }
36    }
37
38    /// Convert EDIFACT input to an assembled tree, serialized as JSON.
39    pub fn convert_to_tree(&self, input: &str) -> Result<serde_json::Value, AssemblyError> {
40        let segments = parse_to_segments(input.as_bytes())?;
41        let assembler = Assembler::new(&self.mig);
42        let tree = assembler.assemble_generic(&segments)?;
43        serde_json::to_value(&tree).map_err(|e| AssemblyError::ParseError(e.to_string()))
44    }
45
46    /// Convert EDIFACT input to an `AssembledTree` (typed, not JSON).
47    pub fn convert_to_assembled_tree(
48        &self,
49        input: &str,
50    ) -> Result<crate::assembler::AssembledTree, AssemblyError> {
51        let segments = parse_to_segments(input.as_bytes())?;
52        let assembler = Assembler::new(&self.mig);
53        assembler.assemble_generic(&segments)
54    }
55
56    /// Convert a complete interchange into per-message assembled trees.
57    ///
58    /// Steps:
59    /// 1. Parse input to segments
60    /// 2. Split at UNH/UNT boundaries
61    /// 3. Assemble each message independently
62    ///
63    /// Returns the `InterchangeChunks` (for envelope access) and a `Vec<AssembledTree>`
64    /// (one per message, in order).
65    pub fn convert_interchange_to_trees(
66        &self,
67        input: &str,
68    ) -> Result<
69        (
70            crate::tokenize::InterchangeChunks,
71            Vec<crate::assembler::AssembledTree>,
72        ),
73        AssemblyError,
74    > {
75        let segments = parse_to_segments(input.as_bytes())?;
76        let chunks = crate::tokenize::split_messages(segments)?;
77
78        let mut trees = Vec::with_capacity(chunks.messages.len());
79        for msg in &chunks.messages {
80            let all_segments = msg.all_segments();
81            let assembler = Assembler::new(&self.mig);
82            let tree = assembler.assemble_generic(&all_segments)?;
83            trees.push(tree);
84        }
85
86        Ok((chunks, trees))
87    }
88
89    /// Convert EDIFACT input to an `AssembledTree` with custom assembler config.
90    pub fn convert_to_assembled_tree_with_config(
91        &self,
92        input: &str,
93        config: AssemblerConfig,
94    ) -> Result<crate::assembler::AssembledTree, AssemblyError> {
95        let segments = parse_to_segments(input.as_bytes())?;
96        let assembler = Assembler::with_config(&self.mig, config);
97        assembler.assemble_generic(&segments)
98    }
99
100    /// Convert a complete interchange into per-message assembled trees with custom config.
101    pub fn convert_interchange_to_trees_with_config(
102        &self,
103        input: &str,
104        config: AssemblerConfig,
105    ) -> Result<
106        (
107            crate::tokenize::InterchangeChunks,
108            Vec<crate::assembler::AssembledTree>,
109        ),
110        AssemblyError,
111    > {
112        let segments = parse_to_segments(input.as_bytes())?;
113        let chunks = crate::tokenize::split_messages(segments)?;
114
115        let mut trees = Vec::with_capacity(chunks.messages.len());
116        for msg in &chunks.messages {
117            let all_segments = msg.all_segments();
118            let assembler = Assembler::with_config(&self.mig, config.clone());
119            let tree = assembler.assemble_generic(&all_segments)?;
120            trees.push(tree);
121        }
122
123        Ok((chunks, trees))
124    }
125
126    /// Get a reference to the loaded MIG schema.
127    pub fn mig(&self) -> &MigSchema {
128        &self.mig
129    }
130}