openehr-rs 0.3.1

A typed asynchronous client for the EHRDB/openEHR REST API.
Documentation
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use std::collections::HashMap;

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AQLResponse<T> {
    pub aql: String,
    pub executed_aql: String,
    pub result_set: Vec<T>,
    pub meta: serde_json::Value,
}

#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct AQLQuery<'a> {
    pub aql: &'a str,
    pub aql_parameters: serde_json::Value,
}

#[derive(Serialize, Deserialize)]
pub struct EhrDbEventTriggerAQLs {
    pub aql: String,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EhrDbEventTrigger {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<i32>,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub active: Option<bool>,
    pub event_time_to_live_hours: i32,
    pub repeat_interval_minutes: i32,
    pub run_immediately: bool,
    pub aqls: EhrDbEventTriggerAQLs,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub archetype_ids: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub template_ids: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub http_result_url: Option<String>,
    pub population: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_by: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub kafka_result_topic: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub kafka_servers: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parent_trigger_id: Option<i32>,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EhrDbView {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<i32>,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub import_export_name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub js: Option<String>,
    pub cacheable: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_by: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parent_id: Option<i32>,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Composition {
    #[serde(default)]
    pub name: String,
    pub template_id: String,
    pub composition_uid: String,
    pub composition: Value,
    #[serde(default)]
    pub tags: Option<Value>,
    #[serde(default)]
    pub deleted: bool,
    #[serde(default)]
    pub last_version: bool,
    #[serde(default)]
    pub ehr_id: Option<String>,
    #[serde(default)]
    pub lifecycle_state: Option<String>,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct CompositionPreview {
    pub uid: String,
    pub name: String,
    pub template_id: String,
    pub start_time: DateTime<Utc>,
    pub link: Option<String>,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TagsPayload {
    pub composition_uid: String,
    pub tags: Vec<Tag>,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EhrDbVersion {
    pub build_time: DateTime<Utc>,
    pub version: String,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Tag {
    pub tag: String,
    pub value: String,
    pub aql_path: String,
}

impl Composition {
    pub fn new(name: &str, template_id: &str) -> Self {
        Self {
            name: name.to_string(),
            template_id: template_id.to_string(),
            composition_uid: "".to_string(),
            composition: json!({}), // Initialize as an empty JSON object
            tags: None,
            deleted: false,
            last_version: true,
            ehr_id: None,
            lifecycle_state: Some("COMPLETE".to_string()),
        }
    }

    pub fn add_content(&mut self, key: &str, value: &str) {
        let mut json_obj = self.composition.clone();

        // Create the new key using the composition name
        let composed_key = format!("{}/{}", self.name, key);

        // Add the new key-value pair to the JSON object
        json_obj[composed_key] = json!(value);

        // Update composition
        self.composition = json_obj;
    }

    pub fn add_content_from_string(&mut self, json_str: &str) {
        let parsed: HashMap<String, String> = serde_json::from_str(json_str).unwrap();
        for (key, value) in parsed.iter() {
            self.add_content(key, value);
        }
    }

    pub fn add_ctx(&mut self, key: &str, value: &str) {
        let mut json_obj = self.composition.clone();
        json_obj[key] = json!(value);
        self.composition = json_obj;
    }

    pub fn add_ctx_from_string(&mut self, json_str: &str) {
        let parsed: HashMap<String, String> = serde_json::from_str(json_str).unwrap();
        for (key, value) in parsed.iter() {
            self.add_ctx(key, value);
        }
    }
}