|
@@ -4,27 +4,91 @@
|
|
|
|
|
|
use std::marker::PhantomData;
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
|
|
+use crate::prelude::*;
|
|
use crate::query::Insertable;
|
|
use crate::query::Insertable;
|
|
use crate::schema::{
|
|
use crate::schema::{
|
|
self,
|
|
self,
|
|
build::{generate_from_schema, generate_single_entity_table, GeneratedSchema},
|
|
build::{generate_from_schema, generate_single_entity_table, GeneratedSchema},
|
|
|
|
+ datum::Datum,
|
|
entity::{Entity, EntityID, EntityPart, EntityPartList, EntityPartVisitor},
|
|
entity::{Entity, EntityID, EntityPart, EntityPartList, EntityPartVisitor},
|
|
|
|
+ relation::{RelationDomain, RelationExt, RelationMap, RelationRange},
|
|
DatabaseItem, Schema, SentinelDatabaseItem,
|
|
DatabaseItem, Schema, SentinelDatabaseItem,
|
|
};
|
|
};
|
|
-use crate::{ConnectionLease, DBResult, Error};
|
|
|
|
|
|
+use crate::{ConnectionLease, DBResult, Error, IDMap};
|
|
|
|
+
|
|
|
|
+pub trait MigratableDatum<From: Datum>: Datum {
|
|
|
|
+ fn migrate_datum(from: &From) -> DBResult<Self>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl MigratableDatum<String> for String {
|
|
|
|
+ fn migrate_datum(from: &String) -> DBResult<Self>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized,
|
|
|
|
+ {
|
|
|
|
+ Ok(from.clone())
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl MigratableDatum<bool> for bool {
|
|
|
|
+ fn migrate_datum(from: &bool) -> DBResult<Self>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized,
|
|
|
|
+ {
|
|
|
|
+ Ok(from.clone())
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<R0: Relation, R1: Relation> MigratableDatum<RelationDomain<R0>> for RelationDomain<R1> {
|
|
|
|
+ fn migrate_datum(_from: &RelationDomain<R0>) -> DBResult<Self>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized,
|
|
|
|
+ {
|
|
|
|
+ R0::try_coerce::<R1>()?;
|
|
|
|
+ Ok(RelationDomain::<R1>::default())
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<R0: Relation, R1: Relation> MigratableDatum<RelationRange<R0>> for RelationRange<R1> {
|
|
|
|
+ fn migrate_datum(_from: &RelationRange<R0>) -> DBResult<Self>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized,
|
|
|
|
+ {
|
|
|
|
+ R0::try_coerce::<R1>()?;
|
|
|
|
+ Ok(RelationRange::<R1>::default())
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<E0: Entity, E1: Entity> MigratableDatum<RelationMap<E0>> for RelationMap<E1> {
|
|
|
|
+ fn migrate_datum(_from: &RelationMap<E0>) -> DBResult<Self>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized,
|
|
|
|
+ {
|
|
|
|
+ if E0::entity_name() == E1::entity_name() {
|
|
|
|
+ Ok(RelationMap::default())
|
|
|
|
+ } else {
|
|
|
|
+ panic!(
|
|
|
|
+ "Cannot coerce a migration of a map between {} and {}",
|
|
|
|
+ std::any::type_name::<E0>(),
|
|
|
|
+ std::any::type_name::<E1>()
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
pub trait MigratableEntity<From: Entity>: 'static + Entity {
|
|
pub trait MigratableEntity<From: Entity>: 'static + Entity {
|
|
- fn migrate(from: From) -> DBResult<Option<Self>>
|
|
|
|
|
|
+ fn migrate(from: &From) -> DBResult<Option<Self>>
|
|
where
|
|
where
|
|
Self: Sized;
|
|
Self: Sized;
|
|
}
|
|
}
|
|
|
|
|
|
-impl<T: 'static + Entity> MigratableEntity<T> for T {
|
|
|
|
- fn migrate(from: T) -> DBResult<Option<Self>>
|
|
|
|
|
|
+impl<T: 'static + Entity + Clone> MigratableEntity<T> for T {
|
|
|
|
+ fn migrate(from: &T) -> DBResult<Option<Self>>
|
|
where
|
|
where
|
|
Self: Sized,
|
|
Self: Sized,
|
|
{
|
|
{
|
|
- Ok(Some(from))
|
|
|
|
|
|
+ Ok(Some(from.clone()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -35,7 +99,6 @@ pub struct MigrationContext<'a, 'b> {
|
|
in_progress: Vec<(&'static str, &'static str)>,
|
|
in_progress: Vec<(&'static str, &'static str)>,
|
|
}
|
|
}
|
|
|
|
|
|
-// impl<'a, 'b, 'c, From: DatabaseItem, Into: DatabaseItem> MigrationContext<'a, 'b, 'c, From
|
|
|
|
impl<'a, 'b> MigrationContext<'a, 'b> {
|
|
impl<'a, 'b> MigrationContext<'a, 'b> {
|
|
pub fn in_progress<E: Entity>(&mut self) -> DBResult<MigrateMap<E>> {
|
|
pub fn in_progress<E: Entity>(&mut self) -> DBResult<MigrateMap<E>> {
|
|
// TODO: check that this is, like, part of the new schema...
|
|
// TODO: check that this is, like, part of the new schema...
|
|
@@ -53,6 +116,22 @@ impl<'a, 'b> MigrationContext<'a, 'b> {
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ pub fn migrate_entity<E0: Entity, E1: Entity>(&mut self) -> DBResult<MigrateMap<E1>>
|
|
|
|
+ where
|
|
|
|
+ E1: MigratableEntity<E0>,
|
|
|
|
+ {
|
|
|
|
+ let mm = self.in_progress::<E1>()?;
|
|
|
|
+
|
|
|
|
+ for e0 in IDMap::<E0>::default().get(self.lease)? {
|
|
|
|
+ let Some(e1) = <E1 as MigratableEntity<E0>>::migrate(e0.as_ref())? else {
|
|
|
|
+ continue;
|
|
|
|
+ };
|
|
|
|
+ mm.insert_matching(self.lease, e1, e0)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(mm)
|
|
|
|
+ }
|
|
|
|
+
|
|
pub fn lease(&mut self) -> &mut ConnectionLease<'b> {
|
|
pub fn lease(&mut self) -> &mut ConnectionLease<'b> {
|
|
self.lease
|
|
self.lease
|
|
}
|
|
}
|
|
@@ -344,7 +423,6 @@ impl<OE: Entity> Default for MigrateMap<OE> {
|
|
|
|
|
|
impl<OE: Entity> Insertable<OE> for MigrateMap<OE> {
|
|
impl<OE: Entity> Insertable<OE> for MigrateMap<OE> {
|
|
fn insert(&self, lease: &mut ConnectionLease, value: OE) -> DBResult<OE::ID> {
|
|
fn insert(&self, lease: &mut ConnectionLease, value: OE) -> DBResult<OE::ID> {
|
|
- use crate::IDMap;
|
|
|
|
let id = IDMap::<IPEntity<OE>>::insert(&IDMap::build(), lease, IPEntity(value))?;
|
|
let id = IDMap::<IPEntity<OE>>::insert(&IDMap::build(), lease, IPEntity(value))?;
|
|
Ok(<OE::ID>::from_raw(id.0))
|
|
Ok(<OE::ID>::from_raw(id.0))
|
|
}
|
|
}
|