ContextKit.CRUD (ContextKit v0.5.0)

View Source

The ContextKit.CRUD module provides a convenient way to generate standard CRUD (Create, Read, Update, Delete) operations for your Ecto schemas. It reduces boilerplate code by automatically generating commonly used database interaction functions.

Setup

Add the following to your context module:

defmodule MyApp.Blog do
  use ContextKit.CRUD,
    repo: MyApp.Repo,
    schema: MyApp.Blog.Comment,
    queries: MyApp.Blog.CommentQueries,
    except: [:delete],                    # Optional: exclude specific operations
    plural_resource_name: "comments"      # Optional: customize plural name
end

Required Options

  • :repo - The Ecto repository module to use for database operations
  • :schema - The Ecto schema module that defines your resource
  • :queries - Module containing query-building functions for advanced filtering

Optional Options

  • :except - List of operation types to exclude (:list, :get, :one, :delete, :create, :update, :change)
  • :plural_resource_name - Custom plural name for list functions (defaults to singular + "s")

Generated Functions

For a schema named Comment, the following functions are generated:

Query Operations

  • query_comments/0 - Returns a base query for all comments
  • query_comments/1 - Returns a filtered query based on options (without executing)

New Operations

  • new_comment/0 - Returns a new comment
  • new_comment/1 - Returns a new comment with params
  • new_comment/2 - Returns a new comment with params and opts

List Operations

  • list_comments/0 - Returns all comments
  • list_comments/1 - Returns filtered comments based on options

Get Operations

  • get_comment/1 - Fetches a single comment by ID
  • get_comment/2 - Fetches a comment by ID with additional filters
  • get_comment!/1 - Like get_comment/1 but raises if not found
  • get_comment!/2 - Like get_comment/2 but raises if not found

Single Record Operations

  • one_comment/1 - Fetches a single comment matching the criteria
  • one_comment!/1 - Like one_comment/1 but raises if not found

Save Operations

  • save_comment/2 - Saves (inserts or updates) a comment with provided attributes
  • save_comment!/2 - Like save_comment/2 but raises on invalid attributes

Create Operations

  • create_comment/1 - Creates a new comment with provided attributes
  • create_comment!/1 - Like create_comment/1 but raises on invalid attributes

Update Operations

  • update_comment/2 - Updates comment with provided attributes
  • update_comment!/2 - Like update_comment/2 but raises on invalid attributes

Change Operations

  • change_comment/2 - Returns a changeset for the comment with optional changes

Delete Operations

  • delete_comment/1 - Deletes a comment struct or by query criteria

Query Options

All functions that accept options support:

  • Basic filtering with field-value pairs
  • Complex queries via Ecto.Query
  • Pagination via paginate: true or paginate: [page: 1, per_page: 20]
  • Custom query options defined in your queries module

Examples

# Get a query for comments (for use with Repo.aggregate, etc.)
query = MyApp.Blog.query_comments(status: :published)
MyApp.Repo.aggregate(query, :count)

# New comment
MyApp.Blog.new_comment()

# List all comments
MyApp.Blog.list_comments()

# List published comments with pagination
MyApp.Blog.list_comments(status: :published, paginate: [page: 1])

# Get comment by ID with preloads
MyApp.Blog.get_comment(123, preload: [:user])

# Save a comment (insert if new, update if existing)
MyApp.Blog.save_comment(comment, %{body: "New or updated content"})

# Create a new comment
MyApp.Blog.create_comment(%{body: "Great post!", user_id: 1})

# Update a comment
MyApp.Blog.update_comment(comment, %{body: "Updated content"})

# Get a changeset for updates
MyApp.Blog.change_comment(comment, %{body: "Changed content"})

# Delete comment matching criteria
MyApp.Blog.delete_comment(body: "Specific content to delete")

Queries Module

The required :queries module should implement apply_query_option/2, which receives a query option and the current query and returns a modified query. This allows for custom filtering, sorting, and other query modifications.

defmodule MyApp.Blog.CommentQueries do
  import Ecto.Query

  def apply_query_option({:with_user_name, name}, query) do
    query
    |> join(:inner, [c], u in assoc(c, :user))
    |> where([_, u], ilike(u.name, ^"%#{name}%"))
  end

  def apply_query_option({:recent_first, true}, query) do
    order_by(query, [c], desc: c.inserted_at)
  end

  def apply_query_option(_, query), do: query
end

Each generated function can be overridden in your context module if you need custom behavior.