Repositories
ARO provides built-in in-memory repositories for storing and retrieving data.
Repositories are automatically created when you store data using the naming convention
<entity-repository> and support querying, updating, and observation.
Storing Data
Store entities into a repository using the Store action:
Create the <user: User> with {
name: "Alice",
email: "alice@example.com"
}.
Store the <user> into the <user-repository>.
The repository is automatically created on first use. Each stored entity
receives a unique id if not already present.
Retrieving Data
Get All Entities
Retrieve the <all-users> from the <user-repository>.
Query by Field
Retrieve the <user> from the <user-repository> where id = <userId>.
Retrieve the <admins> from the <user-repository> where role = "admin".
Get First or Last
Retrieve the <latest: last> from the <message-repository>.
Retrieve the <oldest: first> from the <message-repository>.
Updating Data
Update the <user-repository> where id = <userId> with {
status: "active",
lastLogin: <now>
}.
Deleting Data
Delete from the <user-repository> where id = <userId>.
Repository Observers
React to repository changes with observer feature sets. Observers are triggered whenever data is stored, updated, or deleted.
Observer Pattern
(Log User Changes: user-repository Observer) {
Extract the <action> from the <event: action>.
Extract the <entity> from the <event: entity>.
Log "User repository: " to the <console>.
Log <action> to the <console>.
Return an <OK: status> for the <observation>.
}
Conditional Observers with when Guard
Add a when clause to trigger observers only when a condition is met.
Use <repository-name: count> to access the repository size.
(* Only triggers when message count exceeds 100 *)
(Cleanup Messages: message-repository Observer) when <message-repository: count> > 100 {
Retrieve the <all-messages> from the <message-repository>.
Extract the <keep-messages: 0-49> from the <all-messages>.
Clear the <all> from the <message-repository>.
Store the <keep-messages> into the <message-repository>.
Return an <OK: status> for the <cleanup>.
}
The when guard is evaluated before the observer runs. If the condition
is false, the observer is silently skipped. This prevents infinite loops when the
observer modifies the same repository it observes.
The observer receives an event with:
| Property | Description |
|---|---|
action |
"stored", "updated", or "deleted" |
entity |
The affected entity |
repository |
Repository name |
Complete Example: User Management
api.aro
(createUser: User API) {
Extract the <body> from the <request: body>.
Create the <user: User> with {
name: <body: name>,
email: <body: email>,
createdAt: <now>
}.
Store the <user> into the <user-repository>.
Return a <Created: status> with <user>.
}
(listUsers: User API) {
Retrieve the <users> from the <user-repository>.
Return an <OK: status> with <users>.
}
(getUser: User API) {
Extract the <id> from the <pathParameters: id>.
Retrieve the <user> from the <user-repository> where id = <id>.
Return an <OK: status> with <user>.
}
(deleteUser: User API) {
Extract the <id> from the <pathParameters: id>.
Delete from the <user-repository> where id = <id>.
Return an <OK: status> for the <deletion>.
}
observers.aro
(Audit User Changes: user-repository Observer) {
Extract the <action> from the <event: action>.
Extract the <user> from the <event: entity>.
Create the <audit-entry> with {
action: <action>,
userId: <user: id>,
timestamp: <now>
}.
Store the <audit-entry> into the <audit-repository>.
Return an <OK: status> for the <audit>.
}
Important Notes
- In-memory storage - Data is lost on application restart
- Automatic IDs - UUIDs are generated for entities without an
id - Type safety - Define schemas in OpenAPI for validation
- Deduplication - Storing the same entity twice updates the existing one