Skip to content

Commit

Permalink
chore: check control / limit condition
Browse files Browse the repository at this point in the history
  • Loading branch information
bodymindarts committed Oct 2, 2024
1 parent f0e8ca4 commit 8c14a77
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 6 deletions.
16 changes: 16 additions & 0 deletions cala-cel-interpreter/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,22 @@ impl<'a> TryFrom<&'a CelValue> for &'a Decimal {
}
}

impl<'a> TryFrom<CelResult<'a>> for bool {
type Error = ResultCoercionError;

fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
if let CelValue::Bool(b) = val {
Ok(b)
} else {
Err(ResultCoercionError::BadCoreTypeCoercion(
format!("{expr:?}"),
CelType::from(&val),
CelType::Bool,
))
}
}
}

impl<'a> TryFrom<CelResult<'a>> for NaiveDate {
type Error = ResultCoercionError;

Expand Down
18 changes: 18 additions & 0 deletions cala-ledger-core-types/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,21 @@ pub struct EntryValues {
pub direction: DebitOrCredit,
pub description: Option<String>,
}

mod cel {
use cel_interpreter::{CelMap, CelValue};

impl From<&super::EntryValues> for CelValue {
fn from(entry: &super::EntryValues) -> Self {
let mut map = CelMap::new();
map.insert("id", entry.id);
map.insert("entry_type", entry.entry_type.clone());
map.insert("sequence", CelValue::UInt(entry.sequence as u64));
map.insert("layer", entry.layer);
map.insert("direction", entry.direction);
map.insert("units", entry.units);
map.insert("currency", entry.currency);
map.into()
}
}
}
25 changes: 25 additions & 0 deletions cala-ledger-core-types/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ impl<'a> TryFrom<CelResult<'a>> for DebitOrCredit {
}
}

impl Into<CelValue> for DebitOrCredit {
fn into(self) -> CelValue {
match self {
DebitOrCredit::Debit => "DEBIT".into(),
DebitOrCredit::Credit => "CREDIT".into(),
}
}
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, sqlx::Type)]
#[sqlx(type_name = "Status", rename_all = "snake_case")]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -108,6 +117,16 @@ impl Default for Layer {
}
}

impl Into<CelValue> for Layer {
fn into(self) -> CelValue {
match self {
Layer::Settled => "SETTLED".into(),
Layer::Pending => "PENDING".into(),
Layer::Encumbrance => "ENCUMBRANCE".into(),
}
}
}

#[derive(Debug, Clone, Copy, Eq, Serialize, Deserialize)]
#[serde(try_from = "String")]
#[serde(into = "&str")]
Expand All @@ -131,6 +150,12 @@ impl std::fmt::Display for Currency {
}
}

impl Into<CelValue> for Currency {
fn into(self) -> CelValue {
self.code().into()
}
}

impl std::hash::Hash for Currency {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.code().hash(state);
Expand Down
19 changes: 19 additions & 0 deletions cala-ledger-core-types/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,22 @@ pub struct TransactionValues {
pub description: Option<String>,
pub metadata: Option<serde_json::Value>,
}

mod cel {
use cel_interpreter::{CelMap, CelValue};

impl From<&super::TransactionValues> for CelValue {
fn from(tx: &super::TransactionValues) -> Self {
let mut map = CelMap::new();
map.insert("id", tx.id);
map.insert("journal_id", tx.journal_id);
map.insert("tx_template_id", tx.tx_template_id);
map.insert("effective", tx.effective);
map.insert("correlation_id", tx.correlation_id.clone());
if let Some(metadata) = &tx.metadata {
map.insert("metadata", metadata.clone());
}
map.into()
}
}
}
2 changes: 1 addition & 1 deletion cala-ledger/src/cel_context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cel_interpreter::CelContext;
pub use cel_interpreter::CelContext;

pub(crate) fn initialize() -> CelContext {
let mut ctx = CelContext::new();
Expand Down
39 changes: 39 additions & 0 deletions cala-ledger/src/velocity/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::collections::HashMap;

use cala_types::{entry::EntryValues, transaction::TransactionValues};
use cel_interpreter::{CelMap, CelValue};

use crate::{cel_context::*, primitives::EntryId};

pub struct EvalContext {
transaction: CelValue,
entry_values: HashMap<EntryId, CelValue>,
}

impl EvalContext {
pub fn new(transaction: &TransactionValues) -> Self {
Self {
transaction: transaction.into(),
entry_values: HashMap::new(),
}
}

pub fn control_context(&mut self, entry: &EntryValues) -> CelContext {
let entry = self
.entry_values
.entry(entry.id)
.or_insert_with(|| entry.into());

let mut vars = CelMap::new();
vars.insert("transaction", self.transaction.clone());
vars.insert("entry", entry.clone());

let mut context = CelMap::new();
context.insert("vars", vars);

let mut ctx = initialize();
ctx.add_variable("context", context);

ctx
}
}
38 changes: 34 additions & 4 deletions cala-ledger/src/velocity/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
mod account_control;
mod context;
mod control;
pub mod error;
mod limit;

use cala_types::{entry::EntryValues, transaction::TransactionValues};
use chrono::{DateTime, Utc};
use sqlx::PgPool;

use cala_types::{entry::EntryValues, transaction::TransactionValues};

pub use crate::param::Params;
use crate::{atomic_operation::*, outbox::*, primitives::AccountId};

Expand Down Expand Up @@ -127,16 +129,44 @@ impl Velocities {
op: &mut AtomicOperation<'_>,
created_at: DateTime<Utc>,
transaction: &TransactionValues,
entries: &Vec<EntryValues>,
entries: &[EntryValues],
account_ids: &[AccountId],
) -> Result<(), VelocityError> {
let controls = self
.account_controls
.find_for_enforcement(op, account_ids)
.await?;

for control in controls {
//
let empty = Vec::new();

let mut context = context::EvalContext::new(transaction);

for entry in entries {
for control in controls.get(&entry.account_id).unwrap_or(&empty) {
let ctx = context.control_context(entry);
let control_active = if let Some(condition) = &control.condition {
let control_active: bool = condition.try_evaluate(&ctx)?;
control_active
} else {
true
};
if control_active {
for limit in &control.velocity_limits {
if let Some(currenty) = &limit.currency {

Check warning on line 155 in cala-ledger/src/velocity/mod.rs

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"currenty" should be "currently".
if currenty != &entry.currency {

Check warning on line 156 in cala-ledger/src/velocity/mod.rs

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"currenty" should be "currently".
continue;
}
}

let limit_active = if let Some(condition) = &limit.condition {
let limit_active: bool = condition.try_evaluate(&ctx)?;
limit_active
} else {
true
};
}
}
}
}
Ok(())
}
Expand Down
4 changes: 3 additions & 1 deletion cala-ledger/tests/velocity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ async fn create_control() -> anyhow::Result<()> {
.add_limit_to_control(control.id(), deposit_limit.id())
.await?;

let (one, _) = helpers::test_accounts();
let (one, two) = helpers::test_accounts();
let one = cala.accounts().create(one).await.unwrap();
let _ = cala.accounts().create(two).await.unwrap();

let mut params = Params::new();
params.insert("withdrawal_limit", Decimal::from(100));
params.insert("deposit_limit", Decimal::from(100));
Expand Down

0 comments on commit 8c14a77

Please sign in to comment.