View Source AshPagify.Validation (ash_pagify v1.3.0)

Utilities for validating and transforming full-text search, scoping, filtering, ordering, and pagination parameters.

Summary

Functions

Validates the form filter in the given parameters.

Validates the filters in the given parameters.

Validates the order by in the given parameters.

Validates the pagination parameters in the given parameters.

Validates the scopes in the given parameters.

Validates the search attribute in the given parameters.

Functions

validate_filter_form(params, opts)

@spec validate_filter_form(map(), Keyword.t()) :: map()

Validates the form filter in the given parameters.

Uses AshPagify.FormFilter.validate/3 to parse the form filter.

If replace_invalid_params? is true, invalid filter_form parameters are removed and an error is added to the :errors key in the returned map. If replace_invalid_params? is false, invalid filter_form parameters are not removed and an error is added to the :errors key in the returned map.

If the :filter_form key is nil, it is returned as is.

Examples

iex> AshPagify.Validation.validate_filter_form(%{}, for: Post)
%{}

iex> AshPagify.Validation.validate_filter_form(%{filter_form: nil}, for: Post)
%{filter_form: nil}

iex> %{filter_form: filter_form} = AshPagify.Validation.validate_filter_form(%{filter_form: %{}}, for: Post)
iex> filter_form
%{}

iex> %{filter_form: filter_form} = AshPagify.Validation.validate_filter_form(%{filter_form: %{}}, for: Post, replace_invalid_params?: true)
iex> filter_form
%{}

iex> %{filter_form: filter_form, errors: errors} = AshPagify.Validation.validate_filter_form(%{filter_form:  %{"field" => "non_existent", "operator" => "eq", "value" => "Post 1"}}, for: Post)
iex> filter_form
%{"field" => "non_existent", "operator" => "eq", "value" => "Post 1"}
iex> errors
[filter_form: [{:field, {"No such field non_existent", []}}]]

iex> %{filter_form: filter_form, errors: errors} = AshPagify.Validation.validate_filter_form(%{filter_form:  %{"field" => "non_existent", "operator" => "eq", "value" => "Post 1"}}, for: Post, replace_invalid_params?: true)
iex> filter_form
%{}
iex> errors
[filter_form: [{:field, {"No such field non_existent", []}}]]

validate_filters(params, opts)

@spec validate_filters(map(), Keyword.t()) :: map()

Validates the filters in the given parameters.

If replace_invalid_params? is true, invalid filters are removed and an error is added to the :errors key in the returned map. If replace_invalid_params? is false, invalid filters are not removed and an error is added to the :errors key in the returned map. Only the first error is added to the :errors key.

If the :filters key is nil, it is returned as is.

Examples

iex> AshPagify.Validation.validate_filters(%{}, for: Post)
%{}

iex> AshPagify.Validation.validate_filters(%{filters: nil}, for: Post)
%{filters: nil}

iex> %{filters: filters} = AshPagify.Validation.validate_filters(%{filters: [%{name: "Post 1"}]}, for: Post)
iex> filters
#Ash.Filter<name == "Post 1">

iex> %{filters: filters, errors: errors} = AshPagify.Validation.validate_filters(%{filters: 1}, for: Post, replace_invalid_params?: true)
iex> filters
nil
iex> AshPagify.Error.clear_stacktrace(errors)
[
  filters: [
    %Ash.Error.Query.InvalidFilterValue{value: 1}
  ]
]

iex> %{filters: filters, errors: errors} = AshPagify.Validation.validate_filters(%{filters: 1}, for: Post)
iex> filters
1
iex> AshPagify.Error.clear_stacktrace(errors)
[
  filters: [
    %Ash.Error.Query.InvalidFilterValue{value: 1}
  ]
]

validate_order_by(params, opts)

@spec validate_order_by(map(), Keyword.t()) :: map()

Validates the order by in the given parameters.

If replace_invalid_params? is true, invalid order by values are removed and an error is added to the :errors key in the returned map. If replace_invalid_params? is false, invalid order by values are not removed and an error is added to the :errors key in the returned map. Only the first error is added to the :errors key.

If the :order_by key is nil, it is returned as is.

Examples

iex> AshPagify.Validation.validate_order_by(%{}, for: Post)
%{}

iex> AshPagify.Validation.validate_order_by(%{order_by: nil}, for: Post)
%{order_by: nil}

iex> %{order_by: order_by} = AshPagify.Validation.validate_order_by(%{order_by: ["name"]}, for: Post)
iex> order_by
[name: :asc]

iex> %{order_by: order_by} = AshPagify.Validation.validate_order_by(%{order_by: "++name"}, for: Post)
iex> order_by
[name: :asc_nils_first]

iex> %{order_by: order_by} = AshPagify.Validation.validate_order_by(%{order_by: "name,--comments_count"}, for: Post)
iex> order_by
[name: :asc, comments_count: :desc_nils_last]

iex> %{order_by: order_by, errors: errors} = AshPagify.Validation.validate_order_by(%{order_by: "--name,non_existent"}, for: Post, replace_invalid_params?: true)
iex> order_by
[name: :desc_nils_last]
iex> AshPagify.Error.clear_stacktrace(errors)
[
  order_by: [
    %Ash.Error.Query.NoSuchField{field: "non_existent", resource: Post}
  ]
]

validate_pagination(params, opts)

@spec validate_pagination(map(), Keyword.t()) :: map()

Validates the pagination parameters in the given parameters.

If replace_invalid_params? is true, invalid pagination parameters are removed / replaced and an error is added to the :errors key in the returned map. If replace_invalid_params? is false, invalid pagination parameters are not removed and an error is added to the :errors key in the returned map.

