|
@@ -0,0 +1,149 @@
|
|
|
|
+use super::CacheStorage;
|
|
|
|
+use crate::{
|
|
|
|
+ changelog::Changelog,
|
|
|
|
+ storage::{Batch, Error, Storage},
|
|
|
|
+ transaction::from_db,
|
|
|
|
+ AccountId, Amount, Payment, PaymentId, Status, Transaction, TransactionId,
|
|
|
|
+};
|
|
|
|
+use serde::{de::DeserializeOwned, Serialize};
|
|
|
|
+use std::{collections::HashMap, marker::PhantomData};
|
|
|
|
+
|
|
|
|
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
+pub enum Ids {
|
|
|
|
+ Transaction(TransactionId),
|
|
|
|
+ Payment(PaymentId),
|
|
|
|
+ Account(AccountId),
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub struct CacheBatch<'a, S>
|
|
|
|
+where
|
|
|
|
+ S: Storage<'a>,
|
|
|
|
+{
|
|
|
|
+ inner: S::Batch,
|
|
|
|
+ payments: CacheStorage<PaymentId, Payment>,
|
|
|
|
+ balances: CacheStorage<AccountId, Vec<Amount>>,
|
|
|
|
+ transactions: CacheStorage<TransactionId, from_db::Transaction>,
|
|
|
|
+ to_invalidate: HashMap<Ids, ()>,
|
|
|
|
+ _phantom: PhantomData<&'a ()>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'a, S> CacheBatch<'a, S>
|
|
|
|
+where
|
|
|
|
+ S: Storage<'a> + Sync + Send,
|
|
|
|
+{
|
|
|
|
+ pub fn new(
|
|
|
|
+ batch: S::Batch,
|
|
|
|
+ payments: CacheStorage<PaymentId, Payment>,
|
|
|
|
+ balances: CacheStorage<AccountId, Vec<Amount>>,
|
|
|
|
+ transactions: CacheStorage<TransactionId, from_db::Transaction>,
|
|
|
|
+ ) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ inner: batch,
|
|
|
|
+ payments,
|
|
|
|
+ balances,
|
|
|
|
+ transactions,
|
|
|
|
+ to_invalidate: HashMap::new(),
|
|
|
|
+ _phantom: PhantomData,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[async_trait::async_trait]
|
|
|
|
+impl<'a, S> Batch<'a> for CacheBatch<'a, S>
|
|
|
|
+where
|
|
|
|
+ S: Storage<'a> + Sync + Send,
|
|
|
|
+{
|
|
|
|
+ async fn commit(self) -> Result<(), Error> {
|
|
|
|
+ let mut payments = self.payments.write().await;
|
|
|
|
+ let mut balances = self.balances.write().await;
|
|
|
|
+ let mut transactions = self.transactions.write().await;
|
|
|
|
+
|
|
|
|
+ self.inner.commit().await?;
|
|
|
|
+
|
|
|
|
+ for (id, _) in self.to_invalidate {
|
|
|
|
+ match id {
|
|
|
|
+ Ids::Transaction(id) => {
|
|
|
|
+ transactions.remove(&id);
|
|
|
|
+ }
|
|
|
|
+ Ids::Payment(id) => {
|
|
|
|
+ payments.remove(&id);
|
|
|
|
+ }
|
|
|
|
+ Ids::Account(id) => {
|
|
|
|
+ balances.remove(&id);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn rollback(self) -> Result<(), Error> {
|
|
|
|
+ self.inner.rollback().await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn store_changelogs<T: DeserializeOwned + Serialize + Send + Sync>(
|
|
|
|
+ &mut self,
|
|
|
|
+ changelog: &[Changelog<T>],
|
|
|
|
+ ) -> Result<(), Error> {
|
|
|
|
+ self.inner.store_changelogs(changelog).await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn update_payment(
|
|
|
|
+ &mut self,
|
|
|
|
+ payment_id: &PaymentId,
|
|
|
|
+ spent_by: &TransactionId,
|
|
|
|
+ spent_status: Status,
|
|
|
|
+ ) -> Result<(), Error> {
|
|
|
|
+ self.to_invalidate
|
|
|
|
+ .insert(Ids::Payment(payment_id.clone()), ());
|
|
|
|
+ self.to_invalidate
|
|
|
|
+ .insert(Ids::Transaction(spent_by.clone()), ());
|
|
|
|
+ self.inner
|
|
|
|
+ .update_payment(payment_id, spent_by, spent_status)
|
|
|
|
+ .await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn get_payment_status(
|
|
|
|
+ &mut self,
|
|
|
|
+ transaction_id: &TransactionId,
|
|
|
|
+ ) -> Result<Option<Status>, Error> {
|
|
|
|
+ self.to_invalidate
|
|
|
|
+ .insert(Ids::Transaction(transaction_id.clone()), ());
|
|
|
|
+ self.inner.get_payment_status(transaction_id).await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn store_new_payment(&mut self, payment: &Payment) -> Result<(), Error> {
|
|
|
|
+ self.to_invalidate
|
|
|
|
+ .insert(Ids::Payment(payment.id.clone()), ());
|
|
|
|
+ self.inner.store_new_payment(payment).await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn store_transaction(&mut self, transaction: &Transaction) -> Result<(), Error> {
|
|
|
|
+ self.to_invalidate
|
|
|
|
+ .insert(Ids::Transaction(transaction.id().clone()), ());
|
|
|
|
+ self.inner.store_transaction(transaction).await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn tag_transaction(
|
|
|
|
+ &mut self,
|
|
|
|
+ transaction: &Transaction,
|
|
|
|
+ tags: &[String],
|
|
|
|
+ ) -> Result<(), Error> {
|
|
|
|
+ self.to_invalidate
|
|
|
|
+ .insert(Ids::Transaction(transaction.id().clone()), ());
|
|
|
|
+ self.inner.tag_transaction(transaction, tags).await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn relate_account_to_transaction(
|
|
|
|
+ &mut self,
|
|
|
|
+ transaction: &Transaction,
|
|
|
|
+ account: &AccountId,
|
|
|
|
+ ) -> Result<(), Error> {
|
|
|
|
+ self.to_invalidate
|
|
|
|
+ .insert(Ids::Transaction(transaction.id().clone()), ());
|
|
|
|
+ self.to_invalidate.insert(Ids::Account(account.clone()), ());
|
|
|
|
+ self.inner
|
|
|
|
+ .relate_account_to_transaction(transaction, account)
|
|
|
|
+ .await
|
|
|
|
+ }
|
|
|
|
+}
|