Skip to main content

openehr_store/
error.rs

1//! Errors.
2//!
3//! The rule from the `openehr` crate applies here unchanged and matters more:
4//! **an error must not echo stored content** (`X11.7`). A store error is the
5//! one that reaches a connection-pool log, an APM trace, and a paging alert at
6//! once, so these messages name identifiers, tables, and rules — never a
7//! patient's data.
8
9/// What went wrong.
10#[derive(Debug, thiserror::Error)]
11#[non_exhaustive]
12pub enum StoreError {
13    /// The commit would produce a history that reads back and does not connect.
14    ///
15    /// Wraps the `openehr` crate's own rules rather than restating them, so the
16    /// database and the library cannot disagree about what a valid history is.
17    #[error("commit refused: {0}")]
18    Commit(#[from] openehr::rm::common::CommitError),
19
20    /// The record, container, or version named does not exist.
21    #[error("no such {kind}: {id}")]
22    NotFound {
23        /// What was looked for — `ehr`, `versioned_object`, `version`.
24        kind: &'static str,
25        /// Its identifier. Identifiers are design-time or system-minted, not
26        /// clinical content, so naming one is safe and is the only way a caller
27        /// can act (`X11.7a`).
28        id: String,
29    },
30
31    /// The record already exists.
32    #[error("{kind} already exists: {id}")]
33    Conflict {
34        /// What was being created.
35        kind: &'static str,
36        /// Its identifier.
37        id: String,
38    },
39
40    /// A stored document failed Reference Model validation on the way in.
41    ///
42    /// The store validates before it writes. A store that accepted an invalid
43    /// composition would make every later reader's `validate()` fail on data it
44    /// cannot fix.
45    #[error("{0}")]
46    Invalid(#[from] openehr::ValidationReport),
47
48    /// A value could not be parsed or built.
49    #[error(transparent)]
50    Parse(#[from] openehr::ParseError),
51
52    /// Canonical JSON could not be written or read.
53    #[error("canonical JSON: {0}")]
54    Json(#[from] serde_json::Error),
55
56    /// The engine reported an error.
57    ///
58    /// A string, because the five drivers have five unrelated error types and
59    /// this crate does not depend on any of them. The engine crate is expected
60    /// to have logged the typed error already.
61    #[error("{engine}: {message}")]
62    Engine {
63        /// Which engine.
64        engine: &'static str,
65        /// What it said. The engine crate MUST NOT put row data in here.
66        message: String,
67    },
68
69    /// The database was installed under a different schema version.
70    ///
71    /// Refusing is the whole point. `install()` is `CREATE TABLE IF NOT EXISTS`,
72    /// so against an older database every statement no-ops and the *first
73    /// commit* fails on a column that is not there. A store that returned `Ok`
74    /// here would report success and then fail inexplicably later, which is
75    /// worse than not starting.
76    ///
77    /// There is no migration mechanism (`O10.14`); a deployment holding data
78    /// under `found` must export, recreate, and reload.
79    #[error(
80        "database is at schema version {found}, this build writes {expected}; \
81         there is no migration path (see spec/databases/10-operations.md O10.14)"
82    )]
83    SchemaVersionMismatch {
84        /// The version recorded in the database.
85        found: i64,
86        /// The version this build writes.
87        expected: i64,
88    },
89
90    /// The operation is defined by this crate and not implemented by this
91    /// engine.
92    ///
93    /// Never a silent no-op. An engine crate at a conformance level below
94    /// `Store` returns this rather than pretending.
95    #[error("unsupported by {engine}: {what} (see {spec_ref})")]
96    Unsupported {
97        /// Which engine.
98        engine: &'static str,
99        /// What was asked for.
100        what: &'static str,
101        /// Where the exclusion is recorded.
102        spec_ref: &'static str,
103    },
104}
105
106/// This crate's result alias.
107pub type Result<T, E = StoreError> = core::result::Result<T, E>;