mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 05:23:03 +12:00
fix: properly honor the return_errors?
option
This commit is contained in:
parent
1ddba9499c
commit
5af9dc6696
4 changed files with 106 additions and 28 deletions
|
@ -150,11 +150,7 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
{[batch(state)], %{state | batch: [item], count: 0, must_return_records?: false}}
|
||||
|
||||
{:error, error}, state ->
|
||||
if opts[:return_errors?] do
|
||||
{[{:error, error}], state}
|
||||
else
|
||||
{[], state}
|
||||
end
|
||||
end,
|
||||
fn state ->
|
||||
{[batch(state)], state}
|
||||
|
@ -338,19 +334,17 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
if opts[:stop_on_error?] do
|
||||
{:halt, {[], error}}
|
||||
else
|
||||
{error
|
||||
|> List.wrap()
|
||||
|> Stream.map(&{:error, &1}), nil}
|
||||
{error_stream(error, opts), nil}
|
||||
end
|
||||
|
||||
{:error, notifications, error} ->
|
||||
if opts[:stop_on_error?] do
|
||||
{:halt, {notify_stream([], notifications, resource, action, opts), error}}
|
||||
else
|
||||
{error
|
||||
|> List.wrap()
|
||||
|> Stream.map(&{:error, &1})
|
||||
|> notify_stream(notifications, resource, action, opts), nil}
|
||||
{
|
||||
notify_stream(error_stream(error, opts), notifications, resource, action, opts),
|
||||
nil
|
||||
}
|
||||
end
|
||||
|
||||
{:ok, invalid, notifications} ->
|
||||
|
@ -358,26 +352,25 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
{:halt,
|
||||
{[],
|
||||
invalid
|
||||
|> Stream.map(&{:error, &1})
|
||||
|> error_stream(opts)
|
||||
|> notify_stream(notifications, resource, action, opts)}}
|
||||
else
|
||||
{invalid
|
||||
|> Stream.map(&{:error, &1})
|
||||
|> error_stream(opts)
|
||||
|> notify_stream(notifications, resource, action, opts), nil}
|
||||
end
|
||||
|
||||
{:ok, batch_result, invalid, notifications} ->
|
||||
if opts[:stop_on_error?] && !Enum.empty?(invalid) do
|
||||
{:halt, {invalid, batch_result}}
|
||||
{:halt, {error_stream(invalid, opts), batch_result}}
|
||||
else
|
||||
if opts[:return_records?] do
|
||||
{batch_result
|
||||
|> Stream.map(&{:ok, &1})
|
||||
|> Stream.concat(Stream.map(invalid, &{:error, &1}))
|
||||
|> Stream.concat(error_stream(invalid, opts))
|
||||
|> notify_stream(notifications, resource, action, opts), nil}
|
||||
else
|
||||
{invalid
|
||||
|> Stream.map(&{:error, &1})
|
||||
{error_stream(invalid, opts)
|
||||
|> notify_stream(notifications, resource, action, opts), nil}
|
||||
end
|
||||
end
|
||||
|
@ -391,7 +384,7 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
remaining_items =
|
||||
successes
|
||||
|> Stream.map(&{:ok, &1})
|
||||
|> Stream.concat(Stream.map(errors, &{:error, &1}))
|
||||
|> Stream.concat(error_stream(errors, opts))
|
||||
|
||||
{remaining_items, nil}
|
||||
|
||||
|
@ -404,16 +397,22 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
result
|
||||
|> Enum.reduce(%Ash.BulkResult{status: :empty, records: [], errors: []}, fn
|
||||
{:error, error}, result ->
|
||||
{error_count, errors} = errors(result, error, opts)
|
||||
|
||||
%{
|
||||
result
|
||||
| errors: [error | result.errors],
|
||||
| errors: errors,
|
||||
error_count: error_count,
|
||||
status: errored(result.status)
|
||||
}
|
||||
|
||||
{:error, notifications, error}, result ->
|
||||
{error_count, errors} = errors(result, error, opts)
|
||||
|
||||
%{
|
||||
result
|
||||
| errors: [error | result.errors],
|
||||
| errors: errors,
|
||||
error_count: error_count,
|
||||
status: errored(result.status),
|
||||
notifications: (result.notifications || []) ++ notifications
|
||||
}
|
||||
|
@ -426,9 +425,12 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
}
|
||||
|
||||
{:ok, invalid, notifications}, result ->
|
||||
{error_count, errors} = errors(result, invalid, opts)
|
||||
|
||||
%{
|
||||
result
|
||||
| errors: invalid ++ result.errors,
|
||||
| errors: errors,
|
||||
error_count: error_count,
|
||||
status: :partial_success,
|
||||
notifications: (result.notifications || []) ++ notifications
|
||||
}
|
||||
|
@ -447,10 +449,13 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
result.records
|
||||
end
|
||||
|
||||
{error_count, errors} = errors(result, invalid, opts)
|
||||
|
||||
%{
|
||||
result
|
||||
| records: records,
|
||||
errors: invalid ++ result.errors,
|
||||
errors: errors,
|
||||
error_count: error_count,
|
||||
status: status,
|
||||
notifications: (result.notifications || []) ++ notifications
|
||||
}
|
||||
|
@ -475,11 +480,47 @@ defmodule Ash.Actions.Create.Bulk do
|
|||
:error
|
||||
end
|
||||
|
||||
%Ash.BulkResult{
|
||||
result = %Ash.BulkResult{
|
||||
status: status,
|
||||
errors: List.wrap(error),
|
||||
notifications: notifications
|
||||
}
|
||||
|
||||
{errors, error_count} = errors(result, error, opts)
|
||||
|
||||
%{result | errors: errors, error_count: error_count}
|
||||
end
|
||||
|
||||
defp errors(result, invalid, opts) when is_list(invalid) do
|
||||
Enum.reduce(invalid, {result.error_count, result.errors}, fn invalid, {error_count, errors} ->
|
||||
errors(%{result | error_count: error_count, errors: errors}, invalid, opts)
|
||||
end)
|
||||
end
|
||||
|
||||
defp errors(result, {:error, error}, opts) do
|
||||
if opts[:return_errors?] do
|
||||
{result.error_count + 1, [error | result.errors]}
|
||||
else
|
||||
{result.error_count + 1, []}
|
||||
end
|
||||
end
|
||||
|
||||
defp errors(result, invalid, opts) do
|
||||
if Enumerable.impl_for(invalid) do
|
||||
invalid = Enum.to_list(invalid)
|
||||
errors(result, invalid, opts)
|
||||
else
|
||||
errors(result, {:error, invalid}, opts)
|
||||
end
|
||||
end
|
||||
|
||||
defp error_stream(error, opts) do
|
||||
if opts[:return_errors?] do
|
||||
error
|
||||
|> List.wrap()
|
||||
|> Stream.map(&{:error, &1})
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defp run_bulk_before_batches(
|
||||
|
|
|
@ -392,6 +392,12 @@ defmodule Ash.Api do
|
|||
doc:
|
||||
"Wether or not to return all of the records that were inserted. Defaults to false to account for large inserts."
|
||||
],
|
||||
return_errors?: [
|
||||
type: :boolean,
|
||||
default: false,
|
||||
doc:
|
||||
"Wether or not to return all of the errors that occur. Defaults to false to account for large inserts."
|
||||
],
|
||||
batch_size: [
|
||||
type: :pos_integer,
|
||||
doc: """
|
||||
|
|
|
@ -7,13 +7,15 @@ defmodule Ash.BulkResult do
|
|||
status: :success | :partial_success | :error,
|
||||
notifications: list(Ash.Notifier.Notification.t()) | nil,
|
||||
records: list(Ash.Resource.record()) | nil,
|
||||
errors: list(Ash.Error.t() | Ash.Changeset.t()) | nil
|
||||
errors: list(Ash.Error.t() | Ash.Changeset.t()) | nil,
|
||||
error_count: non_neg_integer()
|
||||
}
|
||||
|
||||
defstruct [
|
||||
:status,
|
||||
:errors,
|
||||
:records,
|
||||
:notifications
|
||||
:notifications,
|
||||
error_count: 0
|
||||
]
|
||||
end
|
||||
|
|
|
@ -97,6 +97,33 @@ defmodule Ash.Test.Actions.BulkCreateTest do
|
|||
)
|
||||
end
|
||||
|
||||
test "will return error count" do
|
||||
assert %Ash.BulkResult{records: [%{title: "title1_stuff"}], error_count: 1, errors: []} =
|
||||
Api.bulk_create!(
|
||||
[%{title: "title1"}, %{title: %{foo: :bar}}],
|
||||
Post,
|
||||
:create_with_change,
|
||||
return_records?: true,
|
||||
sorted?: true
|
||||
)
|
||||
end
|
||||
|
||||
test "will return errors on request" do
|
||||
assert %Ash.BulkResult{
|
||||
records: [%{title: "title1_stuff"}],
|
||||
error_count: 1,
|
||||
errors: [%Ash.Changeset{}]
|
||||
} =
|
||||
Api.bulk_create!(
|
||||
[%{title: "title1"}, %{title: %{foo: :bar}}],
|
||||
Post,
|
||||
:create_with_change,
|
||||
return_records?: true,
|
||||
return_errors?: true,
|
||||
sorted?: true
|
||||
)
|
||||
end
|
||||
|
||||
test "can upsert" do
|
||||
assert %Ash.BulkResult{
|
||||
records: [
|
||||
|
@ -179,6 +206,7 @@ defmodule Ash.Test.Actions.BulkCreateTest do
|
|||
:create_with_policy,
|
||||
authorize?: true,
|
||||
return_records?: true,
|
||||
return_errors?: true,
|
||||
sorted?: true
|
||||
)
|
||||
end
|
||||
|
@ -278,7 +306,8 @@ defmodule Ash.Test.Actions.BulkCreateTest do
|
|||
notify?: true,
|
||||
return_stream?: true,
|
||||
return_notifications?: true,
|
||||
return_records?: true
|
||||
return_records?: true,
|
||||
return_errors?: true
|
||||
)
|
||||
|> Enum.to_list()
|
||||
|> Enum.sort_by(fn
|
||||
|
|
Loading…
Reference in a new issue