1use std::fmt;
2
3use thiserror::Error;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum DbAdapterKind {
8 Generic,
10 Sqlx,
12 Diesel,
14 SeaOrm,
16}
17
18impl fmt::Display for DbAdapterKind {
19 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
20 formatter.write_str(match self {
21 Self::Generic => "generic",
22 Self::Sqlx => "sqlx",
23 Self::Diesel => "diesel",
24 Self::SeaOrm => "seaorm",
25 })
26 }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum DbResultShape {
32 One,
34 Optional,
36 All,
38 Custom,
40}
41
42impl fmt::Display for DbResultShape {
43 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
44 formatter.write_str(match self {
45 Self::One => "one",
46 Self::Optional => "optional",
47 Self::All => "all",
48 Self::Custom => "custom",
49 })
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct DbOperationContext {
60 pub adapter: DbAdapterKind,
62 pub operation: String,
64 pub namespace: String,
66 pub physical_key: Option<String>,
68 pub result_shape: DbResultShape,
70}
71
72impl fmt::Display for DbOperationContext {
73 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
74 let namespace = if self.namespace.is_empty() {
75 "<empty>"
76 } else {
77 &self.namespace
78 };
79 let physical_key = self.physical_key.as_deref().unwrap_or("<missing>");
80
81 write!(
82 formatter,
83 "adapter={}, namespace={}, key={}, result_shape={}",
84 self.adapter, namespace, physical_key, self.result_shape
85 )
86 }
87}
88
89#[derive(Debug, Error)]
91pub enum DbCacheError {
92 #[error(
94 "database cached operation `{operation}` is missing an explicit cache key \
95 (adapter={adapter}, namespace={namespace}, result_shape={result_shape})"
96 )]
97 MissingKey {
98 operation: String,
100 adapter: DbAdapterKind,
102 namespace: String,
104 result_shape: DbResultShape,
106 },
107
108 #[error("database cached operation `{operation}` failed ({context}): {source}")]
110 Operation {
111 operation: String,
113 context: Box<DbOperationContext>,
115 #[source]
117 source: Box<hydracache::CacheError>,
118 },
119
120 #[error(transparent)]
122 Cache(#[from] hydracache::CacheError),
123}
124
125impl DbCacheError {
126 pub(crate) fn operation(context: DbOperationContext, source: hydracache::CacheError) -> Self {
127 Self::Operation {
128 operation: context.operation.clone(),
129 context: Box::new(context),
130 source: Box::new(source),
131 }
132 }
133}
134
135pub type Result<T> = std::result::Result<T, DbCacheError>;