Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: custom filters on context level #63

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

subaru9
Copy link

@subaru9 subaru9 commented Oct 4, 2024

Overview

Introduced ability to convert params into custom queries and apply them to accumulator query using:

  • query builder functions at context level
  • custom query functions from schema

Example Usage

The following example illustrates how to define custom filters in a context that tracks balances in different currencies:

  1. Migration:
defmodule PaySys.Repo.Migrations.CreateMoneyWithCurrencyAndBalances do
  use Ecto.Migration

  def up do
    execute("""
    CREATE TYPE public.money_with_currency AS (
      currency_code varchar,
      amount numeric
    );
    """)

    create table(:balances) do
      add :balance, :money_with_currency
      add :user_id, references(:users, on_delete: :nothing)

      timestamps(type: :utc_datetime_usec)
    end

    create index(:balances, [:user_id])
  end

  def down do
    drop table(:balances)
    execute("DROP TYPE public.money_with_currency;")
  end
end
  1. Context with query builder implementation.
defmodule PaySys.Funds do
  
  alias EctoShorts.Actions.QueryBuilder
  alias PaySys.Funds.Balance

  @behaviour QueryBuilder
  
  @impl QueryBuilder
  def filters, do: [:currency_code, :amount_gte]
  
  @impl QueryBuilder
  def build_query(Balance, %{currency_code: val}, query), 
    do: Balance.by_currency_code(query, val)

  @impl QueryBuilder
  def build_query(Balance, %{amount_gte: val}, query), 
    do: Balance.by_amount_gte(query, val)
end
  1. Schema with custom query functions:
defmodule PaySys.Funds.Balance do
  use Ecto.Schema

  import Ecto.Query, only: [where: 3, fragment: 1]

  def by_currency_code(query \\ __MODULE__) do
    where(query, [b], fragment("(?).currency_code = ?", b.balance, ^to_string(val)))
  end

  def by_amount_gte(query \\ __MODULE__) do
    where(query, [b], fragment("(?).amount >= ?", b.balance, ^val))
  end
end
  1. Context for Querying:
defmodule PaySys.Funds do

  alias EctoShorts.Actions
  alias PaySys.Funds
  alias PaySys.Funds.Balance

  @doc """
  ## Examples

      iex> Funds.list_balances(%{currency_code: "USD", amount_gte: 100})
      [%Balance{balance: %Money{currency: :USD, amount: 200}}]

      iex> Funds.list_balances(%{currency_code: "EUR", amount_gte: 50})
      [%Balance{balance: %Money{currency: :EUR, amount: 150}}]

      iex> Funds.list_balances(%{currency_code: "USD", amount_gte: 1000})
      []
  """
  @spec list_balances(Actions.filter_params()) :: [Balance.t()] | []
  def list_balances(params \\ %{}) do
    Actions.all(Balance, params)
  end
end

@subaru9
Copy link
Author

subaru9 commented Oct 4, 2024

@MikaAK, @cylkdev pls review. PR based on our conversation

@subaru9 subaru9 force-pushed the feat/query-builder-in-context branch from b4012d1 to ce836ac Compare October 21, 2024 10:43
Introduced ability to convert params into custom queries and apply them
to accumulator query using:
  * query builder functions at context level
  * custom query functions from schema
@subaru9 subaru9 force-pushed the feat/query-builder-in-context branch from ce836ac to 452ed30 Compare October 21, 2024 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant