ContextKit.CRUD (ContextKit v0.5.0)
View SourceThe 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 commentsquery_comments/1
- Returns a filtered query based on options (without executing)
New Operations
new_comment/0
- Returns a new commentnew_comment/1
- Returns a new comment with paramsnew_comment/2
- Returns a new comment with params and opts
List Operations
list_comments/0
- Returns all commentslist_comments/1
- Returns filtered comments based on options
Get Operations
get_comment/1
- Fetches a single comment by IDget_comment/2
- Fetches a comment by ID with additional filtersget_comment!/1
- Likeget_comment/1
but raises if not foundget_comment!/2
- Likeget_comment/2
but raises if not found
Single Record Operations
one_comment/1
- Fetches a single comment matching the criteriaone_comment!/1
- Likeone_comment/1
but raises if not found
Save Operations
save_comment/2
- Saves (inserts or updates) a comment with provided attributessave_comment!/2
- Likesave_comment/2
but raises on invalid attributes
Create Operations
create_comment/1
- Creates a new comment with provided attributescreate_comment!/1
- Likecreate_comment/1
but raises on invalid attributes
Update Operations
update_comment/2
- Updates comment with provided attributesupdate_comment!/2
- Likeupdate_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
orpaginate: [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.