use crate::error::{GermanicError, GermanicResult};
use crate::schema::{GermanicSerialize, SchemaMetadata, Validate};
use crate::types::GrmHeader;
use serde::de::DeserializeOwned;
use std::path::Path;
pub fn compile<S>(schema: &S) -> GermanicResult<Vec<u8>>
where
S: SchemaMetadata + Validate + GermanicSerialize,
{
schema.validate().map_err(GermanicError::Validation)?;
let header = GrmHeader::new(schema.schema_id());
let header_bytes = header
.to_bytes()
.map_err(|e| GermanicError::General(e.to_string()))?;
let payload_bytes = schema.to_bytes();
let mut output = Vec::with_capacity(header_bytes.len() + payload_bytes.len());
output.extend_from_slice(&header_bytes);
output.extend_from_slice(&payload_bytes);
Ok(output)
}
pub fn compile_json<S>(json: &str) -> GermanicResult<Vec<u8>>
where
S: DeserializeOwned + SchemaMetadata + Validate + GermanicSerialize,
{
let value: serde_json::Value = serde_json::from_str(json)?;
crate::pre_validate::pre_validate(json, &value).map_err(|errors| {
GermanicError::Validation(crate::error::ValidationError::RequiredFieldsMissing(errors))
})?;
let schema: S = serde_json::from_value(value)?;
compile(&schema)
}
pub fn compile_file<S>(path: &Path) -> GermanicResult<Vec<u8>>
where
S: DeserializeOwned + SchemaMetadata + Validate + GermanicSerialize,
{
let json = std::fs::read_to_string(path)?;
compile_json::<S>(&json)
}
pub fn write_grm(data: &[u8], path: &Path) -> GermanicResult<()> {
std::fs::write(path, data)?;
Ok(())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchemaType {
Practice,
}
impl SchemaType {
pub fn parse(name: &str) -> Option<Self> {
match name.to_lowercase().as_str() {
"praxis" | "practice" => Some(Self::Practice),
_ => None,
}
}
pub fn name(&self) -> &'static str {
match self {
Self::Practice => "practice",
}
}
pub fn schema_id(&self) -> &'static str {
match self {
Self::Practice => "de.gesundheit.praxis.v1",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::schemas::{AdresseSchema, PraxisSchema};
#[test]
fn test_schema_type_parsing() {
assert_eq!(SchemaType::parse("praxis"), Some(SchemaType::Practice));
assert_eq!(SchemaType::parse("practice"), Some(SchemaType::Practice));
assert_eq!(SchemaType::parse("PRAXIS"), Some(SchemaType::Practice));
assert_eq!(SchemaType::parse("unknown"), None);
}
#[test]
fn test_compile_practice() {
let practice = PraxisSchema {
name: "Test".to_string(),
bezeichnung: "Arzt".to_string(),
adresse: AdresseSchema {
strasse: "Teststr.".to_string(),
hausnummer: None,
plz: "12345".to_string(),
ort: "Berlin".to_string(),
land: "DE".to_string(),
},
..Default::default()
};
let bytes = compile(&practice).expect("Compilation should succeed");
assert_eq!(&bytes[0..3], b"GRM");
let schema_id_len = u16::from_le_bytes([bytes[4], bytes[5]]) as usize;
let schema_id = std::str::from_utf8(&bytes[6..6 + schema_id_len]).unwrap();
assert_eq!(schema_id, "de.gesundheit.praxis.v1");
}
#[test]
fn test_compile_json_practice() {
let json = r#"{
"name": "Dr. Müller",
"bezeichnung": "Arzt",
"adresse": {
"strasse": "Hauptstraße",
"plz": "12345",
"ort": "Berlin"
}
}"#;
let bytes = compile_json::<PraxisSchema>(json).expect("Compilation should succeed");
assert!(!bytes.is_empty());
assert_eq!(&bytes[0..3], b"GRM");
}
#[test]
fn test_compile_validation_error() {
let practice = PraxisSchema::default();
let result = compile(&practice);
assert!(result.is_err());
assert!(matches!(result, Err(GermanicError::Validation(_))));
}
}