egze

egze

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
  • :magnifying_glass_tilted_left: Dynamic query building with extensive filtering options
  • :page_facing_up: Built-in pagination support
  • :wrench: Flexible and extensible design
  • :bullseye: 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

https://github.com/egze/context_kit

Showing Posts 1 to 5

egze

egze OP

Released version 0.3.0

The main feature is the support of Phoenix 1.8 scopes.

Use the new ContextKit.CRUD.Scoped in your context.

defmodule MyApp.Blog do
  use ContextKit.CRUD.Scoped,
    repo: MyApp.Repo,
    schema: MyApp.Blog.Comment,
    queries: MyApp.Blog.CommentQueries,
    pubsub: MyApp.PubSub,                 # For realtime notifications via PubSub
    scope: Application.compile_env(:my_app, :scopes)[:user] # To gain support for Phoenix 1.8 scopes.
  end

Now, besides all the functions from before, you will get all functions with the scope as first argument.

# List all comments
MyApp.Blog.list_comments()

# List all comments belonging to current user
MyApp.Blog.list_comments(socket.assigns.current_scope)
hubertlepicki

hubertlepicki

What do you use on top of that to ensure that only the fields that can and should be allowed to be updated will be updated by the user? Let’s say you have User schema, with is_admin: boolean field. The generated code will allow updating that field. Do you build something on top of that that casts and validates only allowed fields/values before you pass params to your context CRUD functions?

egze

egze OP

It still calls the User.changeset function, so one way would be to not cast :is_admin in this changeset.

For the use-case when you do want to update the :is_admin field, you would need to create your own update_user_admin function.

This is how update_#{resource} function is generated context_kit/lib/context_kit/crud/scoped.ex at main · egze/context_kit · GitHub

FedericoAlcantara

FedericoAlcantara

I just published a similar tool, with a somewhat different approach, but aiming at reducing the code boilerplate.

Check AuroraCTX

egze

egze OP

v0.5.0 of ContextKit has just been released.

I noticed that when you list resources, it always selects all schema fields, and there is no way to override it. Now there is.

Example:

MyApp.Comments.list_comments(select: [:id, :text])

This will select only the id and text fields from the database.

— All posts loaded —

Where Next? Top

Trending in Announcing Top

woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
fuelen
Hi all! I want to present a small library which provides a mix task for generating an Entity-Relationship Diagram for Ecto schemas. You...
New
anuaralfetahe
Hello Published a new library - ProcessHub! ProcessHub is a library designed to manage process distribution within the Elixir cluster. ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
AstonJ
This showed up on my feed.. anyone heard of it? Just hype? Ox Alpha is a reasoning model designed for coding, sustained ag...
New
sergio
It’s not that it’s vocabulary is too advanced. It’s something worse. I get lost trying to follow even a paragraph written by Claude. It’...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
akoutmos
@hugobarauna, Dr. Dimitrios Koutmos (my brother) and I (Alex Koutmos) have been hard at work on writing a book on how you can use Elixir ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews