1use crate::{
10 db::{StatementContext, StatementRow, Transaction},
11 DBResult, Error,
12};
13
14use self::{
15 datum::{ConcreteDatum, Datum, DatumDiscriminator, DatumDiscriminatorRef},
16 entity::{Entity, EntityPartList},
17};
18
19pub mod datum;
21pub mod entity;
24
25pub mod relation;
27
28pub mod index;
30
31mod build;
32mod check;
33mod collect;
34pub(crate) mod meta;
35
36pub mod migration;
38
39mod detail;
40
41pub struct Stored<T: Entity> {
47 id: T::ID,
48 wrap: T,
49}
50
51impl<T: Entity> Stored<T> {
52 pub(crate) fn new(id: T::ID, value: T) -> Self {
53 Self { id, wrap: value }
54 }
55
56 pub fn id(&self) -> T::ID {
58 self.id
59 }
60
61 pub fn wrapped(self) -> T {
63 self.wrap
64 }
65}
66
67impl<T: Entity + std::fmt::Debug> std::fmt::Debug for Stored<T> {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 f.write_fmt(format_args!(
70 "Stored {{ id: {:?}, value: {:?} }}",
71 self.id, self.wrap
72 ))
73 }
74}
75
76impl<T: Entity> AsRef<T> for Stored<T> {
77 fn as_ref(&self) -> &T {
78 &self.wrap
79 }
80}
81
82impl<T: Entity> AsMut<T> for Stored<T> {
83 fn as_mut(&mut self) -> &mut T {
84 &mut self.wrap
85 }
86}
87
88impl<T: Entity> std::ops::Deref for Stored<T> {
89 type Target = T;
90 fn deref(&self) -> &Self::Target {
91 &self.wrap
92 }
93}
94
95impl<T: Entity> std::ops::DerefMut for Stored<T> {
96 fn deref_mut(&mut self) -> &mut Self::Target {
97 &mut self.wrap
98 }
99}
100
101impl<T: Entity + Clone> Clone for Stored<T> {
102 fn clone(&self) -> Self {
103 Self {
104 id: self.id,
105 wrap: self.wrap.clone(),
106 }
107 }
108}
109
110impl<T: Entity> PartialEq for Stored<T> {
111 fn eq(&self, other: &Self) -> bool {
112 self.id == other.id
113 }
114}
115
116#[derive(Clone)]
122pub struct Serialized<T: serde::Serialize + serde::de::DeserializeOwned + Clone> {
123 wrapped: T,
124}
125
126impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> Serialized<T> {
127 pub fn wrapped(self) -> T {
129 self.wrapped
130 }
131}
132
133impl<T: serde::Serialize + serde::de::DeserializeOwned + Default + Clone> Default
134 for Serialized<T>
135{
136 fn default() -> Self {
137 Self {
138 wrapped: T::default(),
139 }
140 }
141}
142
143impl<T: serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone> std::fmt::Debug
144 for Serialized<T>
145{
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 <T as std::fmt::Debug>::fmt(&self.wrapped, f)
148 }
149}
150
151impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> From<T> for Serialized<T> {
152 fn from(value: T) -> Self {
153 Self { wrapped: value }
154 }
155}
156
157impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> AsRef<T> for Serialized<T> {
158 fn as_ref(&self) -> &T {
159 &self.wrapped
160 }
161}
162
163impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> AsMut<T> for Serialized<T> {
164 fn as_mut(&mut self) -> &mut T {
165 &mut self.wrapped
166 }
167}
168
169impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> std::ops::Deref for Serialized<T> {
170 type Target = T;
171 fn deref(&self) -> &Self::Target {
172 &self.wrapped
173 }
174}
175
176impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> std::ops::DerefMut
177 for Serialized<T>
178{
179 fn deref_mut(&mut self) -> &mut Self::Target {
180 &mut self.wrapped
181 }
182}
183
184impl<T: 'static + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone> Datum
185 for Serialized<T>
186{
187 fn sql_type() -> &'static str {
188 "text"
189 }
190
191 fn bind_to(&self, stmt: &mut StatementContext, index: i32) {
192 let json = std::pin::Pin::new(
193 serde_json::to_string(&self.wrapped).expect("couldn't serialize object into JSON"),
194 );
195
196 <&str as Datum>::bind_to(&&*json.as_ref(), stmt, index);
197
198 stmt.transfer(json);
200 }
201
202 fn build_from(
203 rdata: relation::RelationData,
204 stmt: &mut StatementRow,
205 index: &mut i32,
206 ) -> DBResult<Self>
207 where
208 Self: Sized,
209 {
210 let s = <String as Datum>::build_from(rdata, stmt, index)?;
211
212 let d = serde_json::from_str::<T>(s.as_str()).map_err(Error::JSON)?;
213
214 Ok(Self { wrapped: d })
215 }
216
217 fn accept_discriminator(d: &mut impl DatumDiscriminator)
218 where
219 Self: Sized,
220 {
221 d.visit_serialized::<T>();
222 }
223
224 fn accept_discriminator_ref(&self, d: &mut impl DatumDiscriminatorRef)
225 where
226 Self: Sized,
227 {
228 d.visit_serialized::<T>(&self.wrapped);
229 }
230}
231
232impl<T: 'static + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone>
233 ConcreteDatum for Serialized<T>
234{
235}
236
237pub trait Serializable:
239 serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone
240{
241 fn into_serialized(self) -> Serialized<Self>
243 where
244 Self: Sized;
245}
246
247impl<T: 'static + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone>
248 Serializable for T
249{
250 fn into_serialized(self) -> Serialized<Self>
251 where
252 Self: Sized,
253 {
254 Serialized { wrapped: self }
255 }
256}
257
258pub struct IDMap<T: Entity> {
264 _ghost: std::marker::PhantomData<T>,
265}
266
267impl<T: Entity> Clone for IDMap<T> {
268 fn clone(&self) -> Self {
269 Self {
270 _ghost: Default::default(),
271 }
272 }
273}
274
275impl<E: Entity> DatabaseItem for IDMap<E> {
276 fn accept_item_visitor(visitor: &mut impl DatabaseItemVisitor) {
277 visitor.visit_idmap::<E>();
278 }
279
280 fn build(_: BuildSeal) -> Self
281 where
282 Self: Sized,
283 {
284 Self {
285 _ghost: std::marker::PhantomData,
286 }
287 }
288
289 type Subitems = ();
290}
291
292#[derive(Clone, Copy)]
293pub(crate) struct Sealed;
294
295#[derive(Clone, Copy)]
297pub struct BuildSeal(Sealed);
298impl BuildSeal {
299 pub(crate) fn new() -> Self {
300 Self(Sealed)
301 }
302}
303
304pub trait DatabaseItem {
306 fn accept_item_visitor(visitor: &mut impl DatabaseItemVisitor);
308
309 fn build(_: BuildSeal) -> Self
311 where
312 Self: Sized;
313
314 type Subitems: DatabaseItemList;
316}
317
318#[derive(Default, Debug, Clone, Copy)]
320pub struct SentinelDatabaseItem;
321impl DatabaseItem for SentinelDatabaseItem {
322 fn accept_item_visitor(_visitor: &mut impl DatabaseItemVisitor) {}
323
324 fn build(_: BuildSeal) -> Self
325 where
326 Self: Sized,
327 {
328 Self
329 }
330
331 type Subitems = ();
332}
333
334pub trait DatabaseItemList {
336 type Head: DatabaseItem;
338 type Tail: DatabaseItemList;
340 const EMPTY: bool = false;
342}
343
344impl DatabaseItemList for () {
345 type Head = SentinelDatabaseItem;
346 type Tail = ();
347 const EMPTY: bool = true;
348}
349
350impl<DI0: DatabaseItem> DatabaseItemList for (DI0,) {
351 type Head = DI0;
352 type Tail = ();
353}
354
355pub trait DatabaseItemVisitor {
357 fn visit_idmap<T: Entity>(&mut self)
359 where
360 Self: Sized;
361 fn visit_index<T: Entity, PL: EntityPartList<Entity = T>>(&mut self)
363 where
364 Self: Sized;
365}
366
367pub trait Schema: 'static + DatabaseItem {
369 fn install(&self, txn: &mut Transaction) -> DBResult<()>
371 where
372 Self: Sized,
373 {
374 let schema = build::generate_from_schema::<Self>();
375 match schema.check(txn) {
376 Some(true) => {},
378 Some(false) => Err(Error::IncompatibleSchema)?,
380 None => {
382 schema.create(txn)?;
383 },
384 }
385 Ok(())
386 }
387
388 fn clone(&self) -> Self
395 where
396 Self: Sized,
397 {
398 Self::build(BuildSeal::new())
399 }
400
401 const NAME: Option<&'static str> = None;
403}
404
405impl crate::ConnectionPool {
406 pub fn open<S: Schema>(
408 config: impl Into<crate::db::ConnectionPoolConfig>,
409 ) -> DBResult<(Self, S)> {
410 let pool = Self::new(config)?;
411 let schema = S::build(BuildSeal::new());
412
413 let mut txn = pool.start()?;
414 schema.install(&mut txn)?;
415 txn.commit()?;
416
417 Ok((pool, schema))
418 }
419}