Skip to content

Commit

Permalink
Merge pull request #490 from martosaur/am/parameterized_type
Browse files Browse the repository at this point in the history
Change docs and tests to use new style parameterized types
  • Loading branch information
woylie authored Aug 19, 2024
2 parents 051526e + d2e2a58 commit 05c0ffc
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 29 deletions.
2 changes: 1 addition & 1 deletion lib/flop/custom_types/any.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ defmodule Flop.CustomTypes.Any do
def type, do: :string
def load(_), do: :error
def dump(_), do: :error
# coveralls-ignore-end
# coveralls-ignore-stop
end
2 changes: 1 addition & 1 deletion lib/flop/custom_types/existing_atom.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ defmodule Flop.CustomTypes.ExistingAtom do
def type, do: :string
def load(_), do: :error
def dump(_), do: :error
# coveralls-ignore-end
# coveralls-ignore-stop
end
2 changes: 1 addition & 1 deletion lib/flop/custom_types/like.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ defmodule Flop.CustomTypes.Like do
def type, do: :string
def load(_), do: :error
def dump(_), do: :error
# coveralls-ignore-end
# coveralls-ignore-stop
end
61 changes: 41 additions & 20 deletions lib/flop/filter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ defmodule Flop.Filter do
end

defp expand_type({:ecto_enum, values}) do
{:parameterized, Ecto.Enum, Ecto.Enum.init(values: values)}
Ecto.ParameterizedType.init(Ecto.Enum, values: values)
end

defp expand_type(type), do: type
Expand Down Expand Up @@ -275,14 +275,19 @@ defmodule Flop.Filter do
end

def allowed_operators(%FieldInfo{ecto_type: ecto_type}) do
ecto_type |> expand_type() |> allowed_operators()
ecto_type |> expand_type() |> get_allowed_operators()
end

def allowed_operators(type) when type in [:decimal, :float, :id, :integer] do
def allowed_operators(type) do
type |> expand_type() |> get_allowed_operators()
end

defp get_allowed_operators(type)
when type in [:decimal, :float, :id, :integer] do
[:==, :!=, :empty, :not_empty, :<=, :<, :>=, :>, :in, :not_in]
end

def allowed_operators(type) when type in [:binary_id, :string] do
defp get_allowed_operators(type) when type in [:binary_id, :string] do
[
:==,
:!=,
Expand All @@ -306,11 +311,11 @@ defmodule Flop.Filter do
]
end

def allowed_operators(:boolean) do
defp get_allowed_operators(:boolean) do
[:==, :!=, :=~, :empty, :not_empty]
end

def allowed_operators({:array, _}) do
defp get_allowed_operators({:array, _}) do
[
:==,
:!=,
Expand All @@ -327,28 +332,44 @@ defmodule Flop.Filter do
]
end

def allowed_operators({:map, _}) do
defp get_allowed_operators({:map, _}) do
[:==, :!=, :empty, :not_empty, :in, :not_in]
end

def allowed_operators(:map) do
defp get_allowed_operators(:map) do
[:==, :!=, :empty, :not_empty, :in, :not_in]
end

def allowed_operators(type)
when type in [
:date,
:time,
:time_usec,
:naive_datetime,
:naive_datetime_usec,
:utc_datetime,
:utc_datetime_usec
] do
defp get_allowed_operators(type)
when type in [
:date,
:time,
:time_usec,
:naive_datetime,
:naive_datetime_usec,
:utc_datetime,
:utc_datetime_usec
] do
[:==, :!=, :empty, :not_empty, :<=, :<, :>=, :>, :in, :not_in]
end

def allowed_operators({:parameterized, Ecto.Enum, _}) do
defp get_allowed_operators({:parameterized, {Ecto.Enum, _}}) do
[
:==,
:!=,
:empty,
:not_empty,
:<=,
:<,
:>=,
:>,
:in,
:not_in
]
end

# for backward compatibility with Ecto < 3.12.0
defp get_allowed_operators({:parameterized, Ecto.Enum, _}) do
[
:==,
:!=,
Expand All @@ -363,7 +384,7 @@ defmodule Flop.Filter do
]
end

