ContextKit - automatic CRUD operations in your context and more

ContextKit is a modular toolkit for building robust Phoenix/Ecto contexts with standardized CRUD operations. It helps reduce boilerplate code while providing powerful querying capabilities and built-in pagination support.

Features

  • :rocket: Automatic CRUD operation generation
  • :mag: Dynamic query building with extensive filtering options
  • :page_facing_up: Built-in pagination support
  • :wrench: Flexible and extensible design
  • :dart: Custom query options for complex filtering

Description

I always end up customising the generated context functions via mix phx.gen.... Typically I want to query records via the list_{resource} function, paginate records and more. With ContextKit I generate all of that.

Examples

Let’s say, we have a schema MyApp.Accounts.User. To get the auto-generated functions, you would need to add a small snippet to your context module:

defmodule MyApp.Accounts do
  use ContextKit.CRUD,
    repo: MyApp.Repo,
    schema: MyApp.Accounts.User,
    queries: __MODULE__
end

This generates some functions in your module, and you can do things like:

# List all users
Accounts.list_users()

# List with filters and pagination
{users, pagination} = Accounts.list_users(
  status: "active",
  paginate: [page: 1, per_page: 20]
)

# Get single user
user = Accounts.get_user(123)
user = Accounts.get_user!(123)  # Raises if not found

# Get one user by criteria
user = Accounts.one_user(email: "user@example.com")

# Create a new user
MyApp.Accounts.create_user(%{email: "new@example.com"})

# Update a user
MyApp.Accounts.update_user(user, %{email: "updated@example.com"})

# Get a changeset for updates
MyApp.Accounts.change_user(user, %{email: "changed@example.com"})

# Delete user
Accounts.delete_user(user)
Accounts.delete_user(email: "user@example.com")

All the fields in the schema can be queried on automatically. There are many operators for advanced queries.

Accounts.list_users(
  filters: [
    %{field: :email, op: :ilike, value: "@gmail.com"},
    %{field: :status, op: :in, value: ["active", "pending"]},
    %{field: :name, op: :like_or, value: ["john", "jane"]}
  ]
)

Additionally you can define any custom query:

defmodule MyApp.Accounts do
  def apply_query_option({:with_active_posts, true}, query) do
    query
    |> join(:inner, [u], p in assoc(u, :posts))
    |> where([_, p], p.status == "active")
  end
end

and then you can do: MyApp.Accounts.list_users(with_active_posts: true)

You can also define query functions in a different module. Then just pass it instead of queries: __MODULE__.

Links

8 Likes