use crate::{
db::{StatementContext, StatementRow},
schema::{
datum::{BorrowedDatum, Datum, DatumDiscriminator, DatumDiscriminatorRef, OwnedDatum},
entity::{Entity, EntityVisitor},
},
DBResult,
};
pub trait Relation: 'static {
type Domain: Entity;
type Range: Entity;
const INJECTIVE: bool = false;
const NAME: &'static str;
}
pub(crate) trait RelationExt: Relation {
fn try_coerce<Q: Relation>() -> DBResult<()>
where
Self: Sized,
{
if Self::NAME == Q::NAME
&& Self::Domain::entity_name() == Q::Domain::entity_name()
&& Self::Range::entity_name() == Q::Range::entity_name()
&& Self::INJECTIVE == Q::INJECTIVE
{
Ok(())
} else {
panic!(
"Bad relation migration: types {} and {} have different semantics. Name: {}/{}, Domain: {}/{}, Range: {}/{}, injective: {}/{}",
std::any::type_name::<Self>(),
std::any::type_name::<Q>(),
Self::NAME, Q::NAME,
Self::Domain::entity_name(), Q::Domain::entity_name(),
Self::Range::entity_name(), Q::Range::entity_name(),
Self::INJECTIVE, Q::INJECTIVE
);
}
}
}
impl<R: Relation> RelationExt for R {}
#[derive(Debug)]
pub enum LocalSide {
Domain,
Range,
}
#[derive(Clone, Copy)]
pub struct RelationData {
pub(crate) local_name: &'static str,
pub(crate) part_name: &'static str,
pub(crate) local_id: i64,
}
pub struct RelationMap<T: Entity> {
pub(crate) data: Option<RelationData>,
_ghost: std::marker::PhantomData<T>,
}
impl<T: Entity> Clone for RelationMap<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Entity> Copy for RelationMap<T> {}
impl<T: Entity> std::fmt::Debug for RelationMap<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"RelationMap {{ id: {:?} }}",
self.data.as_ref().map(|d| d.local_id)
))
}
}
impl<T: Entity> Default for RelationMap<T> {
fn default() -> Self {
Self {
data: None,
_ghost: Default::default(),
}
}
}
impl<T: Entity> Datum for RelationMap<T> {
const INTERNAL_DATUM: bool = false;
fn sql_type() -> &'static str {
unreachable!()
}
fn debug_field(&self, _field: &'static str, _fmt: &mut std::fmt::DebugStruct)
where
Self: Sized,
{
}
fn accept_entity_visitor(v: &mut impl EntityVisitor) {
v.visit::<T>();
}
fn accept_discriminator(d: &mut impl DatumDiscriminator)
where
Self: Sized,
{
d.visit_relation_map::<T>();
}
fn accept_discriminator_ref(&self, d: &mut impl DatumDiscriminatorRef)
where
Self: Sized,
{
d.visit_relation_map::<T>(self);
}
fn bind_to(&self, _stmt: &mut StatementContext, _index: i32) -> DBResult<()> {
unreachable!()
}
fn build_from(rdata: RelationData, _stmt: &mut StatementRow, _index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(Self {
data: Some(rdata),
_ghost: Default::default(),
})
}
fn update_adata(&mut self, rdata: RelationData) {
self.data = Some(rdata);
}
}
impl<T: Entity> OwnedDatum for RelationMap<T> {
type RefData<'a> = Self;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
impl<T: Entity> BorrowedDatum<'_, RelationMap<T>> for RelationMap<T> {
fn as_owned(&self) -> Self {
*self
}
}
pub struct RelationDomain<R: Relation> {
pub(crate) data: Option<RelationData>,
_ghost: std::marker::PhantomData<R>,
}
impl<R: Relation> Clone for RelationDomain<R> {
fn clone(&self) -> Self {
*self
}
}
impl<R: Relation> Copy for RelationDomain<R> {}
impl<R: Relation> Default for RelationDomain<R> {
fn default() -> Self {
Self {
data: None,
_ghost: Default::default(),
}
}
}
impl<R: Relation> std::fmt::Debug for RelationDomain<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"RelationDomain {{ id: {:?} }}",
self.data.as_ref().map(|d| d.local_id)
))
}
}
impl<R: Relation> Datum for RelationDomain<R> {
const INTERNAL_DATUM: bool = false;
fn sql_type() -> &'static str {
unreachable!()
}
fn debug_field(&self, _field: &'static str, _fmt: &mut std::fmt::DebugStruct)
where
Self: Sized,
{
}
fn accept_entity_visitor(v: &mut impl EntityVisitor) {
v.visit::<R::Range>();
}
fn accept_discriminator(d: &mut impl DatumDiscriminator)
where
Self: Sized,
{
d.visit_relation_domain::<R>();
}
fn accept_discriminator_ref(&self, d: &mut impl DatumDiscriminatorRef)
where
Self: Sized,
{
d.visit_relation_domain(self);
}
fn bind_to(&self, _stmt: &mut StatementContext, _index: i32) -> DBResult<()> {
unreachable!()
}
fn build_from(rdata: RelationData, _stmt: &mut StatementRow, _index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(Self {
data: Some(rdata),
_ghost: Default::default(),
})
}
fn update_adata(&mut self, rdata: RelationData) {
self.data = Some(rdata);
}
}
impl<R: Relation> OwnedDatum for RelationDomain<R> {
type RefData<'a> = Self;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
impl<R: Relation> BorrowedDatum<'_, RelationDomain<R>> for RelationDomain<R> {
fn as_owned(&self) -> Self {
*self
}
}
pub struct RelationRange<R: Relation> {
pub(crate) data: Option<RelationData>,
_ghost: std::marker::PhantomData<R>,
}
impl<R: Relation> Clone for RelationRange<R> {
fn clone(&self) -> Self {
*self
}
}
impl<R: Relation> Copy for RelationRange<R> {}
impl<R: Relation> Default for RelationRange<R> {
fn default() -> Self {
Self {
data: None,
_ghost: Default::default(),
}
}
}
impl<R: Relation> std::fmt::Debug for RelationRange<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"RelationRange {{ id: {:?} }}",
self.data.as_ref().map(|d| d.local_id)
))
}
}
impl<R: Relation> Datum for RelationRange<R> {
const INTERNAL_DATUM: bool = false;
fn sql_type() -> &'static str {
unreachable!()
}
fn debug_field(&self, _field: &'static str, _fmt: &mut std::fmt::DebugStruct)
where
Self: Sized,
{
}
fn accept_entity_visitor(v: &mut impl EntityVisitor) {
v.visit::<R::Domain>();
}
fn accept_discriminator(d: &mut impl DatumDiscriminator)
where
Self: Sized,
{
d.visit_relation_range::<R>();
}
fn accept_discriminator_ref(&self, d: &mut impl DatumDiscriminatorRef)
where
Self: Sized,
{
d.visit_relation_range(self);
}
fn bind_to(&self, _stmt: &mut StatementContext, _index: i32) -> DBResult<()> {
unreachable!()
}
fn build_from(rdata: RelationData, _stmt: &mut StatementRow, _index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(Self {
data: Some(rdata),
_ghost: Default::default(),
})
}
fn update_adata(&mut self, rdata: RelationData) {
self.data = Some(rdata);
}
}
impl<R: Relation> OwnedDatum for RelationRange<R> {
type RefData<'a> = Self;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
impl<R: Relation> BorrowedDatum<'_, RelationRange<R>> for RelationRange<R> {
fn as_owned(&self) -> Self {
*self
}
}