1use async_graphql::*;
2
3use cala_ledger::VelocityControlId;
4
5use crate::app::CalaApp;
6
7use super::{
8 convert::ToGlobalId,
9 primitives::*,
10 tx_template::{ParamDefinition, ParamDefinitionInput},
11 DbOp,
12};
13
14#[derive(SimpleObject, Clone)]
15pub struct VelocityLimit {
16 id: ID,
17 velocity_limit_id: UUID,
18 name: String,
19 description: String,
20 condition: Option<Expression>,
21 window: Vec<PartitionKey>,
22 currency: Option<CurrencyCode>,
23 params: Option<Vec<ParamDefinition>>,
24 limit: Limit,
25}
26
27#[derive(SimpleObject, Clone)]
28struct Limit {
29 timestamp_source: Option<Expression>,
30 balance: Vec<BalanceLimit>,
31}
32
33#[derive(SimpleObject, Clone)]
34struct BalanceLimit {
35 layer: Expression,
36 amount: Expression,
37 normal_balance_type: Expression,
38 start: Option<Expression>,
39 end: Option<Expression>,
40}
41
42#[derive(SimpleObject, Clone)]
43struct PartitionKey {
44 alias: String,
45 value: Expression,
46}
47
48#[derive(InputObject)]
49pub(super) struct VelocityLimitCreateInput {
50 pub velocity_limit_id: UUID,
51 pub name: String,
52 pub description: String,
53 pub window: Vec<PartitionKeyInput>,
54 pub condition: Option<Expression>,
55 pub limit: LimitInput,
56 pub currency: Option<CurrencyCode>,
57 pub params: Option<Vec<ParamDefinitionInput>>,
58}
59
60#[derive(InputObject)]
61pub(super) struct PartitionKeyInput {
62 pub alias: String,
63 pub value: Expression,
64}
65
66#[derive(InputObject)]
67pub(super) struct LimitInput {
68 pub timestamp_source: Option<Expression>,
69 pub balance: Vec<BalanceLimitInput>,
70}
71
72#[derive(InputObject)]
73pub(super) struct BalanceLimitInput {
74 #[graphql(default)]
75 pub limit_type: BalanceLimitType,
76 pub layer: Expression,
77 pub amount: Expression,
78 pub normal_balance_type: Expression,
79 pub start: Option<Expression>,
80 pub end: Option<Expression>,
81}
82
83#[derive(Enum, Default, Copy, Clone, Eq, PartialEq)]
84#[graphql(remote = "cala_ledger::velocity::BalanceLimitType")]
85pub(super) enum BalanceLimitType {
86 #[default]
87 Available,
88}
89
90#[derive(SimpleObject)]
91pub(super) struct VelocityLimitCreatePayload {
92 velocity_limit: VelocityLimit,
93}
94
95#[derive(SimpleObject, Clone)]
96#[graphql(complex)]
97pub struct VelocityControl {
98 id: ID,
99 velocity_control_id: UUID,
100 name: String,
101 description: String,
102 enforcement: VelocityEnforcement,
103 condition: Option<Expression>,
104}
105
106#[ComplexObject]
107impl VelocityControl {
108 async fn limits(&self, ctx: &Context<'_>) -> Result<Vec<VelocityLimit>> {
109 let app = ctx.data_unchecked::<CalaApp>();
110 let control_id = VelocityControlId::from(self.velocity_control_id);
111
112 let res = match ctx.data_opt::<DbOp>() {
113 Some(op) => {
114 let mut op = op.try_lock().expect("Lock held concurrently");
115 app.ledger()
116 .velocities()
117 .list_limits_for_control_in_op(&mut op, control_id)
118 .await?
119 }
120 None => {
121 app.ledger()
122 .velocities()
123 .list_limits_for_control(control_id)
124 .await?
125 }
126 };
127
128 let limits = res.into_iter().map(VelocityLimit::from).collect();
129 Ok(limits)
130 }
131}
132
133#[derive(SimpleObject, Clone)]
134struct VelocityEnforcement {
135 velocity_enforcement_action: VelocityEnforcementAction,
136}
137
138#[derive(InputObject)]
139pub(super) struct VelocityControlCreateInput {
140 pub velocity_control_id: UUID,
141 pub name: String,
142 pub description: String,
143 pub enforcement: VelocityEnforcementInput,
144 pub condition: Option<Expression>,
145}
146
147#[derive(InputObject)]
148pub(super) struct VelocityEnforcementInput {
149 #[graphql(default)]
150 pub velocity_enforcement_action: VelocityEnforcementAction,
151}
152
153#[derive(Enum, Default, Copy, Clone, Eq, PartialEq)]
154#[graphql(remote = "cala_ledger::velocity::VelocityEnforcementAction")]
155pub(super) enum VelocityEnforcementAction {
156 #[default]
157 Reject,
158}
159
160#[derive(SimpleObject)]
161pub(super) struct VelocityControlCreatePayload {
162 velocity_control: VelocityControl,
163}
164
165#[derive(InputObject)]
166pub(super) struct VelocityControlAttachInput {
167 pub velocity_control_id: UUID,
168 pub account_id: UUID,
169 pub params: JSON,
170}
171
172#[derive(SimpleObject)]
173pub(super) struct VelocityControlAttachPayload {
174 velocity_control: VelocityControl,
175}
176
177impl From<cala_ledger::velocity::VelocityControl> for VelocityControlAttachPayload {
178 fn from(entity: cala_ledger::velocity::VelocityControl) -> Self {
179 Self {
180 velocity_control: VelocityControl::from(entity),
181 }
182 }
183}
184
185impl ToGlobalId for cala_ledger::VelocityControlId {
186 fn to_global_id(&self) -> async_graphql::types::ID {
187 async_graphql::types::ID::from(format!("velocity_control:{}", self))
188 }
189}
190
191impl From<cala_ledger::velocity::VelocityControl> for VelocityControl {
192 fn from(velocity_control: cala_ledger::velocity::VelocityControl) -> Self {
193 let cala_ledger::velocity::VelocityControlValues {
194 id,
195 name,
196 description,
197 enforcement,
198 condition,
199 } = velocity_control.into_values();
200
201 let enforcement = VelocityEnforcement::from(enforcement);
202
203 Self {
204 id: id.to_global_id(),
205 velocity_control_id: UUID::from(id),
206 name,
207 description,
208 enforcement,
209 condition: condition.map(Expression::from),
210 }
211 }
212}
213
214impl From<cala_ledger::velocity::VelocityEnforcement> for VelocityEnforcement {
215 fn from(enforcement: cala_ledger::velocity::VelocityEnforcement) -> Self {
216 Self {
217 velocity_enforcement_action: enforcement.action.into(),
218 }
219 }
220}
221
222impl From<cala_ledger::velocity::VelocityControl> for VelocityControlCreatePayload {
223 fn from(entity: cala_ledger::velocity::VelocityControl) -> Self {
224 Self {
225 velocity_control: VelocityControl::from(entity),
226 }
227 }
228}
229
230#[derive(InputObject)]
231pub(super) struct VelocityControlAddLimitInput {
232 pub velocity_control_id: UUID,
233 pub velocity_limit_id: UUID,
234}
235
236#[derive(SimpleObject)]
237pub(super) struct VelocityControlAddLimitPayload {
238 velocity_control: VelocityControl,
239}
240
241impl From<cala_ledger::velocity::VelocityControl> for VelocityControlAddLimitPayload {
242 fn from(entity: cala_ledger::velocity::VelocityControl) -> Self {
243 Self {
244 velocity_control: VelocityControl::from(entity),
245 }
246 }
247}
248
249impl ToGlobalId for cala_ledger::VelocityLimitId {
250 fn to_global_id(&self) -> async_graphql::types::ID {
251 async_graphql::types::ID::from(format!("velocity_limit:{}", self))
252 }
253}
254
255impl From<cala_ledger::velocity::VelocityLimit> for VelocityLimit {
256 fn from(velocity_limit: cala_ledger::velocity::VelocityLimit) -> Self {
257 let cala_ledger::velocity::VelocityLimitValues {
258 id,
259 name,
260 description,
261 condition,
262 currency,
263 params,
264 limit,
265 window,
266 } = velocity_limit.into_values();
267
268 let params = params.map(|params| params.into_iter().map(ParamDefinition::from).collect());
269 let window = window.into_iter().map(PartitionKey::from).collect();
270
271 Self {
272 id: id.to_global_id(),
273 velocity_limit_id: UUID::from(id),
274 name,
275 description,
276 condition: condition.map(Expression::from),
277 currency: currency.map(CurrencyCode::from),
278 params,
279 window,
280 limit: Limit::from(limit),
281 }
282 }
283}
284
285impl From<cala_ledger::velocity::Limit> for Limit {
286 fn from(limit: cala_ledger::velocity::Limit) -> Self {
287 let balance = limit.balance.into_iter().map(BalanceLimit::from).collect();
288
289 Self {
290 timestamp_source: limit.timestamp_source.map(Expression::from),
291 balance,
292 }
293 }
294}
295
296impl From<cala_ledger::velocity::BalanceLimit> for BalanceLimit {
297 fn from(balance_limit: cala_ledger::velocity::BalanceLimit) -> Self {
298 Self {
299 layer: balance_limit.layer.into(),
300 amount: balance_limit.amount.into(),
301 normal_balance_type: balance_limit.enforcement_direction.into(),
302 start: balance_limit.start.map(Expression::from),
303 end: balance_limit.end.map(Expression::from),
304 }
305 }
306}
307
308impl From<cala_ledger::velocity::PartitionKey> for PartitionKey {
309 fn from(partition_key: cala_ledger::velocity::PartitionKey) -> Self {
310 Self {
311 alias: partition_key.alias,
312 value: Expression::from(partition_key.value),
313 }
314 }
315}
316
317impl From<cala_ledger::velocity::VelocityLimit> for VelocityLimitCreatePayload {
318 fn from(entity: cala_ledger::velocity::VelocityLimit) -> Self {
319 Self {
320 velocity_limit: VelocityLimit::from(entity),
321 }
322 }
323}