1mod commit;
2pub mod executor;
3pub mod identity;
4pub mod index;
5pub mod primitives;
6pub mod query;
7pub mod response;
8pub mod store;
9pub mod traits;
10pub mod types;
11
12pub(crate) use commit::*;
13
14use crate::{
15 db::{
16 executor::{Context, DeleteExecutor, LoadExecutor, SaveExecutor, UpsertExecutor},
17 index::IndexStoreRegistry,
18 store::DataStoreRegistry,
19 traits::FromKey,
20 },
21 error::InternalError,
22 obs::sink::{self, MetricsSink},
23 traits::{CanisterKind, EntityKind},
24};
25use std::{marker::PhantomData, thread::LocalKey};
26
27pub struct Db<C: CanisterKind> {
39 data: &'static LocalKey<DataStoreRegistry>,
40 index: &'static LocalKey<IndexStoreRegistry>,
41 _marker: PhantomData<C>,
42}
43
44impl<C: CanisterKind> Db<C> {
45 #[must_use]
46 pub const fn new(
47 data: &'static LocalKey<DataStoreRegistry>,
48 index: &'static LocalKey<IndexStoreRegistry>,
49 ) -> Self {
50 Self {
51 data,
52 index,
53 _marker: PhantomData,
54 }
55 }
56
57 #[must_use]
58 pub const fn context<E>(&self) -> Context<'_, E>
59 where
60 E: EntityKind<Canister = C>,
61 {
62 Context::new(self)
63 }
64
65 pub fn with_data<R>(&self, f: impl FnOnce(&DataStoreRegistry) -> R) -> R {
67 self.data.with(|reg| f(reg))
68 }
69
70 pub fn with_index<R>(&self, f: impl FnOnce(&IndexStoreRegistry) -> R) -> R {
72 self.index.with(|reg| f(reg))
73 }
74}
75
76impl<C: CanisterKind> Copy for Db<C> {}
80
81impl<C: CanisterKind> Clone for Db<C> {
82 fn clone(&self) -> Self {
83 *self
84 }
85}
86
87pub struct DbSession<C: CanisterKind> {
93 db: Db<C>,
94 debug: bool,
95 metrics: Option<&'static dyn MetricsSink>,
96}
97
98impl<C: CanisterKind> DbSession<C> {
99 #[must_use]
100 pub const fn new(db: Db<C>) -> Self {
102 Self {
103 db,
104 debug: false,
105 metrics: None,
106 }
107 }
108
109 #[must_use]
110 pub const fn debug(mut self) -> Self {
112 self.debug = true;
113 self
114 }
115
116 #[must_use]
117 pub const fn metrics_sink(mut self, sink: &'static dyn MetricsSink) -> Self {
119 self.metrics = Some(sink);
120 self
121 }
122
123 fn with_metrics<T>(&self, f: impl FnOnce() -> T) -> T {
124 if let Some(sink) = self.metrics {
125 sink::with_metrics_sink(sink, f)
126 } else {
127 f()
128 }
129 }
130
131 #[must_use]
138 pub const fn load<E>(&self) -> LoadExecutor<E>
139 where
140 E: EntityKind<Canister = C>,
141 {
142 LoadExecutor::new(self.db, self.debug)
143 }
144
145 #[must_use]
150 pub const fn save<E>(&self) -> SaveExecutor<E>
151 where
152 E: EntityKind<Canister = C>,
153 {
154 SaveExecutor::new(self.db, self.debug)
155 }
156
157 #[must_use]
160 pub const fn upsert<E>(&self) -> UpsertExecutor<E>
161 where
162 E: EntityKind<Canister = C>,
163 E::PrimaryKey: FromKey,
164 {
165 UpsertExecutor::new(self.db, self.debug)
166 }
167
168 #[must_use]
171 pub const fn delete<E>(&self) -> DeleteExecutor<E>
172 where
173 E: EntityKind<Canister = C>,
174 {
175 DeleteExecutor::new(self.db, self.debug)
176 }
177
178 pub fn insert<E>(&self, entity: E) -> Result<E, InternalError>
184 where
185 E: EntityKind<Canister = C>,
186 {
187 self.with_metrics(|| self.save::<E>().insert(entity))
188 }
189
190 pub fn insert_many<E>(
192 &self,
193 entities: impl IntoIterator<Item = E>,
194 ) -> Result<Vec<E>, InternalError>
195 where
196 E: EntityKind<Canister = C>,
197 {
198 self.with_metrics(|| self.save::<E>().insert_many(entities))
199 }
200
201 pub fn replace<E>(&self, entity: E) -> Result<E, InternalError>
203 where
204 E: EntityKind<Canister = C>,
205 {
206 self.with_metrics(|| self.save::<E>().replace(entity))
207 }
208
209 pub fn replace_many<E>(
211 &self,
212 entities: impl IntoIterator<Item = E>,
213 ) -> Result<Vec<E>, InternalError>
214 where
215 E: EntityKind<Canister = C>,
216 {
217 self.with_metrics(|| self.save::<E>().replace_many(entities))
218 }
219
220 pub fn update<E>(&self, entity: E) -> Result<E, InternalError>
222 where
223 E: EntityKind<Canister = C>,
224 {
225 self.with_metrics(|| self.save::<E>().update(entity))
226 }
227
228 pub fn update_many<E>(
230 &self,
231 entities: impl IntoIterator<Item = E>,
232 ) -> Result<Vec<E>, InternalError>
233 where
234 E: EntityKind<Canister = C>,
235 {
236 self.with_metrics(|| self.save::<E>().update_many(entities))
237 }
238
239 pub fn insert_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
241 where
242 E: EntityKind<Canister = C>,
243 {
244 self.with_metrics(|| self.save::<E>().insert_view(view))
245 }
246
247 pub fn replace_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
249 where
250 E: EntityKind<Canister = C>,
251 {
252 self.with_metrics(|| self.save::<E>().replace_view(view))
253 }
254
255 pub fn update_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
257 where
258 E: EntityKind<Canister = C>,
259 {
260 self.with_metrics(|| self.save::<E>().update_view(view))
261 }
262}