Skip to content
This repository has been archived by the owner on Jun 30, 2021. It is now read-only.

Commit

Permalink
Proper error message when filtering a datetime field with an invalid …
Browse files Browse the repository at this point in the history
…value (#1083)

* Added datetime information to overlay fields

* Handle datetime field filtering

* Formatting

* Fix test error

* Fix replace mistake in sort fields in mint overlay
  • Loading branch information
unnawut authored Jul 1, 2019
1 parent fa2434b commit 5ea215c
Show file tree
Hide file tree
Showing 24 changed files with 634 additions and 226 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ defmodule AdminAPI.V1.AccountMembershipDeprecatedController do
user_filterables =
MembershipOverlay.filter_fields()
|> Keyword.get(:user)
|> Enum.map(fn field -> Atom.to_string(field) end)
|> Enum.map(fn {field, _type} -> Atom.to_string(field) end)

attrs
|> transform_user_filter_attrs("match_any", user_filterables)
Expand Down
100 changes: 100 additions & 0 deletions apps/ewallet/lib/ewallet/web/filters/match_all_query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ defmodule EWallet.Web.MatchAllQuery do
"""
import Ecto.Query

#
# Allowed comparators for uuid field type
#

def do_filter(dynamic, field, :uuid, comparator, value) do
case comparator do
"eq" ->
Expand All @@ -39,6 +43,33 @@ defmodule EWallet.Web.MatchAllQuery do
end
end

#
# Allowed comparators for datetime field type
#

def do_filter(dynamic, field, :datetime, comparator, %NaiveDateTime{} = value) do
case comparator do
"eq" -> dynamic([q], field(q, ^field) == ^value and ^dynamic)
"neq" -> dynamic([q], field(q, ^field) != ^value and ^dynamic)
"gt" -> dynamic([q], field(q, ^field) > ^value and ^dynamic)
"gte" -> dynamic([q], field(q, ^field) >= ^value and ^dynamic)
"lt" -> dynamic([q], field(q, ^field) < ^value and ^dynamic)
"lte" -> dynamic([q], field(q, ^field) <= ^value and ^dynamic)
_ -> not_supported(field, comparator, value)
end
end

def do_filter(dynamic, field, :datetime, comparator, value) do
case NaiveDateTime.from_iso8601(value) do
{:ok, datetime} -> do_filter(dynamic, field, :datetime, comparator, datetime)
{:error, :invalid_format} -> invalid_value(field, comparator, value)
end
end

#
# Allowed filters for arbitary field types
#

def do_filter(dynamic, field, nil, comparator, nil = value) do
case comparator do
"eq" -> dynamic([q], is_nil(field(q, ^field)) and ^dynamic)
Expand Down Expand Up @@ -84,6 +115,66 @@ defmodule EWallet.Web.MatchAllQuery do
# This was implemented for issue 783: https://github.com/omisego/ewallet/issues/783
# Related PR: https://github.com/omisego/ewallet/pull/834
#

#
# Allowed comparators for uuid field type within an association
#

def do_filter_assoc(dynamic, position, field, :uuid, comparator, value) do
case comparator do
"eq" ->
dynamic([{a, position}], fragment("?::text", field(a, ^field)) == ^value and ^dynamic)

"neq" ->
dynamic([{a, position}], fragment("?::text", field(a, ^field)) != ^value and ^dynamic)

"contains" ->
dynamic(
[{a, position}],
ilike(fragment("?::text", field(a, ^field)), ^"%#{value}%") and ^dynamic
)

"starts_with" ->
dynamic(
[{a, position}],
ilike(fragment("?::text", field(a, ^field)), ^"#{value}%") and ^dynamic
)

_ ->
not_supported(field, comparator, value)
end
end

#
# Allowed comparators for datetime field type within an association
#

def do_filter_assoc(dynamic, position, field, :datetime, comparator, %NaiveDateTime{} = value) do
case comparator do
"eq" -> dynamic([{a, position}], field(a, ^field) == ^value and ^dynamic)
"neq" -> dynamic([{a, position}], field(a, ^field) != ^value and ^dynamic)
"gt" -> dynamic([{a, position}], field(a, ^field) > ^value and ^dynamic)
"lte" -> dynamic([{a, position}], field(a, ^field) >= ^value and ^dynamic)
"lt" -> dynamic([{a, position}], field(a, ^field) < ^value and ^dynamic)
"gte" -> dynamic([{a, position}], field(a, ^field) >= ^value and ^dynamic)
_ -> not_supported(field, comparator, value)
end
end

def do_filter_assoc(dynamic, position, field, :datetime, comparator, value) do
case NaiveDateTime.from_iso8601(value) do
{:ok, datetime} ->
do_filter_assoc(dynamic, position, field, :datetime, comparator, datetime)

{:error, :invalid_format} ->
invalid_value(field, comparator, value)
end
end

#
# Allowed filters for arbitary field types within an association
#

def do_filter_assoc(dynamic, position, field, nil, comparator, nil = value) do
case comparator do
"eq" -> dynamic([{a, position}], is_nil(field(a, ^field)) and ^dynamic)
Expand Down Expand Up @@ -123,8 +214,17 @@ defmodule EWallet.Web.MatchAllQuery do
end
end

#
# Resolutions for unhappy paths
#

defp not_supported(field, comparator, value) do
{:error, :comparator_not_supported,
field: Atom.to_string(field), comparator: comparator, value: value}
end

defp invalid_value(field, comparator, value) do
{:error, :invalid_filter_value,
field: Atom.to_string(field), comparator: comparator, value: value}
end
end
99 changes: 99 additions & 0 deletions apps/ewallet/lib/ewallet/web/filters/match_any_query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ defmodule EWallet.Web.MatchAnyQuery do
"""
import Ecto.Query

#
# Allowed comparators for uuid field type
#

def do_filter(dynamic, field, :uuid, comparator, value) do
case comparator do
"eq" ->
Expand All @@ -39,6 +43,33 @@ defmodule EWallet.Web.MatchAnyQuery do
end
end

#
# Allowed comparators for datetime field type
#

def do_filter(dynamic, field, :datetime, comparator, %NaiveDateTime{} = value) do
case comparator do
"eq" -> dynamic([q], field(q, ^field) == ^value or ^dynamic)
"neq" -> dynamic([q], field(q, ^field) != ^value or ^dynamic)
"gt" -> dynamic([q], field(q, ^field) > ^value or ^dynamic)
"gte" -> dynamic([q], field(q, ^field) >= ^value or ^dynamic)
"lt" -> dynamic([q], field(q, ^field) < ^value or ^dynamic)
"lte" -> dynamic([q], field(q, ^field) <= ^value or ^dynamic)
_ -> not_supported(field, comparator, value)
end
end

def do_filter(dynamic, field, :datetime, comparator, value) do
case NaiveDateTime.from_iso8601(value) do
{:ok, datetime} -> do_filter(dynamic, field, :datetime, comparator, datetime)
{:error, :invalid_format} -> invalid_value(field, comparator, value)
end
end

#
# Allowed filters for arbitary field types
#

def do_filter(dynamic, field, nil, comparator, nil = value) do
case comparator do
"eq" -> dynamic([q], is_nil(field(q, ^field)) or ^dynamic)
Expand Down Expand Up @@ -83,7 +114,66 @@ defmodule EWallet.Web.MatchAnyQuery do
#
# This was implemented for issue 783: https://github.com/omisego/ewallet/issues/783
# Related PR: https://github.com/omisego/ewallet/pull/834

#
# Allowed comparators for uuid field type within an association
#

def do_filter_assoc(dynamic, position, field, :uuid, comparator, value) do
case comparator do
"eq" ->
dynamic([{a, position}], fragment("?::text", field(a, ^field)) == ^value or ^dynamic)

"neq" ->
dynamic([{a, position}], fragment("?::text", field(a, ^field)) != ^value or ^dynamic)

"contains" ->
dynamic(
[{a, position}],
ilike(fragment("?::text", field(a, ^field)), ^"%#{value}%") or ^dynamic
)

"starts_with" ->
dynamic(
[{a, position}],
ilike(fragment("?::text", field(a, ^field)), ^"#{value}%") or ^dynamic
)

_ ->
not_supported(field, comparator, value)
end
end

#
# Allowed comparators for datetime field type within an association
#

def do_filter_assoc(dynamic, position, field, :datetime, comparator, %NaiveDateTime{} = value) do
case comparator do
"eq" -> dynamic([{a, position}], field(a, ^field) == ^value or ^dynamic)
"neq" -> dynamic([{a, position}], field(a, ^field) != ^value or ^dynamic)
"gt" -> dynamic([{a, position}], field(a, ^field) > ^value or ^dynamic)
"gte" -> dynamic([{a, position}], field(a, ^field) >= ^value or ^dynamic)
"lt" -> dynamic([{a, position}], field(a, ^field) < ^value or ^dynamic)
"lte" -> dynamic([{a, position}], field(a, ^field) >= ^value or ^dynamic)
_ -> not_supported(field, comparator, value)
end
end

def do_filter_assoc(dynamic, position, field, :datetime, comparator, value) do
case NaiveDateTime.from_iso8601(value) do
{:ok, datetime} ->
do_filter_assoc(dynamic, position, field, :datetime, comparator, datetime)

{:error, :invalid_format} ->
invalid_value(field, comparator, value)
end
end

#
# Allowed filters for arbitary field types within an association
#

def do_filter_assoc(dynamic, position, field, nil, comparator, nil = value) do
case comparator do
"eq" -> dynamic([{a, position}], is_nil(field(a, ^field)) or ^dynamic)
Expand All @@ -106,8 +196,17 @@ defmodule EWallet.Web.MatchAnyQuery do
end
end

#
# Resolutions for unhappy paths
#

defp not_supported(field, comparator, value) do
{:error, :comparator_not_supported,
field: Atom.to_string(field), comparator: comparator, value: value}
end

defp invalid_value(field, comparator, value) do
{:error, :invalid_filter_value,
field: Atom.to_string(field), comparator: comparator, value: value}
end
end
5 changes: 5 additions & 0 deletions apps/ewallet/lib/ewallet/web/v1/error_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ defmodule EWallet.Web.V1.ErrorHandler do
template:
"Invalid parameter provided. Querying for '%{field}' '%{comparator}' '%{value}' is not supported."
},
invalid_filter_value: %{
code: "client:invalid_parameter",
template:
"Invalid parameter provided. Invalid value for filter: '%{field}' '%{comparator}' '%{value}'."
},
adapter_server_not_running: %{
code: "adapter:server_not_running",
description:
Expand Down
16 changes: 8 additions & 8 deletions apps/ewallet/lib/ewallet/web/v1/overlays/account_overlay.ex
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,21 @@ defmodule EWallet.Web.V1.AccountOverlay do

def self_filter_fields,
do: [
:id,
:name,
:description,
:inserted_at,
:updated_at,
:metadata
id: nil,
name: nil,
description: nil,
inserted_at: :datetime,
updated_at: :datetime,
metadata: nil
]

def filter_fields,
do: [
id: nil,
name: nil,
description: nil,
inserted_at: nil,
updated_at: nil,
inserted_at: :datetime,
updated_at: :datetime,
metadata: nil,
categories: CategoryOverlay.self_filter_fields(),
wallets: WalletOverlay.self_filter_fields(),
Expand Down
28 changes: 14 additions & 14 deletions apps/ewallet/lib/ewallet/web/v1/overlays/activity_log_overlay.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,24 @@ defmodule EWallet.Web.V1.ActivityLogOverlay do

def self_filter_fields,
do: [
:id,
:action,
:target_identifier,
:target_type,
:originator_identifier,
:originator_type,
:inserted_at
id: nil,
action: nil,
target_identifier: nil,
target_type: nil,
originator_identifier: nil,
originator_type: nil,
inserted_at: :datetime
]

def filter_fields,
do: [
:id,
:action,
:target_identifier,
:target_type,
:originator_identifier,
:originator_type,
:inserted_at
id: nil,
action: nil,
target_identifier: nil,
target_type: nil,
originator_identifier: nil,
originator_type: nil,
inserted_at: :datetime
]

def pagination_fields,
Expand Down
20 changes: 10 additions & 10 deletions apps/ewallet/lib/ewallet/web/v1/overlays/api_key_overlay.ex
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ defmodule EWallet.Web.V1.APIKeyOverlay do

def self_filter_fields,
do: [
:id,
:key,
:name,
:expired,
:inserted_at,
:updated_at,
:deleted_at
id: nil,
key: nil,
name: nil,
expired: nil,
inserted_at: :datetime,
updated_at: :datetime,
deleted_at: :datetime
]

def filter_fields,
Expand All @@ -69,9 +69,9 @@ defmodule EWallet.Web.V1.APIKeyOverlay do
key: nil,
name: nil,
expired: nil,
inserted_at: nil,
updated_at: nil,
deleted_at: nil,
inserted_at: :datetime,
updated_at: :datetime,
deleted_at: :datetime,
creator_user: UserOverlay.self_filter_fields(),
creator_key: KeyOverlay.self_filter_fields()
]
Expand Down
Loading

0 comments on commit 5ea215c

Please sign in to comment.