If the :limit key is nil, the default_limit value is applied.

If the :offset key is nil, it is returned as is.

Examples

iex> AshPagify.Validation.validate_pagination(%{}, for: Post)
%{limit: 15, offset: 0}

iex> AshPagify.Validation.validate_pagination(%{limit: nil}, for: Post)
%{limit: 15, offset: 0}

iex> %{limit: limit} = AshPagify.Validation.validate_pagination(%{limit: 10}, for: Post)
iex> limit
10

iex> %{limit: limit, errors: errors} = AshPagify.Validation.validate_pagination(%{limit: 0}, for: Post, replace_invalid_params?: true)
iex> limit
15
iex> AshPagify.Error.clear_stacktrace(errors)
[
  limit: [
    %Ash.Error.Query.InvalidLimit{limit: 0}
  ]
]

iex> %{limit: limit} = AshPagify.Validation.validate_pagination(%{limit: 100}, for: Post)
iex> limit
100

iex> %{limit: limit, errors: errors} = AshPagify.Validation.validate_pagination(%{limit: -1}, for: Post, replace_invalid_params?: true)
iex> limit
15
iex> AshPagify.Error.clear_stacktrace(errors)
[
  limit: [
    %Ash.Error.Query.InvalidLimit{limit: -1}
  ]
]

iex> %{offset: offset} = AshPagify.Validation.validate_pagination(%{offset: 10}, for: Post)
iex> offset
10

iex> %{offset: offset, errors: errors} = AshPagify.Validation.validate_pagination(%{offset: -1}, for: Post, replace_invalid_params?: true)
iex> offset
0
iex> AshPagify.Error.clear_stacktrace(errors)
[
  offset: [
    %Ash.Error.Query.InvalidOffset{offset: -1}
  ]
]

iex> %{offset: offset, errors: errors} = AshPagify.Validation.validate_pagination(%{offset: -1}, for: Post)
iex> offset
-1
iex> AshPagify.Error.clear_stacktrace(errors)
[
  offset: [
    %Ash.Error.Query.InvalidOffset{offset: -1}
  ]
]

validate_params(query_or_resource, params, opts \\ [])

@spec validate_params(Ash.Query.t() | Ash.Resource.t(), map(), Keyword.t()) ::
  {:ok, AshPagify.t()} | {:error, any(), map()}

validate_scopes(params, scopes, default_scopes \\ nil, opts \\ [])

@spec validate_scopes(map(), map(), map() | nil, Keyword.t()) :: map()

Validates the scopes in the given parameters.

If replace_invalid_params? is true, invalid scopes are removed and an error is added to the :errors key in the returned map. If replace_invalid_params? is false, invalid scopes are not removed and an error is added to the :errors key in the returned map. Only the first error is added to the :errors key.

If the :scopes key is nil, it is returned as is.

Examples

iex> scopes = %{}
iex> AshPagify.Validation.validate_scopes(%{}, scopes)
%{}

iex> scopes = %{}
iex> AshPagify.Validation.validate_scopes(%{scopes: nil}, scopes)
%{scopes: nil}

iex> scopes = %{}
iex> %{scopes: scopes} = AshPagify.Validation.validate_scopes(%{scopes: %{role: :admin}}, scopes)
iex> scopes
%{role: :admin}

iex> scopes = %{}
iex> %{scopes: scopes, errors: errors} = AshPagify.Validation.validate_scopes(%{scopes: %{role: :non_existent}}, scopes)
iex> scopes
%{role: :non_existent}
iex> AshPagify.Error.clear_stacktrace(errors)
[
  scopes: [
    %AshPagify.Error.Query.NoSuchScope{group: :role, name: :non_existent}
  ]
]

iex> scopes = %{}
iex> %{scopes: scopes, errors: errors} = AshPagify.Validation.validate_scopes(%{scopes: %{role: :non_existent}}, scopes, nil, replace_invalid_params?: true)
iex> scopes
nil
iex> AshPagify.Error.clear_stacktrace(errors)
[
  scopes: [
    %AshPagify.Error.Query.NoSuchScope{group: :role, name: :non_existent}
  ]
]

iex> scopes = %{}
iex> %{scopes: scopes, errors: errors} = AshPagify.Validation.validate_scopes(%{scopes: %{non_existent: :admin}}, scopes)
iex> scopes
%{non_existent: :admin}
iex> AshPagify.Error.clear_stacktrace(errors)
[
  scopes: [
    %AshPagify.Error.Query.NoSuchScope{group: :non_existent, name: :admin}
  ]
]

iex> scopes = %{}
iex> %{scopes: scopes, errors: errors} = AshPagify.Validation.validate_scopes(%{scopes: %{non_existent: :admin}}, scopes, nil, replace_invalid_params?: true)
iex> scopes
nil
iex> AshPagify.Error.clear_stacktrace(errors)
[
  scopes: [
    %AshPagify.Error.Query.NoSuchScope{group: :non_existent, name: :admin}
  ]
]

validate_search(params, opts)

@spec validate_search(map(), Keyword.t()) :: map()

Validates the search attribute in the given parameters.

In case full_text_search is configured, we validate if the given search attribute is a valid full text search attribute.

If replace_invalid_params? is true, invalid search parameters are removed and an error is added to the :errors key in the returned map. If replace_invalid_params? is false, invalid search parameters are not removed and an error is added to the :errors key in the returned map. Only the first error is added to the :errors key.

If the :search key is nil or an empty string, it is returned as is.