Your First Relationship
Continuing the concert app: a relationship is a directed edge between entity types — stored in a dedicated relationship store. Here, a user follows an artist.
Project: Concert app from causet init. Open relationships/follow.relationships.causet.
Prerequisite: Your First State — user and artist entities. The follow events from Your First Event drive projections and the ledger.
Declare the relationship
# relationships/follow.relationships.causet
relationships:
artist_followers:
from: user
to: artist
cardinality: many_to_many
unique: true
emit_events:
created: ARTIST_FOLLOWED
removed: ARTIST_UNFOLLOWED| Field | Purpose |
|---|---|
from / to | Entity types at each end |
cardinality | many_to_many — users follow many artists |
unique | Duplicate follows are no-ops (idempotent retries) |
emit_events | Engine emits follow/unfollow events when edges change |
When emit_events is set, the engine emits ARTIST_FOLLOWED / ARTIST_UNFOLLOWED — the same events your projections already consume.
Create edges from an intent
Use relationship_create in core rules (optional enhancement to FOLLOW_ARTIST):
# actions/follow.actions.causet (core rule addition)
core:
rules:
- name: increment_following
when: {}
then:
- op: add
path: /following_count
value: 1
- op: relationship_create
relationship: artist_followers
from_id: intent.user_id
to_id: intent.artist_idYou can keep the explicit emit in side_effects or rely on emit_events on the relationship — not both for the same edge unless you need extra payload fields on the event.
Submit via CLI
Same command as Your First Intent:
causet intent FOLLOW_ARTIST \
--fork main \
--stream user_stream \
--entity user-1 \
--payload '{"user_id":"user-1","artist_id":"artist-pearl-jam"}'The edge lands in the relationship store; the event feeds user_following; the query returns shows for followed artists.
When to use relationships vs projections alone
| Relationships | Projections only |
|---|---|
| Graph semantics, uniqueness, inverse traversal | Event-derived read tables |
| Engine-managed edge lifecycle | Anything queryable from events |
In this app, the relationship and user_following projection work together — the relationship enforces graph rules; the projection powers the join query.
Concert app so far
concert-app/
app.causet
states/ user.state.causet, artist.state.causet
events/ follow.events.causet, show.events.causet
actions/ follow.actions.causet, show.actions.causet
projections/ follow.projections.causet
queries/ follow.queries.causet
relationships/ follow.relationships.causetNext steps
- Your First Workflow — multi-step show publishing with sagas and
submit - Complete Concert App — compile, deploy, and run everything
- Relationships — full DSL reference