use crate::{
db::{StatementContext, StatementRow, Transaction},
DBResult, Error,
};
use self::{
datum::{Datum, DatumDiscriminator, DatumDiscriminatorRef, OwnedDatum},
entity::{Entity, EntityPartList, EntityRef},
};
pub mod datum;
pub mod entity;
pub mod relation;
pub mod index;
mod build;
mod check;
mod collect;
pub(crate) mod meta;
#[cfg(feature = "track_typesig")]
pub(crate) mod typesig;
pub mod migration;
mod detail;
pub struct Stored<T: Entity> {
id: T::ID,
wrap: T,
}
impl<T: Entity> Stored<T> {
pub(crate) fn new(id: T::ID, value: T) -> Self {
Self { id, wrap: value }
}
pub fn id(&self) -> T::ID {
self.id
}
pub fn wrapped(self) -> T {
self.wrap
}
}
impl<T: Entity + std::fmt::Debug> std::fmt::Debug for Stored<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"Stored {{ id: {:?}, value: {:?} }}",
self.id, self.wrap
))
}
}
impl<T: Entity> AsRef<T> for Stored<T> {
fn as_ref(&self) -> &T {
&self.wrap
}
}
impl<T: Entity> AsMut<T> for Stored<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.wrap
}
}
impl<T: Entity> std::ops::Deref for Stored<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.wrap
}
}
impl<T: Entity> std::ops::DerefMut for Stored<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.wrap
}
}
impl<T: Entity + Clone> Clone for Stored<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
wrap: self.wrap.clone(),
}
}
}
impl<T: Entity> PartialEq for Stored<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T: Entity + PartialEq> PartialEq<T> for Stored<T> {
fn eq(&self, other: &T) -> bool {
&self.wrap == other
}
}
pub struct Borrowed<'a, T: EntityRef<'a>> {
id: <T::Entity as Entity>::ID,
wrap: T,
}
impl<'a, T: EntityRef<'a>> Borrowed<'a, T> {
pub(crate) fn new(id: <T::Entity as Entity>::ID, value: T) -> Self {
Self { id, wrap: value }
}
pub fn id(&self) -> <T::Entity as Entity>::ID {
self.id
}
pub fn wrapped(self) -> T {
self.wrap
}
}
impl<'a, T: EntityRef<'a> + std::fmt::Debug> std::fmt::Debug for Borrowed<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"Borrowed {{ id: {:?}, value: {:?} }}",
self.id, self.wrap
))
}
}
impl<'a, T: EntityRef<'a>> AsRef<T> for Borrowed<'a, T> {
fn as_ref(&self) -> &T {
&self.wrap
}
}
impl<'a, T: EntityRef<'a>> AsMut<T> for Borrowed<'a, T> {
fn as_mut(&mut self) -> &mut T {
&mut self.wrap
}
}
impl<'a, T: EntityRef<'a>> std::ops::Deref for Borrowed<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.wrap
}
}
impl<'a, T: EntityRef<'a>> Clone for Borrowed<'a, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, T: EntityRef<'a>> Copy for Borrowed<'a, T> {}
impl<'a, T: EntityRef<'a>> PartialEq for Borrowed<'a, T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<'a, T: EntityRef<'a> + PartialEq> PartialEq<T> for Borrowed<'a, T> {
fn eq(&self, other: &T) -> bool {
&self.wrap == other
}
}
#[derive(Clone)]
pub struct Serialized<T: serde::Serialize + serde::de::DeserializeOwned + Clone> {
wrapped: T,
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> Serialized<T> {
pub fn wrapped(self) -> T {
self.wrapped
}
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + Default + Clone> Default
for Serialized<T>
{
fn default() -> Self {
Self {
wrapped: T::default(),
}
}
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone> std::fmt::Debug
for Serialized<T>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<T as std::fmt::Debug>::fmt(&self.wrapped, f)
}
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> From<T> for Serialized<T> {
fn from(value: T) -> Self {
Self { wrapped: value }
}
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> AsRef<T> for Serialized<T> {
fn as_ref(&self) -> &T {
&self.wrapped
}
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> AsMut<T> for Serialized<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.wrapped
}
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> std::ops::Deref for Serialized<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.wrapped
}
}
impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone> std::ops::DerefMut
for Serialized<T>
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.wrapped
}
}
impl<T: 'static + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone> Datum
for Serialized<T>
{
fn sql_type() -> &'static str {
"text"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
let json = std::pin::Pin::new(
serde_json::to_string(&self.wrapped).expect("couldn't serialize object into JSON"),
);
let r = <&str as Datum>::bind_to(&&*json.as_ref(), stmt, index);
stmt.transfer(json);
r
}
fn build_from(
rdata: relation::RelationData,
stmt: &mut StatementRow,
index: &mut i32,
) -> DBResult<Self>
where
Self: Sized,
{
let s = <&str as Datum>::build_from(rdata, stmt, index)?;
let d = serde_json::from_str::<T>(s).map_err(Error::JSON)?;
Ok(Self { wrapped: d })
}
fn accept_discriminator(d: &mut impl DatumDiscriminator)
where
Self: Sized,
{
d.visit_serialized::<T>();
}
fn accept_discriminator_ref(&self, d: &mut impl DatumDiscriminatorRef)
where
Self: Sized,
{
d.visit_serialized::<T>(&self.wrapped);
}
}
impl<T: 'static + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone>
OwnedDatum for Serialized<T>
{
type RefData<'a> = &'a Self;
fn as_ref(&self) -> Self::RefData<'_> {
self
}
}
pub trait Serializable:
serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone
{
fn into_serialized(self) -> Serialized<Self>
where
Self: Sized;
}
impl<T: 'static + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone>
Serializable for T
{
fn into_serialized(self) -> Serialized<Self>
where
Self: Sized,
{
Serialized { wrapped: self }
}
}
pub struct IDMap<T: Entity> {
_ghost: std::marker::PhantomData<T>,
}
impl<T: Entity> Clone for IDMap<T> {
fn clone(&self) -> Self {
Self {
_ghost: Default::default(),
}
}
}
impl<E: Entity> DatabaseItem for IDMap<E> {
fn accept_item_visitor(visitor: &mut impl DatabaseItemVisitor) {
visitor.visit_idmap::<E>();
}
fn build(_: BuildSeal) -> Self
where
Self: Sized,
{
Self {
_ghost: std::marker::PhantomData,
}
}
type Subitems = ();
}
#[derive(Clone, Copy)]
pub(crate) struct Sealed;
#[derive(Clone, Copy)]
pub struct BuildSeal(Sealed);
impl BuildSeal {
pub(crate) fn new() -> Self {
Self(Sealed)
}
}
pub trait DatabaseItem {
fn accept_item_visitor(visitor: &mut impl DatabaseItemVisitor);
fn build(_: BuildSeal) -> Self
where
Self: Sized;
type Subitems: DatabaseItemList;
}
#[derive(Default, Debug, Clone, Copy)]
pub struct SentinelDatabaseItem;
impl DatabaseItem for SentinelDatabaseItem {
fn accept_item_visitor(_visitor: &mut impl DatabaseItemVisitor) {}
fn build(_: BuildSeal) -> Self
where
Self: Sized,
{
Self
}
type Subitems = ();
}
pub trait DatabaseItemList {
type Head: DatabaseItem;
type Tail: DatabaseItemList;
const EMPTY: bool = false;
}
impl DatabaseItemList for () {
type Head = SentinelDatabaseItem;
type Tail = ();
const EMPTY: bool = true;
}
impl<DI0: DatabaseItem> DatabaseItemList for (DI0,) {
type Head = DI0;
type Tail = ();
}
pub trait DatabaseItemVisitor {
fn visit_idmap<T: Entity>(&mut self)
where
Self: Sized;
fn visit_index<const UNIQUE: bool, T: Entity, PL: EntityPartList<Entity = T>>(&mut self)
where
Self: Sized;
}
pub trait Schema: 'static + DatabaseItem {
fn install(&self, txn: &mut Transaction) -> DBResult<()>
where
Self: Sized,
{
let schema = build::generate_from_schema::<Self>();
match schema.check(txn) {
Some(true) => {
log::trace!("Schema signature match!");
check::check_schema::<Self>(txn)
},
Some(false) => Err(Error::IncompatibleSchema),
None => {
log::trace!("No schema found. Initializing schema...");
schema.create(txn)
},
}
}
fn clone_schema(&self) -> Self
where
Self: Sized,
{
Self::build(BuildSeal::new())
}
const NAME: Option<&'static str> = None;
}
impl crate::ConnectionPool {
pub fn open<S: Schema>(
config: impl Into<crate::db::ConnectionPoolConfig>,
) -> DBResult<(Self, S)> {
let pool = Self::new(config)?;
let schema = S::build(BuildSeal::new());
let mut txn = pool.start()?;
schema.install(&mut txn)?;
txn.commit()?;
Ok((pool, schema))
}
}