Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/zenflows/db/page.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Ecto.Query
alias Zenflows.DB.{ID, Repo}

@enforce_keys ~w[dir cur num filter]a
defstruct [:cur, :num, :filter, dir: :forw]
defstruct [:cur, :num, :filter, :order_by, dir: :forw]

@typedoc """
Represents a generic struct that has all required information to
Expand All @@ -42,6 +42,7 @@ The fields are:
cur: nil | ID.t(),
num: non_neg_integer(),
filter: nil | map(),
order_by: nil | map(),
}

@doc """
Expand Down
5 changes: 3 additions & 2 deletions src/zenflows/gql/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,16 @@ def parse(params) do
cur: after_ || before,
num: if((n = first || last), do: normalize(n), else: def_page_size()),
filter: data[:filter],
order_by: data[:order_by],
}}
end
end

@doc false
@spec changeset(Schema.params()) :: Changeset.t()
def changeset(params) do
{%{}, %{after: ID, first: :integer, before: ID, last: :integer, filter: :map}}
|> Changeset.cast(params, [:after, :first, :before, :last, :filter])
{%{}, %{after: ID, first: :integer, before: ID, last: :integer, filter: :map, order_by: :map}}
|> Changeset.cast(params, [:after, :first, :before, :last, :filter, :order_by])
|> Changeset.validate_number(:first, greater_than_or_equal_to: 0)
|> Changeset.validate_number(:last, greater_than_or_equal_to: 0)
|> Validate.exist_nand([:first, :last])
Expand Down
6 changes: 6 additions & 0 deletions src/zenflows/vf/economic_resource/domain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ def all!(page \\ Page.new()) do
value
end

@spec count_distinct_primary_accountable(nil | map())
:: {:ok, non_neg_integer()} | {:error, Ecto.Changeset.t()}
def count_distinct_primary_accountable(filter_params) do
Query.count_distinct_primary_accountable(filter_params)
end

@spec previous(EconomicResource.t() | Schema.id()) :: [EconomicEvent.t()]
def previous(_, _ \\ Page.new())
def previous(%EconomicResource{id: id}, page), do: previous(id, page)
Expand Down
47 changes: 45 additions & 2 deletions src/zenflows/vf/economic_resource/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,24 @@ defmodule Zenflows.VF.EconomicResource.Query do
import Ecto.Query

alias Ecto.{Changeset, Queryable}
alias Zenflows.DB.{ID, Page, Schema, Validate}
alias Zenflows.DB.{ID, Page, Repo, Schema, Validate}
alias Zenflows.VF.{EconomicEvent, EconomicResource, SpatialThing}

@spec all(Page.t()) :: {:ok, Queryable.t()} | {:error, Changeset.t()}
def all(%{filter: nil, order_by: nil}), do: {:ok, EconomicResource}
def all(%{filter: nil, order_by: order_by}) do
{:ok, apply_order_by(EconomicResource, order_by)}
end
def all(%{filter: nil}), do: {:ok, EconomicResource}
def all(%{filter: params}) do
def all(%{filter: params} = page) do
with {:ok, filters} <- all_validate(params) do
{geo_filters, other_filters} = Enum.split_with(filters, fn
{k, _} -> k in [:near_lat, :near_long, :near_distance_km]
_ -> false
end)
q = Enum.reduce(other_filters, EconomicResource, &all_f(&2, &1))
q = apply_geo_filter(q, Map.new(geo_filters))
q = apply_order_by(q, Map.get(page, :order_by))
{:ok, q}
end
end
Expand Down Expand Up @@ -98,6 +103,44 @@ defp apply_geo_filter(q, %{near_lat: lat, near_long: long, near_distance_km: dis
end
defp apply_geo_filter(q, _), do: q

@spec apply_order_by(Queryable.t(), map() | nil) :: Queryable.t()
defp apply_order_by(q, nil), do: q
defp apply_order_by(q, %{field: :created_at, direction: :asc}),
do: order_by(q, [x], asc: x.inserted_at)
defp apply_order_by(q, %{field: :created_at, direction: :desc}),
do: order_by(q, [x], desc: x.inserted_at)
defp apply_order_by(q, %{field: :name, direction: :asc}),
do: order_by(q, [x], asc: x.name)
defp apply_order_by(q, %{field: :name, direction: :desc}),
do: order_by(q, [x], desc: x.name)

@doc "Builds a filtered query from filter params (without pagination)."
@spec filtered_query(nil | map()) :: {:ok, Queryable.t()} | {:error, Changeset.t()}
def filtered_query(nil), do: {:ok, EconomicResource}
def filtered_query(params) do
with {:ok, filters} <- all_validate(params) do
{geo_filters, other_filters} = Enum.split_with(filters, fn
{k, _} -> k in [:near_lat, :near_long, :near_distance_km]
_ -> false
end)
q = Enum.reduce(other_filters, EconomicResource, &all_f(&2, &1))
q = apply_geo_filter(q, Map.new(geo_filters))
{:ok, q}
end
end

@doc "Counts distinct primary_accountable_id values for the given filter params."
@spec count_distinct_primary_accountable(nil | map())
:: {:ok, non_neg_integer()} | {:error, Changeset.t()}
def count_distinct_primary_accountable(filter_params) do
with {:ok, q} <- filtered_query(filter_params) do
count =
from(x in q, select: count(x.primary_accountable_id, :distinct))
|> Repo.one()
{:ok, count}
end
end

@spec all_validate(Schema.params())
:: {:ok, Changeset.data()} | {:error, Changeset.t()}
defp all_validate(params) do
Expand Down
7 changes: 5 additions & 2 deletions src/zenflows/vf/economic_resource/resolv.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ end

def economic_resources(params, _) do
with {:ok, page} <- Connection.parse(params),
{:ok, schemas} <- Domain.all(page) do
{:ok, Connection.from_list(schemas, page)}
{:ok, schemas} <- Domain.all(page),
{:ok, count} <- Domain.count_distinct_primary_accountable(page.filter) do
conn = Connection.from_list(schemas, page)
page_info = Map.put(conn.page_info, :distinct_primary_accountable_count, count)
{:ok, %{conn | page_info: page_info}}
end
end

Expand Down
28 changes: 27 additions & 1 deletion src/zenflows/vf/economic_resource/type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,33 @@ object :economic_resource_edge do
field :node, non_null(:economic_resource)
end

enum :economic_resource_sort_field do
value :created_at
value :name
end

enum :sort_direction do
value :asc
value :desc
end

input_object :economic_resource_sort_input do
field :field, non_null(:economic_resource_sort_field)
field :direction, non_null(:sort_direction)
end

object :economic_resource_page_info do
field :start_cursor, :id
field :end_cursor, :id
field :has_previous_page, non_null(:boolean)
field :has_next_page, non_null(:boolean)
field :total_count, :integer
field :page_limit, :integer
field :distinct_primary_accountable_count, :integer
end

object :economic_resource_connection do
field :page_info, non_null(:page_info)
field :page_info, non_null(:economic_resource_page_info)
field :edges, non_null(list_of(non_null(:economic_resource_edge)))
end

Expand Down Expand Up @@ -304,6 +329,7 @@ object :query_economic_resource do
arg :last, :integer
arg :before, :id
arg :filter, :economic_resource_filter_params
arg :order_by, :economic_resource_sort_input
resolve &Resolv.economic_resources/2
end

Expand Down
Loading