def allowed_operators(_) do
defp get_allowed_operators(_) do
[
:==,
:!=,
Expand Down
4 changes: 2 additions & 2 deletions lib/flop/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ defprotocol Flop.Schema do
For parameterized types, use the following syntax:
- `ecto_type: {:parameterized, Ecto.Enum, Ecto.Enum.init(values: [:one, :two])}`
- `ecto_type: Ecto.ParameterizedType.init(Ecto.Enum, values: [:one, :two])`
If you're working with `Ecto.Enum` types, you can use a more convenient
syntax:
Expand Down Expand Up @@ -613,7 +613,7 @@ defprotocol Flop.Schema do
- `:string`
- `:integer`
- `Ecto.UUID`
- `{:parameterized, Ecto.Enum, Ecto.Enum.init(values: [:one, :two])}`
- `{:parameterized, {Ecto.Enum, Ecto.Enum.init(values: [:one, :two])}}`
Or reference a schema field:
Expand Down
48 changes: 45 additions & 3 deletions test/flop/filter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ defmodule Flop.FilterTest do
end

describe "allowed_operators/1" do
test "returns a list of operators for each native Ecto type" do
test "returns a list of operators for each Ecto type" do
types = [
:id,
:binary_id,
Expand All @@ -36,12 +36,54 @@ defmodule Flop.FilterTest do
:naive_datetime_usec,
:utc_datetime,
:utc_datetime_usec,
{:parameterized, Ecto.Enum, type: :string}
{:parameterized, {Ecto.Enum, %{type: :string}}},
{:ecto_enum, [:one, :two]},
{:from_schema, MyApp.Pet, :mood}
]

for type <- types do
assert [op | _] = Filter.allowed_operators(type)
assert [op | _] = ops_for_type = Filter.allowed_operators(type)
assert is_atom(op)

ops_for_field =
Filter.allowed_operators(%Flop.FieldInfo{ecto_type: type})

assert ops_for_type == ops_for_field
end
end

test "returns list of operators for enum" do
types = [
# by internal representation Ecto < 3.12.0
{:parameterized, Ecto.Enum, %{type: :string}},
# by internal representation Ecto >= 3.12.0
{:parameterized, {Ecto.Enum, %{type: :string}}},
# same with init function
Ecto.ParameterizedType.init(Ecto.Enum, values: [:one, :two]),
# by convenience format
{:ecto_enum, [:one, :two]},
# by reference
{:from_schema, MyApp.Pet, :mood}
]

expected_ops = [
:==,
:!=,
:empty,
:not_empty,
:<=,
:<,
:>=,
:>,
:in,
:not_in
]

for type <- types do
assert Filter.allowed_operators(type) == expected_ops

assert Filter.allowed_operators(%Flop.FieldInfo{ecto_type: type}) ==
expected_ops
end
end

Expand Down
18 changes: 18 additions & 0 deletions test/flop/validation_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1050,5 +1050,23 @@ defmodule Flop.ValidationTest do
assert {:error, changeset} = validate(params, for: Owner)
assert [%{value: ["is invalid"]}] = errors_on(changeset)[:filters]
end

test "casts filter values as ecto enums when using parameterized type" do
field = :pet_mood_as_parameterized_type

params = %{filters: [%{field: field, op: :==, value: "happy"}]}
assert %{filters: [%{value: :happy}]} = validate!(params, for: Owner)

params = %{filters: [%{field: field, op: :==, value: :happy}]}
assert %{filters: [%{value: :happy}]} = validate!(params, for: Owner)

params = %{filters: [%{field: field, op: :==, value: "joyful"}]}
assert {:error, changeset} = validate(params, for: Owner)
assert [%{value: ["is invalid"]}] = errors_on(changeset)[:filters]

params = %{filters: [%{field: field, op: :==, value: :joyful}]}
assert {:error, changeset} = validate(params, for: Owner)
assert [%{value: ["is invalid"]}] = errors_on(changeset)[:filters]
end
end
end
13 changes: 12 additions & 1 deletion test/support/owner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ defmodule MyApp.Owner do

@derive {
Flop.Schema,
filterable: [:name, :pet_mood_as_reference, :pet_mood_as_enum],
filterable: [
:name,
:pet_mood_as_reference,
:pet_mood_as_enum,
:pet_mood_as_parameterized_type
],
sortable: [:name, :age],
join_fields: [
pet_age: [
Expand All @@ -24,6 +29,12 @@ defmodule MyApp.Owner do
binding: :pets,
field: :mood,
ecto_type: {:ecto_enum, [:happy, :playful]}
],
pet_mood_as_parameterized_type: [
binding: :pets,
field: :mood,
ecto_type:
Ecto.ParameterizedType.init(Ecto.Enum, values: [:happy, :playful])
]
],
compound_fields: [age_and_pet_age: [:age, :pet_age]],
Expand Down

0 comments on commit 05c0ffc

Please sign in to comment.