DCCommon

Trait DCCommon 

Source
pub trait DCCommon<T, PARENT, const IMMUTABLE: bool = false>:
    DataController<CacheUpdate = CacheUpdates<T::ActiveModel>, Error = SimErrorAny>
    + Send
    + Debug
where T: EntityTrait + Send + Sync + 'static, T::Model: IntoActiveModel<T::ActiveModel>, T::Column: Iterable, T::ActiveModel: ActiveModelTrait + Send + Sync + 'static + From<Self::Value>, PARENT: DBProvider, Self::Value: Send + Sync + 'static, Self::Key: ToString + Send + Sync + 'static, Self: Child<WeakParent = Weak<PARENT>, RcParent = Result<Arc<PARENT>, Self::Error>, FXPParent = Weak<PARENT>>,
{ // Required method fn delete_many_condition( dm: DeleteMany<T>, keys: Vec<Self::Key>, ) -> DeleteMany<T>; // Provided methods fn db_provider(&self) -> <Self as Child>::RcParent { ... } fn wbdc_write_back<'life0, 'async_trait>( &'life0 self, update_records: Arc<UpdateIterator<Self>>, ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait { ... } fn wbdbc_on_new<'life0, 'life1, 'life2, 'async_trait, AM>( &'life0 self, _key: &'life1 Self::Key, value: &'life2 AM, ) -> Pin<Box<dyn Future<Output = Result<DataControllerResponse<Self>, Self::Error>> + Send + 'async_trait>> where AM: Into<T::ActiveModel> + Clone + Send + Sync + 'static + 'async_trait, Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn wbdc_on_delete<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _key: &'life1 Self::Key, update: Option<&'life2 CacheUpdates<T::ActiveModel>>, ) -> Pin<Box<dyn Future<Output = Result<DataControllerResponse<Self>, Self::Error>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn wbdc_on_change<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 Self::Key, value: &'life2 Self::Value, old_value: Self::Value, prev_update: Option<Self::CacheUpdate>, ) -> Pin<Box<dyn Future<Output = Result<DataControllerResponse<Self>, Self::Error>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } }
Expand description

Common implementation of DataController methods.

All models in this simulation share a lot of properties. Primarily due to the use of SeaORM framework. Because of this most of the DataController functionality can be shared among them and this is what is this trait made for.

Though an attempt to provide as much information about the implementation as possible in this documentation will be made, it is recommended to look into the source code as some comments in the code require the context to be understood.

§Type parameters

ParameterDescription
TThe SeaORM Entity type that this data controller is responsible for. It must implement the EntityTrait trait.
PARENTThe data controller implementing DCCommon is expected to be a child of an entity that implements the DBProvider trait, thereby providing a database connection.
IMMUTABLESetting this to true indicates that the database does not modify records when they are written to it; in particular, the primary key is configured with auto-increment disabled.

Required Methods§

Source

fn delete_many_condition( dm: DeleteMany<T>, keys: Vec<Self::Key>, ) -> DeleteMany<T>

Provide correct condition for SeaORM’s DeleteMany operation. See, for example, CustomerManager::delete_many_condition source code.

Provided Methods§

Source

fn db_provider(&self) -> <Self as Child>::RcParent

Where we get our database connection from.

Source

fn wbdc_write_back<'life0, 'async_trait>( &'life0 self, update_records: Arc<UpdateIterator<Self>>, ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait,

Try to send given update records to the database in the most efficient way. This task is accomplished by:

  • using a transaction to group all updates together and possibly avoid re-indexing overhead;
  • sorting updates into inserts, updates, and deletes;
  • batching inserts and deletes.

Updates are performed on a per-record basis because they are, by nature, not batchable.

To be on the safe side, the batches are limited to 1000 records each. Technically, the PostgreSQL protocol allows for up to 65,535 records in a single batch. However, practically, even half of that was causing errors. Considering that even with the limit of 1000 the simulation demonstrates an 80-100 times improvement over the non-cached approach, this is considered a good trade-off.

Source

fn wbdbc_on_new<'life0, 'life1, 'life2, 'async_trait, AM>( &'life0 self, _key: &'life1 Self::Key, value: &'life2 AM, ) -> Pin<Box<dyn Future<Output = Result<DataControllerResponse<Self>, Self::Error>> + Send + 'async_trait>>
where AM: Into<T::ActiveModel> + Clone + Send + Sync + 'static + 'async_trait, Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

For every new data record added this method respond with [CacheUpdates::Insert(record_active_mode)] update. The DataControllerOp depends on the IMMUTABLE flag: if it is set to true, the operation is DataControllerOp::Insert, otherwise it is DataControllerOp::Nop.

Source

fn wbdc_on_delete<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _key: &'life1 Self::Key, update: Option<&'life2 CacheUpdates<T::ActiveModel>>, ) -> Pin<Box<dyn Future<Output = Result<DataControllerResponse<Self>, Self::Error>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute record deletion.

A special perk of this method is that when a new record is inserted into the cache, its associated update record remains as CacheUpdates::Insert until the next flush, even if the record is later modified by the user. This means that for IMMUTABLE data controllers, writing the record to the backend and then deleting it has no side effects and can be safely collapsed into a single operation. This is exactly what this method does: when it finds that the previous update state of an immutable model for the key is an insert, it simply returns a DataControllerOp::Drop operation, meaning that both data and update records are removed without having wasted time writing to the backend.

Source

fn wbdc_on_change<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 Self::Key, value: &'life2 Self::Value, old_value: Self::Value, prev_update: Option<Self::CacheUpdate>, ) -> Pin<Box<dyn Future<Output = Result<DataControllerResponse<Self>, Self::Error>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Called when a record is modified by the user.

This method creates a “diff” active model representing the differences between the unmodified and modified values, where only the changed fields are set. If an update record for the key already exists, it is merged with the diff, and the resulting update record is returned.

The new update record always maintains the same discriminant as the previous one unless no prior update exists.

The DataControllerOp is set to DataControllerOp::Insert if the IMMUTABLE flag is set to true; otherwise, it is DataControllerOp::Nop.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl<DBCP> DCCommon<Entity, DBCP> for wb_cache::test::simulation::db::entity::customer::Manager<DBCP>
where DBCP: DBProvider,

Source§

impl<DBCP> DCCommon<Entity, DBCP, true> for wb_cache::test::simulation::db::entity::inventory_record::Manager<DBCP>
where DBCP: DBProvider,

Source§

impl<DBCP> DCCommon<Entity, DBCP, true> for wb_cache::test::simulation::db::entity::order::Manager<DBCP>
where DBCP: DBProvider,

Source§

impl<DBCP> DCCommon<Entity, DBCP, true> for wb_cache::test::simulation::db::entity::product::Manager<DBCP>
where DBCP: DBProvider,

Source§

impl<DBCP> DCCommon<Entity, DBCP, true> for wb_cache::test::simulation::db::entity::session::Manager<DBCP>
where DBCP: DBProvider,