1pub mod executor;
2pub mod primitives;
3pub mod query;
4pub mod response;
5pub mod store;
6
7use crate::{
8 db::{
9 executor::{Context, DeleteExecutor, LoadExecutor, SaveExecutor, UpsertExecutor},
10 store::{DataStoreRegistry, IndexStoreRegistry},
11 },
12 error::InternalError,
13 obs::sink::{self, MetricsSink},
14 traits::{CanisterKind, EntityKind, FromKey},
15};
16use std::{marker::PhantomData, thread::LocalKey};
17
18pub struct Db<C: CanisterKind> {
30 data: &'static LocalKey<DataStoreRegistry>,
31 index: &'static LocalKey<IndexStoreRegistry>,
32 _marker: PhantomData<C>,
33}
34
35impl<C: CanisterKind> Db<C> {
36 #[must_use]
37 pub const fn new(
38 data: &'static LocalKey<DataStoreRegistry>,
39 index: &'static LocalKey<IndexStoreRegistry>,
40 ) -> Self {
41 Self {
42 data,
43 index,
44 _marker: PhantomData,
45 }
46 }
47
48 #[must_use]
49 pub const fn context<E>(&self) -> Context<'_, E>
50 where
51 E: EntityKind<Canister = C>,
52 {
53 Context::new(self)
54 }
55
56 pub fn with_data<R>(&self, f: impl FnOnce(&DataStoreRegistry) -> R) -> R {
58 self.data.with(|reg| f(reg))
59 }
60
61 pub fn with_index<R>(&self, f: impl FnOnce(&IndexStoreRegistry) -> R) -> R {
63 self.index.with(|reg| f(reg))
64 }
65}
66
67impl<C: CanisterKind> Copy for Db<C> {}
71
72impl<C: CanisterKind> Clone for Db<C> {
73 fn clone(&self) -> Self {
74 *self
75 }
76}
77
78pub struct DbSession<C: CanisterKind> {
84 db: Db<C>,
85 debug: bool,
86 metrics: Option<&'static dyn MetricsSink>,
87}
88
89impl<C: CanisterKind> DbSession<C> {
90 #[must_use]
91 pub const fn new(db: Db<C>) -> Self {
93 Self {
94 db,
95 debug: false,
96 metrics: None,
97 }
98 }
99
100 #[must_use]
101 pub const fn debug(mut self) -> Self {
103 self.debug = true;
104 self
105 }
106
107 #[must_use]
108 pub const fn metrics_sink(mut self, sink: &'static dyn MetricsSink) -> Self {
110 self.metrics = Some(sink);
111 self
112 }
113
114 fn with_metrics<T>(&self, f: impl FnOnce() -> T) -> T {
115 if let Some(sink) = self.metrics {
116 sink::with_metrics_sink(sink, f)
117 } else {
118 f()
119 }
120 }
121
122 #[must_use]
129 pub const fn load<E>(&self) -> LoadExecutor<E>
130 where
131 E: EntityKind<Canister = C>,
132 {
133 LoadExecutor::new(self.db, self.debug)
134 }
135
136 #[must_use]
141 pub const fn save<E>(&self) -> SaveExecutor<E>
142 where
143 E: EntityKind<Canister = C>,
144 {
145 SaveExecutor::new(self.db, self.debug)
146 }
147
148 #[must_use]
151 pub const fn upsert<E>(&self) -> UpsertExecutor<E>
152 where
153 E: EntityKind<Canister = C>,
154 E::PrimaryKey: FromKey,
155 {
156 UpsertExecutor::new(self.db, self.debug)
157 }
158
159 #[must_use]
162 pub const fn delete<E>(&self) -> DeleteExecutor<E>
163 where
164 E: EntityKind<Canister = C>,
165 {
166 DeleteExecutor::new(self.db, self.debug)
167 }
168
169 pub fn insert<E>(&self, entity: E) -> Result<E, InternalError>
175 where
176 E: EntityKind<Canister = C>,
177 {
178 self.with_metrics(|| self.save::<E>().insert(entity))
179 }
180
181 pub fn insert_many<E>(
183 &self,
184 entities: impl IntoIterator<Item = E>,
185 ) -> Result<Vec<E>, InternalError>
186 where
187 E: EntityKind<Canister = C>,
188 {
189 self.with_metrics(|| self.save::<E>().insert_many(entities))
190 }
191
192 pub fn replace<E>(&self, entity: E) -> Result<E, InternalError>
194 where
195 E: EntityKind<Canister = C>,
196 {
197 self.with_metrics(|| self.save::<E>().replace(entity))
198 }
199
200 pub fn replace_many<E>(
202 &self,
203 entities: impl IntoIterator<Item = E>,
204 ) -> Result<Vec<E>, InternalError>
205 where
206 E: EntityKind<Canister = C>,
207 {
208 self.with_metrics(|| self.save::<E>().replace_many(entities))
209 }
210
211 pub fn update<E>(&self, entity: E) -> Result<E, InternalError>
213 where
214 E: EntityKind<Canister = C>,
215 {
216 self.with_metrics(|| self.save::<E>().update(entity))
217 }
218
219 pub fn update_many<E>(
221 &self,
222 entities: impl IntoIterator<Item = E>,
223 ) -> Result<Vec<E>, InternalError>
224 where
225 E: EntityKind<Canister = C>,
226 {
227 self.with_metrics(|| self.save::<E>().update_many(entities))
228 }
229
230 pub fn insert_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
232 where
233 E: EntityKind<Canister = C>,
234 {
235 self.with_metrics(|| self.save::<E>().insert_view(view))
236 }
237
238 pub fn replace_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
240 where
241 E: EntityKind<Canister = C>,
242 {
243 self.with_metrics(|| self.save::<E>().replace_view(view))
244 }
245
246 pub fn update_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
248 where
249 E: EntityKind<Canister = C>,
250 {
251 self.with_metrics(|| self.save::<E>().update_view(view))
252 }
253}