mirror of
https://github.com/ash-project/ash_postgres.git
synced 2024-09-19 13:03:14 +12:00
improvement: support ash main upsert_condition logic
This commit is contained in:
parent
7285b3382e
commit
2015aa658c
4 changed files with 82 additions and 1 deletions
|
@ -1930,7 +1930,8 @@ defmodule AshPostgres.DataLayer do
|
|||
end)
|
||||
end
|
||||
|
||||
defp get_source_for_upsert_field(field, resource) do
|
||||
@doc false
|
||||
def get_source_for_upsert_field(field, resource) do
|
||||
case Ash.Resource.Info.attribute(resource, field) do
|
||||
%{source: source} when not is_nil(source) ->
|
||||
source
|
||||
|
|
|
@ -41,6 +41,33 @@ defmodule AshPostgres.SqlImplementation do
|
|||
{:ok, Ecto.Query.dynamic(fragment("'[]'::jsonb")), acc}
|
||||
end
|
||||
|
||||
def expr(
|
||||
query,
|
||||
%Ash.Query.UpsertConflict{attribute: attribute},
|
||||
_bindings,
|
||||
_embedded?,
|
||||
acc,
|
||||
_type
|
||||
) do
|
||||
query.__ash_bindings__.resource
|
||||
|
||||
{:ok,
|
||||
Ecto.Query.dynamic(
|
||||
[],
|
||||
fragment(
|
||||
"EXCLUDED.?",
|
||||
literal(
|
||||
^to_string(
|
||||
AshPostgres.DataLayer.get_source_for_upsert_field(
|
||||
attribute,
|
||||
query.__ash_bindings__.resource
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
), acc}
|
||||
end
|
||||
|
||||
def expr(query, %AshPostgres.Functions.Binding{}, _bindings, _embedded?, acc, _type) do
|
||||
binding =
|
||||
AshSql.Bindings.get_binding(
|
||||
|
|
|
@ -2,6 +2,8 @@ defmodule AshPostgres.BulkCreateTest do
|
|||
use AshPostgres.RepoCase, async: false
|
||||
alias AshPostgres.Test.{Post, Record}
|
||||
|
||||
import Ash.Expr
|
||||
|
||||
describe "bulk creates" do
|
||||
test "bulk creates insert each input" do
|
||||
Ash.bulk_create!([%{title: "fred"}, %{title: "george"}], Post, :create)
|
||||
|
@ -109,6 +111,51 @@ defmodule AshPostgres.BulkCreateTest do
|
|||
end)
|
||||
end
|
||||
|
||||
test "bulk upsert skips with upsert_condition" 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_no_filter,
|
||||
return_stream?: true,
|
||||
upsert_condition: expr(price != upsert_conflict(:price)),
|
||||
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
|
||||
|
|
|
@ -278,6 +278,12 @@ defmodule AshPostgres.Test.Post do
|
|||
end)
|
||||
end
|
||||
|
||||
create :upsert_with_no_filter do
|
||||
upsert?(true)
|
||||
upsert_identity(:uniq_if_contains_foo)
|
||||
upsert_fields([:price])
|
||||
end
|
||||
|
||||
update :set_title_from_author do
|
||||
change(atomic_update(:title, expr(author.first_name)))
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue