CRUD with State Machines

A complete create/read/update/delete lifecycle using Grove's action-event model. Unlike traditional CRUD, every change produces immutable events, and state machines enforce valid transitions.

Prerequisites: 5-Minute Tutorial. What you'll learn: How to implement full CRUD operations with actions, events, and state machines.

The Pattern

In Grove, CRUD maps to:

Complete Example

module article

enum ArticleStatus { draft, published, archived }

record {
  kind "post"
  title: String
  body: String
  status: ArticleStatus = ArticleStatus.draft
  author_id: Id

  invariant title_not_blank {
    record.title != ""
  }

  state status {
    ArticleStatus.draft -> ArticleStatus.published on published
    ArticleStatus.published -> ArticleStatus.archived on archived
    ArticleStatus.archived -> ArticleStatus.draft on restored
  }
}

// Events
event created {
  title: String
  body: String
  author_id: Id
}

event title_updated {
  title: String
}

event body_updated {
  body: String
}

event published {
  status: ArticleStatus = ArticleStatus.published
}

event archived {
  status: ArticleStatus = ArticleStatus.archived
}

event restored {
  status: ArticleStatus = ArticleStatus.draft
}

@delete
event deleted {}

// Validators
validate title_not_blank {
  params.title != ""
}

// Actions
@create
action create {
  title: String
  body: String
  author_id: Id
  validate title_not_blank
  apply {
    emit created {
      title: params.title
      body: params.body
      author_id: params.author_id
    }
  }
}

action update_title {
  title: String
  validate title_not_blank
  apply {
    emit title_updated { title: params.title }
  }
}

action update_body {
  body: String
  apply {
    emit body_updated { body: params.body }
  }
}

action publish {
  apply {
    emit published {}
  }
}

action archive {
  apply {
    emit archived {}
  }
}

action restore {
  apply {
    emit restored {}
  }
}

action delete {
  apply {
    emit deleted {}
  }
}

Key Takeaways

See Also