mirror of
https://github.com/ash-project/ash.git
synced 2024-09-19 13:03:02 +12:00
fix: honor the countable
option in pagination
the default unfortunately had to be changed to `true`, given that it was being ignored before chore: clean up error declarations
This commit is contained in:
parent
0007d0e60a
commit
9b0fb15ecb
24 changed files with 34 additions and 29 deletions
|
@ -2,7 +2,7 @@ defmodule Ash.Actions.Read do
|
||||||
@moduledoc false
|
@moduledoc false
|
||||||
|
|
||||||
alias Ash.Actions.Helpers
|
alias Ash.Actions.Helpers
|
||||||
alias Ash.Error.Invalid.{LimitRequired, PaginationRequired}
|
alias Ash.Error.Invalid.{LimitRequired, NonCountableAction, PaginationRequired}
|
||||||
alias Ash.Filter
|
alias Ash.Filter
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
@ -2367,6 +2367,10 @@ defmodule Ash.Actions.Read do
|
||||||
{:ok, starting_query}
|
{:ok, starting_query}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
page_opts[:count] == true && !action.pagination.countable ->
|
||||||
|
{:error,
|
||||||
|
NonCountableAction.exception(resource: starting_query.resource, action: action.name)}
|
||||||
|
|
||||||
page_opts[:limit] ->
|
page_opts[:limit] ->
|
||||||
page_opts =
|
page_opts =
|
||||||
Keyword.put(
|
Keyword.put(
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Action.InvalidArgument do
|
defmodule Ash.Error.Action.InvalidArgument do
|
||||||
@moduledoc "Used when an invalid value is provided for an action argument"
|
@moduledoc "Used when an invalid value is provided for an action argument"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:field, :message, :value], class: :invalid
|
use Splode.Error, fields: [:field, :message, :value], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.ActionRequiresActor do
|
defmodule Ash.Error.Changes.ActionRequiresActor do
|
||||||
@moduledoc "Used when an actor is referenced in a filter template, but no actor exists"
|
@moduledoc "Used when an actor is referenced in a filter template, but no actor exists"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [], class: :invalid
|
use Splode.Error, fields: [], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.InvalidArgument do
|
defmodule Ash.Error.Changes.InvalidArgument do
|
||||||
@moduledoc "Used when an invalid value is provided for an action argument"
|
@moduledoc "Used when an invalid value is provided for an action argument"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:field, :message, :value], class: :invalid
|
use Splode.Error, fields: [:field, :message, :value], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.InvalidAttribute do
|
defmodule Ash.Error.Changes.InvalidAttribute do
|
||||||
@moduledoc "Used when an invalid value is provided for an attribute change"
|
@moduledoc "Used when an invalid value is provided for an attribute change"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:field, :message, :private_vars, :value], class: :invalid
|
use Splode.Error, fields: [:field, :message, :private_vars, :value], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.InvalidChanges do
|
defmodule Ash.Error.Changes.InvalidChanges do
|
||||||
@moduledoc "Used when a change is provided that covers multiple attributes/relationships"
|
@moduledoc "Used when a change is provided that covers multiple attributes/relationships"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:fields, :message, :validation, :value], class: :invalid
|
use Splode.Error, fields: [:fields, :message, :validation, :value], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.InvalidRelationship do
|
defmodule Ash.Error.Changes.InvalidRelationship do
|
||||||
@moduledoc "Used when an invalid value is provided for a relationship change"
|
@moduledoc "Used when an invalid value is provided for a relationship change"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:relationship, :message], class: :invalid
|
use Splode.Error, fields: [:relationship, :message], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.NoSuchAttribute do
|
defmodule Ash.Error.Changes.NoSuchAttribute do
|
||||||
@moduledoc "Used when a change is provided for an attribute that does not exist"
|
@moduledoc "Used when a change is provided for an attribute that does not exist"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:resource, :attribute], class: :invalid
|
use Splode.Error, fields: [:resource, :attribute], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.NoSuchRelationship do
|
defmodule Ash.Error.Changes.NoSuchRelationship do
|
||||||
@moduledoc "Used when a change is provided for an relationship that does not exist"
|
@moduledoc "Used when a change is provided for an relationship that does not exist"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:resource, :relationship], class: :invalid
|
use Splode.Error, fields: [:resource, :relationship], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.Required do
|
defmodule Ash.Error.Changes.Required do
|
||||||
@moduledoc "Used when an attribute or relationship is required"
|
@moduledoc "Used when an attribute or relationship is required"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:field, :type, :resource], class: :invalid
|
use Splode.Error, fields: [:field, :type, :resource], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Changes.StaleRecord do
|
defmodule Ash.Error.Changes.StaleRecord do
|
||||||
@moduledoc "Used when a stale record is attempted to be updated or deleted"
|
@moduledoc "Used when a stale record is attempted to be updated or deleted"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:resource, :filter], class: :invalid
|
use Splode.Error, fields: [:resource, :filter], class: :invalid
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Forbidden.CannotFilterCreates do
|
defmodule Ash.Error.Forbidden.CannotFilterCreates do
|
||||||
@moduledoc "Used when a create action would be filtered"
|
@moduledoc "Used when a create action would be filtered"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [], class: :forbidden
|
use Splode.Error, fields: [], class: :forbidden
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Forbidden.DomainRequiresActor do
|
defmodule Ash.Error.Forbidden.DomainRequiresActor do
|
||||||
@moduledoc "Used when a domain that has `require_actor? true` is provided no actor"
|
@moduledoc "Used when a domain that has `require_actor? true` is provided no actor"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:domain], class: :forbidden
|
use Splode.Error, fields: [:domain], class: :forbidden
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Ash.Error.Forbidden.DomainRequiresAuthorization do
|
defmodule Ash.Error.Forbidden.DomainRequiresAuthorization do
|
||||||
@moduledoc "Used when a domain that has `authorize :always` is provided authorize?: false"
|
@moduledoc "Used when a domain that has `authorize :always` is provided authorize?: false"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:domain], class: :forbidden
|
use Splode.Error, fields: [:domain], class: :forbidden
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ defmodule Ash.Error.Forbidden.ForbiddenField do
|
||||||
@moduledoc "Raised in cases where access to a specific field was prevented"
|
@moduledoc "Raised in cases where access to a specific field was prevented"
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:resource, :field], class: :forbidden
|
use Splode.Error, fields: [:resource, :field], class: :forbidden
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
defmodule Ash.Error.Forbidden.InitialDataRequired do
|
defmodule Ash.Error.Forbidden.InitialDataRequired do
|
||||||
@moduledoc "Used when "
|
@moduledoc "Used when initial data was not supplied when it was required"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:source], class: :forbidden
|
use Splode.Error, fields: [:source], class: :forbidden
|
||||||
|
|
||||||
def message(%{source: source}) do
|
def message(%{source: source}) do
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
defmodule Ash.Error.Forbidden.MustPassStrictCheck do
|
defmodule Ash.Error.Forbidden.MustPassStrictCheck do
|
||||||
@moduledoc "Used when unreachable code/conditions are reached in the framework"
|
@moduledoc "Used when unreachable code/conditions are reached in the framework"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [], class: :forbidden
|
use Splode.Error, fields: [], class: :forbidden
|
||||||
|
|
||||||
def message(_) do
|
def message(_) do
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
defmodule Ash.Error.Forbidden.Placeholder do
|
defmodule Ash.Error.Forbidden.Placeholder do
|
||||||
@moduledoc "A placeholder exception that the user should never see"
|
@moduledoc "A placeholder exception that the user should never see"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:authorizer], class: :forbidden
|
use Splode.Error, fields: [:authorizer], class: :forbidden
|
||||||
|
|
||||||
def from_json(%{"authorizer" => authorizer}) do
|
def from_json(%{"authorizer" => authorizer}) do
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
defmodule Ash.Error.Framework.AssumptionFailed do
|
defmodule Ash.Error.Framework.AssumptionFailed do
|
||||||
@moduledoc "Used when unreachable code/conditions are reached in the framework"
|
@moduledoc "Used when unreachable code/conditions are reached in the framework"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:message], class: :framework
|
use Splode.Error, fields: [:message], class: :framework
|
||||||
|
|
||||||
def message(%{message: message}) do
|
def message(%{message: message}) do
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
defmodule Ash.Error.Framework.CanNotBeAtomic do
|
defmodule Ash.Error.Framework.CanNotBeAtomic do
|
||||||
@moduledoc "Used when a change that is only atomic cannot be done atomically"
|
@moduledoc "Used when a change that is only atomic cannot be done atomically"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:resource, :change, :reason], class: :framework
|
use Splode.Error, fields: [:resource, :change, :reason], class: :framework
|
||||||
|
|
||||||
def message(error) do
|
def message(error) do
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
defmodule Ash.Error.Framework.FlagAssertionFailed do
|
defmodule Ash.Error.Framework.FlagAssertionFailed do
|
||||||
@moduledoc "Used when unreachable code/conditions are reached in the framework"
|
@moduledoc "Used when unreachable code/conditions are reached in the framework"
|
||||||
use Ash.Error.Exception
|
|
||||||
|
|
||||||
use Splode.Error, fields: [:flag, :heading], class: :framework
|
use Splode.Error, fields: [:flag, :heading], class: :framework
|
||||||
|
|
||||||
def message(error) do
|
def message(error) do
|
||||||
|
|
8
lib/ash/error/invalid/non_countable_action.ex
Normal file
8
lib/ash/error/invalid/non_countable_action.ex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
defmodule Ash.Error.Invalid.NonCountableAction do
|
||||||
|
@moduledoc "Used when page[:count] option is passed but the action's pagination is not countable."
|
||||||
|
use Splode.Error, fields: [:resource, :action], class: :invalid
|
||||||
|
|
||||||
|
def message(%{resource: resource, action: action}) do
|
||||||
|
"Action #{inspect(resource)}.#{action} cannot be counted while paginating but a count was requested."
|
||||||
|
end
|
||||||
|
end
|
|
@ -109,11 +109,12 @@ defmodule Ash.Resource.Actions.Read do
|
||||||
type: :pos_integer,
|
type: :pos_integer,
|
||||||
doc: "The default page size to apply, if one is not supplied"
|
doc: "The default page size to apply, if one is not supplied"
|
||||||
],
|
],
|
||||||
|
# Change this default in 4.0
|
||||||
countable: [
|
countable: [
|
||||||
type: {:in, [true, false, :by_default]},
|
type: {:in, [true, false, :by_default]},
|
||||||
doc:
|
doc:
|
||||||
"Whether not a returned page will have a full count of all records. Use `:by_default` to do it automatically.",
|
"Whether not a returned page will have a full count of all records. Use `:by_default` to do it automatically.",
|
||||||
default: false
|
default: true
|
||||||
],
|
],
|
||||||
max_page_size: [
|
max_page_size: [
|
||||||
type: :pos_integer,
|
type: :pos_integer,
|
||||||
|
|
|
@ -21,6 +21,14 @@ defmodule Ash.Test.CountTest do
|
||||||
default_limit 5
|
default_limit 5
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
read :non_countable do
|
||||||
|
pagination do
|
||||||
|
offset? true
|
||||||
|
default_limit 5
|
||||||
|
countable false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ets do
|
ets do
|
||||||
|
@ -77,4 +85,14 @@ defmodule Ash.Test.CountTest do
|
||||||
|
|
||||||
assert count == 10
|
assert count == 10
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "trying to count a non-countable action is invalid" do
|
||||||
|
assert_raise Ash.Error.Invalid,
|
||||||
|
~r/cannot be counted while paginating/,
|
||||||
|
fn ->
|
||||||
|
Countable
|
||||||
|
|> Ash.Query.for_read(:non_countable)
|
||||||
|
|> Ash.read!(actor: %{id: "foo"}, page: [count: true])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue