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 operation is defined by this crate and not implemented by this
70 /// engine.
71 ///
72 /// Never a silent no-op. An engine crate at a conformance level below
73 /// `Store` returns this rather than pretending.
74 #[error("unsupported by {engine}: {what} (see {spec_ref})")]
75 Unsupported {
76 /// Which engine.
77 engine: &'static str,
78 /// What was asked for.
79 what: &'static str,
80 /// Where the exclusion is recorded.
81 spec_ref: &'static str,
82 },
83}
84
85/// This crate's result alias.
86pub type Result<T, E = StoreError> = core::result::Result<T, E>;