use async_graphql::*;
use cala_ledger::VelocityControlId;
use crate::app::CalaApp;
use super::{
convert::ToGlobalId,
primitives::*,
tx_template::{ParamDefinition, ParamDefinitionInput},
DbOp,
};
#[derive(SimpleObject, Clone)]
pub struct VelocityLimit {
id: ID,
velocity_limit_id: UUID,
name: String,
description: String,
condition: Option<Expression>,
window: Vec<PartitionKey>,
currency: Option<CurrencyCode>,
params: Option<Vec<ParamDefinition>>,
limit: Limit,
}
#[derive(SimpleObject, Clone)]
struct Limit {
timestamp_source: Option<Expression>,
balance: Vec<BalanceLimit>,
}
#[derive(SimpleObject, Clone)]
struct BalanceLimit {
layer: Expression,
amount: Expression,
normal_balance_type: Expression,
start: Option<Expression>,
end: Option<Expression>,
}
#[derive(SimpleObject, Clone)]
struct PartitionKey {
alias: String,
value: Expression,
}
#[derive(InputObject)]
pub(super) struct VelocityLimitCreateInput {
pub velocity_limit_id: UUID,
pub name: String,
pub description: String,
pub window: Vec<PartitionKeyInput>,
pub condition: Option<Expression>,
pub limit: LimitInput,
pub currency: Option<CurrencyCode>,
pub params: Option<Vec<ParamDefinitionInput>>,
}
#[derive(InputObject)]
pub(super) struct PartitionKeyInput {
pub alias: String,
pub value: Expression,
}
#[derive(InputObject)]
pub(super) struct LimitInput {
pub timestamp_source: Option<Expression>,
pub balance: Vec<BalanceLimitInput>,
}
#[derive(InputObject)]
pub(super) struct BalanceLimitInput {
#[graphql(default)]
pub limit_type: BalanceLimitType,
pub layer: Expression,
pub amount: Expression,
pub normal_balance_type: Expression,
pub start: Option<Expression>,
pub end: Option<Expression>,
}
#[derive(Enum, Default, Copy, Clone, Eq, PartialEq)]
#[graphql(remote = "cala_ledger::velocity::BalanceLimitType")]
pub(super) enum BalanceLimitType {
#[default]
Available,
}
#[derive(SimpleObject)]
pub(super) struct VelocityLimitCreatePayload {
velocity_limit: VelocityLimit,
}
#[derive(SimpleObject, Clone)]
#[graphql(complex)]
pub struct VelocityControl {
id: ID,
velocity_control_id: UUID,
name: String,
description: String,
enforcement: VelocityEnforcement,
condition: Option<Expression>,
}
#[ComplexObject]
impl VelocityControl {
async fn limits(&self, ctx: &Context<'_>) -> Result<Vec<VelocityLimit>> {
let app = ctx.data_unchecked::<CalaApp>();
let control_id = VelocityControlId::from(self.velocity_control_id);
let res = match ctx.data_opt::<DbOp>() {
Some(op) => {
let mut op = op.try_lock().expect("Lock held concurrently");
app.ledger()
.velocities()
.list_limits_for_control_in_op(&mut op, control_id)
.await?
}
None => {
app.ledger()
.velocities()
.list_limits_for_control(control_id)
.await?
}
};
let limits = res.into_iter().map(VelocityLimit::from).collect();
Ok(limits)
}
}
#[derive(SimpleObject, Clone)]
struct VelocityEnforcement {
velocity_enforcement_action: VelocityEnforcementAction,
}
#[derive(InputObject)]
pub(super) struct VelocityControlCreateInput {
pub velocity_control_id: UUID,
pub name: String,
pub description: String,
pub enforcement: VelocityEnforcementInput,
pub condition: Option<Expression>,
}
#[derive(InputObject)]
pub(super) struct VelocityEnforcementInput {
#[graphql(default)]
pub velocity_enforcement_action: VelocityEnforcementAction,
}
#[derive(Enum, Default, Copy, Clone, Eq, PartialEq)]
#[graphql(remote = "cala_ledger::velocity::VelocityEnforcementAction")]
pub(super) enum VelocityEnforcementAction {
#[default]
Reject,
}
#[derive(SimpleObject)]
pub(super) struct VelocityControlCreatePayload {
velocity_control: VelocityControl,
}
#[derive(InputObject)]
pub(super) struct VelocityControlAttachInput {
pub velocity_control_id: UUID,
pub account_id: UUID,
pub params: JSON,
}
#[derive(SimpleObject)]
pub(super) struct VelocityControlAttachPayload {
velocity_control: VelocityControl,
}
impl From<cala_ledger::velocity::VelocityControl> for VelocityControlAttachPayload {
fn from(entity: cala_ledger::velocity::VelocityControl) -> Self {
Self {
velocity_control: VelocityControl::from(entity),
}
}
}
impl ToGlobalId for cala_ledger::VelocityControlId {
fn to_global_id(&self) -> async_graphql::types::ID {
async_graphql::types::ID::from(format!("velocity_control:{}", self))
}
}
impl From<cala_ledger::velocity::VelocityControl> for VelocityControl {
fn from(velocity_control: cala_ledger::velocity::VelocityControl) -> Self {
let cala_ledger::velocity::VelocityControlValues {
id,
name,
description,
enforcement,
condition,
} = velocity_control.into_values();
let enforcement = VelocityEnforcement::from(enforcement);
Self {
id: id.to_global_id(),
velocity_control_id: UUID::from(id),
name,
description,
enforcement,
condition: condition.map(Expression::from),
}
}
}
impl From<cala_ledger::velocity::VelocityEnforcement> for VelocityEnforcement {
fn from(enforcement: cala_ledger::velocity::VelocityEnforcement) -> Self {
Self {
velocity_enforcement_action: enforcement.action.into(),
}
}
}
impl From<cala_ledger::velocity::VelocityControl> for VelocityControlCreatePayload {
fn from(entity: cala_ledger::velocity::VelocityControl) -> Self {
Self {
velocity_control: VelocityControl::from(entity),
}
}
}
#[derive(InputObject)]
pub(super) struct VelocityControlAddLimitInput {
pub velocity_control_id: UUID,
pub velocity_limit_id: UUID,
}
#[derive(SimpleObject)]
pub(super) struct VelocityControlAddLimitPayload {
velocity_control: VelocityControl,
}
impl From<cala_ledger::velocity::VelocityControl> for VelocityControlAddLimitPayload {
fn from(entity: cala_ledger::velocity::VelocityControl) -> Self {
Self {
velocity_control: VelocityControl::from(entity),
}
}
}
impl ToGlobalId for cala_ledger::VelocityLimitId {
fn to_global_id(&self) -> async_graphql::types::ID {
async_graphql::types::ID::from(format!("velocity_limit:{}", self))
}
}
impl From<cala_ledger::velocity::VelocityLimit> for VelocityLimit {
fn from(velocity_limit: cala_ledger::velocity::VelocityLimit) -> Self {
let cala_ledger::velocity::VelocityLimitValues {
id,
name,
description,
condition,
currency,
params,
limit,
window,
} = velocity_limit.into_values();
let params = params.map(|params| params.into_iter().map(ParamDefinition::from).collect());
let window = window.into_iter().map(PartitionKey::from).collect();
Self {
id: id.to_global_id(),
velocity_limit_id: UUID::from(id),
name,
description,
condition: condition.map(Expression::from),
currency: currency.map(CurrencyCode::from),
params,
window,
limit: Limit::from(limit),
}
}
}
impl From<cala_ledger::velocity::Limit> for Limit {
fn from(limit: cala_ledger::velocity::Limit) -> Self {
let balance = limit.balance.into_iter().map(BalanceLimit::from).collect();
Self {
timestamp_source: limit.timestamp_source.map(Expression::from),
balance,
}
}
}
impl From<cala_ledger::velocity::BalanceLimit> for BalanceLimit {
fn from(balance_limit: cala_ledger::velocity::BalanceLimit) -> Self {
Self {
layer: balance_limit.layer.into(),
amount: balance_limit.amount.into(),
normal_balance_type: balance_limit.enforcement_direction.into(),
start: balance_limit.start.map(Expression::from),
end: balance_limit.end.map(Expression::from),
}
}
}
impl From<cala_ledger::velocity::PartitionKey> for PartitionKey {
fn from(partition_key: cala_ledger::velocity::PartitionKey) -> Self {
Self {
alias: partition_key.alias,
value: Expression::from(partition_key.value),
}
}
}
impl From<cala_ledger::velocity::VelocityLimit> for VelocityLimitCreatePayload {
fn from(entity: cala_ledger::velocity::VelocityLimit) -> Self {
Self {
velocity_limit: VelocityLimit::from(entity),
}
}
}