Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ash-project/ash_postgres
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.5.6
Choose a base ref
...
head repository: ash-project/ash_postgres
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.5.7
Choose a head ref
  • 12 commits
  • 11 files changed
  • 6 contributors

Commits on Feb 25, 2025

  1. tests: Schema multitenancy fails (#434)

    pshoukry authored Feb 25, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    6629398 View commit details
  2. chore: update tests

    zachdaniel committed Feb 25, 2025
    Copy the full SHA
    01e066e View commit details

Commits on Feb 26, 2025

  1. fix: don't rely on private function from Ecto.Repo (#492)

    capoccias authored Feb 26, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    4202334 View commit details

Commits on Feb 27, 2025

  1. chore(deps): bump ash_sql in the production-dependencies group (#493)

    Bumps the production-dependencies group with 1 update: [ash_sql](https://github.com/ash-project/ash_sql).
    
    
    Updates `ash_sql` from 0.2.58 to 0.2.59
    - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md)
    - [Commits](ash-project/ash_sql@v0.2.58...v0.2.59)
    
    ---
    updated-dependencies:
    - dependency-name: ash_sql
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: production-dependencies
    ...
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Feb 27, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    9774a81 View commit details
  2. chore(deps-dev): bump git_ops in the dev-dependencies group (#494)

    Bumps the dev-dependencies group with 1 update: [git_ops](https://github.com/zachdaniel/git_ops).
    
    
    Updates `git_ops` from 2.7.0 to 2.7.1
    - [Changelog](https://github.com/zachdaniel/git_ops/blob/master/CHANGELOG.md)
    - [Commits](zachdaniel/git_ops@v2.7.0...v2.7.1)
    
    ---
    updated-dependencies:
    - dependency-name: git_ops
      dependency-type: direct:development
      update-type: version-update:semver-patch
      dependency-group: dev-dependencies
    ...
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Feb 27, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    97e7a05 View commit details
  3. test: schema multitenant aggregates wrong tenant (#491)

    pshoukry authored Feb 27, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f70cd70 View commit details
  4. test: add tenant in aggregate test

    zachdaniel committed Feb 27, 2025
    Copy the full SHA
    55d9b95 View commit details

Commits on Feb 28, 2025

  1. fix: check for stale record errors on destroy

    fixes #1831
    zachdaniel committed Feb 28, 2025
    Copy the full SHA
    8bfbcef View commit details

Commits on Mar 2, 2025

  1. fix: Use exclusion_constraint instead of check_constraint in add_excl…

    …usion_constraints (#495)
    ken-kost authored Mar 2, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    1ec8d82 View commit details

Commits on Mar 3, 2025

  1. test: add tests for fix in ash_sql

    zachdaniel committed Mar 3, 2025
    Copy the full SHA
    20a8631 View commit details

Commits on Mar 4, 2025

  1. fix: handle errors from identities in polymorphic resources properly (#…

    vonagam authored Mar 4, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    de37242 View commit details
  2. chore: release version v2.5.7

    zachdaniel committed Mar 4, 2025
    Copy the full SHA
    9a047a2 View commit details
Showing with 179 additions and 15 deletions.
  1. +15 −0 CHANGELOG.md
  2. +26 −7 lib/data_layer.ex
  3. +13 −2 lib/repo.ex
  4. +1 −1 mix.exs
  5. +2 −2 mix.lock
  6. +63 −0 test/aggregate_test.exs
  7. +25 −0 test/destroy_test.exs
  8. +5 −0 test/support/multitenancy/resources/org.ex
  9. +1 −0 test/support/multitenancy/resources/user.ex
  10. +11 −0 test/support/resources/post.ex
  11. +17 −3 test/update_test.exs
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide

<!-- changelog -->

## [v2.5.7](https://github.com/ash-project/ash_postgres/compare/v2.5.6...v2.5.7) (2025-03-04)




### Bug Fixes:

* handle errors from identities in polymorphic resources properly (#497)

* Use exclusion_constraint instead of check_constraint in add_exclusion_constraints (#495)

* check for stale record errors on destroy

* don't rely on private function from `Ecto.Repo` (#492)

## [v2.5.6](https://github.com/ash-project/ash_postgres/compare/v2.5.5...v2.5.6) (2025-02-25)


33 changes: 26 additions & 7 deletions lib/data_layer.ex
Original file line number Diff line number Diff line change
@@ -1964,7 +1964,17 @@ defmodule AshPostgres.DataLayer do
end
rescue
e ->
changeset = Ash.Changeset.new(resource)
changeset =
case source do
{table, resource} ->
resource
|> Ash.Changeset.new()
|> Ash.Changeset.put_context(:data_layer, %{table: table})

resource ->
resource
|> Ash.Changeset.new()
end

handle_raised_error(
e,
@@ -2555,13 +2565,13 @@ defmodule AshPostgres.DataLayer do
{key, name} ->
case repo.default_constraint_match_type(:check, name) do
{:regex, regex} ->
Ecto.Changeset.check_constraint(changeset, key,
Ecto.Changeset.exclusion_constraint(changeset, key,
name: regex,
match: :exact
)

match ->
Ecto.Changeset.check_constraint(changeset, key,
Ecto.Changeset.exclusion_constraint(changeset, key,
name: name,
match: match
)
@@ -2570,14 +2580,14 @@ defmodule AshPostgres.DataLayer do
{key, name, message} ->
case repo.default_constraint_match_type(:check, name) do
{:regex, regex} ->
Ecto.Changeset.check_constraint(changeset, key,
Ecto.Changeset.exclusion_constraint(changeset, key,
name: regex,
message: message,
match: :exact
)

match ->
Ecto.Changeset.check_constraint(changeset, key,
Ecto.Changeset.exclusion_constraint(changeset, key,
name: name,
message: message,
match: match
@@ -3170,9 +3180,18 @@ defmodule AshPostgres.DataLayer do
query,
repo_opts
)
end)
|> case do
{0, _} ->
{:error,
Ash.Error.Changes.StaleRecord.exception(
resource: resource,
filter: changeset.filter
)}

:ok
_ ->
:ok
end
end)
rescue
e ->
handle_raised_error(e, __STACKTRACE__, ecto_changeset, resource)
15 changes: 13 additions & 2 deletions lib/repo.ex
Original file line number Diff line number Diff line change
@@ -182,6 +182,17 @@ defmodule AshPostgres.Repo do

def on_transaction_begin(_reason), do: :ok

# copied from Ecto.Repo
defp ash_postgres_prepare_opts(operation_name, []),
do: default_options(operation_name)

defp ash_postgres_prepare_opts(operation_name, [{key, _} | _rest] = opts)
when is_atom(key) do
operation_name
|> default_options()
|> Keyword.merge(opts)
end

def insert(struct_or_changeset, opts \\ []) do
struct_or_changeset
|> to_ecto()
@@ -192,7 +203,7 @@ defmodule AshPostgres.Repo do
__MODULE__,
repo,
value,
Ecto.Repo.Supervisor.tuplet(repo, prepare_opts(:insert, opts))
Ecto.Repo.Supervisor.tuplet(repo, ash_postgres_prepare_opts(:insert, opts))
)
end)
|> from_ecto()
@@ -208,7 +219,7 @@ defmodule AshPostgres.Repo do
__MODULE__,
repo,
value,
Ecto.Repo.Supervisor.tuplet(repo, prepare_opts(:insert, opts))
Ecto.Repo.Supervisor.tuplet(repo, ash_postgres_prepare_opts(:insert, opts))
)
end)
|> from_ecto()
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do
The PostgreSQL data layer for Ash Framework
"""

@version "2.5.6"
@version "2.5.7"

def project do
[
4 changes: 2 additions & 2 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
%{
"ash": {:hex, :ash, "3.4.65", "798f90daee12ef9b441381f8e6b1ec0016e70933425a1ec72e60467e648435f7", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:igniter, ">= 0.5.24 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:reactor, "~> 0.11", [hex: :reactor, repo: "hexpm", optional: false]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:spark, ">= 2.2.29 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, ">= 0.2.6 and < 1.0.0-0", [hex: :splode, repo: "hexpm", optional: false]}, {:stream_data, "~> 1.0", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "309febd8866bfdc9506a757687daf2bd54c60949cda04cf8177abc645854defe"},
"ash_sql": {:hex, :ash_sql, "0.2.57", "51a574fed322e0e6fd743362cbea264275fd5799278288a3a41aa9a2e457d56d", [:mix], [{:ash, ">= 3.4.60 and < 4.0.0-0", [hex: :ash, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}], "hexpm", "0b906cef68aceb2c9666a52d4e0350c271de55483d846bed2312c59f51af2f3a"},
"ash_sql": {:hex, :ash_sql, "0.2.59", "86c04d6220772bbb6f48bd93f61afde914467daba81a301f9f77489fae1c9a53", [:mix], [{:ash, ">= 3.4.65 and < 4.0.0-0", [hex: :ash, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}], "hexpm", "5e98bfdfb601805bbc83326bea6b56dfa8dcdf934f355c1c1753b60c33d6508d"},
"benchee": {:hex, :benchee, "1.3.1", "c786e6a76321121a44229dde3988fc772bca73ea75170a73fd5f4ddf1af95ccf", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "76224c58ea1d0391c8309a8ecbfe27d71062878f59bd41a390266bf4ac1cc56d"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"credo": {:hex, :credo, "1.7.11", "d3e805f7ddf6c9c854fd36f089649d7cf6ba74c42bc3795d587814e3c9847102", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "56826b4306843253a66e47ae45e98e7d284ee1f95d53d1612bb483f88a8cf219"},
@@ -20,7 +20,7 @@
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
"git_ops": {:hex, :git_ops, "2.7.0", "fed1400d516d06810ac46a9d4b3e12ca4973683158ddc5931935567075ff1a4c", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "29f1ddb3678969cb81dc56177d0c6e5c85a77a7ce50036207b920005cc6b5b26"},
"git_ops": {:hex, :git_ops, "2.7.1", "127a0a28925372472c37b5e012f872c3edb95ead2824682b5f6bd91180600772", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:igniter, ">= 0.5.27 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "006c6284a08129cc36ba5073dc1337917fa88e85ed98c409c8cc665db9c6a5d4"},
"glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"},
"hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"},
"igniter": {:hex, :igniter, "0.5.29", "6bf7ddaf15e88ae75f6dad514329530ec8f4721ba14782f6386a7345c1be99fd", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "beb6e0f69fc6d4e3975ffa26c5459fc63fd96f85cfaeba984c2dfd3d7333b6ad"},
63 changes: 63 additions & 0 deletions test/aggregate_test.exs
Original file line number Diff line number Diff line change
@@ -65,6 +65,69 @@ defmodule AshSql.AggregateTest do
assert read_post.count_of_comments == 1
end

test "nested filters on aggregates works" do

Check failure on line 68 in test/aggregate_test.exs

GitHub Actions / ash-ci (16) / mix test

test nested filters on aggregates works (AshSql.AggregateTest)

Check failure on line 68 in test/aggregate_test.exs

GitHub Actions / ash-ci (15) / mix test

test nested filters on aggregates works (AshSql.AggregateTest)

Check failure on line 68 in test/aggregate_test.exs

GitHub Actions / ash-ci (14) / mix test

test nested filters on aggregates works (AshSql.AggregateTest)

Check failure on line 68 in test/aggregate_test.exs

GitHub Actions / ash-ci (14) / mix test

test nested filters on aggregates works (AshSql.AggregateTest)

Check failure on line 68 in test/aggregate_test.exs

GitHub Actions / ash-ci (16) / mix test

test nested filters on aggregates works (AshSql.AggregateTest)

Check failure on line 68 in test/aggregate_test.exs

GitHub Actions / ash-ci (15) / mix test

test nested filters on aggregates works (AshSql.AggregateTest)
org =
Organization
|> Ash.Changeset.for_create(:create, %{name: "match"})
|> Ash.create!()

post =
Post
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove)
|> Ash.create!()

post2 =
Post
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.create!()

Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post2, type: :append_and_remove)
|> Ash.create!()

assert [%{count_of_comments_matching_org_name: 1}] =
Post
|> Ash.Query.load(:count_of_comments_matching_org_name)
|> Ash.Query.filter(id == ^post.id)
|> Ash.read!()
end

describe "Context Multitenancy" do
alias AshPostgres.MultitenancyTest.{Org, Post, User}

test "loading a nested aggregate honors tenant" do
alias AshPostgres.MultitenancyTest.{Org, Post, User}

org =
Org
|> Ash.Changeset.for_create(:create, %{name: "BTTF"})
|> Ash.create!()

user =
User
|> Ash.Changeset.for_create(:create, %{name: "Marty", org_id: org.id})
|> Ash.create!()

["Back to 1955", "Forwards to 1985", "Forward to 2015", "Back again to 1985"]
|> Enum.map(
&(Post
|> Ash.Changeset.for_create(:create, %{name: &1, user_id: user.id})
|> Ash.create!(tenant: "org_#{org.id}", load: [:last_word]))
)

assert Ash.load!(user, :count_visited, tenant: "org_#{org.id}")
|> then(& &1.count_visited) == 4

assert Ash.load!(org, :total_posts, tenant: "org_#{org.id}")
|> then(& &1.total_posts) == 0

assert Ash.load!(org, :total_users_posts, tenant: "org_#{org.id}")
|> then(& &1.total_users_posts) == 4
end
end

describe "join filters" do
test "with no data, it does not effect the behavior" do
Author
25 changes: 25 additions & 0 deletions test/destroy_test.exs
Original file line number Diff line number Diff line change
@@ -40,4 +40,29 @@ defmodule AshPostgres.DestroyTest do
|> Ash.destroy!()
end
end

test "can optimistic lock" do
post =
Post
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()

post
|> Ash.Changeset.for_update(
:optimistic_lock,
%{
title: "george"
}
)
|> Ash.update!()

assert_raise Ash.Error.Invalid, ~r/Attempted to update stale record/, fn ->
post
|> Ash.Changeset.for_destroy(
:optimistic_lock_destroy,
%{}
)
|> Ash.destroy!()
end
end
end
5 changes: 5 additions & 0 deletions test/support/multitenancy/resources/org.ex
Original file line number Diff line number Diff line change
@@ -59,6 +59,11 @@ defmodule AshPostgres.MultitenancyTest.Org do
parse_attribute({__MODULE__, :tenant, []})
end

aggregates do
count(:total_users_posts, [:users, :posts])
count(:total_posts, :posts)
end

relationships do
belongs_to :owner, AshPostgres.MultitenancyTest.User do
attribute_public?(false)
1 change: 1 addition & 0 deletions test/support/multitenancy/resources/user.ex
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ defmodule AshPostgres.MultitenancyTest.User do

aggregates do
list(:years_visited, :posts, :last_word)
count(:count_visited, :posts)
end

def parse_tenant("org_" <> id), do: id
11 changes: 11 additions & 0 deletions test/support/resources/post.ex
Original file line number Diff line number Diff line change
@@ -396,6 +396,10 @@ defmodule AshPostgres.Test.Post do
change(optimistic_lock(:version))
end

destroy :optimistic_lock_destroy do
change(optimistic_lock(:version))
end

read :read_with_related_list_agg_filter do
pagination(keyset?: true, default_limit: 25)
filter(expr(count_nils(latest_comment.linked_comment_post_ids) == 0))
@@ -846,6 +850,13 @@ defmodule AshPostgres.Test.Post do
filter(title: "match")
end

count :count_of_comments_matching_org_name, [
:posts_with_matching_title,
:comments
] do
filter(expr(parent(organization.name) == title))
end

count(:count_of_comments_containing_title, :comments_containing_title)

first :first_comment, :comments, :title do
20 changes: 17 additions & 3 deletions test/update_test.exs
Original file line number Diff line number Diff line change
@@ -50,16 +50,30 @@ defmodule AshPostgres.UpdateTest do
}
)

Post
|> Ash.Changeset.for_create(:create, %{title: "fred"})
|> Ash.create!()
post =
Post
|> Ash.Changeset.for_create(:create, %{title: "fred"})
|> Ash.create!()

post
|> Ash.Changeset.for_update(
:optimistic_lock,
%{
title: "george"
}
)
|> Ash.update!()

assert_raise Ash.Error.Invalid, ~r/Attempted to update stale record/, fn ->
post
|> Ash.Changeset.for_update(
:optimistic_lock,
%{
title: "harry"
}
)
|> Ash.update!()
end
end

test "timestamps arent updated if there are no changes non-atomically" do