mirror of
https://github.com/ash-project/ash_postgres.git
synced 2024-09-19 13:03:14 +12:00
fix: handle filter condition on create (#368)
This commit is contained in:
parent
73c7a915e0
commit
a539f6443e
5 changed files with 136 additions and 2 deletions
|
@ -2539,6 +2539,28 @@ defmodule AshPostgres.DataLayer do
|
|||
upsert_fields: upsert_fields,
|
||||
return_records?: true
|
||||
}) do
|
||||
{:ok, []} ->
|
||||
key_filters =
|
||||
Enum.map(keys, fn key ->
|
||||
{key,
|
||||
Ash.Changeset.get_attribute(changeset, key) || Map.get(changeset.params, key) ||
|
||||
Map.get(changeset.params, to_string(key))}
|
||||
end)
|
||||
|
||||
ash_query =
|
||||
resource
|
||||
|> Ash.Query.do_filter(and: [key_filters])
|
||||
|> then(fn
|
||||
query when is_nil(identity) or is_nil(identity.where) -> query
|
||||
query -> Ash.Query.do_filter(query, identity.where)
|
||||
end)
|
||||
|> Ash.Query.set_tenant(changeset.tenant)
|
||||
|
||||
with {:ok, ecto_query} <- Ash.Query.data_layer_query(ash_query),
|
||||
{:ok, [result]} <- run_query(ecto_query, resource) do
|
||||
{:ok, Ash.Resource.put_metadata(result, :upsert_skipped, true)}
|
||||
end
|
||||
|
||||
{:ok, [result]} ->
|
||||
{:ok, result}
|
||||
|
||||
|
|
|
@ -65,6 +65,50 @@ defmodule AshPostgres.BulkCreateTest do
|
|||
end)
|
||||
end
|
||||
|
||||
test "bulk upsert skips with filter" do
|
||||
assert [
|
||||
{:ok, %{title: "fredfoo", uniq_if_contains_foo: "1foo", price: 10}},
|
||||
{:ok, %{title: "georgefoo", uniq_if_contains_foo: "2foo", price: 20}},
|
||||
{:ok, %{title: "herbert", uniq_if_contains_foo: "3", price: 30}}
|
||||
] =
|
||||
Ash.bulk_create!(
|
||||
[
|
||||
%{title: "fredfoo", uniq_if_contains_foo: "1foo", price: 10},
|
||||
%{title: "georgefoo", uniq_if_contains_foo: "2foo", price: 20},
|
||||
%{title: "herbert", uniq_if_contains_foo: "3", price: 30}
|
||||
],
|
||||
Post,
|
||||
:create,
|
||||
return_stream?: true,
|
||||
return_records?: true
|
||||
)
|
||||
|> Enum.sort_by(fn {:ok, result} -> result.title end)
|
||||
|
||||
assert [
|
||||
{:ok, %{title: "georgefoo", uniq_if_contains_foo: "2foo", price: 20_000}},
|
||||
{:ok, %{title: "herbert", uniq_if_contains_foo: "3", price: 30}}
|
||||
] =
|
||||
Ash.bulk_create!(
|
||||
[
|
||||
%{title: "fredfoo", uniq_if_contains_foo: "1foo", price: 10},
|
||||
%{title: "georgefoo", uniq_if_contains_foo: "2foo", price: 20_000},
|
||||
%{title: "herbert", uniq_if_contains_foo: "3", price: 30}
|
||||
],
|
||||
Post,
|
||||
:upsert_with_filter,
|
||||
return_stream?: true,
|
||||
return_errors?: true,
|
||||
return_records?: true
|
||||
)
|
||||
|> Enum.sort_by(fn
|
||||
{:ok, result} ->
|
||||
result.title
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end)
|
||||
end
|
||||
|
||||
# confirmed that this doesn't work because it can't. An upsert must map to a potentially successful insert.
|
||||
# leaving this test here for posterity
|
||||
# test "bulk creates can upsert with id" do
|
||||
|
|
58
test/create_test.exs
Normal file
58
test/create_test.exs
Normal file
|
@ -0,0 +1,58 @@
|
|||
defmodule AshPostgres.CreateTest do
|
||||
use AshPostgres.RepoCase, async: false
|
||||
alias AshPostgres.Test.Post
|
||||
|
||||
test "creates insert" do
|
||||
assert {:ok, %Post{}} =
|
||||
Post
|
||||
|> Ash.Changeset.for_create(:create, %{title: "fred"})
|
||||
|> Ash.create()
|
||||
|
||||
assert [%{title: "fred"}] =
|
||||
Post
|
||||
|> Ash.Query.sort(:title)
|
||||
|> Ash.read!()
|
||||
end
|
||||
|
||||
test "upserts entry" do
|
||||
assert {:ok, %Post{id: id}} =
|
||||
Post
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
title: "fredfoo",
|
||||
uniq_if_contains_foo: "foo",
|
||||
price: 10
|
||||
})
|
||||
|> Ash.create()
|
||||
|
||||
assert {:ok, %Post{id: ^id, price: 20}} =
|
||||
Post
|
||||
|> Ash.Changeset.for_create(:upsert_with_filter, %{
|
||||
title: "fredfoo",
|
||||
uniq_if_contains_foo: "foo",
|
||||
price: 20
|
||||
})
|
||||
|> Ash.create()
|
||||
end
|
||||
|
||||
test "skips upsert with filter" do
|
||||
assert {:ok, %Post{id: id}} =
|
||||
Post
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
title: "fredfoo",
|
||||
uniq_if_contains_foo: "foo",
|
||||
price: 10
|
||||
})
|
||||
|> Ash.create()
|
||||
|
||||
assert {:ok, %Post{id: ^id} = post} =
|
||||
Post
|
||||
|> Ash.Changeset.for_create(:upsert_with_filter, %{
|
||||
title: "fredfoo",
|
||||
uniq_if_contains_foo: "foo",
|
||||
price: 10
|
||||
})
|
||||
|> Ash.create()
|
||||
|
||||
assert Ash.Resource.get_metadata(post, :upsert_skipped)
|
||||
end
|
||||
end
|
|
@ -258,6 +258,16 @@ defmodule AshPostgres.Test.Post do
|
|||
)
|
||||
end
|
||||
|
||||
create :upsert_with_filter do
|
||||
upsert?(true)
|
||||
upsert_identity(:uniq_if_contains_foo)
|
||||
upsert_fields([:price])
|
||||
|
||||
change(fn changeset, _ ->
|
||||
Ash.Changeset.filter(changeset, expr(price != fragment("EXCLUDED.price")))
|
||||
end)
|
||||
end
|
||||
|
||||
update :set_title_from_author do
|
||||
change(atomic_update(:title, expr(author.first_name)))
|
||||
end
|
||||
|
@ -292,7 +302,7 @@ defmodule AshPostgres.Test.Post do
|
|||
identity(:uniq_on_upper, [:upper_thing])
|
||||
|
||||
identity(:uniq_if_contains_foo, [:uniq_if_contains_foo]) do
|
||||
where expr(contains(title, "foo"))
|
||||
where expr(contains(uniq_if_contains_foo, "foo"))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ExUnit.start()
|
||||
ExUnit.start(capture_log: true)
|
||||
ExUnit.configure(stacktrace_depth: 100)
|
||||
|
||||
AshPostgres.TestRepo.start_link()
|
||||
|
|
Loading…
Reference in a new issue