OCL Queries¶
OCL (Object Constraint Language) is a powerful query language for navigating and filtering objects in Bold. It's based on the OMG standard and provides a declarative way to express complex queries.
Basic Syntax¶
Important naming convention: In OCL, uppercase names like Customer refer to classes (metatypes), while lowercase names like orders refer to properties/associations on the current object. Customer.allInstances gets all Customer objects, while self.orders navigates from the current object to its orders.
Getting All Instances¶
Navigating Associations¶
Filtering with Select¶
Checking Existence¶
Customer.allInstances->select(orders->notEmpty)
Customer.allInstances->exists(totalPurchases > 10000)
Common Operations¶
Collection Operations¶
| Operation | Type | Description | Example |
|---|---|---|---|
->select(expr) |
Collection | Filter elements | orders->select(total > 100) |
->reject(expr) |
Collection | Exclude elements | orders->reject(cancelled) |
->collect(expr) |
Collection | Transform elements | orders->collect(total) |
->exists(expr) |
Boolean | Any match? | orders->exists(total > 1000) |
->forAll(expr) |
Boolean | All match? | orders->forAll(paid) |
->isEmpty |
Boolean | Collection empty? | orders->isEmpty |
->notEmpty |
Boolean | Collection has items? | orders->notEmpty |
->size |
Integer | Count elements | orders->size |
->first |
Element | First element | orders->first |
->last |
Element | Last element | orders->last |
->at(n) |
Element | Element at index | orders->at(0) |
->includes(x) |
Boolean | Contains element? | orders->includes(anOrder) |
Aggregation¶
orders->collect(total)->sum // Sum of all totals
orders->collect(total)->avg // Average
orders->collect(total)->max // Maximum
orders->collect(total)->min // Minimum
Sorting¶
Type Operations¶
Class Hierarchy Example¶
classDiagram
Customer <|-- PremiumCustomer
Customer <|-- RegularCustomer
Customer : +name
PremiumCustomer : +discountRate
RegularCustomer : +loyaltyPoints
Type Checking Operations¶
self.oclIsKindOf(Customer) // True for Customer, PremiumCustomer, RegularCustomer
self.oclIsTypeOf(Customer) // True only for exact Customer type
self.oclAsType(PremiumCustomer) // Cast to PremiumCustomer type
Using OCL in Delphi¶
Evaluate Expression¶
var
Result: TBoldElement;
Customers: TBoldObjectList;
begin
Result := BoldSystem.EvaluateExpressionAsNewElement(
'Customer.allInstances->select(orders->size > 5)',
nil // context object (self)
);
Customers := Result as TBoldObjectList;
end;
With Context Object¶
var
Customer: TCustomer;
OrderCount: Integer;
begin
// 'self' refers to Customer
OrderCount := BoldSystem.EvaluateExpressionAsInteger(
'self.orders->size',
Customer
);
end;
In Bold Handles¶
// TBoldListHandle - for lists of objects
BoldListHandle1.Expression := 'Customer.allInstances->select(active)';
// TBoldExpressionHandle - for single values
BoldExpressionHandle1.Expression := 'self.orders->collect(total)->sum';
See TBoldListHandle and TBoldExpressionHandle for more details.
Advanced Examples¶
Complex Filtering¶
// Customers with at least one order over $1000 this year
Customer.allInstances->select(
orders->exists(
(total > 1000) and
(orderDate.year = 2024)
)
)
Note: Customer (uppercase) refers to the class/metatype, while orders (lowercase) is a navigation property on the current object. In OCL, Customer.allInstances accesses all instances of the Customer class, whereas self.orders navigates from the current object to its related orders.
Nested Navigation¶
// All products ordered by premium customers
Customer.allInstances
->select(oclIsKindOf(PremiumCustomer))
->collect(orders)
->collect(orderLines)
->collect(product)
->asSet