Caravela.Domain (Caravela v0.5.3)

Copy Markdown View Source

DSL entry point. use Caravela.Domain in a module to declare a domain:

defmodule MyApp.Domains.Library do
  use Caravela.Domain

  entity :authors do
    field :name, :string, required: true
    field :bio, :text
  end

  entity :books do
    field :title, :string, required: true, min_length: 3
    field :isbn, :string, format: ~r/^\d{13}$/
  end

  relation :authors, :books, type: :has_many

  on_create :books, fn changeset, _context ->
    Ecto.Changeset.validate_required(changeset, [:title])
  end

  can_create :books, fn context ->
    context.current_user.role in [:admin, :editor]
  end
end

After compilation the module exposes __caravela_domain__/0, returning the validated Caravela.Schema.Domain IR, plus __caravela_hook__/4 and __caravela_permission__ clauses for every declared hook and permission.

Summary

Functions

Authorize creation of an entity. Receives only the context and must return a boolean.

Authorize deletion of an entity. Same shape as can_update/2.

Filter a read query by authorization context. Must return an Ecto.Query.

Authorize updating an entity. Receives the loaded entity and the context. Must return a boolean.

Declare an entity (a table/schema) with a do block of fields.

Declare a field inside an entity block.

Declare a create-time hook for an entity. The hook receives the Ecto.Changeset and the caller's context map, and must return an Ecto.Changeset.

Declare a delete-time hook. The hook receives the loaded entity and the context, and must return :ok or {:error, reason}.

Declare an update-time hook. Same shape as on_create/2.

Declare a relation between two entities.

Declare the API version for this domain. Must match ~r/^v\d+$/.

Functions

can_create(entity, fun)

(macro)

Authorize creation of an entity. Receives only the context and must return a boolean.

can_create :books, fn context ->
  context.current_user.role in [:admin, :editor]
end

can_delete(entity, fun)

(macro)

Authorize deletion of an entity. Same shape as can_update/2.

can_read(entity, fun)

(macro)

Filter a read query by authorization context. Must return an Ecto.Query.

can_read :books, fn query, context ->
  case context.current_user.role do
    :admin -> query
    _ -> where(query, [b], b.published == true)
  end
end

can_update(entity, fun)

(macro)

Authorize updating an entity. Receives the loaded entity and the context. Must return a boolean.

can_update :books, fn book, context ->
  context.current_user.role == :admin or book.author_id == context.current_user.author_id
end

entity(name, list)

(macro)

Declare an entity (a table/schema) with a do block of fields.

entity :books do
  field :title, :string, required: true
end

field(name, type, opts \\ [])

(macro)

Declare a field inside an entity block.

field :title, :string, required: true, min_length: 3

on_create(entity, fun)

(macro)

Declare a create-time hook for an entity. The hook receives the Ecto.Changeset and the caller's context map, and must return an Ecto.Changeset.

on_create :books, fn changeset, _context ->
  Ecto.Changeset.validate_required(changeset, [:title])
end

on_delete(entity, fun)

(macro)

Declare a delete-time hook. The hook receives the loaded entity and the context, and must return :ok or {:error, reason}.

on_delete :authors, fn author, _context ->
  if author.published?, do: {:error, :has_published_books}, else: :ok
end

on_update(entity, fun)

(macro)

Declare an update-time hook. Same shape as on_create/2.

on_update :books, fn changeset, _context ->
  changeset
end

relation(from, to, opts)

(macro)

Declare a relation between two entities.

relation :authors, :books, type: :has_many
relation :books, :publishers, type: :belongs_to

version(v)

(macro)

Declare the API version for this domain. Must match ~r/^v\d+$/.

version "v1"

When set, all generated modules are namespaced under the version (MyApp.Library.V1.Book) and controller routes are prefixed with /api/v1/.