Arithmetic Operations
Arithmetic operations allow you to add or subtract values from numeric properties using values from events. Unlike counters that always change by 1, arithmetic operations use variable amounts.
The add operation increases a property by a specified amount:
add {Property} by {expression}Example
Section titled “Example”from PaymentReceived add Balance by amount LastPayment = $eventContext.occurredSubtract
Section titled “Subtract”The subtract operation decreases a property by a specified amount:
subtract {Property} by {expression}Example
Section titled “Example”from WithdrawalMade subtract Balance by amount LastWithdrawal = $eventContext.occurredExpression Values
Section titled “Expression Values”The expression after by can be:
- Event property:
amount,value,cost.total - Literal:
100,10.50 - Template:
`${baseAmount}`
Multiple Operations
Section titled “Multiple Operations”Combine multiple operations in one event:
from OrderPlaced add TotalRevenue by total add OrderCount by 1 increment TotalOrdersExamples
Section titled “Examples”Account Balance
Section titled “Account Balance”projection Account => AccountReadModel from AccountOpened AccountNumber = accountNumber Balance = initialBalance
from DepositMade add Balance by amount LastDeposit = $eventContext.occurred
from WithdrawalMade subtract Balance by amount LastWithdrawal = $eventContext.occurred
from InterestApplied add Balance by interestAmountLoyalty Points
Section titled “Loyalty Points”projection Customer => CustomerReadModel from CustomerRegistered Name = name Points = 0
from PurchaseMade add Points by pointsEarned
from PointsRedeemed subtract Points by pointsUsed LastRedemption = $eventContext.occurredInventory with Variable Quantities
Section titled “Inventory with Variable Quantities”projection Product => ProductReadModel from ProductCreated Name = name StockLevel = initialStock
from StockAdded add StockLevel by quantity LastRestocked = $eventContext.occurred
from StockSold subtract StockLevel by quantity
from StockAdjusted add StockLevel by adjustmentAmountBudget Tracking
Section titled “Budget Tracking”projection Budget => BudgetReadModel from BudgetCreated Category = category AllocatedAmount = amount RemainingAmount = amount
from ExpenseRecorded subtract RemainingAmount by cost add TotalSpent by cost
from BudgetIncreased add AllocatedAmount by additionalAmount add RemainingAmount by additionalAmountOrder Totals
Section titled “Order Totals”projection Order => OrderReadModel from OrderPlaced OrderNumber = orderNumber Subtotal = 0 Tax = 0 Total = 0
from LineItemAdded add Subtotal by itemTotal add Total by itemTotal
from TaxCalculated add Tax by taxAmount add Total by taxAmount
from DiscountApplied subtract Subtotal by discountAmount subtract Total by discountAmountGaming Score
Section titled “Gaming Score”projection PlayerScore => PlayerScoreReadModel from PlayerJoined PlayerName = name Score = 0
from PointsEarned add Score by points LastScored = $eventContext.occurred
from PointsLost subtract Score by points
from BonusAwarded add Score by bonusPoints add BonusTotal by bonusPointsNested Properties
Section titled “Nested Properties”You can use nested properties from events:
from TransactionProcessed add Balance by transaction.amount add TotalTransactions by 1With Counters
Section titled “With Counters”Combine arithmetic with counters for comprehensive tracking:
from SaleCompleted add TotalRevenue by saleAmount add TaxCollected by taxAmount increment SalesCount count CompletedTransactionsProperty Requirements
Section titled “Property Requirements”The target property must be a numeric type:
intlongdecimaldoublefloat
The expression value must be compatible with the target type.
Error Handling
Section titled “Error Handling”Chronicle handles arithmetic operations safely:
- Type mismatches result in compilation errors
- Ensure the event property used exists and is numeric
- Consider domain rules (e.g., balance can’t go negative) in your application logic
Best Practices
Section titled “Best Practices”- Initialize Values: Ensure numeric properties have initial values
- Use Appropriate Types: Use
decimalfor money,intfor counts - Track Both Directions: Pair
addwith correspondingsubtractfor bidirectional operations - Audit Trail: Combine with timestamps and counters for complete tracking
- Validation: Consider adding validation in your domain to prevent invalid states
- Precision: Be aware of floating-point precision issues with
doubleandfloat
Difference from Counters
Section titled “Difference from Counters”| Operation | Amount | Use Case |
|---|---|---|
count / increment / decrement | Always ±1 | Event counting, simple state changes |
add / subtract | Variable from event | Balances, quantities, scores |
See Also
Section titled “See Also”- Counters - Fixed increment/decrement operations
- Property Mapping - Setting properties to specific values
- Expressions - Understanding expression syntax