|
@@ -0,0 +1,259 @@
|
|
|
+use std::{collections::HashMap, hash::Hash, sync::Mutex};
|
|
|
+
|
|
|
+use crate::{
|
|
|
+ db::{StatementContext, StatementRow},
|
|
|
+ schema::{
|
|
|
+ datum::{ConcreteDatum, Datum, DatumList},
|
|
|
+ entity::{Entity, EntityID, EntityPart, EntityPartList, EntityPartVisitor},
|
|
|
+ relation::RelationData,
|
|
|
+ },
|
|
|
+ DBResult,
|
|
|
+};
|
|
|
+
|
|
|
+pub struct NewID<OE: Entity> {
|
|
|
+ value: OE::ID,
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> std::fmt::Debug for NewID<OE> {
|
|
|
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
+ f.write_fmt(format_args!("NewID({})", self.value.into_raw()))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> Clone for NewID<OE> {
|
|
|
+ fn clone(&self) -> Self {
|
|
|
+ Self {
|
|
|
+ value: self.value.clone(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> Copy for NewID<OE> {}
|
|
|
+
|
|
|
+impl<OE: Entity> Hash for NewID<OE> {
|
|
|
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
|
+ self.value.hash(state)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> PartialEq for NewID<OE> {
|
|
|
+ fn eq(&self, other: &Self) -> bool {
|
|
|
+ self.value.eq(&other.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> PartialOrd for NewID<OE> {
|
|
|
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
+ self.value.partial_cmp(&other.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> EntityID for NewID<OE> {
|
|
|
+ type Entity = New<OE>;
|
|
|
+
|
|
|
+ fn from_raw(id: i64) -> Self {
|
|
|
+ Self {
|
|
|
+ value: OE::ID::from_raw(id),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fn into_raw(self) -> i64 {
|
|
|
+ self.value.into_raw()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> Datum for NewID<OE> {
|
|
|
+ fn sql_type() -> &'static str {
|
|
|
+ OE::ID::sql_type()
|
|
|
+ }
|
|
|
+ fn bind_to(&self, stmt: &mut StatementContext, index: i32) {
|
|
|
+ self.value.bind_to(stmt, index)
|
|
|
+ }
|
|
|
+ fn build_from(adata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
|
|
|
+ where
|
|
|
+ Self: Sized,
|
|
|
+ {
|
|
|
+ OE::ID::build_from(adata, stmt, index).map(|value| Self { value })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> ConcreteDatum for NewID<OE> {}
|
|
|
+
|
|
|
+pub struct NewIDPart<OE: Entity> {
|
|
|
+ _ghost: std::marker::PhantomData<&'static OE>,
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> Default for NewIDPart<OE> {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self {
|
|
|
+ _ghost: std::marker::PhantomData,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> Clone for NewIDPart<OE> {
|
|
|
+ fn clone(&self) -> Self {
|
|
|
+ Self::default()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity> EntityPart for NewIDPart<OE> {
|
|
|
+ type Entity = New<OE>;
|
|
|
+ type Datum = NewID<OE>;
|
|
|
+
|
|
|
+ fn desc() -> Option<&'static str> {
|
|
|
+ None
|
|
|
+ }
|
|
|
+ fn unique() -> bool {
|
|
|
+ false
|
|
|
+ }
|
|
|
+ fn part_name() -> &'static str {
|
|
|
+ "id"
|
|
|
+ }
|
|
|
+ fn get_datum(_from: &Self::Entity) -> &Self::Datum {
|
|
|
+ unreachable!()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct NewPart<OE: Entity, OP: EntityPart<Entity = OE>> {
|
|
|
+ _ghost: std::marker::PhantomData<&'static (OE, OP)>,
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity, OP: EntityPart<Entity = OE>> Default for NewPart<OE, OP> {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self {
|
|
|
+ _ghost: std::marker::PhantomData,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity, OP: EntityPart<Entity = OE>> Clone for NewPart<OE, OP> {
|
|
|
+ fn clone(&self) -> Self {
|
|
|
+ Self::default()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity, OP: EntityPart<Entity = OE>> EntityPart for NewPart<OE, OP> {
|
|
|
+ type Entity = New<OE>;
|
|
|
+ type Datum = OP::Datum;
|
|
|
+
|
|
|
+ fn desc() -> Option<&'static str> {
|
|
|
+ OP::desc()
|
|
|
+ }
|
|
|
+ fn unique() -> bool {
|
|
|
+ OP::unique()
|
|
|
+ }
|
|
|
+ fn part_name() -> &'static str {
|
|
|
+ OP::part_name()
|
|
|
+ }
|
|
|
+ fn get_datum(from: &Self::Entity) -> &Self::Datum {
|
|
|
+ OP::get_datum(&from.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct NewPartList<OE: Entity, OPL: EntityPartList> {
|
|
|
+ _ghost: std::marker::PhantomData<&'static (OE, OPL)>,
|
|
|
+}
|
|
|
+
|
|
|
+impl<OE: Entity, OPL: EntityPartList<Entity = OE>> EntityPartList for NewPartList<OE, OPL> {
|
|
|
+ type Entity = New<OE>;
|
|
|
+ type ListHead = NewPart<OE, OPL::ListHead>;
|
|
|
+ type ListTail = NewPartList<OE, OPL::ListTail>;
|
|
|
+ type DatumList = OPL::DatumList;
|
|
|
+
|
|
|
+ const IS_EMPTY: bool = OPL::IS_EMPTY;
|
|
|
+
|
|
|
+ fn build_datum_list(stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
|
|
|
+ OPL::build_datum_list(stmt)
|
|
|
+ }
|
|
|
+ fn accept_part_visitor(visitor: &mut impl EntityPartVisitor<Entity = Self::Entity>) {
|
|
|
+ if Self::IS_EMPTY {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Self::ListHead::accept_part_visitor(visitor);
|
|
|
+ Self::ListTail::accept_part_visitor(visitor);
|
|
|
+ }
|
|
|
+ fn accept_part_visitor_ref(
|
|
|
+ datum_list: &Self::DatumList,
|
|
|
+ visitor: &mut impl EntityPartVisitor<Entity = Self::Entity>,
|
|
|
+ ) {
|
|
|
+ if Self::IS_EMPTY {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ visitor.visit_datum::<Self::ListHead>(datum_list.list_head());
|
|
|
+
|
|
|
+ let tail = datum_list.list_tail();
|
|
|
+ Self::ListTail::accept_part_visitor_ref(&tail, visitor);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug)]
|
|
|
+pub struct New<E: Entity> {
|
|
|
+ value: E,
|
|
|
+}
|
|
|
+
|
|
|
+lazy_static::lazy_static! {
|
|
|
+ static ref NEWNAMES : Mutex<HashMap<std::any::TypeId, &'static str>> = {
|
|
|
+ Default::default()
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+impl<E: Entity> Entity for New<E> {
|
|
|
+ type ID = NewID<E>;
|
|
|
+ type Keys = NewPartList<E, E::Keys>;
|
|
|
+ type Parts = NewPartList<E, E::Parts>;
|
|
|
+ type IDPart = NewIDPart<E>;
|
|
|
+
|
|
|
+ fn entity_name() -> &'static str {
|
|
|
+ let mut nn = NEWNAMES.lock().unwrap();
|
|
|
+ let e = nn.entry(std::any::TypeId::of::<Self>());
|
|
|
+ e.or_insert_with(|| Box::leak(format!("NEW_{}", E::entity_name()).into_boxed_str()))
|
|
|
+ }
|
|
|
+
|
|
|
+ fn build(values: <Self::Parts as EntityPartList>::DatumList) -> Self {
|
|
|
+ Self {
|
|
|
+ value: E::build(values),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn accept_part_visitor(visitor: &mut impl EntityPartVisitor<Entity = Self>) {
|
|
|
+ Self::Parts::accept_part_visitor(visitor)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn accept_part_visitor_ref(&self, visitor: &mut impl EntityPartVisitor<Entity = Self>) {
|
|
|
+ struct PassthroughVisitor<'l, E: Entity, EPV: EntityPartVisitor<Entity = New<E>>>(
|
|
|
+ &'l mut EPV,
|
|
|
+ );
|
|
|
+ impl<'l, E: Entity, EPV: EntityPartVisitor<Entity = New<E>>> EntityPartVisitor
|
|
|
+ for PassthroughVisitor<'l, E, EPV>
|
|
|
+ {
|
|
|
+ type Entity = E;
|
|
|
+ fn visit_datum<EP: EntityPart<Entity = Self::Entity>>(&mut self, datum: &EP::Datum) {
|
|
|
+ self.0.visit_datum::<NewPart<E, EP>>(datum);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut pv = PassthroughVisitor(visitor);
|
|
|
+ self.value.accept_part_visitor_ref(&mut pv);
|
|
|
+ }
|
|
|
+
|
|
|
+ fn accept_part_visitor_mut(&mut self, visitor: &mut impl EntityPartVisitor<Entity = Self>) {
|
|
|
+ struct PassthroughVisitor<'l, E: Entity, EPV: EntityPartVisitor<Entity = New<E>>>(
|
|
|
+ &'l mut EPV,
|
|
|
+ );
|
|
|
+ impl<'l, E: Entity, EPV: EntityPartVisitor<Entity = New<E>>> EntityPartVisitor
|
|
|
+ for PassthroughVisitor<'l, E, EPV>
|
|
|
+ {
|
|
|
+ type Entity = E;
|
|
|
+ fn visit_datum_mut<EP: EntityPart<Entity = Self::Entity>>(
|
|
|
+ &mut self,
|
|
|
+ datum: &mut EP::Datum,
|
|
|
+ ) {
|
|
|
+ self.0.visit_datum_mut::<NewPart<E, EP>>(datum);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut pv = PassthroughVisitor(visitor);
|
|
|
+ self.value.accept_part_visitor_mut(&mut pv);
|
|
|
+ }
|
|
|
+}
|