Crudry v2.4.0 Crudry.Context View Source

Generates CRUD functions to DRY Phoenix Contexts.

  • Assumes Ecto.Repo is being used as the repository.

  • Uses the Ecto Schema source name to generate the pluralized name for the functions, and the module name to generate the singular name.

    This follows the same pattern as the Mix.Tasks.Phx.Gen.Context, so it should be straightforward to replace Phoenix's auto-generated functions with Crudry.

Usage

To generate CRUD functions for a given schema, simply do

defmodule MyApp.MyContext do
  alias MyApp.Repo
  alias MyApp.MySchema
  require Crudry.Context

  Crudry.Context.generate_functions MySchema
end

And the context will have all these functions available:

defmodule MyApp.MyContext do
  alias MyApp.Repo
  alias MyApp.MySchema
  require Crudry.Context

  ## Get functions

  def get_my_schema(id) do
    Repo.get(MySchema, id)
  end

  def get_my_schema!(id) do
    Repo.get!(MySchema, id)
  end

  def get_my_schema_with_assocs(id, assocs) do
    MySchema
    |> Repo.get(id)
    |> Repo.preload(assocs)
  end

  def get_my_schema_with_assocs!(id, assocs) do
    MySchema
    |> Repo.get!(id)
    |> Repo.preload(assocs)
  end

  def get_my_schema_by(clauses) do
    Repo.get_by(MySchema, clauses)
  end

  def get_my_schema_by!(clauses) do
    Repo.get_by!(MySchema, clauses)
  end

  def get_my_schema_by_with_assocs(clauses, assocs) do
    MySchema
    |> Repo.get_by(clauses)
    |> Repo.preload(assocs)
  end

  def get_my_schema_by_with_assocs!(clauses, assocs) do
    MySchema
    |> Repo.get_by!(clauses)
    |> Repo.preload(assocs)
  end

  ## List functions

  def list_my_schemas() do
    Repo.all(MySchema)
  end

  def list_my_schemas(opts) do
    MySchema
    |> Crudry.Query.list(opts)
    |> Repo.all()
  end

  def list_my_schemas_with_assocs(assocs) do
    MySchema
    |> Repo.all()
    |> Repo.preload(assocs)
  end

  def list_my_schemas_with_assocs(assocs, opts) do
    MySchema
    |> Crudry.Query.list(opts)
    |> Repo.all()
    |> Repo.preload(assocs)
  end

  def filter_my_schemas(filters) do
    MySchema
    |> Crudry.Query.filter(filters)
    |> Repo.all()
  end

  def search_my_schemas(search_term) do
    module_fields = MySchema.__schema__(:fields)

    MySchema
    |> Crudry.Query.search(search_term, module_fields)
    |> Repo.all()
  end

  def count_my_schemas(field \\ :id) do
    Repo.aggregate(MySchema, :count, field)
  end

  ## Create functions

  def create_my_schema(attrs) do
    %MySchema{}
    |> MySchema.changeset(attrs)
    |> Repo.insert()
  end

  def create_my_schema!(attrs) do
    %MySchema{}
    |> MySchema.changeset(attrs)
    |> Repo.insert!()
  end

  ## Update functions

  def update_my_schema(%MySchema{} = my_schema, attrs) do
    my_schema
    |> MySchema.changeset(attrs)
    |> Repo.update()
  end

  def update_my_schema!(%MySchema{} = my_schema, attrs) do
    my_schema
    |> MySchema.changeset(attrs)
    |> Repo.update!()
  end

  def update_my_schema_with_assocs(%MySchema{} = my_schema, attrs, assocs) do
    my_schema
    |> Repo.preload(assocs)
    |> MySchema.changeset(attrs)
    |> Repo.update()
  end

  def update_my_schema_with_assocs!(%MySchema{} = my_schema, attrs, assocs) do
    my_schema
    |> Repo.preload(assocs)
    |> MySchema.changeset(attrs)
    |> Repo.update!()
  end

  ## Delete functions

  def delete_my_schema(%MySchema{} = my_schema) do
    my_schema
    |> Ecto.Changeset.change()
    |> check_assocs([])
    |> Repo.delete()
  end

  def delete_my_schema!(%MySchema{} = my_schema) do
    my_schema
    |> Ecto.Changeset.change()
    |> check_assocs([])
    |> Repo.delete!()
  end

  # Function to check no_assoc_constraints, always generated.
  defp check_assocs(changeset, nil), do: changeset
  defp check_assocs(changeset, constraints) do
    Enum.reduce(constraints, changeset, fn i, acc -> Ecto.Changeset.no_assoc_constraint(acc, i) end)
  end
end

Link to this section Summary

Functions

Sets default options for the context.

Generates CRUD functions for the schema_module.

Link to this section Functions

Sets default options for the context.

Options

  • :create - the name of the changeset function used in the create function. Defaults to :changeset.

  • :update - the name of the changeset function used in the update function. Defaults to :changeset.

  • :only - list of functions to be generated. If not empty, functions not specified in this list are not generated. Defaults to [].

  • :except - list of functions to not be generated. If not empty, only functions not specified in this list will be generated. Defaults to [].

    The accepted values for :only and :except are: [:get, :list, :count, :search, :filter, :create, :update, :delete].

Examples

iex> Crudry.Context.default create: :create_changeset, update: :update_changeset
:ok

iex> Crudry.Context.default only: [:create, :list]
:ok

iex> Crudry.Context.default except: [:get!, :list, :delete]
:ok
Link to this macro

generate_functions(schema_module, opts \\ [])

View Source (macro)

Generates CRUD functions for the schema_module.

Custom options can be given. To see the available options, refer to the documenation of Crudry.Context.default/1. There is also one extra option that cannot be set by default:

  • check_constraints_on_delete - list of associations that must be empty to allow deletion. Ecto.Changeset.no_assoc_constraint will be called for each association before deleting. Defaults to [].

Examples

Suppose we want to implement basic CRUD functionality for a User schema, exposed through an Accounts context:

defmodule MyApp.Accounts do
  alias MyApp.Repo
  require Crudry.Context

  # Assuming Accounts.User implements a `changeset/2` function, used both to create and update a user.
  Crudry.Context.generate_functions Accounts.User
end

Now, suppose the changeset for create and update are different, and we want to delete the record only if the association has_many :assocs is empty:

defmodule MyApp.MyContext do
  alias MyApp.Repo
  alias MyApp.MySchema
  require Crudry.Context

  Crudry.Context.generate_functions MySchema,
    create: :create_changeset,
    update: :update_changeset,
    check_constraints_on_delete: [:assocs]
end