pub trait DCCommon<T, PARENT, const IMMUTABLE: bool = false>:
DataController<CacheUpdate = CacheUpdates<T::ActiveModel>, Error = SimErrorAny>
+ Send
+ Debugwhere
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
| Parameter | Description |
|---|---|
T | The SeaORM Entity type that this data controller is responsible for. It must implement the EntityTrait trait. |
PARENT | The data controller implementing DCCommon is expected to be a child of an entity that implements the DBProvider trait, thereby providing a database connection. |
IMMUTABLE | Setting 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§
Sourcefn delete_many_condition(
dm: DeleteMany<T>,
keys: Vec<Self::Key>,
) -> DeleteMany<T>
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§
Sourcefn db_provider(&self) -> <Self as Child>::RcParent
fn db_provider(&self) -> <Self as Child>::RcParent
Where we get our database connection from.
Sourcefn 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 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.
Sourcefn 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>>
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>>
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.
Sourcefn 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_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.
Sourcefn 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,
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.