From c31c8685b9b80ecf168e3b5d6ae9fd9f47ca68a9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 25 Jun 2024 08:25:17 -0400 Subject: [PATCH 001/690] docs: remove unused code from docs --- lib/verifiers/validate_identity_index_names.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/verifiers/validate_identity_index_names.ex b/lib/verifiers/validate_identity_index_names.ex index 7c046869..f09b95e9 100644 --- a/lib/verifiers/validate_identity_index_names.ex +++ b/lib/verifiers/validate_identity_index_names.ex @@ -46,7 +46,7 @@ defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do message: """ Identity #{identity.name} has a name that is too long. Names must be 63 characters or less. - Please configure an index name for this identity in the `identity_index_names` configuration. For example:application + Please configure an index name for this identity in the `identity_index_names` configuration. For example: postgres do identity_index_names #{inspect(identity.name)}: "a_shorter_name" From 278b2a31a559b5700e936ddacad4259adf74d935 Mon Sep 17 00:00:00 2001 From: Igor Barakaiev Date: Wed, 26 Jun 2024 15:00:35 +0300 Subject: [PATCH 002/690] fix: configure_runtime/3 in ash_postgres.install (#335) --- lib/mix/tasks/ash_postgres.install.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 61991661..d5ad6401 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -14,7 +14,7 @@ defmodule Mix.Tasks.AshPostgres.Install do |> configure_config(otp_app, repo) |> configure_dev(otp_app, repo) |> configure_test(otp_app, repo) - |> configure_runtime(repo, otp_app) + |> configure_runtime(otp_app, repo) |> Igniter.Project.Application.add_new_child(repo) |> Igniter.add_task("ash.codegen", ["install_ash_postgres"]) end @@ -47,7 +47,7 @@ defmodule Mix.Tasks.AshPostgres.Install do For example: ecto://USER:PASS@HOST/DATABASE \"\"\" - config #{inspect(otp_app)}, Helpdesk.Repo, + config #{inspect(otp_app)}, #{inspect(repo), url: database_url, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") end From 75a87e854aa8df3f065ce717ac3e0bd4b4934874 Mon Sep 17 00:00:00 2001 From: Igor Barakaiev Date: Wed, 26 Jun 2024 18:40:17 +0300 Subject: [PATCH 003/690] fix: typo in configure_runtime/3 (#336) --- lib/mix/tasks/ash_postgres.install.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index d5ad6401..9a835334 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -47,7 +47,7 @@ defmodule Mix.Tasks.AshPostgres.Install do For example: ecto://USER:PASS@HOST/DATABASE \"\"\" - config #{inspect(otp_app)}, #{inspect(repo), + config #{inspect(otp_app)}, #{inspect(repo)}, url: database_url, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") end From c21cb69979069e34bdff745ddfd9cdf7cca42a0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 09:26:22 -0400 Subject: [PATCH 004/690] chore(deps): bump ash_sql in the production-dependencies group (#337) Bumps the production-dependencies group with 1 update: [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash_sql` from 0.2.6 to 0.2.7 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.6...v0.2.7) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 365c80d3..babf23ca 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.0.16", "8eaebd5a9f3ee404937ac811a240799613b0619026e097436132d60eaf18ed16", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.1.18 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "36c0d7653f7fb1d13cc03e1cc7ea7f6b9aadd278b9c9375ff5f0636ed0d7a785"}, - "ash_sql": {:hex, :ash_sql, "0.2.6", "097a191b138af6bd5104ae0e166db5deb443fe3a4616b349fffe98120382765d", [:mix], [{:ash, "~> 3.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", "076abb07d7762537880a12699b756c7c86c1a4e98fcd0dc8c8059de93f7e9265"}, + "ash_sql": {:hex, :ash_sql, "0.2.7", "56bfddcb4cf3edbbf702e2b665497309e43672fbf449ef049f4805211b9cd1b7", [:mix], [{:ash, "~> 3.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", "14622713cc08ede8fd0d2618b1718d759a6ee28839b8f738e6ee084703bd9437"}, "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"}, "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, @@ -37,12 +37,12 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, "reactor": {:hex, :reactor, "0.8.4", "344d02ba4a0010763851f4e4aa0ff190ebe7e392e3c27c6cd143dde077b986e7", [:mix], [{:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49c1fd3c786603cec8140ce941c41c7ea72cc4411860ccdee9876c4ca2204f81"}, - "req": {:hex, :req, "0.5.0", "6d8a77c25cfc03e06a439fb12ffb51beade53e3fe0e2c5e362899a18b50298b3", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "dda04878c1396eebbfdec6db6f3d4ca609e5c8846b7ee88cc56eb9891406f7a3"}, + "req": {:hex, :req, "0.5.1", "90584216d064389a4ff2d4279fe2c11ff6c812ab00fa01a9fb9d15457f65ba70", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7ea96a1a95388eb0fefa92d89466cdfedba24032794e5c1147d78ec90db7edca"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.3.0", "70ab9e8bf6df085a1effba4b49ad621b7153b065f69ef6cdb82e6088f2026029", [:mix], [], "hexpm", "1794c3ceeca4eb3f9437261721e4d9cbf846d7c64c7aee4f64062b18d5ce1eac"}, - "spark": {:hex, :spark, "2.2.4", "077363750eec4d80ffd4b20075676d17fce8bf82af1aa6aa51d2a539685b8d83", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "fd92bdd4508852bcd445c463d0536d0f130ed828d90401d17a061bcdeca4372a"}, + "sourceror": {:hex, :sourceror, "1.4.0", "be87319b1579191e25464005d465713079b3fd7124a3938a1e6cf4def39735a9", [:mix], [], "hexpm", "16751ca55e3895f2228938b703ad399b0b27acfe288eff6c0e629ed3e6ec0358"}, + "spark": {:hex, :spark, "2.2.5", "3cc24cd72484d8aa87843ddeeda7e92def4c7a5608fcf4021ac2bc1ff27a7b26", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "cac25824be88e5baa4720d298e63aef5c0865b07cb5c4a6d9f8ee21e172f3f95"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 844d9b0717e2da64b45e5dd2706cf918739151b5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 27 Jun 2024 13:48:56 -0400 Subject: [PATCH 005/690] chore: fix 1.17 warning --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index feda08dc..b51da973 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1549,7 +1549,7 @@ defmodule AshPostgres.DataLayer do ecto_changeset = case changeset.data do %Ash.Changeset.OriginalDataNotAvailable{} -> - changeset.resource.__struct__ + changeset.resource.__struct__() data -> data From 58311f715241663fc7d1919b51d5990832596e69 Mon Sep 17 00:00:00 2001 From: Igor Barakaiev Date: Fri, 28 Jun 2024 00:05:53 +0300 Subject: [PATCH 006/690] fix: check for existing installed_extensions/0 in ash_postgres.install (#338) --- lib/mix/tasks/ash_postgres.install.ex | 28 +++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 9a835334..b3593096 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -217,9 +217,9 @@ defmodule Mix.Tasks.AshPostgres.Install do |> Sourceror.Zipper.top() |> use_ash_postgres_instead_of_ecto() |> Sourceror.Zipper.top() - |> add_installed_extensions_function() - |> Sourceror.Zipper.top() |> remove_adapter_option() + |> Sourceror.Zipper.top() + |> configure_installed_extensions_function() end) end @@ -270,15 +270,27 @@ defmodule Mix.Tasks.AshPostgres.Install do end end - defp add_installed_extensions_function(zipper) do + defp configure_installed_extensions_function(zipper) do case Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo) do {:ok, zipper} -> - Igniter.Code.Common.add_code(zipper, """ - def installed_extensions do - # Add extensions here, and the migration generator will install them. - ["ash-functions"] + case Igniter.Code.Module.move_to_def(zipper, :installed_extensions, 0) do + {:ok, zipper} -> + case Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do + {:ok, zipper} -> + Igniter.Code.List.append_new_to_list(zipper, "ash-functions") + + :error -> + {:error, "installed_extensions/0 doesn't return a list"} + end + + _ -> + Igniter.Code.Common.add_code(zipper, """ + def installed_extensions do + # Add extensions here, and the migration generator will install them. + ["ash-functions"] + end + """) end - """) _ -> zipper From ead7db2af7ab26d0e56e26170ef616e696631228 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Sat, 29 Jun 2024 16:20:41 +0300 Subject: [PATCH 007/690] improvement: order keys in snapshot json (#339) --- .../migration_generator.ex | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 85f4f7c0..e395c403 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -316,13 +316,10 @@ defmodule AshPostgres.MigrationGenerator do installed = Enum.map(requesteds, fn {name, _extension} -> name end) snapshot_contents = - Jason.encode!( - %{ - installed: installed - } - |> set_ash_functions(installed), - pretty: true - ) + %{installed: installed} + |> set_ash_functions(installed) + |> to_ordered_object() + |> Jason.encode!(pretty: true) contents = format(migration_file, contents, opts) @@ -3029,6 +3026,7 @@ defmodule AshPostgres.MigrationGenerator do %{identity | keys: keys} end) end) + |> to_ordered_object() |> Jason.encode!(pretty: true) end @@ -3313,4 +3311,15 @@ defmodule AshPostgres.MigrationGenerator do defp maybe_to_atom(value) when is_atom(value), do: value defp maybe_to_atom(value), do: String.to_atom(value) + + defp to_ordered_object(value) when is_map(value) do + value + |> Map.to_list() + |> List.keysort(0) + |> Enum.map(fn {key, value} -> {key, to_ordered_object(value)} end) + |> Jason.OrderedObject.new() + end + + defp to_ordered_object(value) when is_list(value), do: Enum.map(value, &to_ordered_object/1) + defp to_ordered_object(value), do: value end From e42665b14c82cff6f57bd09b18d00ecfa391427e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 1 Jul 2024 21:34:23 -0400 Subject: [PATCH 008/690] chore: update to latest igniter --- mix.exs | 1 + mix.lock | 8 +- .../test_no_sandbox_repo/extensions.json | 10 ++ .../multitenant_orgs/20240627223225.json | 83 ++++++++++++ .../20240627223224_install_5_extensions.exs | 120 ++++++++++++++++++ .../20240627223225_migrate_resources31.exs | 31 +++++ test/multitenancy_test.exs | 21 ++- test/support/multitenancy/resources/org.ex | 21 ++- 8 files changed, 288 insertions(+), 7 deletions(-) create mode 100644 priv/resource_snapshots/test_no_sandbox_repo/extensions.json create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json create mode 100644 priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs create mode 100644 priv/test_repo/migrations/20240627223225_migrate_resources31.exs diff --git a/mix.exs b/mix.exs index d09bb7a1..a75adc4c 100644 --- a/mix.exs +++ b/mix.exs @@ -164,6 +164,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.0 and >= 3.0.15")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.6")}, + {:igniter, "~> 0.2.5"}, {:ecto_sql, "~> 3.9"}, {:ecto, "~> 3.9"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index babf23ca..cda8d477 100644 --- a/mix.lock +++ b/mix.lock @@ -22,15 +22,15 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, - "igniter": {:hex, :igniter, "0.2.3", "932295ef076390ee655dbf761f6cdcf3dc5c993439ac3c950de6d823ef45c4d1", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.3", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "0e9702d58aa592594e5aad5ca28a50e7bd01d536152d0a64ea4bd3684e58aea1"}, - "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, + "igniter": {:hex, :igniter, "0.2.5", "c380ed5e2bffaf73691c330e39f9c21d62bc22ba2c84a59cefba8722be0e1f75", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "ee47845498db546cd56df24f0d71444ba4a827d931b38e3244cf744c33577b52"}, + "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "mint": {:hex, :mint, "1.6.1", "065e8a5bc9bbd46a41099dfea3e0656436c5cbcb6e741c80bd2bad5cd872446f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4fc518dcc191d02f433393a72a7ba3f6f94b101d094cb6bf532ea54c89423780"}, + "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, "mix_audit": {:hex, :mix_audit, "2.1.3", "c70983d5cab5dca923f9a6efe559abfb4ec3f8e87762f02bab00fa4106d17eda", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "8c3987100b23099aea2f2df0af4d296701efd031affb08d0746b2be9e35988ec"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, diff --git a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json new file mode 100644 index 00000000..e084bbff --- /dev/null +++ b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json @@ -0,0 +1,10 @@ +{ + "installed": [ + "ash-functions", + "uuid-ossp", + "pg_trgm", + "citext", + "demo-functions_v1" + ], + "ash_functions_version": 3 +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json b/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json new file mode 100644 index 00000000..fe1362dd --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json @@ -0,0 +1,83 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "primary_key?": true, + "allow_nil?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "name", + "references": null, + "primary_key?": false, + "allow_nil?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "owner_id", + "references": { + "name": "multitenant_orgs_owner_id_fkey", + "table": "users", + "multitenancy": { + "global": true, + "attribute": "org_id", + "strategy": "attribute" + }, + "destination_attribute": "id", + "primary_key?": true, + "schema": "public", + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "index?": false, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "primary_key?": false, + "allow_nil?": true, + "generated?": false + } + ], + "table": "multitenant_orgs", + "hash": "1346D9753C87606612C2B8191FB25221E5AE36698710A1182F9876FA9A6F2C5B", + "repo": "Elixir.AshPostgres.TestRepo", + "identities": [ + { + "name": "unique_by_name", + "keys": [ + { + "type": "atom", + "value": "name" + } + ], + "where": null, + "base_filter": null, + "all_tenants?": false, + "nils_distinct?": true, + "index_name": "multitenant_orgs_unique_by_name_index" + } + ], + "multitenancy": { + "global": true, + "attribute": "id", + "strategy": "attribute" + }, + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs b/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs new file mode 100644 index 00000000..09446bc3 --- /dev/null +++ b/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs @@ -0,0 +1,120 @@ +defmodule AshPostgres.TestNoSandboxRepo.Migrations.Install5Extensions20240627223222 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_or(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) + AS $$ SELECT COALESCE(NULLIF($1, FALSE), $2) $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_or(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) + AS $$ SELECT COALESCE($1, $2) $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_and(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ + SELECT CASE + WHEN $1 IS TRUE THEN $2 + ELSE $1 + END $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_and(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ + SELECT CASE + WHEN $1 IS NOT NULL THEN $2 + ELSE $1 + END $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_trim_whitespace(arr text[]) + RETURNS text[] AS $$ + DECLARE + start_index INT = 1; + end_index INT = array_length(arr, 1); + BEGIN + WHILE start_index <= end_index AND arr[start_index] = '' LOOP + start_index := start_index + 1; + END LOOP; + + WHILE end_index >= start_index AND arr[end_index] = '' LOOP + end_index := end_index - 1; + END LOOP; + + IF start_index > end_index THEN + RETURN ARRAY[]::text[]; + ELSE + RETURN arr[start_index : end_index]; + END IF; + END; $$ + LANGUAGE plpgsql + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error(json_data jsonb) + RETURNS BOOLEAN AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error(json_data jsonb, type_signal ANYCOMPATIBLE) + RETURNS ANYCOMPATIBLE AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql; + """) + + execute("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"") + execute("CREATE EXTENSION IF NOT EXISTS \"pg_trgm\"") + execute("CREATE EXTENSION IF NOT EXISTS \"citext\"") + + execute(""" + CREATE OR REPLACE FUNCTION ash_demo_functions() + RETURNS boolean AS $$ SELECT TRUE $$ + LANGUAGE SQL + IMMUTABLE; + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute( + "DROP FUNCTION IF EXISTS ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[])" + ) + + # execute("DROP EXTENSION IF EXISTS \"uuid-ossp\"") + # execute("DROP EXTENSION IF EXISTS \"pg_trgm\"") + # execute("DROP EXTENSION IF EXISTS \"citext\"") + execute(""" + DROP FUNCTION IF EXISTS ash_demo_functions() + """) + end +end diff --git a/priv/test_repo/migrations/20240627223225_migrate_resources31.exs b/priv/test_repo/migrations/20240627223225_migrate_resources31.exs new file mode 100644 index 00000000..8a90e3d4 --- /dev/null +++ b/priv/test_repo/migrations/20240627223225_migrate_resources31.exs @@ -0,0 +1,31 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources31 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:multitenant_orgs) do + add( + :owner_id, + references(:users, + column: :id, + name: "multitenant_orgs_owner_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + end + + def down do + drop(constraint(:multitenant_orgs, "multitenant_orgs_owner_id_fkey")) + + alter table(:multitenant_orgs) do + remove(:owner_id) + end + end +end diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index cb69da08..9b88b434 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -6,12 +6,12 @@ defmodule AshPostgres.Test.MultitenancyTest do setup do org1 = Org - |> Ash.Changeset.for_create(:create, %{name: "test1"}) + |> Ash.Changeset.for_create(:create, %{name: "test1"}, authorize?: false) |> Ash.create!() org2 = Org - |> Ash.Changeset.for_create(:create, %{name: "test2"}) + |> Ash.Changeset.for_create(:create, %{name: "test2"}, authorize?: false) |> Ash.create!() [org1: org1, org2: org2] @@ -37,6 +37,23 @@ defmodule AshPostgres.Test.MultitenancyTest do |> Ash.read!() end + test "attribute multitenancy works with authorization", %{org1: org1} do + user = + User + |> Ash.Changeset.new() + |> Ash.Changeset.manage_relationship(:org, org1, type: :append_and_remove) + |> Ash.create!() + + Logger.configure(level: :debug) + + assert [] = + Org + |> Ash.Query.set_tenant(tenant(org1)) + |> Ash.Query.for_read(:has_policies, %{}, actor: user, authorize?: true) + |> Ash.read!() + |> IO.inspect() + end + test "context multitenancy works with policies", %{org1: org1} do post = Post diff --git a/test/support/multitenancy/resources/org.ex b/test/support/multitenancy/resources/org.ex index 1ac913ab..b155dde0 100644 --- a/test/support/multitenancy/resources/org.ex +++ b/test/support/multitenancy/resources/org.ex @@ -2,7 +2,18 @@ defmodule AshPostgres.MultitenancyTest.Org do @moduledoc false use Ash.Resource, domain: AshPostgres.MultitenancyTest.Domain, - data_layer: AshPostgres.DataLayer + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + policies do + policy action(:has_policies) do + authorize_if(relates_to_actor_via(:owner)) + end + + # policy always() do + # authorize_if(always()) + # end + end identities do identity(:unique_by_name, [:name]) @@ -17,6 +28,8 @@ defmodule AshPostgres.MultitenancyTest.Org do default_accept(:*) defaults([:create, :read, :update, :destroy]) + + read(:has_policies) end postgres do @@ -36,6 +49,12 @@ defmodule AshPostgres.MultitenancyTest.Org do end relationships do + belongs_to :owner, AshPostgres.MultitenancyTest.User do + attribute_public?(false) + public?(false) + attribute_type(:string) + end + has_many(:posts, AshPostgres.MultitenancyTest.Post, destination_attribute: :org_id, public?: true From 185e9bea832707235f2ae2d8a393e4f553e8209b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 2 Jul 2024 12:30:25 -0400 Subject: [PATCH 009/690] test: adjustments for tests --- config/config.exs | 4 ++++ test/multitenancy_test.exs | 3 --- test/support/multitenancy/domain.ex | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/config/config.exs b/config/config.exs index 24a02437..2b5d4262 100644 --- a/config/config.exs +++ b/config/config.exs @@ -55,5 +55,9 @@ if Mix.env() == :test do AshPostgres.Test.ComplexCalculations.Domain ] + config :ash, :compatible_foreign_key_types, [ + {Ash.Type.String, Ash.Type.UUID} + ] + config :logger, level: :warning end diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 9b88b434..5d107f2b 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -44,14 +44,11 @@ defmodule AshPostgres.Test.MultitenancyTest do |> Ash.Changeset.manage_relationship(:org, org1, type: :append_and_remove) |> Ash.create!() - Logger.configure(level: :debug) - assert [] = Org |> Ash.Query.set_tenant(tenant(org1)) |> Ash.Query.for_read(:has_policies, %{}, actor: user, authorize?: true) |> Ash.read!() - |> IO.inspect() end test "context multitenancy works with policies", %{org1: org1} do diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 664b3919..68a5d9de 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -8,4 +8,8 @@ defmodule AshPostgres.MultitenancyTest.Domain do resource(AshPostgres.MultitenancyTest.Post) resource(AshPostgres.MultitenancyTest.PostLink) end + + authorization do + authorize(:when_requested) + end end From 7d41e69a112170baf9b285314c42c69ebf4730ab Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 2 Jul 2024 12:46:03 -0400 Subject: [PATCH 010/690] chore: gen migrations --- .../multitenant_orgs/20240702164513.json | 83 +++++++++++++++++++ .../20240702164513_migrate_resources32.exs | 23 +++++ 2 files changed, 106 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json create mode 100644 priv/test_repo/migrations/20240702164513_migrate_resources32.exs diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json b/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json new file mode 100644 index 00000000..a7d1b16c --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json @@ -0,0 +1,83 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": "org_id", + "global": true, + "strategy": "attribute" + }, + "name": "multitenant_orgs_owner_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "users" + }, + "size": null, + "source": "owner_id", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "8A0A6960023A27597EB918B7EDCA957E5AA9C78D3BE83FE7924A1F5BFA531F6C", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "multitenant_orgs_unique_by_name_index", + "keys": [ + { + "type": "atom", + "value": "name" + } + ], + "name": "unique_by_name", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "multitenant_orgs" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240702164513_migrate_resources32.exs b/priv/test_repo/migrations/20240702164513_migrate_resources32.exs new file mode 100644 index 00000000..fed5ff72 --- /dev/null +++ b/priv/test_repo/migrations/20240702164513_migrate_resources32.exs @@ -0,0 +1,23 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources32 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:multitenant_orgs) do + remove(:owner_id) + add(:owner_id, :text) + end + end + + def down do + alter table(:multitenant_orgs) do + remove(:owner_id) + add(:owner_id, :uuid) + end + end +end From ffd3ff5a81042752c8f79b6c826c02fc0dc41ef5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 2 Jul 2024 13:01:54 -0400 Subject: [PATCH 011/690] test: rollback change for uuid -> string type in tests --- .../20240702164513_migrate_resources32.exs | 23 ------------------- test/support/multitenancy/resources/org.ex | 1 - 2 files changed, 24 deletions(-) delete mode 100644 priv/test_repo/migrations/20240702164513_migrate_resources32.exs diff --git a/priv/test_repo/migrations/20240702164513_migrate_resources32.exs b/priv/test_repo/migrations/20240702164513_migrate_resources32.exs deleted file mode 100644 index fed5ff72..00000000 --- a/priv/test_repo/migrations/20240702164513_migrate_resources32.exs +++ /dev/null @@ -1,23 +0,0 @@ -defmodule AshPostgres.TestRepo.Migrations.MigrateResources32 do - @moduledoc """ - Updates resources based on their most recent snapshots. - - This file was autogenerated with `mix ash_postgres.generate_migrations` - """ - - use Ecto.Migration - - def up do - alter table(:multitenant_orgs) do - remove(:owner_id) - add(:owner_id, :text) - end - end - - def down do - alter table(:multitenant_orgs) do - remove(:owner_id) - add(:owner_id, :uuid) - end - end -end diff --git a/test/support/multitenancy/resources/org.ex b/test/support/multitenancy/resources/org.ex index b155dde0..3d1353c8 100644 --- a/test/support/multitenancy/resources/org.ex +++ b/test/support/multitenancy/resources/org.ex @@ -52,7 +52,6 @@ defmodule AshPostgres.MultitenancyTest.Org do belongs_to :owner, AshPostgres.MultitenancyTest.User do attribute_public?(false) public?(false) - attribute_type(:string) end has_many(:posts, AshPostgres.MultitenancyTest.Post, From e42be3818361172551a0984d232a27eb9e132f71 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 2 Jul 2024 18:07:50 -0400 Subject: [PATCH 012/690] chore: update to latest igniter goodies --- lib/data_layer.ex | 6 +++--- lib/mix/tasks/ash_postgres.install.ex | 28 ++++++++++++++------------- mix.exs | 2 +- mix.lock | 4 ++-- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index b51da973..488e9fe9 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2922,7 +2922,7 @@ defmodule AshPostgres.DataLayer do end if Code.ensure_loaded?(Igniter) do - def install(igniter, module, Ash.Resource, path, _argv) do + def install(igniter, module, Ash.Resource, _path, _argv) do table_name = module |> Module.split() @@ -2932,8 +2932,8 @@ defmodule AshPostgres.DataLayer do repo = Igniter.Code.Module.module_name("Repo") igniter - |> Spark.Igniter.set_option(Ash.Resource, path, [:postgres, :table], table_name) - |> Spark.Igniter.set_option(Ash.Resource, path, [:postgres, :repo], repo) + |> Spark.Igniter.set_option(module, [:postgres, :table], table_name) + |> Spark.Igniter.set_option(module, [:postgres, :repo], repo) end def install(igniter, _, _, _), do: igniter diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index b3593096..bf4a05c5 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -196,8 +196,6 @@ defmodule Mix.Tasks.AshPostgres.Install do end defp setup_repo_module(igniter, otp_app, repo) do - path = Igniter.Code.Module.proper_location(repo) - default_repo_contents = """ defmodule #{inspect(repo)} do @@ -210,17 +208,21 @@ defmodule Mix.Tasks.AshPostgres.Install do end """ - igniter - |> Igniter.create_or_update_elixir_file(path, default_repo_contents, fn zipper -> - zipper - |> set_otp_app(otp_app) - |> Sourceror.Zipper.top() - |> use_ash_postgres_instead_of_ecto() - |> Sourceror.Zipper.top() - |> remove_adapter_option() - |> Sourceror.Zipper.top() - |> configure_installed_extensions_function() - end) + Igniter.Code.Module.find_and_update_or_create_module( + igniter, + repo, + default_repo_contents, + fn zipper -> + zipper + |> set_otp_app(otp_app) + |> Sourceror.Zipper.top() + |> use_ash_postgres_instead_of_ecto() + |> Sourceror.Zipper.top() + |> remove_adapter_option() + |> Sourceror.Zipper.top() + |> configure_installed_extensions_function() + end + ) end defp use_ash_postgres_instead_of_ecto(zipper) do diff --git a/mix.exs b/mix.exs index a75adc4c..e8fbf66f 100644 --- a/mix.exs +++ b/mix.exs @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.0 and >= 3.0.15")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.6")}, - {:igniter, "~> 0.2.5"}, + {:igniter, "~> 0.2.6"}, {:ecto_sql, "~> 3.9"}, {:ecto, "~> 3.9"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index cda8d477..575f5658 100644 --- a/mix.lock +++ b/mix.lock @@ -3,7 +3,7 @@ "ash_sql": {:hex, :ash_sql, "0.2.7", "56bfddcb4cf3edbbf702e2b665497309e43672fbf449ef049f4805211b9cd1b7", [:mix], [{:ash, "~> 3.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", "14622713cc08ede8fd0d2618b1718d759a6ee28839b8f738e6ee084703bd9437"}, "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"}, - "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, + "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, - "igniter": {:hex, :igniter, "0.2.5", "c380ed5e2bffaf73691c330e39f9c21d62bc22ba2c84a59cefba8722be0e1f75", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "ee47845498db546cd56df24f0d71444ba4a827d931b38e3244cf744c33577b52"}, + "igniter": {:hex, :igniter, "0.2.6", "472a4b97c779dd9f30d3947e23217a7e20bff840fde83a16ca70ce96ca76a803", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "a234c958b90f152fd4145ebaa6463731e24a9bb83749586ac890e37b9868c1c6"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, From bc42cce55bb4fd69f406a619afdec4abd716e785 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 3 Jul 2024 11:52:01 -0400 Subject: [PATCH 013/690] chore: generate migrations --- mix.lock | 2 +- .../multitenant_orgs/20240703155134.json | 83 +++++++++++++++++++ .../20240703155134_migrate_resources32.exs | 21 +++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json create mode 100644 priv/test_repo/migrations/20240703155134_migrate_resources32.exs diff --git a/mix.lock b/mix.lock index 575f5658..32333712 100644 --- a/mix.lock +++ b/mix.lock @@ -42,7 +42,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.4.0", "be87319b1579191e25464005d465713079b3fd7124a3938a1e6cf4def39735a9", [:mix], [], "hexpm", "16751ca55e3895f2228938b703ad399b0b27acfe288eff6c0e629ed3e6ec0358"}, - "spark": {:hex, :spark, "2.2.5", "3cc24cd72484d8aa87843ddeeda7e92def4c7a5608fcf4021ac2bc1ff27a7b26", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "cac25824be88e5baa4720d298e63aef5c0865b07cb5c4a6d9f8ee21e172f3f95"}, + "spark": {:hex, :spark, "2.2.7", "96113e09a52a2a95fd696e06f310950132aabfacf5c7b34e0666d26ce4a7b7a7", [:mix], [{:igniter, "~> 0.2.6", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "e192add56a260382d4d270e1490401786f96545b86d67b466544cecb48c3f9a4"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json b/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json new file mode 100644 index 00000000..fe64338e --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json @@ -0,0 +1,83 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": "org_id", + "global": true, + "strategy": "attribute" + }, + "name": "multitenant_orgs_owner_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "users" + }, + "size": null, + "source": "owner_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "18F627A5130D3D2AED877928324A6A9310B894EFB30F35CA8A2136B5CB0E42A7", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "multitenant_orgs_unique_by_name_index", + "keys": [ + { + "type": "atom", + "value": "name" + } + ], + "name": "unique_by_name", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "multitenant_orgs" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240703155134_migrate_resources32.exs b/priv/test_repo/migrations/20240703155134_migrate_resources32.exs new file mode 100644 index 00000000..47f472a2 --- /dev/null +++ b/priv/test_repo/migrations/20240703155134_migrate_resources32.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources32 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:multitenant_orgs) do + modify(:owner_id, :uuid) + end + end + + def down do + alter table(:multitenant_orgs) do + modify(:owner_id, :text) + end + end +end From ffbfc1c23abb646dcb304e085e99d99b399a6096 Mon Sep 17 00:00:00 2001 From: Igor Barakaiev Date: Wed, 3 Jul 2024 18:12:37 +0200 Subject: [PATCH 014/690] fix: default_repo_contents in ash_postgres.install (#340) --- lib/mix/tasks/ash_postgres.install.ex | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index bf4a05c5..a0096840 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -198,13 +198,11 @@ defmodule Mix.Tasks.AshPostgres.Install do defp setup_repo_module(igniter, otp_app, repo) do default_repo_contents = """ - defmodule #{inspect(repo)} do - use AshPostgres.Repo, otp_app: #{inspect(otp_app)} + use AshPostgres.Repo, otp_app: #{inspect(otp_app)} - def installed_extensions do - # Add extensions here, and the migration generator will install them. - ["ash-functions"] - end + def installed_extensions do + # Add extensions here, and the migration generator will install them. + ["ash-functions"] end """ From afe4a657e9911c43df8edfb0cb40062a3b4d3b47 Mon Sep 17 00:00:00 2001 From: Rebecca Le <543859+sevenseacat@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:45:42 +0800 Subject: [PATCH 015/690] docs: Add note that `nulls_distinct` requires PostgreSQL 15 (#341) Unfortunately it's not an option on indexes in PostgreSQL 14 :( https://www.postgresql.org/docs/14/sql-createindex.html --- lib/custom_index.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/custom_index.ex b/lib/custom_index.ex index 4b77cae3..3a4e6a8c 100644 --- a/lib/custom_index.ex +++ b/lib/custom_index.ex @@ -62,7 +62,7 @@ defmodule AshPostgres.CustomIndex do ], nulls_distinct: [ type: :boolean, - doc: "specify whether null values should be considered distinct for a unique index.", + doc: "specify whether null values should be considered distinct for a unique index. Requires PostgreSQL 15 or later", default: true ], message: [ From 3741bbc0b30d31c87cab96b276242f47fccb7610 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Fri, 5 Jul 2024 18:29:23 +0200 Subject: [PATCH 016/690] chore: fix 1.17 warning (#343) --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 488e9fe9..ff14f31e 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1263,7 +1263,7 @@ defmodule AshPostgres.DataLayer do ecto_changeset = case changeset.data do %Ash.Changeset.OriginalDataNotAvailable{} -> - changeset.resource.__struct__ + changeset.resource.__struct__() data -> data From f0d07a3a4db5b9c6488221a33820be384786f9e8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 6 Jul 2024 06:38:06 -0400 Subject: [PATCH 017/690] fix: ensure that `from_many?` relationships in lateral join are limited --- lib/data_layer.ex | 7 +++++++ mix.lock | 2 +- test/load_test.exs | 29 +++++++++++++++++++++++++++++ test/support/resources/comment.ex | 13 +++++++++++++ test/support/resources/post.ex | 6 ++++++ 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index ff14f31e..a1813511 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -995,6 +995,13 @@ defmodule AshPostgres.DataLayer do query end + base_query = + if Map.get(relationship, :from_many?) do + from(row in base_query, limit: 1) + else + base_query + end + base_query = cond do Map.get(relationship, :manual) -> diff --git a/mix.lock b/mix.lock index 32333712..c9451722 100644 --- a/mix.lock +++ b/mix.lock @@ -29,7 +29,7 @@ "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, "mix_audit": {:hex, :mix_audit, "2.1.3", "c70983d5cab5dca923f9a6efe559abfb4ec3f8e87762f02bab00fa4106d17eda", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "8c3987100b23099aea2f2df0af4d296701efd031affb08d0746b2be9e35988ec"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, diff --git a/test/load_test.exs b/test/load_test.exs index 4ab6d325..f37920e0 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -24,6 +24,35 @@ defmodule AshPostgres.Test.LoadTest do assert [%Post{comments: [%{title: "match"}]}] = results end + test "has_one relationships properly limit in the data layer" do + assert %Post{comments: %Ash.NotLoaded{type: :relationship}} = + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + :timer.sleep(1) + + assert %{id: second_comment_id} = + Comment + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Logger.configure(level: :debug) + + assert %{id: ^second_comment_id} = + Post + |> Ash.Query.load(latest_comment: [:expects_only_one_comment]) + |> Ash.read_one!() + |> Map.get(:latest_comment) + end + test "belongs_to relationships can be loaded" do assert %Comment{post: %Ash.NotLoaded{type: :relationship}} = comment = diff --git a/test/support/resources/comment.ex b/test/support/resources/comment.ex index 4253fbc9..82bccc9a 100644 --- a/test/support/resources/comment.ex +++ b/test/support/resources/comment.ex @@ -50,6 +50,19 @@ defmodule AshPostgres.Test.Comment do list(:posts_for_comments_containing_title, [:post, :comments_containing_title, :post], :title) end + calculations do + calculate(:expects_only_one_comment, :string, fn records, _ -> + if Enum.count(records) > 1 do + raise "expected only one comment" + end + + {:ok, + Enum.map(records, fn _ -> + "hello" + end)} + end) + end + relationships do belongs_to(:post, AshPostgres.Test.Post) do public?(true) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index c59dcfaf..e9f46e52 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -306,6 +306,12 @@ defmodule AshPostgres.Test.Post do has_many(:comments, AshPostgres.Test.Comment, destination_attribute: :post_id, public?: true) + has_one :latest_comment, AshPostgres.Test.Comment do + sort(created_at: :desc) + from_many?(true) + public?(true) + end + has_many :comments_matching_post_title, AshPostgres.Test.Comment do public?(true) filter(expr(title == parent_expr(title))) From 3385bd21f10ec9878248b5f1e2acb2fd98d4105c Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Mon, 8 Jul 2024 15:54:50 +0200 Subject: [PATCH 018/690] improvement: add storage type option (#342) --------- Co-authored-by: Zach Daniel --- .formatter.exs | 1 + .../dsls/DSL:-AshPostgres.DataLayer.md | 3 +- lib/custom_index.ex | 3 +- lib/data_layer.ex | 6 ++ lib/data_layer/info.ex | 5 ++ lib/sql_implementation.ex | 24 ++++++ mix.exs | 2 +- mix.lock | 4 +- .../test_repo/authors/20240705113722.json | 82 +++++++++++++++++++ .../20240705113722_migrate_resources33.exs | 21 +++++ test/storage_types_test.exs | 45 ++++++++++ test/support/resources/author.ex | 4 + 12 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/authors/20240705113722.json create mode 100644 priv/test_repo/migrations/20240705113722_migrate_resources33.exs create mode 100644 test/storage_types_test.exs diff --git a/.formatter.exs b/.formatter.exs index 8211617e..b9c6f498 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -43,6 +43,7 @@ spark_locals_without_parens = [ skip_unique_indexes: 1, statement: 1, statement: 2, + storage_types: 1, table: 1, template: 1, unique: 1, diff --git a/documentation/dsls/DSL:-AshPostgres.DataLayer.md b/documentation/dsls/DSL:-AshPostgres.DataLayer.md index 2579f609..bc5f18c8 100644 --- a/documentation/dsls/DSL:-AshPostgres.DataLayer.md +++ b/documentation/dsls/DSL:-AshPostgres.DataLayer.md @@ -40,6 +40,7 @@ end |------|------|---------|------| | [`repo`](#postgres-repo){: #postgres-repo .spark-required} | `module \| (any, any -> any)` | | The repo that will be used to fetch your data. See the `AshPostgres.Repo` documentation for more. Can also be a function that takes a resource and a type `:read \| :mutate` and returns the repo | | [`migrate?`](#postgres-migrate?){: #postgres-migrate? } | `boolean` | `true` | Whether or not to include this resource in the generated migrations with `mix ash.generate_migrations` | +| [`storage_types`](#postgres-storage_types){: #postgres-storage_types } | `keyword` | `[]` | A keyword list of attribute names to the ecto type that should be used for that attribute. Only necessary if you need to override the defaults. | | [`migration_types`](#postgres-migration_types){: #postgres-migration_types } | `keyword` | `[]` | A keyword list of attribute names to the ecto migration type that should be used for that attribute. Only necessary if you need to override the defaults. | | [`migration_defaults`](#postgres-migration_defaults){: #postgres-migration_defaults } | `keyword` | `[]` | A keyword list of attribute names to the ecto migration default that should be used for that attribute. The string you use will be placed verbatim in the migration. Use fragments like `fragment(\\"now()\\")`, or for `nil`, use `\\"nil\\"`. | | [`calculations_to_sql`](#postgres-calculations_to_sql){: #postgres-calculations_to_sql } | `keyword` | | A keyword list of calculations and their SQL representation. Used when creating unique indexes for identities over calculations | @@ -114,7 +115,7 @@ index ["column", "column2"], unique: true, where: "thing = TRUE" | [`prefix`](#postgres-custom_indexes-index-prefix){: #postgres-custom_indexes-index-prefix } | `String.t` | | specify an optional prefix for the index. | | [`where`](#postgres-custom_indexes-index-where){: #postgres-custom_indexes-index-where } | `String.t` | | specify conditions for a partial index. | | [`include`](#postgres-custom_indexes-index-include){: #postgres-custom_indexes-index-include } | `list(String.t)` | | specify fields for a covering index. This is not supported by all databases. For more information on PostgreSQL support, please read the official docs. | -| [`nulls_distinct`](#postgres-custom_indexes-index-nulls_distinct){: #postgres-custom_indexes-index-nulls_distinct } | `boolean` | `true` | specify whether null values should be considered distinct for a unique index. | +| [`nulls_distinct`](#postgres-custom_indexes-index-nulls_distinct){: #postgres-custom_indexes-index-nulls_distinct } | `boolean` | `true` | specify whether null values should be considered distinct for a unique index. Requires PostgreSQL 15 or later | | [`message`](#postgres-custom_indexes-index-message){: #postgres-custom_indexes-index-message } | `String.t` | | A custom message to use for unique indexes that have been violated | | [`all_tenants?`](#postgres-custom_indexes-index-all_tenants?){: #postgres-custom_indexes-index-all_tenants? } | `boolean` | `false` | Whether or not the index should factor in the multitenancy attribute or not. | diff --git a/lib/custom_index.ex b/lib/custom_index.ex index 3a4e6a8c..9d037331 100644 --- a/lib/custom_index.ex +++ b/lib/custom_index.ex @@ -62,7 +62,8 @@ defmodule AshPostgres.CustomIndex do ], nulls_distinct: [ type: :boolean, - doc: "specify whether null values should be considered distinct for a unique index. Requires PostgreSQL 15 or later", + doc: + "specify whether null values should be considered distinct for a unique index. Requires PostgreSQL 15 or later", default: true ], message: [ diff --git a/lib/data_layer.ex b/lib/data_layer.ex index a1813511..d218f9cf 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -287,6 +287,12 @@ defmodule AshPostgres.DataLayer do doc: "Whether or not to include this resource in the generated migrations with `mix ash.generate_migrations`" ], + storage_types: [ + type: :keyword_list, + default: [], + doc: + "A keyword list of attribute names to the ecto type that should be used for that attribute. Only necessary if you need to override the defaults." + ], migration_types: [ type: :keyword_list, default: [], diff --git a/lib/data_layer/info.ex b/lib/data_layer/info.ex index b16c252f..5dcec0ad 100644 --- a/lib/data_layer/info.ex +++ b/lib/data_layer/info.ex @@ -78,6 +78,11 @@ defmodule AshPostgres.DataLayer.Info do Extension.get_opt(resource, [:postgres], :migration_types, []) end + @doc "A keyword list of customized storage types" + def storage_types(resource) do + Extension.get_opt(resource, [:postgres], :storage_types, []) + end + @doc "A keyword list of customized migration defaults" def migration_defaults(resource) do Extension.get_opt(resource, [:postgres], :migration_defaults, []) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 61ea99c0..836cc93b 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -17,6 +17,30 @@ defmodule AshPostgres.SqlImplementation do def require_extension_for_citext, do: {true, "citext"} @impl true + def storage_type(resource, field) do + case AshPostgres.DataLayer.Info.storage_types(resource)[field] do + nil -> + nil + + {:array, type} -> + parameterized_type({:array, Ash.Type.get_type(type)}, [], false) + + {:array, type, constraints} -> + parameterized_type({:array, Ash.Type.get_type(type)}, constraints, false) + + {type, constraints} -> + parameterized_type(type, constraints, false) + + type -> + parameterized_type(type, [], false) + end + end + + @impl true + def expr(_query, [], _bindings, _embedded?, acc, type) when type in [:map, :jsonb] do + {:ok, Ecto.Query.dynamic(fragment("'[]'::jsonb")), acc} + end + def expr( query, %like{arguments: [arg1, arg2], embedded?: pred_embedded?}, diff --git a/mix.exs b/mix.exs index e8fbf66f..5c37afa0 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.0 and >= 3.0.15")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.6")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.8")}, {:igniter, "~> 0.2.6"}, {:ecto_sql, "~> 3.9"}, {:ecto, "~> 3.9"}, diff --git a/mix.lock b/mix.lock index c9451722..1151b00b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,12 +1,12 @@ %{ "ash": {:hex, :ash, "3.0.16", "8eaebd5a9f3ee404937ac811a240799613b0619026e097436132d60eaf18ed16", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.1.18 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "36c0d7653f7fb1d13cc03e1cc7ea7f6b9aadd278b9c9375ff5f0636ed0d7a785"}, - "ash_sql": {:hex, :ash_sql, "0.2.7", "56bfddcb4cf3edbbf702e2b665497309e43672fbf449ef049f4805211b9cd1b7", [:mix], [{:ash, "~> 3.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", "14622713cc08ede8fd0d2618b1718d759a6ee28839b8f738e6ee084703bd9437"}, + "ash_sql": {:hex, :ash_sql, "0.2.8", "ad20dc5487b68a095a12f84918d8ffab4bef12de59b7c5cf962a7c1dc03f5d81", [:mix], [{:ash, "~> 3.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", "d120568a19f3d72a634c3bfa9ce5fa0fae1d3c44ee4cdb8c78f151e490bf849b"}, "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"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, - "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"}, + "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, diff --git a/priv/resource_snapshots/test_repo/authors/20240705113722.json b/priv/resource_snapshots/test_repo/authors/20240705113722.json new file mode 100644 index 00000000..c5e6fdf7 --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20240705113722.json @@ -0,0 +1,82 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "first_name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "last_name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "bio", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "bios", + "type": "jsonb" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "badges", + "type": [ + "array", + "text" + ] + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "D0080403BD79419DCA499838D2BE1F8AE2744F28A2ADC775B74D8EDA0EC11DB1", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "authors" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240705113722_migrate_resources33.exs b/priv/test_repo/migrations/20240705113722_migrate_resources33.exs new file mode 100644 index 00000000..e06ec7c7 --- /dev/null +++ b/priv/test_repo/migrations/20240705113722_migrate_resources33.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources33 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:authors) do + add(:bios, :jsonb) + end + end + + def down do + alter table(:authors) do + remove(:bios) + end + end +end diff --git a/test/storage_types_test.exs b/test/storage_types_test.exs new file mode 100644 index 00000000..dde647b3 --- /dev/null +++ b/test/storage_types_test.exs @@ -0,0 +1,45 @@ +defmodule AshPostgres.StorageTypesTest do + use AshPostgres.RepoCase, async: false + + alias Ash.BulkResult + alias AshPostgres.Test.Author + + require Ash.Query + + test "can save {:array, :map} as jsonb" do + %{id: id} = + Author + |> Ash.Changeset.for_create( + :create, + %{bios: [%{title: "bio1"}, %{title: "bio2"}]} + ) + |> Ash.create!() + + # testing empty list edge case + %BulkResult{records: [author]} = + Author + |> Ash.Query.filter(id == ^id) + |> Ash.bulk_update(:update, %{bios: []}, + return_errors?: true, + notify?: true, + strategy: [:atomic, :stream, :atomic_batches], + allow_stream_with: :full_read, + return_records?: true + ) + + assert author.bios == [] + + %BulkResult{records: [author]} = + Author + |> Ash.Query.filter(id == ^id) + |> Ash.bulk_update(:update, %{bios: [%{a: 1}]}, + return_errors?: true, + notify?: true, + strategy: [:atomic, :stream, :atomic_batches], + allow_stream_with: :full_read, + return_records?: true + ) + + assert author.bios == [%{"a" => 1}] + end +end diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index 170cb98c..dd358005 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -18,6 +18,9 @@ defmodule AshPostgres.Test.Author do postgres do table("authors") repo(AshPostgres.TestRepo) + + migration_types bios: :jsonb + storage_types(bios: :jsonb) end attributes do @@ -25,6 +28,7 @@ defmodule AshPostgres.Test.Author do attribute(:first_name, :string, public?: true) attribute(:last_name, :string, public?: true) attribute(:bio, AshPostgres.Test.Bio, public?: true) + attribute(:bios, {:array, :map}, public?: true) attribute(:badges, {:array, :atom}, public?: true) end From d293d0f3024ccbebe495f7868daa10517f2ba2c4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 8 Jul 2024 15:56:58 -0400 Subject: [PATCH 019/690] improvement: use `Ash.Igniter.codegen` --- lib/mix/tasks/ash_postgres.install.ex | 2 +- test/load_test.exs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index a0096840..98cd1b9e 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -16,7 +16,7 @@ defmodule Mix.Tasks.AshPostgres.Install do |> configure_test(otp_app, repo) |> configure_runtime(otp_app, repo) |> Igniter.Project.Application.add_new_child(repo) - |> Igniter.add_task("ash.codegen", ["install_ash_postgres"]) + |> Ash.Igniter.codegen("install_ash_postgres") end defp configure_config(igniter, otp_app, repo) do diff --git a/test/load_test.exs b/test/load_test.exs index f37920e0..dd9b0e9d 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -44,8 +44,6 @@ defmodule AshPostgres.Test.LoadTest do |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) |> Ash.create!() - Logger.configure(level: :debug) - assert %{id: ^second_comment_id} = Post |> Ash.Query.load(latest_comment: [:expects_only_one_comment]) From 24576c168c51550b17a0c11b7ec1d2a33792eca9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 07:54:50 -0400 Subject: [PATCH 020/690] fix: ensure that we return `{:ok, zipper}` from `find_and_update_or_create_module` closes #345 --- lib/mix/tasks/ash_postgres.install.ex | 1 + test/atomics_test.exs | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 98cd1b9e..da6fbd21 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -219,6 +219,7 @@ defmodule Mix.Tasks.AshPostgres.Install do |> remove_adapter_option() |> Sourceror.Zipper.top() |> configure_installed_extensions_function() + |> then(&{:ok, &1}) end ) end diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 95d4712c..573b7f21 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -119,9 +119,10 @@ defmodule AshPostgres.AtomicsTest do |> Ash.create!() # just asserting that there is no exception here - post - |> Ash.Changeset.for_update(:change_title_to_foo_unless_its_already_foo) - |> Ash.update!() + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.limit(1) + |> Ash.bulk_update!(:change_title_to_foo_unless_its_already_foo, %{}) end test "an atomic works with a datetime" do From 1f370b6357a6173a7691b1ce324894aacb9a4422 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 11:19:46 -0400 Subject: [PATCH 021/690] docs: update readme with note on version support --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2d9bb79d..fa7bcfc3 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,10 @@ Welcome! `AshPostgres` is the PostgreSQL data layer for [Ash Framework](https://hexdocs.pm/ash). +> ### What versions are supported? {: .info} +> +> Any version higher than 13 is fully supported. Versions lower than this can be made to work, but certain edge cases may need to be manually handled. This becomes more and more true the further back in versions that you go. + ## Tutorials - [Get Started](documentation/tutorials/get-started-with-ash-postgres.md) From a930457d87347c4b5f120814b6ca72d2c6deb5f8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 11:20:36 -0400 Subject: [PATCH 022/690] docs: move new note to what-is-ash-postgres.md --- README.md | 4 ---- .../topics/about-ash-postgres/what-is-ash-postgres.md | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fa7bcfc3..2d9bb79d 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,6 @@ Welcome! `AshPostgres` is the PostgreSQL data layer for [Ash Framework](https://hexdocs.pm/ash). -> ### What versions are supported? {: .info} -> -> Any version higher than 13 is fully supported. Versions lower than this can be made to work, but certain edge cases may need to be manually handled. This becomes more and more true the further back in versions that you go. - ## Tutorials - [Get Started](documentation/tutorials/get-started-with-ash-postgres.md) diff --git a/documentation/topics/about-ash-postgres/what-is-ash-postgres.md b/documentation/topics/about-ash-postgres/what-is-ash-postgres.md index 253c4df3..883b3512 100644 --- a/documentation/topics/about-ash-postgres/what-is-ash-postgres.md +++ b/documentation/topics/about-ash-postgres/what-is-ash-postgres.md @@ -2,6 +2,10 @@ AshPostgres is the PostgreSQL `Ash.DataLayer` for [Ash Framework](https://hexdocs.pm/ash). This is the most fully-featured Ash data layer, and unless you need a specific characteristic or feature of another data layer, you should use `AshPostgres`. +> ### What versions are supported? {: .info} +> +> Any version higher than 13 is fully supported. Versions lower than this can be made to work, but certain edge cases may need to be manually handled. This becomes more and more true the further back in versions that you go. + Use this to persist records in a PostgreSQL table or view. For example, the resource below would be persisted in a table called `tweets`: ```elixir From 7dae2408d4676f5d4b23f654947f9239541697fc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 17:43:06 -0400 Subject: [PATCH 023/690] chore: choose a shorter name for mix task --- lib/mix/tasks/ash_postgres.install.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index da6fbd21..364a315b 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -16,7 +16,7 @@ defmodule Mix.Tasks.AshPostgres.Install do |> configure_test(otp_app, repo) |> configure_runtime(otp_app, repo) |> Igniter.Project.Application.add_new_child(repo) - |> Ash.Igniter.codegen("install_ash_postgres") + |> Ash.Igniter.codegen("initialize") end defp configure_config(igniter, otp_app, repo) do From edb24ef923da465bb3616c8fa6a1320d86705cd6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 19:57:04 -0400 Subject: [PATCH 024/690] chore: update to ash 3.1 --- mix.exs | 4 ++-- mix.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.exs b/mix.exs index 5c37afa0..d7ee138e 100644 --- a/mix.exs +++ b/mix.exs @@ -162,9 +162,9 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.0 and >= 3.0.15")}, + {:ash, ash_version("~> 3.1")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.8")}, - {:igniter, "~> 0.2.6"}, + {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.9"}, {:ecto, "~> 3.9"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index 1151b00b..b4def659 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.0.16", "8eaebd5a9f3ee404937ac811a240799613b0619026e097436132d60eaf18ed16", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.1.18 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "36c0d7653f7fb1d13cc03e1cc7ea7f6b9aadd278b9c9375ff5f0636ed0d7a785"}, + "ash": {:hex, :ash, "3.1.0", "ad8ccd2271a0802b1a657c3558b4ace005ace46ddb3cf262713c891e5b0bdd6b", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.7", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "04b311a93127dc2ac84aeca0ff45c43236e01dfe120ede2c15d5827eef2194c0"}, "ash_sql": {:hex, :ash_sql, "0.2.8", "ad20dc5487b68a095a12f84918d8ffab4bef12de59b7c5cf962a7c1dc03f5d81", [:mix], [{:ash, "~> 3.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", "d120568a19f3d72a634c3bfa9ce5fa0fae1d3c44ee4cdb8c78f151e490bf849b"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, - "igniter": {:hex, :igniter, "0.2.6", "472a4b97c779dd9f30d3947e23217a7e20bff840fde83a16ca70ce96ca76a803", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "a234c958b90f152fd4145ebaa6463731e24a9bb83749586ac890e37b9868c1c6"}, + "igniter": {:hex, :igniter, "0.2.9", "7ef177063b417b6efbc74e57f05b5f3aad65b783f345df03462a2d5547d2bfa9", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "659e36a263325e7f87a8b1b09ef2387308a2ff12b917c27012cbaa0c46c957c9"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, @@ -37,7 +37,7 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, "reactor": {:hex, :reactor, "0.8.4", "344d02ba4a0010763851f4e4aa0ff190ebe7e392e3c27c6cd143dde077b986e7", [:mix], [{:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49c1fd3c786603cec8140ce941c41c7ea72cc4411860ccdee9876c4ca2204f81"}, - "req": {:hex, :req, "0.5.1", "90584216d064389a4ff2d4279fe2c11ff6c812ab00fa01a9fb9d15457f65ba70", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7ea96a1a95388eb0fefa92d89466cdfedba24032794e5c1147d78ec90db7edca"}, + "req": {:hex, :req, "0.5.2", "70b4976e5fbefe84e5a57fd3eea49d4e9aa0ac015301275490eafeaec380f97f", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0c63539ab4c2d6ced6114d2684276cef18ac185ee00674ee9af4b1febba1f986"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, From 72b029be218e2b4c8d611f8490f2a697e1aa51ab Mon Sep 17 00:00:00 2001 From: Alessio Montagnani Date: Wed, 10 Jul 2024 01:57:38 +0200 Subject: [PATCH 025/690] improvement: add support for `:uuid_v7` type (#333) --- lib/migration_generator/ash_functions.ex | 79 +++++++++++++++++-- .../migration_generator.ex | 4 + .../test_repo/extensions.json | 2 +- ...2715_install_ash-functions_extension_4.exs | 54 +++++++++++++ test/migration_generator_test.exs | 10 +++ 5 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index 957f8689..04eefa24 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -1,5 +1,5 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do - @latest_version 3 + @latest_version 4 def latest_version, do: @latest_version @@ -66,6 +66,8 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do \"\"\") #{ash_raise_error()} + + #{uuid_generate_v7()} """ end @@ -89,6 +91,8 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do #{ash_raise_error()} + #{uuid_generate_v7()} + execute(\"\"\" CREATE OR REPLACE FUNCTION ash_trim_whitespace(arr text[]) RETURNS text[] AS $$ @@ -117,27 +121,47 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do end def install(1) do - ash_raise_error() + """ + #{ash_raise_error()} + + #{uuid_generate_v7()} + """ end def install(2) do - ash_raise_error() + """ + #{ash_raise_error()} + + #{uuid_generate_v7()} + """ + end + + def install(3) do + uuid_generate_v7() + end + + def drop(3) do + "execute(\"DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid)\")" end def drop(2) do - ash_raise_error(false) + """ + #{ash_raise_error()} + + "execute(\"DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid)\")" + """ end def drop(1) do - "execute(\"DROP FUNCTION IF EXISTS ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE)\")" + "execute(\"DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE)\")" end def drop(0) do - "execute(\"DROP FUNCTION IF EXISTS ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_trim_whitespace(text[])\")" + "execute(\"DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_trim_whitespace(text[])\")" end def drop(nil) do - "execute(\"DROP FUNCTION IF EXISTS ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[])\")" + "execute(\"DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[])\")" end defp ash_raise_error(prefix? \\ true) do @@ -174,4 +198,45 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do \"\"\") """ end + + defp uuid_generate_v7 do + """ + execute(\"\"\" + CREATE OR REPLACE FUNCTION uuid_generate_v7() + RETURNS UUID + AS $$ + DECLARE + timestamp TIMESTAMPTZ; + microseconds INT; + BEGIN + timestamp = clock_timestamp(); + microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT; + + RETURN encode( + set_byte( + set_byte( + overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6 + ), + 6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int + ), + 7, microseconds::bit(8)::int + ), + 'hex')::UUID; + END + $$ + LANGUAGE PLPGSQL + VOLATILE; + \"\"\") + + execute(\"\"\" + CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid) + RETURNS TIMESTAMP WITHOUT TIME ZONE + AS $$ + SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); + $$ + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE STRICT LEAKPROOF; + \"\"\") + """ + end end diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index e395c403..a6138ebc 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2848,6 +2848,7 @@ defmodule AshPostgres.MigrationGenerator do defp migration_type(Ash.Type.CiString, _), do: :citext defp migration_type(Ash.Type.UUID, _), do: :uuid + defp migration_type(Ash.Type.UUIDv7, _), do: :uuid defp migration_type(Ash.Type.Integer, _), do: :bigint defp migration_type(other, constraints) do @@ -2938,6 +2939,9 @@ defmodule AshPostgres.MigrationGenerator do default in @uuid_functions -> ~S[fragment("gen_random_uuid()")] + default == (&Ash.UUIDv7.generate/0) -> + ~S[fragment("uuid_generate_v7()")] + default == (&DateTime.utc_now/0) -> ~S[fragment("(now() AT TIME ZONE 'utc')")] diff --git a/priv/resource_snapshots/test_repo/extensions.json b/priv/resource_snapshots/test_repo/extensions.json index e084bbff..08191fb2 100644 --- a/priv/resource_snapshots/test_repo/extensions.json +++ b/priv/resource_snapshots/test_repo/extensions.json @@ -6,5 +6,5 @@ "citext", "demo-functions_v1" ], - "ash_functions_version": 3 + "ash_functions_version": 4 } \ No newline at end of file diff --git a/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs b/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs new file mode 100644 index 00000000..17c00fcc --- /dev/null +++ b/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs @@ -0,0 +1,54 @@ +defmodule AshPostgres.TestRepo.Migrations.InstallAshFunctionsExtension420240622192713 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute(""" + CREATE OR REPLACE FUNCTION uuid_generate_v7() + RETURNS UUID + AS $$ + DECLARE + timestamp TIMESTAMPTZ; + microseconds INT; + BEGIN + timestamp = clock_timestamp(); + microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT; + + RETURN encode( + set_byte( + set_byte( + overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6 + ), + 6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int + ), + 7, microseconds::bit(8)::int + ), + 'hex')::UUID; + END + $$ + LANGUAGE PLPGSQL + VOLATILE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid) + RETURNS TIMESTAMP WITHOUT TIME ZONE + AS $$ + SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); + $$ + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE STRICT LEAKPROOF; + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute("DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid)") + end +end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 263c826d..de8e12ae 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -97,6 +97,7 @@ defmodule AshPostgres.MigrationGeneratorTest do attributes do uuid_primary_key(:id) + uuid_v7_primary_key(:other_id) attribute(:title, :string, public?: true) attribute(:second_title, :string, public?: true) attribute(:title_with_source, :string, source: :t_w_s, public?: true) @@ -141,6 +142,10 @@ defmodule AshPostgres.MigrationGeneratorTest do assert file_contents =~ ~S[add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true] + # the migration adds the other_id, with its default + assert file_contents =~ + ~S[add :other_id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true] + # the migration adds the id, with its default assert file_contents =~ ~S[add :title_with_default, :text, default: "fred"] @@ -195,6 +200,7 @@ defmodule AshPostgres.MigrationGeneratorTest do attributes do uuid_primary_key(:id) + uuid_v7_primary_key(:other_id) attribute(:title, :string, public?: true) attribute(:second_title, :string, public?: true) end @@ -247,6 +253,10 @@ defmodule AshPostgres.MigrationGeneratorTest do assert file_contents =~ ~S[add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true] + # the migration adds the other_id, with its default + assert file_contents =~ + ~S[add :other_id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true] + # the migration adds other attributes assert file_contents =~ ~S[add :title, :text] From cdbb5e294fafa6a1be7612e80a6408989fba3255 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 20:28:30 -0400 Subject: [PATCH 026/690] chore: ensure proper return value for installer --- lib/mix/tasks/ash_postgres.install.ex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 364a315b..e3b4f1df 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -219,7 +219,6 @@ defmodule Mix.Tasks.AshPostgres.Install do |> remove_adapter_option() |> Sourceror.Zipper.top() |> configure_installed_extensions_function() - |> then(&{:ok, &1}) end ) end @@ -285,16 +284,17 @@ defmodule Mix.Tasks.AshPostgres.Install do end _ -> - Igniter.Code.Common.add_code(zipper, """ - def installed_extensions do - # Add extensions here, and the migration generator will install them. - ["ash-functions"] - end - """) + {:ok, + Igniter.Code.Common.add_code(zipper, """ + def installed_extensions do + # Add extensions here, and the migration generator will install them. + ["ash-functions"] + end + """)} end _ -> - zipper + {:ok, zipper} end end end From 5b9d0ea18ae19aa05ea17a433cae563eb9f2bbe8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 20:40:05 -0400 Subject: [PATCH 027/690] improvement: add DataCase creation for igniter installer (#346) * improvement: add DataCase creation for igniter installer * chore: remove kind favoring path --------- Co-authored-by: Igor Barakaiev --- lib/mix/tasks/ash_postgres.install.ex | 92 ++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index e3b4f1df..3c8f60bd 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -13,8 +13,9 @@ defmodule Mix.Tasks.AshPostgres.Install do |> setup_repo_module(otp_app, repo) |> configure_config(otp_app, repo) |> configure_dev(otp_app, repo) - |> configure_test(otp_app, repo) |> configure_runtime(otp_app, repo) + |> configure_test(otp_app, repo) + |> setup_data_case() |> Igniter.Project.Application.add_new_child(repo) |> Ash.Igniter.codegen("initialize") end @@ -193,6 +194,95 @@ defmodule Mix.Tasks.AshPostgres.Install do Ecto.Adapters.SQL.Sandbox ) |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :pool_size], 10) + |> Igniter.Project.Config.configure_new("test.exs", :ash, :disable_async?, true) + |> Igniter.Project.Config.configure_new("test.exs", :logger, :level, :warning) + end + + defp setup_data_case(igniter) do + default_data_case_contents = """ + @moduledoc \"\"\" + This module defines the setup for tests requiring + access to the application's data layer. + + You may define functions here to be used as helpers in + your tests. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use AshHq.DataCase, async: true`, although + this option is not recommended for other databases. + \"\"\" + + use ExUnit.CaseTemplate + + using do + quote do + alias #{Igniter.Code.Module.module_name_prefix()}.Repo + + import Ecto + import Ecto.Changeset + import Ecto.Query + import #{Igniter.Code.Module.module_name_prefix()}.DataCase + end + end + + setup tags do + pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{Igniter.Code.Module.module_name_prefix()}.Repo, shared: not tags[:async]) + on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) + :ok + end + """ + + module_name = Igniter.Code.Module.module_name("DataCase") + + igniter + |> Igniter.Code.Module.find_and_update_or_create_module( + module_name, + default_data_case_contents, + # do nothing if already exists + fn zipper -> {:ok, zipper} end, + path: Igniter.Code.Module.proper_location(module_name, "test/support") + ) + end + + defp add_test_supports_to_elixirc_paths(igniter) do + Igniter.update_elixir_file(igniter, "mix.exs", fn zipper -> + with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project), + {:ok, zipper} <- Igniter.Code.Module.move_to_def(zipper, :project, 0), + {:ok, zipper} <- + Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do + case Igniter.Code.List.move_to_list_item( + zipper, + &Kernel.match?({:elixirc_paths, _}, &1) + ) do + {:ok, zipper} -> + Sourceror.Zipper.top(zipper) + + _ -> + with {:ok, zipper} <- + Igniter.Code.List.append_to_list( + zipper, + quote(do: {:elixirc_paths, elixirc_paths(Mix.env())}) + ), + zipper <- Sourceror.Zipper.top(zipper), + {:ok, zipper} <- Igniter.Code.Common.move_to_do_block(zipper), + zipper <- + Igniter.Code.Common.add_code( + zipper, + "defp elixirc_paths(:test), do: [\"lib\", \"test/support\"]" + ), + zipper <- + Igniter.Code.Common.add_code( + zipper, + "defp elixirc_paths(_), do: [\"lib\"]" + ) do + zipper + end + end + end + end) end defp setup_repo_module(igniter, otp_app, repo) do From ca27613f9f0efcb069bb3151cbf14fa9559e26b7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 20:42:04 -0400 Subject: [PATCH 028/690] chore: remove unused function --- lib/mix/tasks/ash_postgres.install.ex | 38 --------------------------- 1 file changed, 38 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 3c8f60bd..d7f6ed0c 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -247,44 +247,6 @@ defmodule Mix.Tasks.AshPostgres.Install do ) end - defp add_test_supports_to_elixirc_paths(igniter) do - Igniter.update_elixir_file(igniter, "mix.exs", fn zipper -> - with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project), - {:ok, zipper} <- Igniter.Code.Module.move_to_def(zipper, :project, 0), - {:ok, zipper} <- - Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do - case Igniter.Code.List.move_to_list_item( - zipper, - &Kernel.match?({:elixirc_paths, _}, &1) - ) do - {:ok, zipper} -> - Sourceror.Zipper.top(zipper) - - _ -> - with {:ok, zipper} <- - Igniter.Code.List.append_to_list( - zipper, - quote(do: {:elixirc_paths, elixirc_paths(Mix.env())}) - ), - zipper <- Sourceror.Zipper.top(zipper), - {:ok, zipper} <- Igniter.Code.Common.move_to_do_block(zipper), - zipper <- - Igniter.Code.Common.add_code( - zipper, - "defp elixirc_paths(:test), do: [\"lib\", \"test/support\"]" - ), - zipper <- - Igniter.Code.Common.add_code( - zipper, - "defp elixirc_paths(_), do: [\"lib\"]" - ) do - zipper - end - end - end - end) - end - defp setup_repo_module(igniter, otp_app, repo) do default_repo_contents = """ From a085303da8689f5469566753e2c52b5377306231 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 20:52:25 -0400 Subject: [PATCH 029/690] chore: fix build --- lib/migration_generator/ash_functions.ex | 9 ++------- lib/mix/tasks/ash_postgres.install.ex | 8 ++++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index 04eefa24..db7716d6 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -164,13 +164,8 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do "execute(\"DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[])\")" end - defp ash_raise_error(prefix? \\ true) do - prefix = - if prefix? do - "ash_error: " - else - "" - end + defp ash_raise_error() do + prefix = "ash_error: " """ execute(\"\"\" diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index d7f6ed0c..cd6ef93c 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -194,12 +194,12 @@ defmodule Mix.Tasks.AshPostgres.Install do Ecto.Adapters.SQL.Sandbox ) |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :pool_size], 10) - |> Igniter.Project.Config.configure_new("test.exs", :ash, :disable_async?, true) - |> Igniter.Project.Config.configure_new("test.exs", :logger, :level, :warning) + |> Igniter.Project.Config.configure_new("test.exs", :ash, [:disable_async?], true) + |> Igniter.Project.Config.configure_new("test.exs", :logger, [:level], :warning) end defp setup_data_case(igniter) do - default_data_case_contents = """ + default_data_case_contents = ~S| @moduledoc \"\"\" This module defines the setup for tests requiring access to the application's data layer. @@ -233,7 +233,7 @@ defmodule Mix.Tasks.AshPostgres.Install do on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) :ok end - """ + | module_name = Igniter.Code.Module.module_name("DataCase") From d8b4091c99f8fdfb2c75b46386099ec59e9c5fbf Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 9 Jul 2024 20:53:31 -0400 Subject: [PATCH 030/690] chore: release version v2.1.0 --- CHANGELOG.md | 19 +++++++++++++++++++ mix.exs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index add91b31..9244234b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.0](https://github.com/ash-project/ash_postgres/compare/v2.0.12...v2.1.0) (2024-07-10) + +### Features: + +- [AshPostgres.DataLayer] add `storage_types` configuration (#342) +- [generators] add `mix ash_postgres.install` (`mix igniter.install ash_postgres`) + +### Bug Fixes: + +- [AshPostgres.DataLayer] ensure that `from_many?` relationships in lateral join have a limit applied + +- [migration generator] properly delete args passed from migrate to ecto + +### Improvements: + +- [Ash.Type.UUIDv7] add support for `:uuid_v7` type (#333) + +- [migration generator] order keys in snapshot json (#339) + ## [v2.0.12](https://github.com/ash-project/ash_postgres/compare/v2.0.11...v2.0.12) (2024-06-20) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index d7ee138e..8e4a8d18 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.0.12" + @version "2.1.0" def project do [ From 63324c19e92709617eccc2b9b775bcb651665e28 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 10 Jul 2024 08:47:06 -0400 Subject: [PATCH 031/690] fix: properly interpolate module names in installer --- lib/mix/tasks/ash_postgres.install.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index cd6ef93c..002303ee 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -199,8 +199,8 @@ defmodule Mix.Tasks.AshPostgres.Install do end defp setup_data_case(igniter) do - default_data_case_contents = ~S| - @moduledoc \"\"\" + default_data_case_contents = ~s| + @moduledoc """ This module defines the setup for tests requiring access to the application's data layer. @@ -213,23 +213,23 @@ defmodule Mix.Tasks.AshPostgres.Install do PostgreSQL, you can even run database tests asynchronously by setting `use AshHq.DataCase, async: true`, although this option is not recommended for other databases. - \"\"\" + """ use ExUnit.CaseTemplate using do quote do - alias #{Igniter.Code.Module.module_name_prefix()}.Repo + alias #{inspect(Igniter.Code.Module.module_name(Repo))} import Ecto import Ecto.Changeset import Ecto.Query - import #{Igniter.Code.Module.module_name_prefix()}.DataCase + import #{inspect(Igniter.Code.Module.module_name(DataCase))} end end setup tags do - pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{Igniter.Code.Module.module_name_prefix()}.Repo, shared: not tags[:async]) + pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(Igniter.Code.Module.module_name(Repo))}, shared: not tags[:async]) on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) :ok end From 2a33a8c28542937a002b26fd046240cdf215bc0b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 10 Jul 2024 08:47:31 -0400 Subject: [PATCH 032/690] chore: release version v2.1.1 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9244234b..f05fb603 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.1](https://github.com/ash-project/ash_postgres/compare/v2.1.0...v2.1.1) (2024-07-10) + + + + +### Bug Fixes: + +* properly interpolate module names in installer + ## [v2.1.0](https://github.com/ash-project/ash_postgres/compare/v2.0.12...v2.1.0) (2024-07-10) ### Features: diff --git a/mix.exs b/mix.exs index 8e4a8d18..d187fc18 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.0" + @version "2.1.1" def project do [ From 7dcf19e8952770d9c05da730524b0d577bccac5d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 11 Jul 2024 08:58:13 -0400 Subject: [PATCH 033/690] fix: update ash_sql to fix `select_merge` behavior --- lib/data_layer.ex | 20 -------------------- mix.exs | 2 +- mix.lock | 8 ++++---- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index d218f9cf..1e8c26c1 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1442,16 +1442,6 @@ defmodule AshPostgres.DataLayer do query.limit || query.offset -> with {:ok, root_query} <- AshSql.Atomics.select_atomics(resource, root_query, atomics) do - select = - Enum.map(Ash.Resource.Info.attributes(resource), & &1.name) - - root_query = - Ecto.Query.select_merge( - root_query, - [record], - map(record, ^select) - ) - {:ok, from(row in Ecto.Query.subquery(root_query), []), atomics != []} end @@ -1459,16 +1449,6 @@ defmodule AshPostgres.DataLayer do with root_query <- Ecto.Query.exclude(root_query, :order_by), {:ok, root_query} <- AshSql.Atomics.select_atomics(resource, root_query, atomics) do - select = - Enum.map(Ash.Resource.Info.attributes(resource), & &1.name) - - root_query = - Ecto.Query.select_merge( - root_query, - [record], - map(record, ^select) - ) - {:ok, from(row in Ecto.Query.subquery(root_query), []), atomics != []} end diff --git a/mix.exs b/mix.exs index d187fc18..81c773dc 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.8")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.11")}, {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.9"}, {:ecto, "~> 3.9"}, diff --git a/mix.lock b/mix.lock index b4def659..8cc658e2 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.1.0", "ad8ccd2271a0802b1a657c3558b4ace005ace46ddb3cf262713c891e5b0bdd6b", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.7", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "04b311a93127dc2ac84aeca0ff45c43236e01dfe120ede2c15d5827eef2194c0"}, - "ash_sql": {:hex, :ash_sql, "0.2.8", "ad20dc5487b68a095a12f84918d8ffab4bef12de59b7c5cf962a7c1dc03f5d81", [:mix], [{:ash, "~> 3.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", "d120568a19f3d72a634c3bfa9ce5fa0fae1d3c44ee4cdb8c78f151e490bf849b"}, + "ash": {:hex, :ash, "3.1.2", "be3d955dc59c3d8314d0768cb9652ccb353f3ee1b7f48390220bddbb980065a6", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "f9109e31583112ec3869a248d79796034c65ab332726d0c0025fe7f2200dd373"}, + "ash_sql": {:hex, :ash_sql, "0.2.11", "93d075524b443475f74d46dadd3a66839874860947da0650ecc91f358c59487b", [:mix], [{:ash, "~> 3.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", "1dbb42da5d2240bc7cf3c4a12d5ba2836914121856c17fd4c4e7eb16b7cecc7e"}, "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"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, - "igniter": {:hex, :igniter, "0.2.9", "7ef177063b417b6efbc74e57f05b5f3aad65b783f345df03462a2d5547d2bfa9", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "659e36a263325e7f87a8b1b09ef2387308a2ff12b917c27012cbaa0c46c957c9"}, + "igniter": {:hex, :igniter, "0.2.12", "e2e8fbb15effecb433f4096edbb0754282553544c75c3130d06ca09bdaa1fb13", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "51f3487a13441cd3e6e0d559689f8b0ba2c716834f86802e8a6760fdd1a2e579"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, @@ -36,7 +36,7 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, - "reactor": {:hex, :reactor, "0.8.4", "344d02ba4a0010763851f4e4aa0ff190ebe7e392e3c27c6cd143dde077b986e7", [:mix], [{:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49c1fd3c786603cec8140ce941c41c7ea72cc4411860ccdee9876c4ca2204f81"}, + "reactor": {:hex, :reactor, "0.8.5", "7a621e0392a5975ed97938a4ddbbc92a6a31157fbd87446bc8bc6b1a0f49e56a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17b1976b9d333e55382dc108779078d5bbdbcd2c3d4033ea6dd52437339fe469"}, "req": {:hex, :req, "0.5.2", "70b4976e5fbefe84e5a57fd3eea49d4e9aa0ac015301275490eafeaec380f97f", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0c63539ab4c2d6ced6114d2684276cef18ac185ee00674ee9af4b1febba1f986"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, From 8f77275be62f19e26e31e3d20f6b6e5df1f7a211 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 11 Jul 2024 12:02:31 -0400 Subject: [PATCH 034/690] chore: express dependencies on latest ecto/ecto_sql --- mix.exs | 4 ++-- mix.lock | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index 81c773dc..50508e3c 100644 --- a/mix.exs +++ b/mix.exs @@ -165,8 +165,8 @@ defmodule AshPostgres.MixProject do {:ash, ash_version("~> 3.1")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.11")}, {:igniter, "~> 0.2.9"}, - {:ecto_sql, "~> 3.9"}, - {:ecto, "~> 3.9"}, + {:ecto_sql, "~> 3.11 and >= 3.11.3"}, + {:ecto, "~> 3.11 and >= 3.11.2"}, {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, # dev/test dependencies diff --git a/mix.lock b/mix.lock index 8cc658e2..fc465fb6 100644 --- a/mix.lock +++ b/mix.lock @@ -5,6 +5,7 @@ "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, + "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, From ef58c783137a55a675f152b2fa082bff0e3023e4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 12 Jul 2024 23:23:42 -0400 Subject: [PATCH 035/690] test: add more tests for atomic update interactions chore: get build passing --- lib/migration_generator/ash_functions.ex | 2 +- lib/mix/tasks/ash_postgres.install.ex | 6 +- mix.lock | 7 +- .../test_no_sandbox_repo/extensions.json | 4 +- .../test_repo/posts/20240712232026.json | 449 ++++++++++++++++++ ...2025_install_ash-functions_extension_4.exs | 54 +++ .../20240712232026_migrate_resources34.exs | 21 + test/atomics_test.exs | 28 ++ test/support/resources/post.ex | 11 + 9 files changed, 572 insertions(+), 10 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/posts/20240712232026.json create mode 100644 priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs create mode 100644 priv/test_repo/migrations/20240712232026_migrate_resources34.exs diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index db7716d6..609bb487 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -164,7 +164,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do "execute(\"DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[])\")" end - defp ash_raise_error() do + defp ash_raise_error do prefix = "ash_error: " """ diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 002303ee..002822c6 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -219,17 +219,17 @@ defmodule Mix.Tasks.AshPostgres.Install do using do quote do - alias #{inspect(Igniter.Code.Module.module_name(Repo))} + alias #{inspect(Igniter.Code.Module.module_name("Repo"))} import Ecto import Ecto.Changeset import Ecto.Query - import #{inspect(Igniter.Code.Module.module_name(DataCase))} + import #{inspect(Igniter.Code.Module.module_name("DataCase"))} end end setup tags do - pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(Igniter.Code.Module.module_name(Repo))}, shared: not tags[:async]) + pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(Igniter.Code.Module.module_name("Repo"))}, shared: not tags[:async]) on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) :ok end diff --git a/mix.lock b/mix.lock index fc465fb6..1d939f82 100644 --- a/mix.lock +++ b/mix.lock @@ -1,11 +1,10 @@ %{ - "ash": {:hex, :ash, "3.1.2", "be3d955dc59c3d8314d0768cb9652ccb353f3ee1b7f48390220bddbb980065a6", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "f9109e31583112ec3869a248d79796034c65ab332726d0c0025fe7f2200dd373"}, - "ash_sql": {:hex, :ash_sql, "0.2.11", "93d075524b443475f74d46dadd3a66839874860947da0650ecc91f358c59487b", [:mix], [{:ash, "~> 3.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", "1dbb42da5d2240bc7cf3c4a12d5ba2836914121856c17fd4c4e7eb16b7cecc7e"}, + "ash": {:hex, :ash, "3.1.3", "c5c65e18107247df4857951fa546e720c6e2ef0afde07ad0c2f523725a751eb2", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "530c04f32b2562352e48c92fab50bc837819c6cd3453c4fa9c9842b2e9d8483b"}, + "ash_sql": {:hex, :ash_sql, "0.2.13", "ac5ad6dad827253d156f0913ef005e279d817bf2d216d461fa8ffbff81c7eb34", [:mix], [{:ash, "~> 3.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", "c493a05570873133896412fff43db6ed21f27527907cf6bbd19b380692e6fa9e"}, "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"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, - "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, @@ -14,7 +13,7 @@ "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, - "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "a663c13478a49d29ae0267b6e45badb803267cf0", []}, diff --git a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json index e084bbff..40d20b77 100644 --- a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json +++ b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json @@ -1,10 +1,10 @@ { + "ash_functions_version": 4, "installed": [ "ash-functions", "uuid-ossp", "pg_trgm", "citext", "demo-functions_v1" - ], - "ash_functions_version": 3 + ] } \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/posts/20240712232026.json b/priv/resource_snapshots/test_repo/posts/20240712232026.json new file mode 100644 index 00000000..60d6a6d1 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240712232026.json @@ -0,0 +1,449 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "D85FE48F112749094A13964D840D9B5ECAC765A2BDCBDCC38FB365FC852E87DE", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} diff --git a/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs b/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs new file mode 100644 index 00000000..97101dca --- /dev/null +++ b/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs @@ -0,0 +1,54 @@ +defmodule AshPostgres.TestNoSandboxRepo.Migrations.InstallAshFunctionsExtension420240712232023 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute(""" + CREATE OR REPLACE FUNCTION uuid_generate_v7() + RETURNS UUID + AS $$ + DECLARE + timestamp TIMESTAMPTZ; + microseconds INT; + BEGIN + timestamp = clock_timestamp(); + microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT; + + RETURN encode( + set_byte( + set_byte( + overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6 + ), + 6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int + ), + 7, microseconds::bit(8)::int + ), + 'hex')::UUID; + END + $$ + LANGUAGE PLPGSQL + VOLATILE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid) + RETURNS TIMESTAMP WITHOUT TIME ZONE + AS $$ + SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); + $$ + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE STRICT LEAKPROOF; + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute("DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid)") + end +end diff --git a/priv/test_repo/migrations/20240712232026_migrate_resources34.exs b/priv/test_repo/migrations/20240712232026_migrate_resources34.exs new file mode 100644 index 00000000..af406cf3 --- /dev/null +++ b/priv/test_repo/migrations/20240712232026_migrate_resources34.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources34 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:constrained_int, :bigint) + end + end + + def down do + alter table(:posts) do + remove(:constrained_int) + end + end +end diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 573b7f21..9bfc8b88 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -125,6 +125,34 @@ defmodule AshPostgres.AtomicsTest do |> Ash.bulk_update!(:change_title_to_foo_unless_its_already_foo, %{}) end + test "an atomic validation can refer to an attribute being cast atomically" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "bar"}) + |> Ash.create!() + + # just asserting that there is no exception here + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.limit(1) + |> Ash.bulk_update!(:update_constrained_int, %{amount: 4}) + end + + test "an atomic validation can refer to an attribute being cast atomically, and will raise an error" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "bar"}) + |> Ash.create!() + + # just asserting that there is no exception here + assert_raise Ash.Error.Invalid, ~r/must be less than or equal to 10/, fn -> + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.limit(1) + |> Ash.bulk_update!(:update_constrained_int, %{amount: 12}) + end + end + test "an atomic works with a datetime" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index e9f46e52..980470a1 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -212,6 +212,15 @@ defmodule AshPostgres.Test.Post do require_atomic?(false) manual(AshPostgres.Test.Post.ManualUpdate) end + + update :update_constrained_int do + argument(:amount, :integer, allow_nil?: false) + change(atomic_update(:constrained_int, expr((constrained_int || 0) + ^arg(:amount)))) + + validate(compare(:constrained_int, greater_than_or_equal_to: 2), + message: "You cannot select less than two." + ) + end end identities do @@ -246,6 +255,8 @@ defmodule AshPostgres.Test.Post do public?: true ) + attribute(:constrained_int, :integer, constraints: [min: 1, max: 10]) + attribute(:point, AshPostgres.Test.Point, public?: true) attribute(:composite_point, AshPostgres.Test.CompositePoint, public?: true) attribute(:stuff, :map, public?: true) From 00a9db3cc072bbce00d5e7472e653a676fc9717a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 13 Jul 2024 15:11:38 -0400 Subject: [PATCH 036/690] improvement: detect more cases when detecting types in expressions --- lib/sql_implementation.ex | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 836cc93b..a3fbc8b3 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -450,6 +450,15 @@ defmodule AshPostgres.SqlImplementation do :error end + %{__predicate__?: true} -> + {:ok, {:boolean, []}} + + %Ash.Query.BooleanExpression{} -> + {:ok, {:boolean, []}} + + %Ash.Query.Exists{} -> + {:ok, {:boolean, []}} + _ -> :error end From 27f63d8d8e2db1c3b3ca084f9606e7964c346bdb Mon Sep 17 00:00:00 2001 From: Robert Timis <65460527+TimisRobert@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:06:52 +0200 Subject: [PATCH 037/690] error reproduction test (#349) --- config/config.exs | 4 +- .../test_repo/items/20240713134055.json | 49 +++++++ .../test_repo/other_items/20240713134055.json | 78 +++++++++++ .../test_repo/sub_items/20240713134055.json | 88 ++++++++++++ ...240713134055_multi_domain_calculations.exs | 127 ++++++++++++++++++ test/multi_domain_calculations_test.exs | 28 ++++ .../multi_domain_calculations/domain_one.ex | 8 ++ .../domain_one/item.ex | 39 ++++++ .../multi_domain_calculations/domain_two.ex | 9 ++ .../domain_two/other_item.ex | 51 +++++++ .../domain_two/sub_item.ex | 44 ++++++ 11 files changed, 524 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/items/20240713134055.json create mode 100644 priv/resource_snapshots/test_repo/other_items/20240713134055.json create mode 100644 priv/resource_snapshots/test_repo/sub_items/20240713134055.json create mode 100644 priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs create mode 100644 test/multi_domain_calculations_test.exs create mode 100644 test/support/multi_domain_calculations/domain_one.ex create mode 100644 test/support/multi_domain_calculations/domain_one/item.ex create mode 100644 test/support/multi_domain_calculations/domain_two.ex create mode 100644 test/support/multi_domain_calculations/domain_two/other_item.ex create mode 100644 test/support/multi_domain_calculations/domain_two/sub_item.ex diff --git a/config/config.exs b/config/config.exs index 2b5d4262..4fc036c7 100644 --- a/config/config.exs +++ b/config/config.exs @@ -52,7 +52,9 @@ if Mix.env() == :test do ash_domains: [ AshPostgres.Test.Domain, AshPostgres.MultitenancyTest.Domain, - AshPostgres.Test.ComplexCalculations.Domain + AshPostgres.Test.ComplexCalculations.Domain, + AshPostgres.Test.MultiDomainCalculations.DomainOne, + AshPostgres.Test.MultiDomainCalculations.DomainTwo ] config :ash, :compatible_foreign_key_types, [ diff --git a/priv/resource_snapshots/test_repo/items/20240713134055.json b/priv/resource_snapshots/test_repo/items/20240713134055.json new file mode 100644 index 00000000..f5b6f4a4 --- /dev/null +++ b/priv/resource_snapshots/test_repo/items/20240713134055.json @@ -0,0 +1,49 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"uuid_generate_v7()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "ABF32E9B15960350C650AA0F324442FEE568688B2176BF9441D168A20241CB44", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "items" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/other_items/20240713134055.json b/priv/resource_snapshots/test_repo/other_items/20240713134055.json new file mode 100644 index 00000000..33c8a3db --- /dev/null +++ b/priv/resource_snapshots/test_repo/other_items/20240713134055.json @@ -0,0 +1,78 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"uuid_generate_v7()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": true, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "other_items_item_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "items" + }, + "size": null, + "source": "item_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "8B0ECD0F08C43760F2F875336943046971139E77662FCAF01D5E9BA0B15009B7", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "other_items" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/sub_items/20240713134055.json b/priv/resource_snapshots/test_repo/sub_items/20240713134055.json new file mode 100644 index 00000000..f4ab908f --- /dev/null +++ b/priv/resource_snapshots/test_repo/sub_items/20240713134055.json @@ -0,0 +1,88 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"uuid_generate_v7()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "amount", + "type": "bigint" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": true, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "sub_items_other_item_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "other_items" + }, + "size": null, + "source": "other_item_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "977777A71F41127683F7EB559EB79213EE7516FA45B94D489C8869DD200F02F5", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "sub_items" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs b/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs new file mode 100644 index 00000000..04dce9a0 --- /dev/null +++ b/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs @@ -0,0 +1,127 @@ +defmodule AshPostgres.TestRepo.Migrations.MultiDomainCalculations do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:sub_items, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true) + add(:amount, :bigint, null: false) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:other_item_id, :uuid, null: false) + end + + create table(:other_items, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true) + end + + alter table(:sub_items) do + modify( + :other_item_id, + references(:other_items, + column: :id, + name: "sub_items_other_item_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :delete_all + ) + ) + end + + create(index(:sub_items, [:other_item_id])) + + alter table(:other_items) do + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:item_id, :uuid, null: false) + end + + create table(:items, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true) + end + + alter table(:other_items) do + modify( + :item_id, + references(:items, + column: :id, + name: "other_items_item_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :delete_all + ) + ) + end + + create(index(:other_items, [:item_id])) + + alter table(:items) do + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + end + end + + def down do + alter table(:items) do + remove(:updated_at) + remove(:inserted_at) + end + + drop_if_exists(index(:other_items, [:item_id])) + + drop(constraint(:other_items, "other_items_item_id_fkey")) + + alter table(:other_items) do + modify(:item_id, :uuid) + end + + drop(table(:items)) + + alter table(:other_items) do + remove(:item_id) + remove(:updated_at) + remove(:inserted_at) + end + + drop_if_exists(index(:sub_items, [:other_item_id])) + + drop(constraint(:sub_items, "sub_items_other_item_id_fkey")) + + alter table(:sub_items) do + modify(:other_item_id, :uuid) + end + + drop(table(:other_items)) + + drop(table(:sub_items)) + end +end diff --git a/test/multi_domain_calculations_test.exs b/test/multi_domain_calculations_test.exs new file mode 100644 index 00000000..ba49aeb2 --- /dev/null +++ b/test/multi_domain_calculations_test.exs @@ -0,0 +1,28 @@ +defmodule AshPostgres.Test.MultiDomainCalculationsTest do + use AshPostgres.RepoCase, async: false + + require Ash.Query + + test "total is returned correctly" do + item = + AshPostgres.Test.MultiDomainCalculations.DomainOne.Item + |> Ash.Changeset.for_create(:create, %{}) + |> Ash.create!() + + other_item = + AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem + |> Ash.Changeset.for_create(:create, %{item_id: item.id}) + |> Ash.create!() + + for i <- 0..2 do + AshPostgres.Test.MultiDomainCalculations.DomainTwo.SubItem + |> Ash.Changeset.for_create(:create, %{other_item_id: other_item.id, amount: i}) + |> Ash.create!() + end + + assert %{total_amount: 3} = + Ash.read!(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item, + load: [:total_amount] + ) + end +end diff --git a/test/support/multi_domain_calculations/domain_one.ex b/test/support/multi_domain_calculations/domain_one.ex new file mode 100644 index 00000000..ff4e072f --- /dev/null +++ b/test/support/multi_domain_calculations/domain_one.ex @@ -0,0 +1,8 @@ +defmodule AshPostgres.Test.MultiDomainCalculations.DomainOne do + @moduledoc false + use Ash.Domain + + resources do + resource(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item) + end +end diff --git a/test/support/multi_domain_calculations/domain_one/item.ex b/test/support/multi_domain_calculations/domain_one/item.ex new file mode 100644 index 00000000..5d76e9eb --- /dev/null +++ b/test/support/multi_domain_calculations/domain_one/item.ex @@ -0,0 +1,39 @@ +defmodule AshPostgres.Test.MultiDomainCalculations.DomainOne.Item do + @moduledoc false + + use Ash.Resource, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer], + domain: AshPostgres.Test.MultiDomainCalculations.DomainOne + + alias AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem + + attributes do + uuid_v7_primary_key(:id) + create_timestamp(:inserted_at) + update_timestamp(:updated_at) + end + + relationships do + has_one(:other_item, OtherItem) + end + + actions do + defaults([:read, :destroy, update: :*, create: :*]) + end + + calculations do + calculate(:total_amount, :integer, expr(other_item.total_amount)) + end + + policies do + policy always() do + authorize_if(always()) + end + end + + postgres do + table "items" + repo(AshPostgres.TestRepo) + end +end diff --git a/test/support/multi_domain_calculations/domain_two.ex b/test/support/multi_domain_calculations/domain_two.ex new file mode 100644 index 00000000..f9ccde38 --- /dev/null +++ b/test/support/multi_domain_calculations/domain_two.ex @@ -0,0 +1,9 @@ +defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo do + @moduledoc false + use Ash.Domain + + resources do + resource(AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem) + resource(AshPostgres.Test.MultiDomainCalculations.DomainTwo.SubItem) + end +end diff --git a/test/support/multi_domain_calculations/domain_two/other_item.ex b/test/support/multi_domain_calculations/domain_two/other_item.ex new file mode 100644 index 00000000..60cdea7a --- /dev/null +++ b/test/support/multi_domain_calculations/domain_two/other_item.ex @@ -0,0 +1,51 @@ +defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem do + @moduledoc false + + use Ash.Resource, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer], + domain: AshPostgres.Test.MultiDomainCalculations.DomainTwo + + alias AshPostgres.Test.MultiDomainCalculations.DomainOne.Item + alias AshPostgres.Test.MultiDomainCalculations.DomainTwo.SubItem + + attributes do + uuid_v7_primary_key(:id) + create_timestamp(:inserted_at) + update_timestamp(:updated_at) + end + + relationships do + belongs_to(:item, Item, allow_nil?: false) + has_many(:sub_items, SubItem) + end + + actions do + defaults([:read, :destroy, create: [:*, :item_id], update: :*]) + end + + aggregates do + sum :total_sub_items_amount, :sub_items, :total_amount do + default(0) + end + end + + calculations do + calculate(:total_amount, :integer, expr(total_sub_items_amount)) + end + + policies do + policy always() do + authorize_if(always()) + end + end + + postgres do + table "other_items" + repo(AshPostgres.TestRepo) + + references do + reference :item, on_delete: :delete, index?: true + end + end +end diff --git a/test/support/multi_domain_calculations/domain_two/sub_item.ex b/test/support/multi_domain_calculations/domain_two/sub_item.ex new file mode 100644 index 00000000..c5411e51 --- /dev/null +++ b/test/support/multi_domain_calculations/domain_two/sub_item.ex @@ -0,0 +1,44 @@ +defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.SubItem do + @moduledoc false + + use Ash.Resource, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer], + domain: AshPostgres.Test.MultiDomainCalculations.DomainTwo + + alias AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem + + attributes do + uuid_v7_primary_key(:id) + attribute(:amount, :integer, allow_nil?: false) + create_timestamp(:inserted_at) + update_timestamp(:updated_at) + end + + relationships do + belongs_to(:other_item, OtherItem, allow_nil?: false) + end + + actions do + defaults([:read, :destroy, create: [:*, :other_item_id, :amount], update: :*]) + end + + calculations do + calculate(:total_amount, :integer, expr(amount)) + end + + policies do + policy always() do + authorize_if(always()) + end + end + + postgres do + table "sub_items" + repo(AshPostgres.TestRepo) + + references do + reference :other_item, on_delete: :delete, index?: true + end + end +end From 8aaab0b6d4ab6ae3ce444c4d9b526c508a3d068d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 13 Jul 2024 16:15:03 -0400 Subject: [PATCH 038/690] chore: update ash dependency --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 50508e3c..585871c1 100644 --- a/mix.exs +++ b/mix.exs @@ -162,7 +162,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.1")}, + {:ash, ash_version("~> 3.1 and >= 3.1.4")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.11")}, {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, From 1cabf102be4e70262b4fba49b98f469eb05c1c83 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 13 Jul 2024 16:15:55 -0400 Subject: [PATCH 039/690] chore: release version v2.1.2 --- CHANGELOG.md | 5 +++++ mix.exs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f05fb603..b80cec42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.2](https://github.com/ash-project/ash_postgres/compare/v2.1.1...v2.1.2) (2024-07-13) + + + + ## [v2.1.1](https://github.com/ash-project/ash_postgres/compare/v2.1.0...v2.1.1) (2024-07-10) diff --git a/mix.exs b/mix.exs index 585871c1..b5ecef0f 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.1" + @version "2.1.2" def project do [ From 0803c65694961faea82ed7cc2a3f98e17f10aec2 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 13 Jul 2024 16:16:44 -0400 Subject: [PATCH 040/690] chore: update changelog --- CHANGELOG.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b80cec42..35e5bdf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,17 +7,13 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.1.2](https://github.com/ash-project/ash_postgres/compare/v2.1.1...v2.1.2) (2024-07-13) - - +- [query builder] update ash & improve type casting behavior ## [v2.1.1](https://github.com/ash-project/ash_postgres/compare/v2.1.0...v2.1.1) (2024-07-10) - - - ### Bug Fixes: -* properly interpolate module names in installer +- [mix ash_postgres.install] properly interpolate module names in installer ## [v2.1.0](https://github.com/ash-project/ash_postgres/compare/v2.0.12...v2.1.0) (2024-07-10) From ca02cef7fc17e324b55fb34c64bda22e5f1b417b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 13 Jul 2024 16:17:01 -0400 Subject: [PATCH 041/690] chore: update mix.lock --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 1d939f82..0be76904 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.1.3", "c5c65e18107247df4857951fa546e720c6e2ef0afde07ad0c2f523725a751eb2", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "530c04f32b2562352e48c92fab50bc837819c6cd3453c4fa9c9842b2e9d8483b"}, + "ash": {:hex, :ash, "3.1.4", "5e77bd66d3008b9d03ce1d172cebe6a7a916ea61a715b1a84421819c70cda85a", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "8c5e1b777fdd2ee488c60ea973aa9e1d0da255d2bd362a547482c047f9f0c362"}, "ash_sql": {:hex, :ash_sql, "0.2.13", "ac5ad6dad827253d156f0913ef005e279d817bf2d216d461fa8ffbff81c7eb34", [:mix], [{:ash, "~> 3.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", "c493a05570873133896412fff43db6ed21f27527907cf6bbd19b380692e6fa9e"}, "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"}, From cef4c8fce033868f82abef90138181fb3c612f00 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 14 Jul 2024 09:25:49 -0400 Subject: [PATCH 042/690] improvement: support new type determination code --- lib/data_layer.ex | 1 + lib/sql_implementation.ex | 250 ++------------------------------- mix.exs | 2 +- test/atomics_test.exs | 7 + test/support/resources/post.ex | 8 +- 5 files changed, 28 insertions(+), 240 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 1e8c26c1..69322681 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1,5 +1,6 @@ defmodule AshPostgres.DataLayer do require Ecto.Query + require Ash.Expr @manage_tenant %Spark.Dsl.Section{ name: :manage_tenant, diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index a3fbc8b3..c0530bd4 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -228,247 +228,21 @@ defmodule AshPostgres.SqlImplementation do end @impl true - def determine_types(mod, values) do - Code.ensure_compiled(mod) + def determine_types(mod, args) do + {types, returns} = Ash.Expr.determine_types(mod, args) - name = - cond do - function_exported?(mod, :operator, 0) -> - mod.operator() - - function_exported?(mod, :name, 0) -> - mod.name() - - true -> - nil + returns = + case returns do + {type, constraints} -> parameterized_type(type, constraints) + other -> other end - cond do - :erlang.function_exported(mod, :types, 0) -> - mod.types() - - :erlang.function_exported(mod, :args, 0) -> - mod.args() - - true -> - [:any] - end - |> then(fn types -> - Enum.concat(Map.keys(Ash.Query.Operator.operator_overloads(name) || %{}), types) - end) - |> Enum.reject(&(&1 == :any)) - |> Enum.filter(fn typeset -> - typeset == :same || - length(typeset) == length(values) - end) - |> Enum.find_value(Enum.map(values, fn _ -> nil end), fn typeset -> - types_and_values = - if typeset == :same do - Enum.map(values, &{:same, &1}) - else - Enum.zip(typeset, values) - end - - types_and_values - |> Enum.with_index() - |> Enum.reduce_while(%{must_adopt_basis: [], basis: nil, types: [], fallback_basis: nil}, fn - {{vague_type, value}, index}, acc when vague_type in [:any, :same] -> - case determine_type(value) do - {:ok, {type, constraints}} -> - case acc[:basis] do - nil -> - if vague_type == :any do - acc = Map.update!(acc, :types, &[{type, constraints} | &1]) - {:cont, Map.put(acc, :basis, {type, constraints})} - else - acc = - acc - |> Map.update!(:types, &[nil | &1]) - |> Map.put(:fallback_basis, {type, constraints}) - - {:cont, Map.update!(acc, :must_adopt_basis, &[{index, fn x -> x end} | &1])} - end - - {^type, matched_constraints} -> - {:cont, Map.update!(acc, :types, &[{type, matched_constraints} | &1])} - - _ -> - {:halt, :error} - end - - :error -> - acc = Map.update!(acc, :types, &[nil | &1]) - {:cont, Map.update!(acc, :must_adopt_basis, &[{index, fn x -> x end} | &1])} - end - - {{{:array, vague_type}, value}, index}, acc when vague_type in [:any, :same] -> - case determine_type(value) do - {:ok, {{:array, type}, constraints}} -> - case acc[:basis] do - nil -> - if vague_type == :any do - acc = Map.update!(acc, :types, &[{:array, {type, constraints}} | &1]) - {:cont, Map.put(acc, :basis, {type, constraints})} - else - acc = - acc - |> Map.update!(:types, &[nil | &1]) - |> Map.put(:fallback_basis, {type, constraints}) - - {:cont, - Map.update!( - acc, - :must_adopt_basis, - &[ - {index, - fn {type, constraints} -> {{:array, type}, items: constraints} end} - | &1 - ] - )} - end - - {^type, matched_constraints} -> - {:cont, Map.update!(acc, :types, &[{:array, {type, matched_constraints}} | &1])} - - _ -> - {:halt, :error} - end - - _ -> - acc = Map.update!(acc, :types, &[nil | &1]) - - {:cont, - Map.update!( - acc, - :must_adopt_basis, - &[ - {index, fn {type, constraints} -> {{:array, type}, items: constraints} end} - | &1 - ] - )} - end - - {{{type, constraints}, value}, _index}, acc -> - cond do - !Ash.Expr.expr?(value) && !matches_type?(type, value, constraints) -> - {:halt, :error} - - Ash.Expr.expr?(value) -> - case determine_type(value) do - {:ok, {^type, matched_constraints}} -> - {:cont, Map.update!(acc, :types, &[{type, matched_constraints} | &1])} - - _ -> - {:halt, :error} - end - - true -> - {:cont, Map.update!(acc, :types, &[{type, constraints} | &1])} - end - - {{type, value}, _index}, acc -> - cond do - !Ash.Expr.expr?(value) && !matches_type?(type, value, []) -> - {:halt, :error} - - Ash.Expr.expr?(value) -> - case determine_type(value) do - {:ok, {^type, matched_constraints}} -> - {:cont, Map.update!(acc, :types, &[{type, matched_constraints} | &1])} - - _ -> - {:halt, :error} - end - - true -> - {:cont, Map.update!(acc, :types, &[{type, []} | &1])} - end - end) - |> then(fn - %{basis: nil, fallback_basis: fallback_basis} = data when not is_nil(fallback_basis) -> - %{data | basis: fallback_basis} - - data -> - data - end) - |> case do - :error -> - nil - - %{basis: nil, must_adopt_basis: [], types: types} -> - types - |> Enum.reverse() - |> Enum.map(fn {type, constraints} -> - parameterized_type(type, constraints) - end) - - %{basis: nil, must_adopt_basis: _} -> - nil - - %{basis: basis, must_adopt_basis: basis_adopters, types: types} -> - basis_adopters - |> Enum.reduce( - Enum.reverse(types), - fn {index, function_of_basis}, types -> - List.replace_at(types, index, function_of_basis.(basis)) - end - ) - |> Enum.map(fn {type, constraints} -> - parameterized_type(type, constraints) - end) - end - end) - end - - defp determine_type(value) do - case value do - %Ash.Query.Function.Type{arguments: [_, type, constraints]} -> - if Ash.Type.ash_type?(type) do - {:ok, {type, constraints}} - else - :error - end - - %Ash.Query.Function.Type{arguments: [_, type]} -> - if Ash.Type.ash_type?(type) do - {:ok, {type, []}} - else - :error - end - - %Ash.Query.Ref{attribute: %{type: type, constraints: constraints}} -> - if Ash.Type.ash_type?(type) do - {:ok, {type, constraints}} - else - :error - end - - %Ash.Query.Ref{attribute: %{type: type}} -> - if Ash.Type.ash_type?(type) do - {:ok, {type, []}} - else - :error - end - - %{__predicate__?: true} -> - {:ok, {:boolean, []}} - - %Ash.Query.BooleanExpression{} -> - {:ok, {:boolean, []}} - - %Ash.Query.Exists{} -> - {:ok, {:boolean, []}} - - _ -> - :error - end - end - - defp matches_type?({:array, type}, %MapSet{} = value, constraints) do - Enum.all?(value, &matches_type?(&1, type, constraints[:items])) - end + {Enum.map(types, fn + {type, constraints} -> + parameterized_type(type, constraints) - defp matches_type?(type, value, constraints) do - Ash.Type.matches_type?(type, value, constraints) + other -> + other + end), returns} end end diff --git a/mix.exs b/mix.exs index b5ecef0f..e0d9a9b2 100644 --- a/mix.exs +++ b/mix.exs @@ -162,7 +162,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.1 and >= 3.1.4")}, + {:ash, ash_version("~> 3.1 and >= 3.1.5")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.11")}, {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 9bfc8b88..a0a34200 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -151,6 +151,13 @@ defmodule AshPostgres.AtomicsTest do |> Ash.Query.limit(1) |> Ash.bulk_update!(:update_constrained_int, %{amount: 12}) end + + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "bar", constrained_int: 5}) + |> Ash.create!() + + assert %{constrained_int: 10} = Post.update_constrained_int!(post.id, 5) end test "an atomic works with a datetime" do diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 980470a1..dbcfe9f2 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -255,7 +255,12 @@ defmodule AshPostgres.Test.Post do public?: true ) - attribute(:constrained_int, :integer, constraints: [min: 1, max: 10]) + attribute(:constrained_int, :integer, + constraints: [min: 1, max: 10], + default: 2, + allow_nil?: false, + public?: true + ) attribute(:point, AshPostgres.Test.Point, public?: true) attribute(:composite_point, AshPostgres.Test.CompositePoint, public?: true) @@ -287,6 +292,7 @@ defmodule AshPostgres.Test.Post do define(:get_by_id, action: :read, get_by: [:id]) define(:increment_score, args: [{:optional, :amount}]) define(:destroy) + define(:update_constrained_int, args: [:amount]) end relationships do From f55f146bd7bafb576e43458b46a8d8037aa369fc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 14 Jul 2024 09:26:37 -0400 Subject: [PATCH 043/690] chore: release version v2.1.3 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35e5bdf1..dbdc15bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.3](https://github.com/ash-project/ash_postgres/compare/v2.1.2...v2.1.3) (2024-07-14) + + + + +### Improvements: + +* support new type determination code + ## [v2.1.2](https://github.com/ash-project/ash_postgres/compare/v2.1.1...v2.1.2) (2024-07-13) - [query builder] update ash & improve type casting behavior diff --git a/mix.exs b/mix.exs index e0d9a9b2..a541428c 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.2" + @version "2.1.3" def project do [ From 6a4586795e7b6fd680743d9cf64e4f7e6341e1ec Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 14 Jul 2024 09:27:01 -0400 Subject: [PATCH 044/690] chore: update mix.lock --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 0be76904..a7f6af72 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.1.4", "5e77bd66d3008b9d03ce1d172cebe6a7a916ea61a715b1a84421819c70cda85a", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "8c5e1b777fdd2ee488c60ea973aa9e1d0da255d2bd362a547482c047f9f0c362"}, + "ash": {:hex, :ash, "3.1.5", "2e9b3c54ce5d52661e51ae76cf1648aa47a41876749025760267ca57e153c6ef", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9f43e066e0b478343091242c133d7a32b22f9f9be111d1bc950f76f1609c83e3"}, "ash_sql": {:hex, :ash_sql, "0.2.13", "ac5ad6dad827253d156f0913ef005e279d817bf2d216d461fa8ffbff81c7eb34", [:mix], [{:ash, "~> 3.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", "c493a05570873133896412fff43db6ed21f27527907cf6bbd19b380692e6fa9e"}, "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"}, From bfd3b64dd6b4f76326316e95989986ea9641d43b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 14 Jul 2024 10:07:32 -0400 Subject: [PATCH 045/690] chore: update ash_sql --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index a541428c..ed09179c 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1 and >= 3.1.5")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.11")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.16")}, {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index a7f6af72..51fb1de5 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.1.5", "2e9b3c54ce5d52661e51ae76cf1648aa47a41876749025760267ca57e153c6ef", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9f43e066e0b478343091242c133d7a32b22f9f9be111d1bc950f76f1609c83e3"}, - "ash_sql": {:hex, :ash_sql, "0.2.13", "ac5ad6dad827253d156f0913ef005e279d817bf2d216d461fa8ffbff81c7eb34", [:mix], [{:ash, "~> 3.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", "c493a05570873133896412fff43db6ed21f27527907cf6bbd19b380692e6fa9e"}, + "ash_sql": {:hex, :ash_sql, "0.2.16", "48317c1d353f9c0578dbf9ae7cc913f6d409a8bcccff5c76a81daf2d6d883df6", [:mix], [{:ash, ">= 3.1.5 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", "7355a75bfa335bbaa73e4f7ba429fc487adfc178d054e7aa0af7ea1a57a35b4c"}, "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"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, From da925604a8a467e2f42b2eb5f61754869e654d0f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 14 Jul 2024 11:44:33 -0400 Subject: [PATCH 046/690] improvement: use latest type casting code from ash --- lib/sql_implementation.ex | 10 +++++----- mix.exs | 4 ++-- mix.lock | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index c0530bd4..aa0a7c7e 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -228,11 +228,11 @@ defmodule AshPostgres.SqlImplementation do end @impl true - def determine_types(mod, args) do - {types, returns} = Ash.Expr.determine_types(mod, args) + def determine_types(mod, args, returns \\ nil) do + {types, new_returns} = Ash.Expr.determine_types(mod, args, returns) - returns = - case returns do + new_returns = + case new_returns do {type, constraints} -> parameterized_type(type, constraints) other -> other end @@ -243,6 +243,6 @@ defmodule AshPostgres.SqlImplementation do other -> other - end), returns} + end), new_returns || returns} end end diff --git a/mix.exs b/mix.exs index ed09179c..59ea23c7 100644 --- a/mix.exs +++ b/mix.exs @@ -162,8 +162,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.1 and >= 3.1.5")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.16")}, + {:ash, ash_version("~> 3.1 and >= 3.1.7")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.17")}, {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index 51fb1de5..a18e9712 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.1.5", "2e9b3c54ce5d52661e51ae76cf1648aa47a41876749025760267ca57e153c6ef", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9f43e066e0b478343091242c133d7a32b22f9f9be111d1bc950f76f1609c83e3"}, - "ash_sql": {:hex, :ash_sql, "0.2.16", "48317c1d353f9c0578dbf9ae7cc913f6d409a8bcccff5c76a81daf2d6d883df6", [:mix], [{:ash, ">= 3.1.5 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", "7355a75bfa335bbaa73e4f7ba429fc487adfc178d054e7aa0af7ea1a57a35b4c"}, + "ash": {:hex, :ash, "3.1.7", "99e50347e70dd6fa62c9afa5246ef83e363bb7c0236b2081d7b7f35b6095c099", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "c16b5a8c9dc5bd081b61e76e97abff6f61fbf7f0f34955901755644dcd7519ce"}, + "ash_sql": {:hex, :ash_sql, "0.2.17", "bc548b434ce9ca6f2bf85469ecef9353bfbf99fad11382fe8a2219e16feeb4ff", [:mix], [{:ash, ">= 3.1.7 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", "e2ab3b6b545b20ec037f76af0ddc3a99f9da96f2f7d10f3c17c766b9fd7b6445"}, "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"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, From 1c4a887ba99595dc7c9fa48d5dee716aaae4d839 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 14 Jul 2024 11:45:10 -0400 Subject: [PATCH 047/690] chore: release version v2.1.4 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbdc15bb..221cd765 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.4](https://github.com/ash-project/ash_postgres/compare/v2.1.3...v2.1.4) (2024-07-14) + + + + +### Improvements: + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.3](https://github.com/ash-project/ash_postgres/compare/v2.1.2...v2.1.3) (2024-07-14) diff --git a/mix.exs b/mix.exs index 59ea23c7..cc689cdd 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.3" + @version "2.1.4" def project do [ From 252acd423a0a0417ec67da32408d2ffc482e8cf0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 14 Jul 2024 22:11:06 -0400 Subject: [PATCH 048/690] chore: don't use deprecated function --- lib/mix/tasks/ash_postgres.install.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 002822c6..2231d4d8 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -325,7 +325,7 @@ defmodule Mix.Tasks.AshPostgres.Install do defp configure_installed_extensions_function(zipper) do case Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo) do {:ok, zipper} -> - case Igniter.Code.Module.move_to_def(zipper, :installed_extensions, 0) do + case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do {:ok, zipper} -> case Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do {:ok, zipper} -> From 5a9812f0164dd270d28129c72f6ec80bc7788955 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 09:20:39 -0400 Subject: [PATCH 049/690] fix: ensure synthesized query aggregates have context set --- lib/data_layer.ex | 4 ++-- mix.lock | 4 ++-- test/multi_domain_calculations_test.exs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 69322681..0ed9f72f 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1268,8 +1268,8 @@ defmodule AshPostgres.DataLayer do end @impl true - def resource_to_query(resource, _) do - AshSql.Query.resource_to_query(resource, AshPostgres.SqlImplementation) + def resource_to_query(resource, domain) do + AshSql.Query.resource_to_query(resource, AshPostgres.SqlImplementation, domain) end @impl true diff --git a/mix.lock b/mix.lock index a18e9712..ecbe9eac 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.1.7", "99e50347e70dd6fa62c9afa5246ef83e363bb7c0236b2081d7b7f35b6095c099", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "c16b5a8c9dc5bd081b61e76e97abff6f61fbf7f0f34955901755644dcd7519ce"}, + "ash": {:hex, :ash, "3.1.8", "427fa57ad03185cc3e4ea83179d8a07e8158578ce4048e7485a4f2f9375c4329", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9749695ce573efc3cc9f799697e3aeb3e69e9d4409e90aefc410d55309044182"}, "ash_sql": {:hex, :ash_sql, "0.2.17", "bc548b434ce9ca6f2bf85469ecef9353bfbf99fad11382fe8a2219e16feeb4ff", [:mix], [{:ash, ">= 3.1.7 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", "e2ab3b6b545b20ec037f76af0ddc3a99f9da96f2f7d10f3c17c766b9fd7b6445"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, - "igniter": {:hex, :igniter, "0.2.12", "e2e8fbb15effecb433f4096edbb0754282553544c75c3130d06ca09bdaa1fb13", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "51f3487a13441cd3e6e0d559689f8b0ba2c716834f86802e8a6760fdd1a2e579"}, + "igniter": {:hex, :igniter, "0.2.13", "dbf743887f73de135f38a121e31dd16ce29ea355b1de85c876848fecf335ca0a", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "f6e7e98ac9f42ca5fa6121d4212c6d462049e43fbf91ec56e3b2cf2895eba86b"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, diff --git a/test/multi_domain_calculations_test.exs b/test/multi_domain_calculations_test.exs index ba49aeb2..bf659855 100644 --- a/test/multi_domain_calculations_test.exs +++ b/test/multi_domain_calculations_test.exs @@ -20,7 +20,7 @@ defmodule AshPostgres.Test.MultiDomainCalculationsTest do |> Ash.create!() end - assert %{total_amount: 3} = + assert [%{total_amount: 3}] = Ash.read!(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item, load: [:total_amount] ) From c2596a5d0f932f42edcf24fd56f80b9cb27bb69d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 09:24:59 -0400 Subject: [PATCH 050/690] chore: update ash_sql for fix --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index cc689cdd..954dcb4a 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1 and >= 3.1.7")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.17")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.18")}, {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index ecbe9eac..fb2234b8 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.1.8", "427fa57ad03185cc3e4ea83179d8a07e8158578ce4048e7485a4f2f9375c4329", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9749695ce573efc3cc9f799697e3aeb3e69e9d4409e90aefc410d55309044182"}, - "ash_sql": {:hex, :ash_sql, "0.2.17", "bc548b434ce9ca6f2bf85469ecef9353bfbf99fad11382fe8a2219e16feeb4ff", [:mix], [{:ash, ">= 3.1.7 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", "e2ab3b6b545b20ec037f76af0ddc3a99f9da96f2f7d10f3c17c766b9fd7b6445"}, + "ash_sql": {:hex, :ash_sql, "0.2.18", "2ad66b4cbad0009d78b801948a32507274412d85c76cd90b8d691d37149f07aa", [:mix], [{:ash, ">= 3.1.7 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", "ea1849f397909373cd0b728677f1d5a1155ed7fe5f7e9db03cd16dd5a506d0d6"}, "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"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, From c75875a556010ea5b8c1b980497262960fe37753 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 09:53:36 -0400 Subject: [PATCH 051/690] chore: clean mix.lock --- mix.lock | 7 ------- 1 file changed, 7 deletions(-) diff --git a/mix.lock b/mix.lock index fb2234b8..a6ad9f7e 100644 --- a/mix.lock +++ b/mix.lock @@ -3,7 +3,6 @@ "ash_sql": {:hex, :ash_sql, "0.2.18", "2ad66b4cbad0009d78b801948a32507274412d85c76cd90b8d691d37149f07aa", [:mix], [{:ash, ">= 3.1.7 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", "ea1849f397909373cd0b728677f1d5a1155ed7fe5f7e9db03cd16dd5a506d0d6"}, "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"}, - "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, @@ -18,26 +17,20 @@ "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "a663c13478a49d29ae0267b6e45badb803267cf0", []}, "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, - "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, "igniter": {:hex, :igniter, "0.2.13", "dbf743887f73de135f38a121e31dd16ce29ea355b1de85c876848fecf335ca0a", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "f6e7e98ac9f42ca5fa6121d4212c6d462049e43fbf91ec56e3b2cf2895eba86b"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, - "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, - "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, "mix_audit": {:hex, :mix_audit, "2.1.3", "c70983d5cab5dca923f9a6efe559abfb4ec3f8e87762f02bab00fa4106d17eda", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "8c3987100b23099aea2f2df0af4d296701efd031affb08d0746b2be9e35988ec"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, - "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, "reactor": {:hex, :reactor, "0.8.5", "7a621e0392a5975ed97938a4ddbbc92a6a31157fbd87446bc8bc6b1a0f49e56a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17b1976b9d333e55382dc108779078d5bbdbcd2c3d4033ea6dd52437339fe469"}, - "req": {:hex, :req, "0.5.2", "70b4976e5fbefe84e5a57fd3eea49d4e9aa0ac015301275490eafeaec380f97f", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0c63539ab4c2d6ced6114d2684276cef18ac185ee00674ee9af4b1febba1f986"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, From 52f02506526b0379be60bbf63d81535a267ac188 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 09:54:09 -0400 Subject: [PATCH 052/690] chore: generate migrations --- .../test_repo/posts/20240715135403.json | 449 ++++++++++++++++++ .../20240715135403_migrate_resources35.exs | 21 + 2 files changed, 470 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/posts/20240715135403.json create mode 100644 priv/test_repo/migrations/20240715135403_migrate_resources35.exs diff --git a/priv/resource_snapshots/test_repo/posts/20240715135403.json b/priv/resource_snapshots/test_repo/posts/20240715135403.json new file mode 100644 index 00000000..2aca8e19 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240715135403.json @@ -0,0 +1,449 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "E051B6EFFFE6A769AF04B32B8E148FF2B763024D7781796A4ED44F27B7D15979", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240715135403_migrate_resources35.exs b/priv/test_repo/migrations/20240715135403_migrate_resources35.exs new file mode 100644 index 00000000..5819ea53 --- /dev/null +++ b/priv/test_repo/migrations/20240715135403_migrate_resources35.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources35 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + modify(:constrained_int, :bigint, null: false, default: 2) + end + end + + def down do + alter table(:posts) do + modify(:constrained_int, :bigint, null: true, default: nil) + end + end +end From 6f7d163da8cf386000eee8d3eb112e62a978c000 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 10:00:47 -0400 Subject: [PATCH 053/690] chore: update typespecs --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index a6ad9f7e..ca537d5f 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.1.8", "427fa57ad03185cc3e4ea83179d8a07e8158578ce4048e7485a4f2f9375c4329", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9749695ce573efc3cc9f799697e3aeb3e69e9d4409e90aefc410d55309044182"}, - "ash_sql": {:hex, :ash_sql, "0.2.18", "2ad66b4cbad0009d78b801948a32507274412d85c76cd90b8d691d37149f07aa", [:mix], [{:ash, ">= 3.1.7 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", "ea1849f397909373cd0b728677f1d5a1155ed7fe5f7e9db03cd16dd5a506d0d6"}, + "ash_sql": {:hex, :ash_sql, "0.2.18", "e88b316ae6b820e0b19ddb4487662b24ef661a48de3ae836dda3d18f6de66556", [:mix], [{:ash, ">= 3.1.7 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", "b43c7dfc1136377d55f9082d752503ff1afadccc3aa4d4abde7c09be5e025ef2"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, From ab97b2947b4a5a5fff5017694e6e3424b85f6031 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 10:25:39 -0400 Subject: [PATCH 054/690] improvement: add `binding()` expression --- lib/data_layer.ex | 3 ++- lib/functions/binding.ex | 9 +++++++++ lib/sql_implementation.ex | 15 +++++++++++++++ test/calculation_test.exs | 14 ++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 lib/functions/binding.ex diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 0ed9f72f..450acc8d 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -785,7 +785,8 @@ defmodule AshPostgres.DataLayer do functions = [ AshPostgres.Functions.Like, - AshPostgres.Functions.ILike + AshPostgres.Functions.ILike, + AshPostgres.Functions.Binding ] functions = diff --git a/lib/functions/binding.ex b/lib/functions/binding.ex new file mode 100644 index 00000000..92fc9d6f --- /dev/null +++ b/lib/functions/binding.ex @@ -0,0 +1,9 @@ +defmodule AshPostgres.Functions.Binding do + @moduledoc """ + Refers to the current table binding. + """ + + use Ash.Query.Function, name: :binding + + def args, do: [[]] +end diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index aa0a7c7e..90414cf3 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -41,6 +41,21 @@ defmodule AshPostgres.SqlImplementation do {:ok, Ecto.Query.dynamic(fragment("'[]'::jsonb")), acc} end + def expr(query, %AshPostgres.Functions.Binding{}, _bindings, _embedded?, acc, _type) do + binding = AshSql.Bindings.get_binding( + query.__ash_bindings__.resource, + [], + query, + [:left, :inner, :root] + ) + + if is_nil(binding) do + raise "Error while constructing explicit `binding()` reference." + end + + {:ok, Ecto.Query.dynamic([{^binding, row}], row), acc} + end + def expr( query, %like{arguments: [arg1, arg2], embedded?: pred_embedded?}, diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 186cf112..e15dbbc8 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -800,6 +800,20 @@ defmodule AshPostgres.CalculationTest do |> Ash.read_one!() end + test "binding() can be used to refer to the current binding in a fragment" do + post = + Post + |> Ash.Changeset.for_create(:create, %{}) + |> Ash.create!() + + post_id = post.id + + assert [%{id: ^post_id}] = + Post + |> Ash.Query.filter(fragment("(?).id", binding()) == type(^post.id, :uuid)) + |> Ash.read!() + end + test "exists with a relationship that has a filtered read action works" do post = Post From 39c5a9daf4685247939534c4e9b4ebb628497c74 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 13:52:40 -0400 Subject: [PATCH 055/690] chore: update ash_sql version --- mix.exs | 2 +- mix.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 954dcb4a..06be10c8 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1 and >= 3.1.7")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.18")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.20")}, {:igniter, "~> 0.2.9"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index ca537d5f..f937365c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.1.8", "427fa57ad03185cc3e4ea83179d8a07e8158578ce4048e7485a4f2f9375c4329", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9749695ce573efc3cc9f799697e3aeb3e69e9d4409e90aefc410d55309044182"}, - "ash_sql": {:hex, :ash_sql, "0.2.18", "e88b316ae6b820e0b19ddb4487662b24ef661a48de3ae836dda3d18f6de66556", [:mix], [{:ash, ">= 3.1.7 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", "b43c7dfc1136377d55f9082d752503ff1afadccc3aa4d4abde7c09be5e025ef2"}, + "ash_sql": {:hex, :ash_sql, "0.2.20", "f4e4fbed0954f0652bd5ace2f31f90eabd2e24470d450f66a31905cd381422cb", [:mix], [{:ash, ">= 3.1.7 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", "41a0fdc2e26d6b4b750d4a4b2404ceeae7e9e240bc37052fc2179641a66b6cb3"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -35,7 +35,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.4.0", "be87319b1579191e25464005d465713079b3fd7124a3938a1e6cf4def39735a9", [:mix], [], "hexpm", "16751ca55e3895f2228938b703ad399b0b27acfe288eff6c0e629ed3e6ec0358"}, - "spark": {:hex, :spark, "2.2.7", "96113e09a52a2a95fd696e06f310950132aabfacf5c7b34e0666d26ce4a7b7a7", [:mix], [{:igniter, "~> 0.2.6", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "e192add56a260382d4d270e1490401786f96545b86d67b466544cecb48c3f9a4"}, + "spark": {:hex, :spark, "2.2.8", "f61b5097c43c8562df0e78720be863d21c1c63bc4679c5cdbc8ef063276479de", [:mix], [{:igniter, "~> 0.2.6", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "309db664494a4dd08513476b8f77a65ad513b642773f193e7af6c2181c9b782d"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From a2efec05a6921a1c83162fdeb02ade3fa3fc969f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 13:53:00 -0400 Subject: [PATCH 056/690] chore: release version v2.1.5 --- CHANGELOG.md | 17 +++++++++++++++++ mix.exs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 221cd765..3f82cd3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.5](https://github.com/ash-project/ash_postgres/compare/v2.1.4...v2.1.5) (2024-07-15) + + + + +### Bug Fixes: + +* ensure synthesized query aggregates have context set + +### Improvements: + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.4](https://github.com/ash-project/ash_postgres/compare/v2.1.3...v2.1.4) (2024-07-14) diff --git a/mix.exs b/mix.exs index 06be10c8..a3da1315 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.4" + @version "2.1.5" def project do [ From 6b100a05595b415927e147fc5ce83593849aafa1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 13:54:29 -0400 Subject: [PATCH 057/690] chore: update changelog --- CHANGELOG.md | 23 +++++------------------ lib/sql_implementation.ex | 15 ++++++++------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f82cd3f..e8383bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,40 +7,27 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.1.5](https://github.com/ash-project/ash_postgres/compare/v2.1.4...v2.1.5) (2024-07-15) - - - ### Bug Fixes: -* ensure synthesized query aggregates have context set +- ensure synthesized query aggregates have context set ### Improvements: -* add `binding()` expression +- [`Ash.Expr`] add `binding()` expression to refer to current table -* use latest type casting code from ash - -* support new type determination code +- [`Ash.Expr`] use latest type casting code from ash ## [v2.1.4](https://github.com/ash-project/ash_postgres/compare/v2.1.3...v2.1.4) (2024-07-14) - - - ### Improvements: -* use latest type casting code from ash - -* support new type determination code +- [`Ash.Expr`] use latest type casting code from ash ## [v2.1.3](https://github.com/ash-project/ash_postgres/compare/v2.1.2...v2.1.3) (2024-07-14) - - - ### Improvements: -* support new type determination code +- [`Ash.Expr`] support new type determination code ## [v2.1.2](https://github.com/ash-project/ash_postgres/compare/v2.1.1...v2.1.2) (2024-07-13) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 90414cf3..7c556076 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -42,15 +42,16 @@ defmodule AshPostgres.SqlImplementation do end def expr(query, %AshPostgres.Functions.Binding{}, _bindings, _embedded?, acc, _type) do - binding = AshSql.Bindings.get_binding( - query.__ash_bindings__.resource, - [], - query, - [:left, :inner, :root] - ) + binding = + AshSql.Bindings.get_binding( + query.__ash_bindings__.resource, + [], + query, + [:left, :inner, :root] + ) if is_nil(binding) do - raise "Error while constructing explicit `binding()` reference." + raise "Error while constructing explicit `binding()` reference." end {:ok, Ecto.Query.dynamic([{^binding, row}], row), acc} From 8cd8650f5a81f236aea1d8af66e707833a36b3f6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 22:01:18 -0400 Subject: [PATCH 058/690] improvement: update ash/igniter dependencies --- mix.exs | 2 +- mix.lock | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mix.exs b/mix.exs index a3da1315..cbd2f714 100644 --- a/mix.exs +++ b/mix.exs @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.1 and >= 3.1.7")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.20")}, - {:igniter, "~> 0.2.9"}, + {:igniter, "~> 0.3"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index f937365c..746d2c57 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.1.8", "427fa57ad03185cc3e4ea83179d8a07e8158578ce4048e7485a4f2f9375c4329", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "9749695ce573efc3cc9f799697e3aeb3e69e9d4409e90aefc410d55309044182"}, + "ash": {:hex, :ash, "3.2.0", "9569a7d31ebbb218bbef652235989a9943a8cd0775cf8dfad3004b8399e8a8e6", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "aef9a42268462fc9756e5f7152a5fba54707d632787c726d4b3db462d6301d8c"}, "ash_sql": {:hex, :ash_sql, "0.2.20", "f4e4fbed0954f0652bd5ace2f31f90eabd2e24470d450f66a31905cd381422cb", [:mix], [{:ash, ">= 3.1.7 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", "41a0fdc2e26d6b4b750d4a4b2404ceeae7e9e240bc37052fc2179641a66b6cb3"}, "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"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "igniter": {:hex, :igniter, "0.2.13", "dbf743887f73de135f38a121e31dd16ce29ea355b1de85c876848fecf335ca0a", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "f6e7e98ac9f42ca5fa6121d4212c6d462049e43fbf91ec56e3b2cf2895eba86b"}, + "igniter": {:hex, :igniter, "0.3.2", "f1a60895c0ee40543efd8f8c57f3eb07373e97320e7673272589e611f3f8ac30", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "b8ffae7e6860ffdc0abe89d0cf4104c110bf1296748600de1e5744e03ff2e663"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, @@ -29,19 +29,21 @@ "mix_audit": {:hex, :mix_audit, "2.1.3", "c70983d5cab5dca923f9a6efe559abfb4ec3f8e87762f02bab00fa4106d17eda", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "8c3987100b23099aea2f2df0af4d296701efd031affb08d0746b2be9e35988ec"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "owl": {:hex, :owl, "0.9.0", "9b33d64734bd51d3fc1d6ed01b12f8c2ed23e1fbf8c43658a6dfbff62578bd03", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "cd70b55327985f8f24d38cb7de5bf8a8d24040e1b49cca2345508f8119ce81fd"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, "reactor": {:hex, :reactor, "0.8.5", "7a621e0392a5975ed97938a4ddbbc92a6a31157fbd87446bc8bc6b1a0f49e56a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17b1976b9d333e55382dc108779078d5bbdbcd2c3d4033ea6dd52437339fe469"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.4.0", "be87319b1579191e25464005d465713079b3fd7124a3938a1e6cf4def39735a9", [:mix], [], "hexpm", "16751ca55e3895f2228938b703ad399b0b27acfe288eff6c0e629ed3e6ec0358"}, - "spark": {:hex, :spark, "2.2.8", "f61b5097c43c8562df0e78720be863d21c1c63bc4679c5cdbc8ef063276479de", [:mix], [{:igniter, "~> 0.2.6", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "309db664494a4dd08513476b8f77a65ad513b642773f193e7af6c2181c9b782d"}, + "spark": {:hex, :spark, "2.2.8", "e146eabeada4aec2a0aa1952ab6af385bee5d2b4b9145f4acb0f9d1450769685", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "b0c366c429e65cb2f132a3b308fb6ec7f29daff8388853e1c13f59b51abd9a7a"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"}, + "ucwidth": {:hex, :ucwidth, "0.2.0", "1f0a440f541d895dff142275b96355f7e91e15bca525d4a0cc788ea51f0e3441", [:mix], [], "hexpm", "c1efd1798b8eeb11fb2bec3cafa3dd9c0c3647bee020543f0340b996177355bf"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"}, } From de69ec076fe7b51857d19f0a6e6ba4f355cd05c3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 15 Jul 2024 22:01:45 -0400 Subject: [PATCH 059/690] chore: release version v2.1.6 --- CHANGELOG.md | 19 +++++++++++++++++++ mix.exs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8383bf6..b22569ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.6](https://github.com/ash-project/ash_postgres/compare/v2.1.5...v2.1.6) (2024-07-16) + + + + +### Bug Fixes: + +* ensure synthesized query aggregates have context set + +### Improvements: + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.5](https://github.com/ash-project/ash_postgres/compare/v2.1.4...v2.1.5) (2024-07-15) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index cbd2f714..421a8a52 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.5" + @version "2.1.6" def project do [ From a121ba177f44eaba888b2deb3eb74c9eeb7c64c0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 16 Jul 2024 08:58:04 -0400 Subject: [PATCH 060/690] chore: test changes & update dependency --- mix.exs | 1 + mix.lock | 3 ++- test/aggregate_test.exs | 7 +++++++ test/support/resources/post.ex | 1 + test/support/resources/rating.ex | 4 ++++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 421a8a52..411a27c8 100644 --- a/mix.exs +++ b/mix.exs @@ -170,6 +170,7 @@ defmodule AshPostgres.MixProject do {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, # dev/test dependencies + {:eflame, "~> 1.0", only: [:dev, :test]}, {:simple_sat, "~> 0.1", only: [:dev, :test]}, {:benchee, "~> 1.1", only: [:dev, :test]}, {:git_ops, "~> 2.5", only: [:dev, :test]}, diff --git a/mix.lock b/mix.lock index 746d2c57..43038c0f 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.2.0", "9569a7d31ebbb218bbef652235989a9943a8cd0775cf8dfad3004b8399e8a8e6", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "aef9a42268462fc9756e5f7152a5fba54707d632787c726d4b3db462d6301d8c"}, - "ash_sql": {:hex, :ash_sql, "0.2.20", "f4e4fbed0954f0652bd5ace2f31f90eabd2e24470d450f66a31905cd381422cb", [:mix], [{:ash, ">= 3.1.7 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", "41a0fdc2e26d6b4b750d4a4b2404ceeae7e9e240bc37052fc2179641a66b6cb3"}, + "ash_sql": {:hex, :ash_sql, "0.2.22", "935243e93c32c0d28d8425428d876649708597b36f7b6035d4118f9684e7545c", [:mix], [{:ash, ">= 3.1.7 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", "272938074895122cbd48fd05c04a2e1229bc7657b9d4690a41abd1adf4e3d3a9"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -12,6 +12,7 @@ "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, + "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 588f6e41..af9c5003 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -5,6 +5,13 @@ defmodule AshSql.AggregateTest do require Ash.Query import Ash.Expr + test "nested sum aggregates" do + # asserting an error is not raised + assert Post + |> Ash.Query.load(:sum_of_comment_ratings_calc) + |> Ash.read!() == [] + end + test "relates to actor via has_many and with an aggregate" do org = Organization diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index dbcfe9f2..3fbb9af4 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -566,6 +566,7 @@ defmodule AshPostgres.Test.Post do end aggregates do + sum(:sum_of_comment_ratings_calc, [:comments, :ratings], :double_score) count(:count_of_comments, :comments) count(:count_of_linked_posts, :linked_posts) diff --git a/test/support/resources/rating.ex b/test/support/resources/rating.ex index 0006ea01..99509206 100644 --- a/test/support/resources/rating.ex +++ b/test/support/resources/rating.ex @@ -20,4 +20,8 @@ defmodule AshPostgres.Test.Rating do attribute(:score, :integer, public?: true) attribute(:resource_id, :uuid, public?: true) end + + calculations do + calculate(:double_score, :integer, expr(score * 2)) + end end From 1e637f9205b7ebe1774fc47e679b56b1ffc73aa3 Mon Sep 17 00:00:00 2001 From: Robert Timis <65460527+TimisRobert@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:39:04 +0200 Subject: [PATCH 061/690] test: replicate error when building json object and using inline aggregate (#350) --- test/complex_calculations_test.exs | 17 +++++++++++++++++ .../resources/documentation.ex | 2 ++ .../complex_calculations/resources/skill.ex | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index da13ab30..a1268c0b 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -86,6 +86,23 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do assert certification.count_of_skills_ever_demonstrated == 1 end + test "calculation of inline aggregate" do + skill = + AshPostgres.Test.ComplexCalculations.Skill + |> Ash.Changeset.new() + |> Ash.create!() + + AshPostgres.Test.ComplexCalculations.Documentation + |> Ash.Changeset.for_create(:create, %{status: :demonstrated}) + |> Ash.Changeset.manage_relationship(:skill, skill, type: :append) + |> Ash.create!() + + skill = Ash.load!(skill, [:documentations_custom]) + + assert %{one: "One", documentations: [%{two: "Two", status: :demonstrated}]} = + skill.documentations_custom + end + test "channel: first_member and second member" do channel = AshPostgres.Test.ComplexCalculations.Channel diff --git a/test/support/complex_calculations/resources/documentation.ex b/test/support/complex_calculations/resources/documentation.ex index 7ec79404..ad961895 100644 --- a/test/support/complex_calculations/resources/documentation.ex +++ b/test/support/complex_calculations/resources/documentation.ex @@ -29,6 +29,8 @@ defmodule AshPostgres.Test.ComplexCalculations.Documentation do end calculations do + calculate(:custom_map, :map, expr(%{status: status, two: "Two"})) + calculate( :timestamp, :utc_datetime_usec, diff --git a/test/support/complex_calculations/resources/skill.ex b/test/support/complex_calculations/resources/skill.ex index 7715900e..6c81ceda 100644 --- a/test/support/complex_calculations/resources/skill.ex +++ b/test/support/complex_calculations/resources/skill.ex @@ -39,6 +39,12 @@ defmodule AshPostgres.Test.ComplexCalculations.Skill do ) end + calculate( + :documentations_custom, + :map, + expr(%{one: "One", documentations: list(documentations, field: :custom_map)}) + ) + calculate :count_ever_demonstrated, :integer do calculation( expr( From 2393c2c633c8bc0424a69c2ccbbc39afaa3d44b5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 16 Jul 2024 18:22:23 -0400 Subject: [PATCH 062/690] chore: update tests to account for non-keepable-atom-keys --- test/complex_calculations_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index a1268c0b..dfa5e13d 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -99,7 +99,7 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do skill = Ash.load!(skill, [:documentations_custom]) - assert %{one: "One", documentations: [%{two: "Two", status: :demonstrated}]} = + assert %{one: "One", documentations: [%{"two" => "Two", "status" => "demonstrated"}]} = skill.documentations_custom end From 7cf06f395688fe1b1c3446115263ac322bd555ac Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 16 Jul 2024 22:39:51 -0400 Subject: [PATCH 063/690] fix: update ash_sql for include_nil? fix and test it --- mix.exs | 2 +- mix.lock | 2 +- test/aggregate_test.exs | 56 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 5 +++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index 411a27c8..bc72da72 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1 and >= 3.1.7")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.20")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.23")}, {:igniter, "~> 0.3"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index 43038c0f..b6b2b2de 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.2.0", "9569a7d31ebbb218bbef652235989a9943a8cd0775cf8dfad3004b8399e8a8e6", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "aef9a42268462fc9756e5f7152a5fba54707d632787c726d4b3db462d6301d8c"}, - "ash_sql": {:hex, :ash_sql, "0.2.22", "935243e93c32c0d28d8425428d876649708597b36f7b6035d4118f9684e7545c", [:mix], [{:ash, ">= 3.1.7 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", "272938074895122cbd48fd05c04a2e1229bc7657b9d4690a41abd1adf4e3d3a9"}, + "ash_sql": {:hex, :ash_sql, "0.2.23", "8e00592827bfc99d1d8410e600d053da99f931007a4e87eeb579a2222aa02549", [:mix], [{:ash, ">= 3.1.7 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", "e1902d694181e03202d3fa4b888e62146bb86ab1ffd9e45bde8d3992fa08e229"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index af9c5003..6f01db92 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -378,6 +378,62 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end + test "does not return nil values" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "bbb"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: nil}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "aaa"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert %{comment_titles: ["aaa", "bbb"]} = + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.load(:comment_titles) + |> Ash.read_one!() + end + + test "returns nil values if `include_nil?` is set to `true`" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "bbb"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: nil}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "aaa"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert %{comment_titles_with_nils: ["aaa", "bbb", nil]} = + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.load(:comment_titles_with_nils) + |> Ash.read_one!() + end + test "with related data, it returns the value" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 3fbb9af4..03f5c85a 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -606,6 +606,11 @@ defmodule AshPostgres.Test.Post do sort(title: :asc_nils_last) end + list :comment_titles_with_nils, :comments, :title do + sort(title: :asc_nils_last) + include_nil?(true) + end + list :uniq_comment_titles, :comments, :title do uniq?(true) sort(title: :asc_nils_last) From 67ab07abcea329fb5e144e8e9b1ed034f866961b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 16 Jul 2024 22:42:53 -0400 Subject: [PATCH 064/690] fix: update to latest ash version for aggregate fix --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index bc72da72..72709157 100644 --- a/mix.exs +++ b/mix.exs @@ -162,7 +162,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.1 and >= 3.1.7")}, + {:ash, ash_version("~> 3.1 and >= 3.2.1")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.23")}, {:igniter, "~> 0.3"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, diff --git a/mix.lock b/mix.lock index b6b2b2de..df76634f 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.2.0", "9569a7d31ebbb218bbef652235989a9943a8cd0775cf8dfad3004b8399e8a8e6", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "aef9a42268462fc9756e5f7152a5fba54707d632787c726d4b3db462d6301d8c"}, + "ash": {:hex, :ash, "3.2.1", "cc9b2b1d8ceaf795ff4cf26a09914eeb4e1fa3105bb34e60f5a32690bac83e3c", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "8c70299b3b0f37ebb9f6619fc85f3dd030f493a946cc3941e84aa3351142add5"}, "ash_sql": {:hex, :ash_sql, "0.2.23", "8e00592827bfc99d1d8410e600d053da99f931007a4e87eeb579a2222aa02549", [:mix], [{:ash, ">= 3.1.7 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", "e1902d694181e03202d3fa4b888e62146bb86ab1ffd9e45bde8d3992fa08e229"}, "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"}, From d5f5bae117f8158fba92e8546261be7c673b2718 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 16 Jul 2024 22:58:14 -0400 Subject: [PATCH 065/690] test: add tests for `include_nil?` on `first` aggregates as well --- CHANGELOG.md | 23 +++++++++++++++++ mix.exs | 2 +- test/aggregate_test.exs | 46 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 9 +++++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b22569ff..b3a6c5f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,29 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.7](https://github.com/ash-project/ash_postgres/compare/v2.1.6...v2.1.7) (2024-07-17) + + + + +### Bug Fixes: + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.6](https://github.com/ash-project/ash_postgres/compare/v2.1.5...v2.1.6) (2024-07-16) diff --git a/mix.exs b/mix.exs index 72709157..198c9851 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.6" + @version "2.1.7" def project do [ diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 6f01db92..9c8c27d8 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -577,6 +577,52 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end + test "it does not return `nil` values by default" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: nil}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert %{first_comment_nils_first: "match"} = + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.load(:first_comment_nils_first) + |> Ash.read_one!() + end + + test "it returns `nil` values when `include_nil?` is `true`" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: nil}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert %{first_comment_nils_first_include_nil: "match"} = + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.load(:first_comment_nils_first_include_nil) + |> Ash.read_one!() + end + test "it can be sorted on" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 03f5c85a..e99bff53 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -584,6 +584,15 @@ defmodule AshPostgres.Test.Post do sort(title: :asc_nils_last) end + first :first_comment_nils_first, :comments, :title do + sort(title: :asc_nils_first) + end + + first :first_comment_nils_first_include_nil, :comments, :title do + include_nil?(true) + sort(title: :asc_nils_first) + end + first :last_comment, :comments, :title do sort(title: :desc, title: :asc) end From aedbaeeb10f5176a9dadc8b7fca2e37111a06f02 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 16 Jul 2024 23:01:10 -0400 Subject: [PATCH 066/690] chore: release version v2.1.8 --- CHANGELOG.md | 17 +++++++++++++++++ mix.exs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3a6c5f4..abc7f478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.8](https://github.com/ash-project/ash_postgres/compare/v2.1.7...v2.1.8) (2024-07-17) + + + + +### Bug Fixes: + +* [aggregates] update ash_sql & ash for include_nil? fix (and test it) + +* [aggregates] ensure synthesized query aggregates have context set + +### Improvements: + +* [installers] update igniter dependencies + +* [expressions] add `binding()` expression, for referring to the current table + ## [v2.1.7](https://github.com/ash-project/ash_postgres/compare/v2.1.6...v2.1.7) (2024-07-17) diff --git a/mix.exs b/mix.exs index 198c9851..0c8cbccb 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.7" + @version "2.1.8" def project do [ From 455106be7eb5bf4508533a3954d66b4a2ba57778 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 16 Jul 2024 23:10:18 -0400 Subject: [PATCH 067/690] chore: update changelog --- CHANGELOG.md | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abc7f478..6e9467a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,62 +7,53 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.1.8](https://github.com/ash-project/ash_postgres/compare/v2.1.7...v2.1.8) (2024-07-17) - - - ### Bug Fixes: -* [aggregates] update ash_sql & ash for include_nil? fix (and test it) +- [aggregates] update ash_sql & ash for include_nil? fix (and test it) -* [aggregates] ensure synthesized query aggregates have context set +- [aggregates] ensure synthesized query aggregates have context set ### Improvements: -* [installers] update igniter dependencies +- [installers] update igniter dependencies -* [expressions] add `binding()` expression, for referring to the current table +- [expressions] add `binding()` expression, for referring to the current table ## [v2.1.7](https://github.com/ash-project/ash_postgres/compare/v2.1.6...v2.1.7) (2024-07-17) - - - ### Bug Fixes: -* update to latest ash version for aggregate fix +- update to latest ash version for aggregate fix -* update ash_sql for include_nil? fix and test it +- update ash_sql for include_nil? fix and test it -* ensure synthesized query aggregates have context set +- ensure synthesized query aggregates have context set ### Improvements: -* update ash/igniter dependencies +- update ash/igniter dependencies -* add `binding()` expression +- add `binding()` expression -* use latest type casting code from ash +- use latest type casting code from ash -* support new type determination code +- support new type determination code ## [v2.1.6](https://github.com/ash-project/ash_postgres/compare/v2.1.5...v2.1.6) (2024-07-16) - - - ### Bug Fixes: -* ensure synthesized query aggregates have context set +- ensure synthesized query aggregates have context set ### Improvements: -* update ash/igniter dependencies +- update ash/igniter dependencies -* add `binding()` expression +- add `binding()` expression -* use latest type casting code from ash +- use latest type casting code from ash -* support new type determination code +- support new type determination code ## [v2.1.5](https://github.com/ash-project/ash_postgres/compare/v2.1.4...v2.1.5) (2024-07-15) From 64740bac186480687cb904d3745779f1307568f2 Mon Sep 17 00:00:00 2001 From: Robert Timis <65460527+TimisRobert@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:09:45 +0200 Subject: [PATCH 068/690] test: replicate error when using calculation over nested relationship (#351) --- config/config.exs | 3 +- .../test_repo/items/20240717104854.json | 69 +++++++++++++++++++ ...7104854_no_attributes_calculation_test.exs | 23 +++++++ test/multi_domain_calculations_test.exs | 28 ++++++++ .../domain_one/item.ex | 10 ++- .../multi_domain_calculations/domain_three.ex | 8 +++ .../domain_three/relationship_item.ex | 31 +++++++++ .../domain_two/other_item.ex | 5 ++ .../domain_two/sub_item.ex | 6 ++ 9 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/items/20240717104854.json create mode 100644 priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs create mode 100644 test/support/multi_domain_calculations/domain_three.ex create mode 100644 test/support/multi_domain_calculations/domain_three/relationship_item.ex diff --git a/config/config.exs b/config/config.exs index 4fc036c7..6861abc5 100644 --- a/config/config.exs +++ b/config/config.exs @@ -54,7 +54,8 @@ if Mix.env() == :test do AshPostgres.MultitenancyTest.Domain, AshPostgres.Test.ComplexCalculations.Domain, AshPostgres.Test.MultiDomainCalculations.DomainOne, - AshPostgres.Test.MultiDomainCalculations.DomainTwo + AshPostgres.Test.MultiDomainCalculations.DomainTwo, + AshPostgres.Test.MultiDomainCalculations.DomainThree ] config :ash, :compatible_foreign_key_types, [ diff --git a/priv/resource_snapshots/test_repo/items/20240717104854.json b/priv/resource_snapshots/test_repo/items/20240717104854.json new file mode 100644 index 00000000..4339840d --- /dev/null +++ b/priv/resource_snapshots/test_repo/items/20240717104854.json @@ -0,0 +1,69 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"uuid_generate_v7()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "key", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "value", + "type": "bigint" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "4C97C976528D44A7E55E873A1EF3539C3778EC7EFE3EC5AF644C0A736EF679FC", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "items" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs b/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs new file mode 100644 index 00000000..04a9f3f6 --- /dev/null +++ b/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs @@ -0,0 +1,23 @@ +defmodule AshPostgres.TestRepo.Migrations.NoAttributesCalculationTest do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:items) do + add(:key, :text) + add(:value, :bigint) + end + end + + def down do + alter table(:items) do + remove(:value) + remove(:key) + end + end +end diff --git a/test/multi_domain_calculations_test.exs b/test/multi_domain_calculations_test.exs index bf659855..8a9f456b 100644 --- a/test/multi_domain_calculations_test.exs +++ b/test/multi_domain_calculations_test.exs @@ -25,4 +25,32 @@ defmodule AshPostgres.Test.MultiDomainCalculationsTest do load: [:total_amount] ) end + + test "total using relationship is returned correctly" do + item = + AshPostgres.Test.MultiDomainCalculations.DomainOne.Item + |> Ash.Changeset.for_create(:create, %{key: "key"}) + |> Ash.create!() + + _relationship_item = + AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem + |> Ash.Changeset.for_create(:create, %{key: "key", value: 1}) + |> Ash.create!() + + other_item = + AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem + |> Ash.Changeset.for_create(:create, %{item_id: item.id}) + |> Ash.create!() + + for i <- 0..2 do + AshPostgres.Test.MultiDomainCalculations.DomainTwo.SubItem + |> Ash.Changeset.for_create(:create, %{other_item_id: other_item.id, amount: i}) + |> Ash.create!() + end + + assert [%{total_amount: 3}] = + Ash.read!(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item, + load: [:total_amount_relationship] + ) + end end diff --git a/test/support/multi_domain_calculations/domain_one/item.ex b/test/support/multi_domain_calculations/domain_one/item.ex index 5d76e9eb..36090798 100644 --- a/test/support/multi_domain_calculations/domain_one/item.ex +++ b/test/support/multi_domain_calculations/domain_one/item.ex @@ -6,24 +6,32 @@ defmodule AshPostgres.Test.MultiDomainCalculations.DomainOne.Item do authorizers: [Ash.Policy.Authorizer], domain: AshPostgres.Test.MultiDomainCalculations.DomainOne + alias AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem alias AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem attributes do uuid_v7_primary_key(:id) + attribute(:key, :string) create_timestamp(:inserted_at) update_timestamp(:updated_at) end relationships do has_one(:other_item, OtherItem) + + has_one(:relationship_item, RelationshipItem) do + no_attributes?(true) + filter(expr(parent(key) == key)) + end end actions do - defaults([:read, :destroy, update: :*, create: :*]) + defaults([:read, :destroy, update: :*, create: [:*, :key]]) end calculations do calculate(:total_amount, :integer, expr(other_item.total_amount)) + calculate(:total_amount_relationship, :integer, expr(other_item.total_amount_relationship)) end policies do diff --git a/test/support/multi_domain_calculations/domain_three.ex b/test/support/multi_domain_calculations/domain_three.ex new file mode 100644 index 00000000..95eda02d --- /dev/null +++ b/test/support/multi_domain_calculations/domain_three.ex @@ -0,0 +1,8 @@ +defmodule AshPostgres.Test.MultiDomainCalculations.DomainThree do + @moduledoc false + use Ash.Domain + + resources do + resource(AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem) + end +end diff --git a/test/support/multi_domain_calculations/domain_three/relationship_item.ex b/test/support/multi_domain_calculations/domain_three/relationship_item.ex new file mode 100644 index 00000000..fe7aa8c8 --- /dev/null +++ b/test/support/multi_domain_calculations/domain_three/relationship_item.ex @@ -0,0 +1,31 @@ +defmodule AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem do + @moduledoc false + + use Ash.Resource, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer], + domain: AshPostgres.Test.MultiDomainCalculations.DomainThree + + attributes do + uuid_v7_primary_key(:id) + attribute(:key, :string, allow_nil?: false) + attribute(:value, :integer, allow_nil?: false) + create_timestamp(:inserted_at) + update_timestamp(:updated_at) + end + + actions do + defaults([:read, :destroy, update: :*, create: [:*, :key, :value]]) + end + + policies do + policy always() do + authorize_if(always()) + end + end + + postgres do + table "items" + repo(AshPostgres.TestRepo) + end +end diff --git a/test/support/multi_domain_calculations/domain_two/other_item.ex b/test/support/multi_domain_calculations/domain_two/other_item.ex index 60cdea7a..1bd3e754 100644 --- a/test/support/multi_domain_calculations/domain_two/other_item.ex +++ b/test/support/multi_domain_calculations/domain_two/other_item.ex @@ -28,10 +28,15 @@ defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem do sum :total_sub_items_amount, :sub_items, :total_amount do default(0) end + + sum :total_sub_items_relationship_amount, :sub_items, :total_amount_relationship do + default(0) + end end calculations do calculate(:total_amount, :integer, expr(total_sub_items_amount)) + calculate(:total_amount_relationship, :integer, expr(total_sub_items_relationship_amount)) end policies do diff --git a/test/support/multi_domain_calculations/domain_two/sub_item.ex b/test/support/multi_domain_calculations/domain_two/sub_item.ex index c5411e51..c9f8b491 100644 --- a/test/support/multi_domain_calculations/domain_two/sub_item.ex +++ b/test/support/multi_domain_calculations/domain_two/sub_item.ex @@ -25,6 +25,12 @@ defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.SubItem do calculations do calculate(:total_amount, :integer, expr(amount)) + + calculate( + :total_amount_relationship, + :integer, + expr(amount * other_item.item.relationship_item.value) + ) end policies do From 10983856b11cbcd48ef9e5ec12c156b7183053fe Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 17 Jul 2024 11:40:17 -0400 Subject: [PATCH 069/690] chore: update tests/migrations --- .../test_repo/items/20240717153736.json | 59 ++++++++++++ .../test_repo/other_items/20240717151815.json | 93 +++++++++++++++++++ .../relationship_items/20240717153736.json | 69 ++++++++++++++ .../20240717151815_migrate_resources36.exs | 19 ++++ .../20240717153736_migrate_resources37.exs | 39 ++++++++ test/multi_domain_calculations_test.exs | 6 +- .../domain_three/relationship_item.ex | 2 +- .../domain_two/other_item.ex | 4 + 8 files changed, 289 insertions(+), 2 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/items/20240717153736.json create mode 100644 priv/resource_snapshots/test_repo/other_items/20240717151815.json create mode 100644 priv/resource_snapshots/test_repo/relationship_items/20240717153736.json create mode 100644 priv/test_repo/migrations/20240717151815_migrate_resources36.exs create mode 100644 priv/test_repo/migrations/20240717153736_migrate_resources37.exs diff --git a/priv/resource_snapshots/test_repo/items/20240717153736.json b/priv/resource_snapshots/test_repo/items/20240717153736.json new file mode 100644 index 00000000..445e6467 --- /dev/null +++ b/priv/resource_snapshots/test_repo/items/20240717153736.json @@ -0,0 +1,59 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"uuid_generate_v7()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "key", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "571E95D3DAC0A3C7446601D96857C70384A20159928EE335D3A421FA61555158", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "items" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/other_items/20240717151815.json b/priv/resource_snapshots/test_repo/other_items/20240717151815.json new file mode 100644 index 00000000..8a057d24 --- /dev/null +++ b/priv/resource_snapshots/test_repo/other_items/20240717151815.json @@ -0,0 +1,93 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"uuid_generate_v7()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": true, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "other_items_item_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "items" + }, + "size": null, + "source": "item_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "43CBB861ACD2A789B2871FAF147C4480E7854D422D70213A4DB321CECC68A203", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "other_items_unique_parent_index", + "keys": [ + { + "type": "atom", + "value": "item_id" + } + ], + "name": "unique_parent", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "other_items" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json b/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json new file mode 100644 index 00000000..4d5a8093 --- /dev/null +++ b/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json @@ -0,0 +1,69 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"uuid_generate_v7()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "key", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "value", + "type": "bigint" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "FC7547C74057DE3A87306D14A0AD1621D9BE7812D8BF94D68D8B319C5AA84C55", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "relationship_items" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240717151815_migrate_resources36.exs b/priv/test_repo/migrations/20240717151815_migrate_resources36.exs new file mode 100644 index 00000000..1a885fcf --- /dev/null +++ b/priv/test_repo/migrations/20240717151815_migrate_resources36.exs @@ -0,0 +1,19 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources36 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create(unique_index(:other_items, [:item_id], name: "other_items_unique_parent_index")) + end + + def down do + drop_if_exists( + unique_index(:other_items, [:item_id], name: "other_items_unique_parent_index") + ) + end +end diff --git a/priv/test_repo/migrations/20240717153736_migrate_resources37.exs b/priv/test_repo/migrations/20240717153736_migrate_resources37.exs new file mode 100644 index 00000000..ba2f6bfe --- /dev/null +++ b/priv/test_repo/migrations/20240717153736_migrate_resources37.exs @@ -0,0 +1,39 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources37 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:relationship_items, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true) + add(:key, :text, null: false) + add(:value, :bigint, null: false) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + end + + alter table(:items) do + remove(:value) + end + end + + def down do + alter table(:items) do + add(:value, :bigint) + end + + drop(table(:relationship_items)) + end +end diff --git a/test/multi_domain_calculations_test.exs b/test/multi_domain_calculations_test.exs index 8a9f456b..8b079073 100644 --- a/test/multi_domain_calculations_test.exs +++ b/test/multi_domain_calculations_test.exs @@ -32,6 +32,10 @@ defmodule AshPostgres.Test.MultiDomainCalculationsTest do |> Ash.Changeset.for_create(:create, %{key: "key"}) |> Ash.create!() + Ash.read!(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item, + load: [:total_amount_relationship] + ) + _relationship_item = AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem |> Ash.Changeset.for_create(:create, %{key: "key", value: 1}) @@ -48,7 +52,7 @@ defmodule AshPostgres.Test.MultiDomainCalculationsTest do |> Ash.create!() end - assert [%{total_amount: 3}] = + assert [%{total_amount_relationship: 3}] = Ash.read!(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item, load: [:total_amount_relationship] ) diff --git a/test/support/multi_domain_calculations/domain_three/relationship_item.ex b/test/support/multi_domain_calculations/domain_three/relationship_item.ex index fe7aa8c8..b90b93a7 100644 --- a/test/support/multi_domain_calculations/domain_three/relationship_item.ex +++ b/test/support/multi_domain_calculations/domain_three/relationship_item.ex @@ -25,7 +25,7 @@ defmodule AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem end postgres do - table "items" + table "relationship_items" repo(AshPostgres.TestRepo) end end diff --git a/test/support/multi_domain_calculations/domain_two/other_item.ex b/test/support/multi_domain_calculations/domain_two/other_item.ex index 1bd3e754..2e01406e 100644 --- a/test/support/multi_domain_calculations/domain_two/other_item.ex +++ b/test/support/multi_domain_calculations/domain_two/other_item.ex @@ -15,6 +15,10 @@ defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem do update_timestamp(:updated_at) end + identities do + identity :unique_parent, [:item_id] + end + relationships do belongs_to(:item, Item, allow_nil?: false) has_many(:sub_items, SubItem) From 0bf9c4e9ec07deb92b1623e381d83d0ed2f58e2e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 17 Jul 2024 11:41:42 -0400 Subject: [PATCH 070/690] fix: update `ash_sql` for `parent_as` binding fix --- mix.exs | 2 +- mix.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 0c8cbccb..c167c648 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1 and >= 3.2.1")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.23")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.24")}, {:igniter, "~> 0.3"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index df76634f..8c7fc012 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.2.1", "cc9b2b1d8ceaf795ff4cf26a09914eeb4e1fa3105bb34e60f5a32690bac83e3c", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "8c70299b3b0f37ebb9f6619fc85f3dd030f493a946cc3941e84aa3351142add5"}, - "ash_sql": {:hex, :ash_sql, "0.2.23", "8e00592827bfc99d1d8410e600d053da99f931007a4e87eeb579a2222aa02549", [:mix], [{:ash, ">= 3.1.7 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", "e1902d694181e03202d3fa4b888e62146bb86ab1ffd9e45bde8d3992fa08e229"}, + "ash_sql": {:hex, :ash_sql, "0.2.24", "324f3fd65e249ad2e7df56a585a768edf6cc91246b7c8048ac16a684edc1437a", [:mix], [{:ash, ">= 3.1.7 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", "38f3066059be9f567ab5c3a8d99e812417069b881bc12fa33c067b1ea7742145"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -37,7 +37,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.4.0", "be87319b1579191e25464005d465713079b3fd7124a3938a1e6cf4def39735a9", [:mix], [], "hexpm", "16751ca55e3895f2228938b703ad399b0b27acfe288eff6c0e629ed3e6ec0358"}, - "spark": {:hex, :spark, "2.2.8", "e146eabeada4aec2a0aa1952ab6af385bee5d2b4b9145f4acb0f9d1450769685", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "b0c366c429e65cb2f132a3b308fb6ec7f29daff8388853e1c13f59b51abd9a7a"}, + "spark": {:hex, :spark, "2.2.9", "cc86e39895e1e1b2360e333fe37fa8cdb5624d265d234c0c945b1b1e11b49563", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "d855e3971f568527bdd43377a8088ae96a7798a1df732c9b7a631730ba2f705d"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 0cac01fe30002e655634e24d8bfd1c69e57814f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 08:33:38 -0400 Subject: [PATCH 071/690] chore(deps): bump ash in the production-dependencies group (#352) Bumps the production-dependencies group with 1 update: [ash](https://github.com/ash-project/ash). Updates `ash` from 3.2.1 to 3.2.2 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.2.1...v3.2.2) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 8c7fc012..a4f140d9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.2.1", "cc9b2b1d8ceaf795ff4cf26a09914eeb4e1fa3105bb34e60f5a32690bac83e3c", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "8c70299b3b0f37ebb9f6619fc85f3dd030f493a946cc3941e84aa3351142add5"}, + "ash": {:hex, :ash, "3.2.2", "f079fbe7f4f7e3279825c841aa69f6b83333a86267b31435ca97031a805c4b41", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "b9a9165d1aafec1fa719df6182ddee0b2a29c83f67079a04a9a8060f49cc1e7f"}, "ash_sql": {:hex, :ash_sql, "0.2.24", "324f3fd65e249ad2e7df56a585a768edf6cc91246b7c8048ac16a684edc1437a", [:mix], [{:ash, ">= 3.1.7 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", "38f3066059be9f567ab5c3a8d99e812417069b881bc12fa33c067b1ea7742145"}, "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"}, From 4cb3a72c54d42ead9619672f538d5ceab8416a08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 08:34:08 -0400 Subject: [PATCH 072/690] chore(deps-dev): bump mix_audit in the dev-dependencies group (#353) Bumps the dev-dependencies group with 1 update: [mix_audit](https://github.com/mirego/mix_audit). Updates `mix_audit` from 2.1.3 to 2.1.4 - [Changelog](https://github.com/mirego/mix_audit/blob/main/CHANGELOG.md) - [Commits](https://github.com/mirego/mix_audit/compare/v2.1.3...v2.1.4) --- updated-dependencies: - dependency-name: mix_audit dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index a4f140d9..c9f59dae 100644 --- a/mix.lock +++ b/mix.lock @@ -27,7 +27,7 @@ "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, - "mix_audit": {:hex, :mix_audit, "2.1.3", "c70983d5cab5dca923f9a6efe559abfb4ec3f8e87762f02bab00fa4106d17eda", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "8c3987100b23099aea2f2df0af4d296701efd031affb08d0746b2be9e35988ec"}, + "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.9.0", "9b33d64734bd51d3fc1d6ed01b12f8c2ed23e1fbf8c43658a6dfbff62578bd03", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "cd70b55327985f8f24d38cb7de5bf8a8d24040e1b49cca2345508f8119ce81fd"}, @@ -46,5 +46,5 @@ "typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"}, "ucwidth": {:hex, :ucwidth, "0.2.0", "1f0a440f541d895dff142275b96355f7e91e15bca525d4a0cc788ea51f0e3441", [:mix], [], "hexpm", "c1efd1798b8eeb11fb2bec3cafa3dd9c0c3647bee020543f0340b996177355bf"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, - "yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"}, + "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, } From c63c988339451277685803802e685eaf312e1012 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 18 Jul 2024 12:52:27 -0400 Subject: [PATCH 073/690] improvement: pluralize table name in extender chore: get build passing & clean up code closes #354 --- .tool-versions | 4 +-- lib/data_layer.ex | 29 +++++++++---------- mix.exs | 2 +- mix.lock | 3 +- test/multi_domain_calculations_test.exs | 6 ++-- .../domain_two/other_item.ex | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.tool-versions b/.tool-versions index 61c2916b..ce0360e0 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -erlang 27.0 -elixir 1.17.0 +erlang 27.0.1 +elixir 1.17.2-otp-27 diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 450acc8d..1602df49 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2916,24 +2916,23 @@ defmodule AshPostgres.DataLayer do end end - if Code.ensure_loaded?(Igniter) do - def install(igniter, module, Ash.Resource, _path, _argv) do - table_name = - module - |> Module.split() - |> List.last() - |> Macro.underscore() - - repo = Igniter.Code.Module.module_name("Repo") - - igniter - |> Spark.Igniter.set_option(module, [:postgres, :table], table_name) - |> Spark.Igniter.set_option(module, [:postgres, :repo], repo) - end + def install(igniter, module, Ash.Resource, _path, _argv) do + table_name = + module + |> Module.split() + |> List.last() + |> Macro.underscore() + |> Inflex.pluralize() + + repo = Igniter.Code.Module.module_name("Repo") - def install(igniter, _, _, _), do: igniter + igniter + |> Spark.Igniter.set_option(module, [:postgres, :table], table_name) + |> Spark.Igniter.set_option(module, [:postgres, :repo], repo) end + def install(igniter, _, _, _), do: igniter + @impl true def rollback(resource, term) do AshPostgres.DataLayer.Info.repo(resource, :mutate).rollback(term) diff --git a/mix.exs b/mix.exs index c167c648..9fc30514 100644 --- a/mix.exs +++ b/mix.exs @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.1 and >= 3.2.1")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.24")}, - {:igniter, "~> 0.3"}, + {:igniter, "~> 0.3 and >= 0.3.3"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index c9f59dae..a66a5c92 100644 --- a/mix.lock +++ b/mix.lock @@ -21,7 +21,8 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "igniter": {:hex, :igniter, "0.3.2", "f1a60895c0ee40543efd8f8c57f3eb07373e97320e7673272589e611f3f8ac30", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "b8ffae7e6860ffdc0abe89d0cf4104c110bf1296748600de1e5744e03ff2e663"}, + "igniter": {:hex, :igniter, "0.3.3", "5cfc2c8b26df4c390d0238838ed9b993c1d0e12c4cae7e83e8ffbce342c7d3da", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "766429591d12022960ce358b019b11c2bf0fac172d3b09af2f848aabb86d8b95"}, + "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, diff --git a/test/multi_domain_calculations_test.exs b/test/multi_domain_calculations_test.exs index 8b079073..8cc9bc55 100644 --- a/test/multi_domain_calculations_test.exs +++ b/test/multi_domain_calculations_test.exs @@ -32,9 +32,9 @@ defmodule AshPostgres.Test.MultiDomainCalculationsTest do |> Ash.Changeset.for_create(:create, %{key: "key"}) |> Ash.create!() - Ash.read!(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item, - load: [:total_amount_relationship] - ) + Ash.read!(AshPostgres.Test.MultiDomainCalculations.DomainOne.Item, + load: [:total_amount_relationship] + ) _relationship_item = AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem diff --git a/test/support/multi_domain_calculations/domain_two/other_item.ex b/test/support/multi_domain_calculations/domain_two/other_item.ex index 2e01406e..1524b47d 100644 --- a/test/support/multi_domain_calculations/domain_two/other_item.ex +++ b/test/support/multi_domain_calculations/domain_two/other_item.ex @@ -16,7 +16,7 @@ defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem do end identities do - identity :unique_parent, [:item_id] + identity(:unique_parent, [:item_id]) end relationships do From c47ed40a5504e7d7c1a1ece264c0a1ef8a4554e0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 18 Jul 2024 12:57:04 -0400 Subject: [PATCH 074/690] chore: release version v2.1.9 --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e9467a1..83efac5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,33 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.9](https://github.com/ash-project/ash_postgres/compare/v2.1.8...v2.1.9) (2024-07-18) + + + + +### Bug Fixes: + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.8](https://github.com/ash-project/ash_postgres/compare/v2.1.7...v2.1.8) (2024-07-17) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 9fc30514..7f18ccde 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.8" + @version "2.1.9" def project do [ From 8f79fcb59ddaef5a9542cec24f374a6e21ea5f3f Mon Sep 17 00:00:00 2001 From: Jesse Williams Date: Thu, 18 Jul 2024 13:37:31 -0700 Subject: [PATCH 075/690] fix: allow non-unique has_many source_attributes (#355) * fix: allow non-unique has_many source_attributes * fix composite primary key case --- lib/data_layer.ex | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 1602df49..b0676b61 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1044,9 +1044,43 @@ defmodule AshPostgres.DataLayer do {:ok, data_layer_query} -> source_values = Enum.map(root_data, &Map.get(&1, source_attribute)) + source_filter = + case source_pkey do + [] -> + Ecto.Query.dynamic([source], field(source, ^source_attribute) in ^source_values) + + [field] -> + values = Enum.map(root_data, &Map.get(&1, field)) + Ecto.Query.dynamic([source], field(source, ^field) in ^values) + + fields -> + Enum.reduce(root_data, nil, fn record, acc -> + row_match = + Enum.reduce(fields, nil, fn field, acc -> + if is_nil(acc) do + Ecto.Query.dynamic( + [source], + field(source, ^field) == ^Map.get(record, field) + ) + else + Ecto.Query.dynamic( + [source], + field(source, ^field) == ^Map.get(record, field) and ^acc + ) + end + end) + + if is_nil(acc) do + row_match + else + Ecto.Query.dynamic(^row_match or ^acc) + end + end) + end + data_layer_query = from(source in data_layer_query, - where: field(source, ^source_attribute) in ^source_values + where: ^source_filter ) if query.__ash_bindings__[:__order__?] do From a1d0d7a97ad4d8aa5ff38b75d582f56ed6a4c4cd Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 18 Jul 2024 18:48:40 -0400 Subject: [PATCH 076/690] chore: release version v2.1.10 --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83efac5e..32baaa3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,37 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.10](https://github.com/ash-project/ash_postgres/compare/v2.1.9...v2.1.10) (2024-07-18) + + + + +### Bug Fixes: + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.9](https://github.com/ash-project/ash_postgres/compare/v2.1.8...v2.1.9) (2024-07-18) diff --git a/mix.exs b/mix.exs index 7f18ccde..fff00e8e 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.9" + @version "2.1.10" def project do [ From ff7b854c3e6e0e5985c06d83e2b6beaef08bb015 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 18 Jul 2024 18:51:04 -0400 Subject: [PATCH 077/690] chore: update changelog --- CHANGELOG.md | 48 ++---------------------------------------------- 1 file changed, 2 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32baaa3f..c1f81a3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,61 +7,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.1.10](https://github.com/ash-project/ash_postgres/compare/v2.1.9...v2.1.10) (2024-07-18) - - - ### Bug Fixes: -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - -### Improvements: - -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression - -* use latest type casting code from ash - -* support new type determination code +- [lateral joins] allow non-unique has_many source_attributes (#355) ## [v2.1.9](https://github.com/ash-project/ash_postgres/compare/v2.1.8...v2.1.9) (2024-07-18) - - - ### Bug Fixes: -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - ### Improvements: -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression - -* use latest type casting code from ash - -* support new type determination code +- [`mix ash.gen.resource`] pluralize table name in extender ## [v2.1.8](https://github.com/ash-project/ash_postgres/compare/v2.1.7...v2.1.8) (2024-07-17) From 142e74f02650640fdde8ef7d43ff1079ce2a39c3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Jul 2024 08:34:34 -0400 Subject: [PATCH 078/690] improvement: prepend `:postgres` to section order --- lib/mix/tasks/ash_postgres.install.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 2231d4d8..ee048aec 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -17,6 +17,7 @@ defmodule Mix.Tasks.AshPostgres.Install do |> configure_test(otp_app, repo) |> setup_data_case() |> Igniter.Project.Application.add_new_child(repo) + |> Spark.Igniter.prepend_to_section_order(:"Ash.Resource", [:postgres]) |> Ash.Igniter.codegen("initialize") end From 8b5b5b4b6ba97fa810a0b7a78fa18eb9a9dd4880 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Jul 2024 12:34:06 -0400 Subject: [PATCH 079/690] fix: properly perform or don't perform configuration modification code --- lib/mix/tasks/ash_postgres.install.ex | 60 ++++++++++++++------------- mix.exs | 2 +- mix.lock | 2 +- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index ee048aec..e58a80fe 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -2,6 +2,7 @@ defmodule Mix.Tasks.AshPostgres.Install do @moduledoc "Installs AshPostgres. Should be run with `mix igniter.install ash_postgres`" @shortdoc @moduledoc require Igniter.Code.Common + require Igniter.Code.Function use Igniter.Mix.Task def igniter(igniter, _argv) do @@ -77,35 +78,36 @@ defmodule Mix.Tasks.AshPostgres.Install do |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do {:ok, zipper} -> - case Igniter.Code.Function.move_to_function_call_in_current_scope( - zipper, - :=, - 2, - fn call -> - Igniter.Code.Function.argument_matches_predicate?( - call, - 0, - &match?({:database_url, _, Elixir}, &1) - ) - end - ) do - {:ok, zipper} -> - zipper - |> Igniter.Project.Config.modify_configuration_code( - [repo, :url], - otp_app, - {:database_url, [], Elixir} - ) - |> Igniter.Project.Config.modify_configuration_code( - [repo, :pool_size], - otp_app, - quote do - String.to_integer(System.get_env("POOL_SIZE") || "10") - end - ) - |> then(&{:ok, &1}) - - :error -> + with {:ok, _zipper} <- + Igniter.Code.Function.move_to_function_call_in_current_scope( + zipper, + :=, + 2, + fn call -> + Igniter.Code.Function.argument_matches_pattern?( + call, + 0, + {:database_url, _, ctx} when is_atom(ctx) + ) + end + ) do + zipper + |> Igniter.Project.Config.modify_configuration_code( + [repo, :url], + otp_app, + {:database_url, [], nil} + ) + |> Igniter.Util.Debug.puts_code_at_node() + |> Igniter.Project.Config.modify_configuration_code( + [repo, :pool_size], + otp_app, + Sourceror.parse_string!(""" + String.to_integer(System.get_env("POOL_SIZE") || "10") + """) + ) + |> then(&{:ok, &1}) + else + _ -> Igniter.Code.Common.add_code(zipper, """ database_url = System.get_env("DATABASE_URL") || diff --git a/mix.exs b/mix.exs index fff00e8e..d3e46547 100644 --- a/mix.exs +++ b/mix.exs @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.1 and >= 3.2.1")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.24")}, - {:igniter, "~> 0.3 and >= 0.3.3"}, + {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index a66a5c92..1d361ab7 100644 --- a/mix.lock +++ b/mix.lock @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "igniter": {:hex, :igniter, "0.3.3", "5cfc2c8b26df4c390d0238838ed9b993c1d0e12c4cae7e83e8ffbce342c7d3da", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "766429591d12022960ce358b019b11c2bf0fac172d3b09af2f848aabb86d8b95"}, + "igniter": {:hex, :igniter, "0.3.6", "30951d75604e88d6d893753e7331c9793625fbeb5fb34f06148e61ffcdca590f", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "9fc32f2fc6eff9c24abe1d942a6632f5d50ccaeb031504064c1176f78f892b65"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From 938611f4bae84ea80d00f2e45878ea0f8d48d430 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Jul 2024 12:35:44 -0400 Subject: [PATCH 080/690] chore: release version v2.1.11 --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f81a3e..9d8ae08e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,41 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.11](https://github.com/ash-project/ash_postgres/compare/v2.1.10...v2.1.11) (2024-07-19) + + + + +### Bug Fixes: + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.10](https://github.com/ash-project/ash_postgres/compare/v2.1.9...v2.1.10) (2024-07-18) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index d3e46547..92e12e15 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.10" + @version "2.1.11" def project do [ From b3eea1e440e62f80d110bbfa415c476004cd189c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Jul 2024 13:28:39 -0400 Subject: [PATCH 081/690] chore: fix build --- lib/mix/tasks/ash_postgres.install.ex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index e58a80fe..bec3d024 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -58,7 +58,7 @@ defmodule Mix.Tasks.AshPostgres.Install do igniter |> Igniter.create_or_update_elixir_file("config/runtime.exs", default_runtime, fn zipper -> - if Igniter.Project.Config.configures?(zipper, [repo, :url], otp_app) do + if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo, :url]) do zipper else patterns = [ @@ -78,8 +78,7 @@ defmodule Mix.Tasks.AshPostgres.Install do |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do {:ok, zipper} -> - with {:ok, _zipper} <- - Igniter.Code.Function.move_to_function_call_in_current_scope( + case Igniter.Code.Function.move_to_function_call_in_current_scope( zipper, :=, 2, @@ -91,6 +90,7 @@ defmodule Mix.Tasks.AshPostgres.Install do ) end ) do + {:ok, zipper} -> zipper |> Igniter.Project.Config.modify_configuration_code( [repo, :url], @@ -106,7 +106,6 @@ defmodule Mix.Tasks.AshPostgres.Install do """) ) |> then(&{:ok, &1}) - else _ -> Igniter.Code.Common.add_code(zipper, """ database_url = From 5d9f2cd69378578353d97455eb6b3bf2d98143f0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Jul 2024 13:30:13 -0400 Subject: [PATCH 082/690] chore: remove debugging code --- lib/mix/tasks/ash_postgres.install.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index bec3d024..7aaae584 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -97,7 +97,6 @@ defmodule Mix.Tasks.AshPostgres.Install do otp_app, {:database_url, [], nil} ) - |> Igniter.Util.Debug.puts_code_at_node() |> Igniter.Project.Config.modify_configuration_code( [repo, :pool_size], otp_app, From 384344ab6bfabb5cb704ef7796ce6c7bdf694b49 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Jul 2024 15:11:44 -0400 Subject: [PATCH 083/690] fix: properly add prod config in installer --- lib/mix/tasks/ash_postgres.install.ex | 55 ++++++++++++++------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 7aaae584..48d490c9 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -78,33 +78,34 @@ defmodule Mix.Tasks.AshPostgres.Install do |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do {:ok, zipper} -> - case Igniter.Code.Function.move_to_function_call_in_current_scope( - zipper, - :=, - 2, - fn call -> - Igniter.Code.Function.argument_matches_pattern?( - call, - 0, - {:database_url, _, ctx} when is_atom(ctx) - ) - end - ) do - {:ok, zipper} -> - zipper - |> Igniter.Project.Config.modify_configuration_code( - [repo, :url], - otp_app, - {:database_url, [], nil} - ) - |> Igniter.Project.Config.modify_configuration_code( - [repo, :pool_size], - otp_app, - Sourceror.parse_string!(""" - String.to_integer(System.get_env("POOL_SIZE") || "10") - """) - ) - |> then(&{:ok, &1}) + case Igniter.Code.Function.move_to_function_call_in_current_scope( + zipper, + :=, + 2, + fn call -> + Igniter.Code.Function.argument_matches_pattern?( + call, + 0, + {:database_url, _, ctx} when is_atom(ctx) + ) + end + ) do + {:ok, _zipper} -> + zipper + |> Igniter.Project.Config.modify_configuration_code( + [repo, :url], + otp_app, + {:database_url, [], nil} + ) + |> Igniter.Project.Config.modify_configuration_code( + [repo, :pool_size], + otp_app, + Sourceror.parse_string!(""" + String.to_integer(System.get_env("POOL_SIZE") || "10") + """) + ) + |> then(&{:ok, &1}) + _ -> Igniter.Code.Common.add_code(zipper, """ database_url = From 01edc539fc45de89f1744362ca71c0d70846e3fe Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Jul 2024 15:12:46 -0400 Subject: [PATCH 084/690] chore: release version v2.1.12 --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d8ae08e..784a7b4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,43 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.12](https://github.com/ash-project/ash_postgres/compare/v2.1.11...v2.1.12) (2024-07-19) + + + + +### Bug Fixes: + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.11](https://github.com/ash-project/ash_postgres/compare/v2.1.10...v2.1.11) (2024-07-19) diff --git a/mix.exs b/mix.exs index 92e12e15..38934d69 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.11" + @version "2.1.12" def project do [ From ece56c2bc9e1951ed135728e221d1a4d3f7d9512 Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Mon, 22 Jul 2024 16:29:00 +0200 Subject: [PATCH 085/690] test: add test for list aggregate in atomic validation (#358) --- test/atomics_test.exs | 20 ++++++++++++++++++++ test/support/resources/post.ex | 15 +++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/test/atomics_test.exs b/test/atomics_test.exs index a0a34200..b57b5697 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -1,4 +1,5 @@ defmodule AshPostgres.AtomicsTest do + alias AshPostgres.Test.Comment alias AshPostgres.Test.Author use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post @@ -291,4 +292,23 @@ defmodule AshPostgres.AtomicsTest do |> Ash.bulk_update!(:set_title_from_author, %{}, return_records?: true) |> Map.get(:records) end + + test "can use list aggregate in validation" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "foo", price: 1}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) + |> Ash.create!() + + Logger.configure(level: :debug) + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) + |> Ash.destroy() + end + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index e99bff53..ecd0a708 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -13,6 +13,17 @@ defmodule PassIfOriginalDataPresent do end end +defmodule HasNoComments do + alias Ash.Error.Invalid + use Ash.Resource.Validation + + def atomic(_changeset, _opts, _context) do + # This uses the list aggregate because we want to specifically test this aggregate + {:atomic, [], expr(list(comments, field: :id) > 0), + expr(error(^Invalid, %{message: "Can only delete if Post has no comments"}))} + end +end + defmodule AshPostgres.Test.Post do @moduledoc false use Ash.Resource, @@ -92,6 +103,10 @@ defmodule AshPostgres.Test.Post do change(filter(expr(title == "fred"))) end + destroy :destroy_if_no_comments do + validate(HasNoComments) + end + update :update_only_freds do change(filter(expr(title == "fred"))) end From a672c8969751be9539b7f907e0ec11aa9311bad6 Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Mon, 22 Jul 2024 17:25:00 +0200 Subject: [PATCH 086/690] test: test more aggregates (#359) --- test/atomics_test.exs | 2 -- test/support/resources/post.ex | 12 +++++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/test/atomics_test.exs b/test/atomics_test.exs index b57b5697..418206ce 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -303,8 +303,6 @@ defmodule AshPostgres.AtomicsTest do |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) |> Ash.create!() - Logger.configure(level: :debug) - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> post |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index ecd0a708..a058bce4 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -18,9 +18,15 @@ defmodule HasNoComments do use Ash.Resource.Validation def atomic(_changeset, _opts, _context) do - # This uses the list aggregate because we want to specifically test this aggregate - {:atomic, [], expr(list(comments, field: :id) > 0), - expr(error(^Invalid, %{message: "Can only delete if Post has no comments"}))} + # Test multiple types of aggregates in a single validation + [ + {:atomic, [], + expr( + list(comments, field: :id) > 0 or + count(comments) > 0 or + exists(comments, true) + ), expr(error(^Invalid, %{message: "Can only delete if Post has no comments"}))} + ] end end From b00a7e64826657903846ceed120adb3a260a388f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 22 Jul 2024 11:49:59 -0400 Subject: [PATCH 087/690] fix: update ash & ash_sql for fixes, test atomic alidations in destroys --- lib/data_layer.ex | 74 +++++++++++++++++++++++----------- mix.exs | 4 +- mix.lock | 13 +++--- test/atomics_test.exs | 5 ++- test/support/resources/post.ex | 11 +++-- 5 files changed, 70 insertions(+), 37 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index b0676b61..aeaff306 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2776,42 +2776,68 @@ defmodule AshPostgres.DataLayer do @impl true def destroy(resource, %{data: record} = changeset) do - ecto_changeset = ecto_changeset(record, changeset, :delete) - - try do - repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) - - source = resolve_source(resource, changeset) + source = resolve_source(resource, changeset) + query = from(row in source, as: ^0) |> AshSql.Bindings.default_bindings( resource, AshPostgres.SqlImplementation, changeset.context ) - |> filter(changeset.filter, resource) - |> case do - {:ok, query} -> - query - |> pkey_filter(record) - |> repo.delete_all( - AshSql.repo_opts( - repo, - AshPostgres.SqlImplementation, - changeset.timeout, - changeset.tenant, - changeset.resource - ) - ) + |> pkey_filter(record) - :ok + with {:ok, query} <- filter(query, changeset.filter, resource) do + ecto_changeset = + case changeset.data do + %Ash.Changeset.OriginalDataNotAvailable{} -> + changeset.resource.__struct__() + + data -> + data + end + |> Map.update!(:__meta__, &Map.put(&1, :source, table(resource, changeset))) + |> ecto_changeset(changeset, :delete, true) + case bulk_updatable_query( + query, + resource, + [], + [], + changeset.context, + :destroy + ) do {:error, error} -> {:error, error} + + {:ok, query} -> + try do + repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) + + repo_opts = + AshSql.repo_opts( + repo, + AshPostgres.SqlImplementation, + changeset.timeout, + changeset.tenant, + changeset.resource + ) + + query = Ecto.Query.exclude(query, :select) + + with_savepoint(repo, query, fn -> + repo.delete_all( + query, + repo_opts + ) + end) + + :ok + rescue + e -> + handle_raised_error(e, __STACKTRACE__, ecto_changeset, resource) + end end - rescue - e -> - handle_raised_error(e, __STACKTRACE__, ecto_changeset, resource) end end diff --git a/mix.exs b/mix.exs index 38934d69..bfe171b0 100644 --- a/mix.exs +++ b/mix.exs @@ -162,8 +162,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.1 and >= 3.2.1")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.24")}, + {:ash, ash_version("~> 3.1 and >= 3.2.5")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.25")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index 1d361ab7..3e553de9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.2.2", "f079fbe7f4f7e3279825c841aa69f6b83333a86267b31435ca97031a805c4b41", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.8.1 and < 1.0.0-0", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "b9a9165d1aafec1fa719df6182ddee0b2a29c83f67079a04a9a8060f49cc1e7f"}, - "ash_sql": {:hex, :ash_sql, "0.2.24", "324f3fd65e249ad2e7df56a585a768edf6cc91246b7c8048ac16a684edc1437a", [:mix], [{:ash, ">= 3.1.7 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", "38f3066059be9f567ab5c3a8d99e812417069b881bc12fa33c067b1ea7742145"}, + "ash": {:hex, :ash, "3.2.5", "15702f44075cd34e0bd2756d1e286298c2c6b7b30990794940199885f43d8a44", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "f7790ca7a77ec53d06f9b25820c5219e8ea0e7d05e3c477d783cf9d11428dc9a"}, + "ash_sql": {:hex, :ash_sql, "0.2.25", "a9489f5bd54a3a91e161f59b0c95385d62ca239fad6d4851011f532832f0f5ca", [:mix], [{:ash, ">= 3.1.7 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", "caeb8c5ea277aca8e9add5583bf9603bf7517c896a6e9d5eb4327a51f1209051"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -21,8 +21,9 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "igniter": {:hex, :igniter, "0.3.6", "30951d75604e88d6d893753e7331c9793625fbeb5fb34f06148e61ffcdca590f", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "9fc32f2fc6eff9c24abe1d942a6632f5d50ccaeb031504064c1176f78f892b65"}, + "igniter": {:hex, :igniter, "0.3.8", "e6f423170e90a4547f3aca6b4e1879d742787bf7a577db9beee835c6b3890cc2", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "0850066244fead51ac7f749482889878db550c23c3c8addaf5b0d87956a44c91"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, + "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, @@ -31,14 +32,14 @@ "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, - "owl": {:hex, :owl, "0.9.0", "9b33d64734bd51d3fc1d6ed01b12f8c2ed23e1fbf8c43658a6dfbff62578bd03", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "cd70b55327985f8f24d38cb7de5bf8a8d24040e1b49cca2345508f8119ce81fd"}, + "owl": {:hex, :owl, "0.10.0", "1104390ee3e1b29e2c67c1539ffd7554d9f40e8ef67e4817098e9325684bed30", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "c16e35e00e8dd2bc23527678024e7f491064596d78ad40669d44992cac6afdff"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, - "reactor": {:hex, :reactor, "0.8.5", "7a621e0392a5975ed97938a4ddbbc92a6a31157fbd87446bc8bc6b1a0f49e56a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17b1976b9d333e55382dc108779078d5bbdbcd2c3d4033ea6dd52437339fe469"}, + "reactor": {:hex, :reactor, "0.9.0", "f48af9f300454b979a22d5a04b18b59e16959478ffa7f88d50b5e142b5d055dc", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c5ffd700ac669d0992a9e296978abe2110670b23addc0970fca9108d506489c"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.4.0", "be87319b1579191e25464005d465713079b3fd7124a3938a1e6cf4def39735a9", [:mix], [], "hexpm", "16751ca55e3895f2228938b703ad399b0b27acfe288eff6c0e629ed3e6ec0358"}, - "spark": {:hex, :spark, "2.2.9", "cc86e39895e1e1b2360e333fe37fa8cdb5624d265d234c0c945b1b1e11b49563", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "d855e3971f568527bdd43377a8088ae96a7798a1df732c9b7a631730ba2f705d"}, + "spark": {:hex, :spark, "2.2.10", "834c5f6c6874d019116096b82fe8a3e9bfe92077c3e06ead14b6daff528b69ef", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "78972edb0cc1539e56d42f08aabc88b8b2892d64e3e8bd44d58113b7f63622fa"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 418206ce..d1c25ecb 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -1,6 +1,7 @@ defmodule AshPostgres.AtomicsTest do - alias AshPostgres.Test.Comment alias AshPostgres.Test.Author + alias AshPostgres.Test.Comment + use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post @@ -306,7 +307,7 @@ defmodule AshPostgres.AtomicsTest do assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> post |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) - |> Ash.destroy() + |> Ash.destroy!() end end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index a058bce4..ca814737 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -14,7 +14,7 @@ defmodule PassIfOriginalDataPresent do end defmodule HasNoComments do - alias Ash.Error.Invalid + @moduledoc false use Ash.Resource.Validation def atomic(_changeset, _opts, _context) do @@ -22,10 +22,15 @@ defmodule HasNoComments do [ {:atomic, [], expr( - list(comments, field: :id) > 0 or + length(list(comments, field: :id)) > 0 or count(comments) > 0 or exists(comments, true) - ), expr(error(^Invalid, %{message: "Can only delete if Post has no comments"}))} + ), + expr( + error(^Ash.Error.Changes.InvalidChanges, %{ + message: "Can only delete if Post has no comments" + }) + )} ] end end From 8cd441a64664625d8efc7e64fa4bdf96b05a82bd Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 22 Jul 2024 11:50:22 -0400 Subject: [PATCH 088/690] chore: release version v2.1.13 --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 784a7b4e..84aa475f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,45 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.13](https://github.com/ash-project/ash_postgres/compare/v2.1.12...v2.1.13) (2024-07-22) + + + + +### Bug Fixes: + +* update ash & ash_sql for fixes, test atomic alidations in destroys + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.12](https://github.com/ash-project/ash_postgres/compare/v2.1.11...v2.1.12) (2024-07-19) diff --git a/mix.exs b/mix.exs index bfe171b0..e7eabc3f 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.12" + @version "2.1.13" def project do [ From 1b687b6c2a37634443af5712a3553c8b405719e4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 22 Jul 2024 15:38:42 -0400 Subject: [PATCH 089/690] fix: properly convert tenant to string when building lateral join --- lib/data_layer.ex | 2 +- test/multitenancy_test.exs | 27 ++++++++++++++-------- test/support/multitenancy/resources/org.ex | 15 ++++++++++++ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index aeaff306..e5f9aed6 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1271,7 +1271,7 @@ defmodule AshPostgres.DataLayer do query_tenant = case source_query do %{__tenant__: tenant} -> tenant - %{tenant: tenant} -> tenant + %{tenant: tenant} -> Ash.ToTenant.to_tenant(tenant, resource) _ -> nil end diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 5d107f2b..bacd210a 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -30,10 +30,17 @@ defmodule AshPostgres.Test.MultitenancyTest do assert Enum.sort(AshPostgres.TestRepo.all_tenants()) == tenant_ids end + test "lateral joining attribute multitenancy to context multitenancy works", %{org1: org1} do + Org + |> Ash.Query.for_read(:read, %{}, tenant: org1) + |> Ash.Query.load(posts: Ash.Query.limit(Post, 2)) + |> Ash.read!() + end + test "attribute multitenancy works", %{org1: %{id: org_id} = org1} do assert [%{id: ^org_id}] = Org - |> Ash.Query.set_tenant(tenant(org1)) + |> Ash.Query.set_tenant(org1) |> Ash.read!() end @@ -46,7 +53,7 @@ defmodule AshPostgres.Test.MultitenancyTest do assert [] = Org - |> Ash.Query.set_tenant(tenant(org1)) + |> Ash.Query.set_tenant(org1) |> Ash.Query.for_read(:has_policies, %{}, actor: user, authorize?: true) |> Ash.read!() end @@ -54,11 +61,11 @@ defmodule AshPostgres.Test.MultitenancyTest do test "context multitenancy works with policies", %{org1: org1} do post = Post - |> Ash.Changeset.for_create(:create, %{name: "foo"}, tenant: tenant(org1)) + |> Ash.Changeset.for_create(:create, %{name: "foo"}, tenant: org1) |> Ash.create!() post - |> Ash.Changeset.for_update(:update_with_policy, %{}, authorize?: true, tenant: tenant(org1)) + |> Ash.Changeset.for_update(:update_with_policy, %{}, authorize?: true, tenant: org1) |> Ash.update!() end @@ -77,11 +84,11 @@ defmodule AshPostgres.Test.MultitenancyTest do test "schema multitenancy works", %{org1: org1, org2: org2} do Post |> Ash.Changeset.for_create(:create, %{name: "foo"}) - |> Ash.Changeset.set_tenant(tenant(org1)) + |> Ash.Changeset.set_tenant(org1) |> Ash.create!() - assert [_] = Post |> Ash.Query.set_tenant(tenant(org1)) |> Ash.read!() - assert [] = Post |> Ash.Query.set_tenant(tenant(org2)) |> Ash.read!() + assert [_] = Post |> Ash.Query.set_tenant(org1) |> Ash.read!() + assert [] = Post |> Ash.Query.set_tenant(org2) |> Ash.read!() end test "schema rename on update works", %{org1: org1} do @@ -198,7 +205,7 @@ defmodule AshPostgres.Test.MultitenancyTest do user = User |> Ash.Changeset.new() |> Ash.create!() Post - |> Ash.Changeset.for_create(:create, %{}, tenant: tenant(org)) + |> Ash.Changeset.for_create(:create, %{}, tenant: org) |> Ash.Changeset.manage_relationship(:user, user, type: :append_and_remove) |> Ash.create!() end @@ -247,7 +254,7 @@ defmodule AshPostgres.Test.MultitenancyTest do post = Post |> Ash.Changeset.for_create(:create, %{}) - |> Ash.Changeset.set_tenant(tenant(org1)) + |> Ash.Changeset.set_tenant(org1) |> Ash.create!() assert_raise Ash.Error.Invalid, @@ -255,7 +262,7 @@ defmodule AshPostgres.Test.MultitenancyTest do fn -> Post |> Ash.Changeset.for_create(:create, %{id: post.id}) - |> Ash.Changeset.set_tenant(tenant(org1)) + |> Ash.Changeset.set_tenant(org1) |> Ash.create!() end end diff --git a/test/support/multitenancy/resources/org.ex b/test/support/multitenancy/resources/org.ex index 3d1353c8..15c24e05 100644 --- a/test/support/multitenancy/resources/org.ex +++ b/test/support/multitenancy/resources/org.ex @@ -5,6 +5,17 @@ defmodule AshPostgres.MultitenancyTest.Org do data_layer: AshPostgres.DataLayer, authorizers: [Ash.Policy.Authorizer] + defimpl Ash.ToTenant do + def to_tenant(%{id: id}, resource) do + if Ash.Resource.Info.data_layer(resource) == AshPostgres.DataLayer && + Ash.Resource.Info.multitenancy_strategy(resource) == :context do + "org_#{id}" + else + id + end + end + end + policies do policy action(:has_policies) do authorize_if(relates_to_actor_via(:owner)) @@ -68,4 +79,8 @@ defmodule AshPostgres.MultitenancyTest.Org do def tenant("org_" <> tenant) do tenant end + + def tenant(tenant) do + tenant + end end From 605703c2e57837405c019221f95277cda7c2eaa3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 22 Jul 2024 15:41:55 -0400 Subject: [PATCH 090/690] chore: release version v2.1.14 --- CHANGELOG.md | 101 +++++---------------------------------------------- mix.exs | 2 +- 2 files changed, 11 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84aa475f..784f964c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,116 +5,35 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline -## [v2.1.13](https://github.com/ash-project/ash_postgres/compare/v2.1.12...v2.1.13) (2024-07-22) - - - +## [v2.1.14](https://github.com/ash-project/ash_postgres/compare/v2.1.13...v2.1.14) (2024-07-22) ### Bug Fixes: -* update ash & ash_sql for fixes, test atomic alidations in destroys - -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) +- [multitenancy] properly convert tenant to string when building lateral join -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - -### Improvements: - -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression +## [v2.1.13](https://github.com/ash-project/ash_postgres/compare/v2.1.12...v2.1.13) (2024-07-22) -* use latest type casting code from ash +### Bug Fixes: -* support new type determination code +- [atomic validations] update ash & ash_sql for fixes, test atomic validations in destroys ## [v2.1.12](https://github.com/ash-project/ash_postgres/compare/v2.1.11...v2.1.12) (2024-07-19) - - - ### Bug Fixes: -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - -### Improvements: - -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression - -* use latest type casting code from ash - -* support new type determination code - -## [v2.1.11](https://github.com/ash-project/ash_postgres/compare/v2.1.10...v2.1.11) (2024-07-19) - - - +- [`mix ash_postgres.install`] properly add prod config in installer ### Bug Fixes: -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix +- [`mix ash_postgres.install`] properly perform or don't perform configuration modification code -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set +- [`has_many` relationships] allow non-unique has_many source_attributes (#355) ### Improvements: -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression - -* use latest type casting code from ash +- [`mix ash_postgres.install`] prepend `:postgres` to section order -* support new type determination code +- [`mix ash.patch.extend`] pluralize table name in extender ## [v2.1.10](https://github.com/ash-project/ash_postgres/compare/v2.1.9...v2.1.10) (2024-07-18) diff --git a/mix.exs b/mix.exs index e7eabc3f..72e603d4 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.13" + @version "2.1.14" def project do [ From 0a6f8909078c78e906efbce6b1177a5c0becf7de Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Tue, 23 Jul 2024 09:39:18 +0200 Subject: [PATCH 091/690] add update case to validation test --- test/atomics_test.exs | 10 +++++++++- test/support/resources/post.ex | 10 +++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/test/atomics_test.exs b/test/atomics_test.exs index d1c25ecb..97025cb6 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -294,7 +294,7 @@ defmodule AshPostgres.AtomicsTest do |> Map.get(:records) end - test "can use list aggregate in validation" do + test "can use aggregates in validation" do post = Post |> Ash.Changeset.for_create(:create, %{title: "foo", price: 1}) @@ -304,6 +304,14 @@ defmodule AshPostgres.AtomicsTest do |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) |> Ash.create!() + Logger.configure(level: :debug) + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.for_update(:update_if_no_comments, %{title: "bar"}) + |> Ash.update!() + end + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> post |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index ca814737..79299dfd 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -22,9 +22,9 @@ defmodule HasNoComments do [ {:atomic, [], expr( - length(list(comments, field: :id)) > 0 or - count(comments) > 0 or - exists(comments, true) + # length(list(comments, field: :id)) > 0 or + # count(comments) > 0 or + exists(comments, true) ), expr( error(^Ash.Error.Changes.InvalidChanges, %{ @@ -118,6 +118,10 @@ defmodule AshPostgres.Test.Post do validate(HasNoComments) end + update :update_if_no_comments do + validate(HasNoComments) + end + update :update_only_freds do change(filter(expr(title == "fred"))) end From 9e4efa7b9bdbb9b73e033b83c007bfb280203eb8 Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Tue, 23 Jul 2024 10:00:52 +0200 Subject: [PATCH 092/690] remove Logger config and enable aggregates in validation again --- test/atomics_test.exs | 2 -- test/support/resources/post.ex | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 97025cb6..48d77514 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -304,8 +304,6 @@ defmodule AshPostgres.AtomicsTest do |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) |> Ash.create!() - Logger.configure(level: :debug) - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> post |> Ash.Changeset.for_update(:update_if_no_comments, %{title: "bar"}) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 79299dfd..3dbd324d 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -22,9 +22,9 @@ defmodule HasNoComments do [ {:atomic, [], expr( - # length(list(comments, field: :id)) > 0 or - # count(comments) > 0 or - exists(comments, true) + length(list(comments, field: :id)) > 0 or + count(comments) > 0 or + exists(comments, true) ), expr( error(^Ash.Error.Changes.InvalidChanges, %{ From 306dc84ac27b42ae7b6797a75689662ef890ffeb Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Tue, 23 Jul 2024 12:55:44 +0200 Subject: [PATCH 093/690] test validation aggregates individually as well (#360) * test aggregates individually as well * test with atomic and non atomic actions * test atomic and non atomic actions * use message in context --- test/atomics_test.exs | 72 ++++++++++++++++++++++++---------- test/support/resources/post.ex | 54 ++++++++++++++++++++----- 2 files changed, 95 insertions(+), 31 deletions(-) diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 48d77514..4ad038d9 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -294,26 +294,56 @@ defmodule AshPostgres.AtomicsTest do |> Map.get(:records) end - test "can use aggregates in validation" do - post = - Post - |> Ash.Changeset.for_create(:create, %{title: "foo", price: 1}) - |> Ash.create!() - - Comment - |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) - |> Ash.create!() - - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - post - |> Ash.Changeset.for_update(:update_if_no_comments, %{title: "bar"}) - |> Ash.update!() - end - - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - post - |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) - |> Ash.destroy!() + Enum.each( + [ + :exists, + :list, + :count, + :combined + ], + fn aggregate -> + test "can use #{aggregate} in validation" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "foo", price: 1}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) + |> Ash.create!() + + assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_update(:update_if_no_comments, %{title: "bar"}) + |> Ash.update!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_update(:update_if_no_comments_non_atomic, %{title: "bar"}) + |> Ash.update!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_destroy(:destroy_if_no_comments_non_atomic, %{}) + |> Ash.destroy!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) + |> Ash.destroy!() + end + end end - end + ) end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 3dbd324d..473a0103 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -17,18 +17,32 @@ defmodule HasNoComments do @moduledoc false use Ash.Resource.Validation - def atomic(_changeset, _opts, _context) do + def atomic(changeset, _opts, context) do # Test multiple types of aggregates in a single validation + condition = + case changeset.context.aggregate do + :exists -> + expr(exists(comments, true)) + + :list -> + expr(length(list(comments, field: :id)) > 0) + + :count -> + expr(count(comments) > 0) + + :combined -> + expr( + exists(comments, true) and + length(list(comments, field: :id)) > 0 and + count(comments) > 0 + ) + end + [ - {:atomic, [], - expr( - length(list(comments, field: :id)) > 0 or - count(comments) > 0 or - exists(comments, true) - ), + {:atomic, [], condition, expr( error(^Ash.Error.Changes.InvalidChanges, %{ - message: "Can only delete if Post has no comments" + message: ^context.message || "Post has comments" }) )} ] @@ -115,11 +129,31 @@ defmodule AshPostgres.Test.Post do end destroy :destroy_if_no_comments do - validate(HasNoComments) + validate HasNoComments do + message "Can only delete if Post has no comments" + end end update :update_if_no_comments do - validate(HasNoComments) + validate HasNoComments do + message "Can only update if Post has no comments" + end + end + + destroy :destroy_if_no_comments_non_atomic do + require_atomic?(false) + + validate HasNoComments do + message "Can only delete if Post has no comments" + end + end + + update :update_if_no_comments_non_atomic do + require_atomic?(false) + + validate HasNoComments do + message "Can only update if Post has no comments" + end end update :update_only_freds do From cb397e9387930e4ee2f0ffc884c7d537d6ac014c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 23 Jul 2024 07:57:57 -0400 Subject: [PATCH 094/690] fix: use a subquery if any exists aggregates are in play improvement: update ash_sql dependencies for bug fixes --- lib/data_layer.ex | 114 ++++++++++++++++------------------------------ mix.exs | 2 +- mix.lock | 6 +-- 3 files changed, 42 insertions(+), 80 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index e5f9aed6..36a54834 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1465,9 +1465,20 @@ defmodule AshPostgres.DataLayer do end) end + has_exists? = + Enum.any?(atomics, fn {_key, expr} -> + Ash.Filter.find(expr, fn + %Ash.Query.Exists{} -> + true + + _ -> + false + end) + end) + needs_to_join? = requires_adding_inner_join? || - query.limit || query.offset + query.limit || query.offset || has_exists? query = if needs_to_join? do @@ -1481,7 +1492,7 @@ defmodule AshPostgres.DataLayer do {:ok, from(row in Ecto.Query.subquery(root_query), []), atomics != []} end - !Enum.empty?(query.joins) -> + !Enum.empty?(query.joins) || has_exists? -> with root_query <- Ecto.Query.exclude(root_query, :order_by), {:ok, root_query} <- AshSql.Atomics.select_atomics(resource, root_query, atomics) do @@ -2011,7 +2022,7 @@ defmodule AshPostgres.DataLayer do ) end - defp ecto_changeset(record, changeset, type, table_error? \\ true) do + defp ecto_changeset(record, changeset, type, table_error?) do attributes = changeset.resource |> Ash.Resource.Info.attributes() @@ -2673,11 +2684,6 @@ defmodule AshPostgres.DataLayer do @impl true def update(resource, changeset) do - ecto_changeset = - changeset.data - |> Map.update!(:__meta__, &Map.put(&1, :source, table(resource, changeset))) - |> ecto_changeset(changeset, :update) - source = resolve_source(resource, changeset) query = @@ -2689,78 +2695,34 @@ defmodule AshPostgres.DataLayer do ) |> pkey_filter(changeset.data) - case bulk_updatable_query(query, resource, changeset.atomics, [], changeset.context) do - {:error, error} -> - {:error, error} - - {:ok, query} -> - modifying = - Map.keys(changeset.attributes) ++ - Keyword.keys(changeset.atomics) ++ Ash.Resource.Info.primary_key(resource) - - query = Ecto.Query.select(query, ^modifying) - - try do - case AshSql.Atomics.query_with_atomics( - resource, - query, - changeset.filter, - changeset.atomics, - ecto_changeset.changes, - [] - ) do - :empty -> - {:ok, changeset.data} - - {:ok, query} -> - repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) - - repo_opts = - AshSql.repo_opts( - repo, - AshPostgres.SqlImplementation, - changeset.timeout, - changeset.tenant, - changeset.resource - ) - - repo_opts = - Keyword.put(repo_opts, :returning, Keyword.keys(changeset.atomics)) - - result = - with_savepoint(repo, query, fn -> - repo.update_all( - query, - [], - repo_opts - ) - end) - - case result do - {0, []} -> - {:error, - Ash.Error.Changes.StaleRecord.exception( - resource: resource, - filter: changeset.filter - )} + changeset = + Ash.Changeset.set_context(changeset, %{ + data_layer: %{ + use_atomic_update_data?: true + } + }) + + case update_query(query, changeset, resource, %{ + return_records?: true, + calculations: [] + }) do + {:ok, []} -> + {:error, + Ash.Error.Changes.StaleRecord.exception( + resource: resource, + filter: changeset.filter + )} - {1, [result]} -> - record = - changeset.data - |> Map.merge(Map.take(result, modifying)) + {:ok, [record]} -> + maybe_update_tenant(resource, changeset, record) - maybe_update_tenant(resource, changeset, record) + {:ok, record} - {:ok, record} - end + {:error, error} -> + {:error, error} - {:error, error} -> - {:error, error} - end - rescue - e -> - handle_raised_error(e, __STACKTRACE__, ecto_changeset, resource) - end + {:error, :no_rollback, error} -> + {:error, :no_rollback, error} end end diff --git a/mix.exs b/mix.exs index 72e603d4..32b724c9 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1 and >= 3.2.5")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.25")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.26")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index 3e553de9..b0c30357 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.2.5", "15702f44075cd34e0bd2756d1e286298c2c6b7b30990794940199885f43d8a44", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "f7790ca7a77ec53d06f9b25820c5219e8ea0e7d05e3c477d783cf9d11428dc9a"}, - "ash_sql": {:hex, :ash_sql, "0.2.25", "a9489f5bd54a3a91e161f59b0c95385d62ca239fad6d4851011f532832f0f5ca", [:mix], [{:ash, ">= 3.1.7 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", "caeb8c5ea277aca8e9add5583bf9603bf7517c896a6e9d5eb4327a51f1209051"}, + "ash": {:hex, :ash, "3.2.6", "a09042b76c5b573831fcdf004d1109592f9b63fdebc5b464a750289cfaecad83", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "ee850c1e77f987ac094199175610e86558087469a930762e3cd8f6d91ef9da8d"}, + "ash_sql": {:hex, :ash_sql, "0.2.26", "79158f0ec945c83a4403eaa75f7349dde573c4115ef477f57c22624f27607f21", [:mix], [{:ash, ">= 3.1.7 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", "a19b591df382cbc30131e5724514b3737c10a2ab7baf497f5229d1b3557d1244"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "igniter": {:hex, :igniter, "0.3.8", "e6f423170e90a4547f3aca6b4e1879d742787bf7a577db9beee835c6b3890cc2", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "0850066244fead51ac7f749482889878db550c23c3c8addaf5b0d87956a44c91"}, + "igniter": {:hex, :igniter, "0.3.9", "2a3c80e3d5a0f3758670eaa7658fe6334633dab3fd9bca9aae69802f8282a0b3", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "2a5b8618a0aef8e5a545d05d389ba20fc5b0b4b8a6c45cf4f900890c263c7fdc"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, From de2d344de710144094f86228009886b4d495aa2e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 23 Jul 2024 08:11:00 -0400 Subject: [PATCH 095/690] chore: release version v2.1.15 --- CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 784f964c..53d37a7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,51 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.15](https://github.com/ash-project/ash_postgres/compare/v2.1.14...v2.1.15) (2024-07-23) + + + + +### Bug Fixes: + +* use a subquery if any exists aggregates are in play + +* properly convert tenant to string when building lateral join + +* update ash & ash_sql for fixes, test atomic alidations in destroys + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* update ash_sql dependencies for bug fixes + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.14](https://github.com/ash-project/ash_postgres/compare/v2.1.13...v2.1.14) (2024-07-22) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 32b724c9..789b8fb5 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.14" + @version "2.1.15" def project do [ From e49b678351495d0b6b9e50252912b5247092d8d1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 24 Jul 2024 17:22:14 -0400 Subject: [PATCH 096/690] fix: ensure app is compiled before using repo modules --- lib/mix/helpers.ex | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/mix/helpers.ex b/lib/mix/helpers.ex index dc0918a3..9168165b 100644 --- a/lib/mix/helpers.ex +++ b/lib/mix/helpers.ex @@ -85,6 +85,13 @@ defmodule AshPostgres.Mix.Helpers do repos end else + if Code.ensure_loaded?(Mix.Tasks.App.Config) do + Mix.Task.run("app.config", args) + else + Mix.Task.run("loadpaths", args) + "--no-compile" not in args && Mix.Task.run("compile", args) + end + Mix.Project.config()[:app] |> Application.get_env(:ecto_repos, []) |> Enum.filter(fn repo -> From 2b4befedf117e00d83882641880b98291e26b770 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 25 Jul 2024 07:02:12 -0400 Subject: [PATCH 097/690] chore: add `igniter.install` version of getting started guide --- .../get-started-with-ash-postgres.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/documentation/tutorials/get-started-with-ash-postgres.md b/documentation/tutorials/get-started-with-ash-postgres.md index 5897b4ff..db8e1c15 100644 --- a/documentation/tutorials/get-started-with-ash-postgres.md +++ b/documentation/tutorials/get-started-with-ash-postgres.md @@ -1,27 +1,22 @@ # Get Started With Postgres -## Goals +## Installation -In this guide we will: +We recommend [reading up on postgresql](https://www.postgresql.org/docs/16/index.html) if you haven't. -1. Setup AshPostgres, which includes setting up [Ecto](https://hexdocs.pm/ecto/Ecto.html) -2. Add AshPostgres to the resources created in [the Ash getting started guide](https://hexdocs.pm/ash/get-started.html) -3. Show how the various features of AshPostgres can help you work quickly and cleanly against a postgres database -4. Highlight some of the more advanced features you can use when using AshPostgres. -5. Point you to additional resources you may need on your journey +- [Postgres must be installed](https://www.postgresql.org/download/) with a sufficiently permissive user -## Things you may want to read + -- [Install PostgreSQL](https://www.postgresql.org/download/) (I recommend the homebrew option for mac users) +### Using Igniter (recommended) -## Requirements - -- A working Postgres installation, with a sufficiently permissive user -- If you would like to follow along, you will need to add begin with [the Ash getting started guide](https://hexdocs.pm/ash/get-started.html) +```sh +mix igniter.install ash_postgres +``` -## Steps +### Manually -### Add AshPostgres +#### Add AshPostgres Add the `:ash_postgres` dependency to your application @@ -37,7 +32,7 @@ Add `:ash_postgres` to your `.formatter.exs` file ] ``` -### Create and configure your Repo +#### Create and configure your Repo Create `lib/helpdesk/repo.ex` with the following contents. `AshPostgres.Repo` is a thin wrapper around `Ecto.Repo`, so see their documentation for how to use it if you need to use it directly. For standard Ash usage, all you will need to do is configure your resources to use your repo. @@ -153,7 +148,7 @@ And finally, add the repo to your application ... ``` -### Add AshPostgres to our resources +#### Add AshPostgres to our resources Now we can add the data layer to our resources. The basic configuration for a resource requires the `d:AshPostgres.postgres|table` and the `d:AshPostgres.postgres|repo`. @@ -183,7 +178,7 @@ Now we can add the data layer to our resources. The basic configuration for a re end ``` -### Create the database and tables +#### Create the database and tables First, we'll create the database with `mix ash.setup`. @@ -205,8 +200,13 @@ Finally, we will create the local database and apply the generated migrations: mix ash.setup ``` + + ### Try it out +This is based on the [Getting Started](https://hexdocs.pm/ash/getting_started.html) guide. +If you haven't already, you should read that first. + And now we're ready to try it out! Run the following in iex: Lets create some data. We'll make a representative and give them some open and some closed tickets. From be7329d21ac841dd3c4c308918a14df9b8838095 Mon Sep 17 00:00:00 2001 From: Robert Timis <65460527+TimisRobert@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:46:14 +0200 Subject: [PATCH 098/690] docs: Update migrations-and-tasks.md (#363) Add missing filter to account for resources without repo --- documentation/topics/development/migrations-and-tasks.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/topics/development/migrations-and-tasks.md b/documentation/topics/development/migrations-and-tasks.md index 1165569a..619dded2 100644 --- a/documentation/topics/development/migrations-and-tasks.md +++ b/documentation/topics/development/migrations-and-tasks.md @@ -129,6 +129,7 @@ Tasks that need to be executed in the released application (because mix is not p domain |> Ash.Domain.Info.resources() |> Enum.map(&AshPostgres.DataLayer.Info.repo/1) + |> Enum.reject(&is_nil/1) end) |> Enum.uniq() end From ac08104b25ea1e8189fcbe5a25086b74ab757676 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 25 Jul 2024 16:15:23 -0400 Subject: [PATCH 099/690] fix: don't overwrite non-updated fields on update improvement: update ash_sql for cleaner queries --- lib/data_layer.ex | 7 +++++++ mix.exs | 2 +- mix.lock | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 36a54834..798b4a47 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2685,6 +2685,9 @@ defmodule AshPostgres.DataLayer do @impl true def update(resource, changeset) do source = resolve_source(resource, changeset) + modifying = + Map.keys(changeset.attributes) ++ + Keyword.keys(changeset.atomics) ++ Ash.Resource.Info.primary_key(resource) query = from(row in source, as: ^0) @@ -2714,6 +2717,10 @@ defmodule AshPostgres.DataLayer do )} {:ok, [record]} -> + record = + changeset.data + |> Map.merge(Map.take(record, modifying)) + maybe_update_tenant(resource, changeset, record) {:ok, record} diff --git a/mix.exs b/mix.exs index 789b8fb5..666cc66f 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.1 and >= 3.2.5")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.26")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.27")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index b0c30357..0ece96bf 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.2.6", "a09042b76c5b573831fcdf004d1109592f9b63fdebc5b464a750289cfaecad83", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "ee850c1e77f987ac094199175610e86558087469a930762e3cd8f6d91ef9da8d"}, - "ash_sql": {:hex, :ash_sql, "0.2.26", "79158f0ec945c83a4403eaa75f7349dde573c4115ef477f57c22624f27607f21", [:mix], [{:ash, ">= 3.1.7 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", "a19b591df382cbc30131e5724514b3737c10a2ab7baf497f5229d1b3557d1244"}, + "ash_sql": {:hex, :ash_sql, "0.2.27", "57e3dedf749d80f170c424cfccadc58e2a069831c560334aa57e6b5196094a5c", [:mix], [{:ash, ">= 3.1.7 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", "826c4da87157bbdc7e8149576f4b6aecfc6b8481e2b893f7e85747ce594f24e1"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -32,13 +32,13 @@ "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, - "owl": {:hex, :owl, "0.10.0", "1104390ee3e1b29e2c67c1539ffd7554d9f40e8ef67e4817098e9325684bed30", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "c16e35e00e8dd2bc23527678024e7f491064596d78ad40669d44992cac6afdff"}, + "owl": {:hex, :owl, "0.11.0", "2cd46185d330aa2400f1c8c3cddf8d2ff6320baeff23321d1810e58127082cae", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "73f5783f0e963cc04a061be717a0dbb3e49ae0c4bfd55fb4b78ece8d33a65efe"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, "reactor": {:hex, :reactor, "0.9.0", "f48af9f300454b979a22d5a04b18b59e16959478ffa7f88d50b5e142b5d055dc", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c5ffd700ac669d0992a9e296978abe2110670b23addc0970fca9108d506489c"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.4.0", "be87319b1579191e25464005d465713079b3fd7124a3938a1e6cf4def39735a9", [:mix], [], "hexpm", "16751ca55e3895f2228938b703ad399b0b27acfe288eff6c0e629ed3e6ec0358"}, + "sourceror": {:hex, :sourceror, "1.5.0", "3e65d5fbb1a8e2864ad6411262c8018fee73474f5789dda12285c82999253d5d", [:mix], [], "hexpm", "4a32b5d189d8453f73278c15712f8731b89e9211e50726b798214b303b51bfc7"}, "spark": {:hex, :spark, "2.2.10", "834c5f6c6874d019116096b82fe8a3e9bfe92077c3e06ead14b6daff528b69ef", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "78972edb0cc1539e56d42f08aabc88b8b2892d64e3e8bd44d58113b7f63622fa"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, From 07d84d4034f6b6c52495971ea67ab4ecd15901fe Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 25 Jul 2024 16:17:08 -0400 Subject: [PATCH 100/690] chore: release version v2.1.16 --- CHANGELOG.md | 41 +++++++---------------------------------- mix.exs | 2 +- 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53d37a7e..f8749284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,50 +5,23 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline -## [v2.1.15](https://github.com/ash-project/ash_postgres/compare/v2.1.14...v2.1.15) (2024-07-23) - - - +## [v2.1.16](https://github.com/ash-project/ash_postgres/compare/v2.1.15...v2.1.16) (2024-07-25) ### Bug Fixes: -* use a subquery if any exists aggregates are in play - -* properly convert tenant to string when building lateral join - -* update ash & ash_sql for fixes, test atomic alidations in destroys - -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) +- [updates] don't overwrite non-updated fields on update -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set +- [`mix ash_postgres.generate_migrations`] ensure app is compiled before using repo modules ### Improvements: -* update ash_sql dependencies for bug fixes - -* prepend `:postgres` to section order +- [`ash_sql`] update ash_sql for cleaner queries -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression +## [v2.1.15](https://github.com/ash-project/ash_postgres/compare/v2.1.14...v2.1.15) (2024-07-23) -* use latest type casting code from ash +### Bug Fixes: -* support new type determination code +- [query building] use a subquery if any exists aggregates are in play ## [v2.1.14](https://github.com/ash-project/ash_postgres/compare/v2.1.13...v2.1.14) (2024-07-22) diff --git a/mix.exs b/mix.exs index 666cc66f..bd2b7026 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.15" + @version "2.1.16" def project do [ From 793d27ddd180fab8b185dc0a63dcebf57a593c80 Mon Sep 17 00:00:00 2001 From: Robert Timis <65460527+TimisRobert@users.noreply.github.com> Date: Sat, 27 Jul 2024 20:27:02 +0200 Subject: [PATCH 101/690] test: replicate type mismatch bug (#364) --- .../user_invites/20240727145758.json | 49 ++++++++ .../test_repo/users/20240727145758.json | 117 ++++++++++++++++++ .../20240727145758_user_invites.exs | 29 +++++ test/atomics_test.exs | 21 ++++ test/support/domain.ex | 1 + test/support/resources/invite.ex | 23 ++++ test/support/resources/role.ex | 5 + test/support/resources/user.ex | 11 ++ 8 files changed, 256 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/user_invites/20240727145758.json create mode 100644 priv/resource_snapshots/test_repo/users/20240727145758.json create mode 100644 priv/test_repo/migrations/20240727145758_user_invites.exs create mode 100644 test/support/resources/invite.ex create mode 100644 test/support/resources/role.ex diff --git a/priv/resource_snapshots/test_repo/user_invites/20240727145758.json b/priv/resource_snapshots/test_repo/user_invites/20240727145758.json new file mode 100644 index 00000000..7373a8d8 --- /dev/null +++ b/priv/resource_snapshots/test_repo/user_invites/20240727145758.json @@ -0,0 +1,49 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "E2260A6737875A739EB4AFA8896BE4E95F3DC5A624E701AA5F1D09D68C315BBD", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "user_invites" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/users/20240727145758.json b/priv/resource_snapshots/test_repo/users/20240727145758.json new file mode 100644 index 00000000..54b6b916 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20240727145758.json @@ -0,0 +1,117 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "is_active", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "\"user\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "users_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "name": "users_org_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_orgs" + }, + "size": null, + "source": "org_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "80A9C5429DDFAB41DA8448FEC86BEDEEA7CB6A53B69E9A03BD938098A55D6815", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "users" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240727145758_user_invites.exs b/priv/test_repo/migrations/20240727145758_user_invites.exs new file mode 100644 index 00000000..abfce2fb --- /dev/null +++ b/priv/test_repo/migrations/20240727145758_user_invites.exs @@ -0,0 +1,29 @@ +defmodule AshPostgres.TestRepo.Migrations.UserInvites do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:users) do + add(:role, :text, default: "user") + end + + create table(:user_invites, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:name, :text, null: false) + add(:role, :text, null: false) + end + end + + def down do + drop(table(:user_invites)) + + alter table(:users) do + remove(:role) + end + end +end diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 4ad038d9..2ab42b6c 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -3,7 +3,9 @@ defmodule AshPostgres.AtomicsTest do alias AshPostgres.Test.Comment use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Invite alias AshPostgres.Test.Post + alias AshPostgres.Test.User import Ash.Expr require Ash.Query @@ -37,6 +39,25 @@ defmodule AshPostgres.AtomicsTest do |> Ash.update!() end + test "a basic atomic works with enum/allow_nil? false" do + user = + User + |> Ash.Changeset.for_create(:create, %{name: "Dude", role: :user}) + |> Ash.create!() + + Invite + |> Ash.Changeset.for_create(:create, %{ + name: "Dude", + role: :admin + }) + |> Ash.create!() + + assert %{role: :admin} = + user + |> Ash.Changeset.for_update(:accept_invite, %{}) + |> Ash.update!() + end + test "atomics work with maps that contain lists" do post = Post diff --git a/test/support/domain.ex b/test/support/domain.ex index e322c204..a1037a47 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -12,6 +12,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Author) resource(AshPostgres.Test.Profile) resource(AshPostgres.Test.User) + resource(AshPostgres.Test.Invite) resource(AshPostgres.Test.Account) resource(AshPostgres.Test.Organization) resource(AshPostgres.Test.Manager) diff --git a/test/support/resources/invite.ex b/test/support/resources/invite.ex new file mode 100644 index 00000000..32406d1f --- /dev/null +++ b/test/support/resources/invite.ex @@ -0,0 +1,23 @@ +defmodule AshPostgres.Test.Invite do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, allow_nil?: false, public?: true) + attribute(:role, AshPostgres.Test.Role, allow_nil?: false, public?: true) + end + + postgres do + table "user_invites" + repo(AshPostgres.TestRepo) + end +end diff --git a/test/support/resources/role.ex b/test/support/resources/role.ex new file mode 100644 index 00000000..5ce35a73 --- /dev/null +++ b/test/support/resources/role.ex @@ -0,0 +1,5 @@ +defmodule AshPostgres.Test.Role do + @moduledoc false + + use Ash.Type.Enum, values: [:admin, :user] +end diff --git a/test/support/resources/user.ex b/test/support/resources/user.ex index bc57fe4f..25a99f18 100644 --- a/test/support/resources/user.ex +++ b/test/support/resources/user.ex @@ -9,6 +9,11 @@ defmodule AshPostgres.Test.User do defaults([:create, :read, :update, :destroy]) + update :accept_invite do + require_atomic?(false) + change(atomic_update(:role, expr(invite.role))) + end + read :active do filter(expr(active)) @@ -37,6 +42,7 @@ defmodule AshPostgres.Test.User do uuid_primary_key(:id) attribute(:is_active, :boolean, public?: true) attribute(:name, :string, public?: true) + attribute(:role, AshPostgres.Test.Role, allow_nil?: false, default: :user, public?: true) end postgres do @@ -53,5 +59,10 @@ defmodule AshPostgres.Test.User do has_many(:accounts, AshPostgres.Test.Account) do public?(true) end + + has_one(:invite, AshPostgres.Test.Invite) do + source_attribute(:name) + destination_attribute(:name) + end end end From fb5e57cccfb445e7a69993d4a81372ae949bd73d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Jul 2024 17:06:58 -0400 Subject: [PATCH 102/690] improvement: update ash & ash_sql for various fixes --- mix.exs | 4 ++-- mix.lock | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mix.exs b/mix.exs index bd2b7026..6f610c6d 100644 --- a/mix.exs +++ b/mix.exs @@ -162,8 +162,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.1 and >= 3.2.5")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.27")}, + {:ash, ash_version("~> 3.3")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.28")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index 0ece96bf..7e1e5c3d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.2.6", "a09042b76c5b573831fcdf004d1109592f9b63fdebc5b464a750289cfaecad83", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "ee850c1e77f987ac094199175610e86558087469a930762e3cd8f6d91ef9da8d"}, - "ash_sql": {:hex, :ash_sql, "0.2.27", "57e3dedf749d80f170c424cfccadc58e2a069831c560334aa57e6b5196094a5c", [:mix], [{:ash, ">= 3.1.7 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", "826c4da87157bbdc7e8149576f4b6aecfc6b8481e2b893f7e85747ce594f24e1"}, + "ash": {:hex, :ash, "3.3.0", "0391883fe544beb354c6fc4d15a6c693e90aed0336ee1b9051da65ddc8134f6e", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "f1f49225a620cd9c3f0acfcbe24e99d6f8227a312009dbe3889295c4ef1bb869"}, + "ash_sql": {:hex, :ash_sql, "0.2.28", "633ad465e1c4dd1246d2e75b82b5cbdc9abab4fa897094f6de08bf21517bb664", [:mix], [{:ash, ">= 3.1.7 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", "b076f825b81beaaa0a6e90257afbd0173f34690ce936080d72b2d79224a3609e"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -20,11 +20,11 @@ "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, - "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "igniter": {:hex, :igniter, "0.3.9", "2a3c80e3d5a0f3758670eaa7658fe6334633dab3fd9bca9aae69802f8282a0b3", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "2a5b8618a0aef8e5a545d05d389ba20fc5b0b4b8a6c45cf4f900890c263c7fdc"}, + "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, + "igniter": {:hex, :igniter, "0.3.11", "1039c38eaf4e3c677712d097e18be96231479c3e9d7d8fd9c04397b1f6d3601d", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "1381104faaa5c51b2cc540f185e72d3bbab0ea3eb57348c50af4440c7e469491"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, - "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, From b84713cca765f2358634978b4ce81fe0ad951d72 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Jul 2024 17:13:49 -0400 Subject: [PATCH 103/690] chore: release version v2.1.17 --- CHANGELOG.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8749284..a7a67b47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,59 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.17](https://github.com/ash-project/ash_postgres/compare/v2.1.16...v2.1.17) (2024-07-27) + + + + +### Bug Fixes: + +* don't overwrite non-updated fields on update + +* ensure app is compiled before using repo modules + +* use a subquery if any exists aggregates are in play + +* properly convert tenant to string when building lateral join + +* update ash & ash_sql for fixes, test atomic alidations in destroys + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* update ash & ash_sql for various fixes + +* update ash_sql for cleaner queries + +* update ash_sql dependencies for bug fixes + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.16](https://github.com/ash-project/ash_postgres/compare/v2.1.15...v2.1.16) (2024-07-25) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 6f610c6d..28f8ed43 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.16" + @version "2.1.17" def project do [ From cba3966569a4b04e170828cc59e53ed34a7a7b0e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 30 Jul 2024 17:15:39 -0400 Subject: [PATCH 104/690] improvement: update ash_sql for latest fixes test: add test for exists w/ from_many? relationship --- mix.exs | 2 +- mix.lock | 8 ++++---- test/filter_test.exs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/mix.exs b/mix.exs index 28f8ed43..917cc54b 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.3")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.28")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.29")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index 7e1e5c3d..3108ce27 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.3.0", "0391883fe544beb354c6fc4d15a6c693e90aed0336ee1b9051da65ddc8134f6e", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "f1f49225a620cd9c3f0acfcbe24e99d6f8227a312009dbe3889295c4ef1bb869"}, - "ash_sql": {:hex, :ash_sql, "0.2.28", "633ad465e1c4dd1246d2e75b82b5cbdc9abab4fa897094f6de08bf21517bb664", [:mix], [{:ash, ">= 3.1.7 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", "b076f825b81beaaa0a6e90257afbd0173f34690ce936080d72b2d79224a3609e"}, + "ash": {:hex, :ash, "3.3.1", "fc67719590b3f3488f90b267666364f6ac364e7658bee3806c2739c9850d05d9", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "de8568f528194edd6d22f8941f5f67589788fe9a3868e900efac81e2ded25955"}, + "ash_sql": {:hex, :ash_sql, "0.2.29", "d99a40818667d1843e61edae6b3eeeaedda62f34e6477e4dd29017f81fddbf07", [:mix], [{:ash, ">= 3.1.7 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", "1d3cc1c3a26cf87bb913fdf7bcbe9d901d35f260aac36225b8054541836e5752"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.11", "1039c38eaf4e3c677712d097e18be96231479c3e9d7d8fd9c04397b1f6d3601d", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "1381104faaa5c51b2cc540f185e72d3bbab0ea3eb57348c50af4440c7e469491"}, + "igniter": {:hex, :igniter, "0.3.14", "9b93dce6b40a51306ce6f11e5951d81df7eb7cd4e119ba8a781ca3eeca8dd98e", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "d4cf3ca7cdad5e10cb9767e5947d4e358557ed310f1333db26892e96bf3950ff"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,7 +39,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.5.0", "3e65d5fbb1a8e2864ad6411262c8018fee73474f5789dda12285c82999253d5d", [:mix], [], "hexpm", "4a32b5d189d8453f73278c15712f8731b89e9211e50726b798214b303b51bfc7"}, - "spark": {:hex, :spark, "2.2.10", "834c5f6c6874d019116096b82fe8a3e9bfe92077c3e06ead14b6daff528b69ef", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "78972edb0cc1539e56d42f08aabc88b8b2892d64e3e8bd44d58113b7f63622fa"}, + "spark": {:hex, :spark, "2.2.11", "6589ac0e50d69e5095871a5e8f3bb6107755b1cc71f05a31d7398902506dab9a", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "662d297d0ad49a5990a72cbf342d70e90894218062da2893f2df529f70ecc2b4"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/filter_test.exs b/test/filter_test.exs index a1abe491..cff2dae4 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -785,6 +785,37 @@ defmodule AshPostgres.FilterTest do ) |> Ash.read!() end + + test "it works with synthesized to-one relationships" do + for i <- 1..4 do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: to_string(i), category: "foo"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "comment"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + if rem(i, 2) == 0 do + Comment + |> Ash.Changeset.for_create(:create, %{title: "later_comment"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + end + + post + end + + matching_post_count = + Post + |> Ash.Query.filter(exists(latest_comment, title == "later_comment")) + |> Ash.read!() + |> Enum.count() + + assert 2 = matching_post_count + end end describe "filtering on enum types" do From 2ddc53885b9074714bb2af8800c6e69d75368502 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 31 Jul 2024 17:48:55 -0400 Subject: [PATCH 105/690] improvement: dynamically select and allow setting a repo --- lib/data_layer.ex | 18 ++++-- lib/igniter.ex | 84 +++++++++++++++++++++++++++ lib/mix/tasks/ash_postgres.install.ex | 12 +--- 3 files changed, 99 insertions(+), 15 deletions(-) create mode 100644 lib/igniter.ex diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 798b4a47..6f85e935 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2685,9 +2685,10 @@ defmodule AshPostgres.DataLayer do @impl true def update(resource, changeset) do source = resolve_source(resource, changeset) + modifying = - Map.keys(changeset.attributes) ++ - Keyword.keys(changeset.atomics) ++ Ash.Resource.Info.primary_key(resource) + Map.keys(changeset.attributes) ++ + Keyword.keys(changeset.atomics) ++ Ash.Resource.Info.primary_key(resource) query = from(row in source, as: ^0) @@ -2945,7 +2946,7 @@ defmodule AshPostgres.DataLayer do end end - def install(igniter, module, Ash.Resource, _path, _argv) do + def install(igniter, module, Ash.Resource, _path, argv) do table_name = module |> Module.split() @@ -2953,7 +2954,16 @@ defmodule AshPostgres.DataLayer do |> Macro.underscore() |> Inflex.pluralize() - repo = Igniter.Code.Module.module_name("Repo") + {options, _, _} = OptionParser.parse(argv, switches: [repo: :string]) + + repo = + case options[:repo] do + nil -> + Igniter.Code.Module.module_name("Repo") + + repo -> + Igniter.Code.Module.parse(repo) + end igniter |> Spark.Igniter.set_option(module, [:postgres, :table], table_name) diff --git a/lib/igniter.ex b/lib/igniter.ex new file mode 100644 index 00000000..cc99b05c --- /dev/null +++ b/lib/igniter.ex @@ -0,0 +1,84 @@ +defmodule AshPostgres.Igniter do + @moduledoc "Codemods and utilities for working with AshPostgres & Igniter" + + @doc false + def default_repo_contents(otp_app) do + """ + use AshPostgres.Repo, otp_app: #{inspect(otp_app)} + + def installed_extensions do + # Add extensions here, and the migration generator will install them. + ["ash-functions"] + end + """ + end + + def add_postgres_extension(igniter, repo_name, extension) do + Igniter.Code.Module.find_and_update_module!(igniter, repo_name, fn zipper -> + case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do + {:ok, zipper} -> + case Igniter.Code.List.append_new_to_list(zipper, extension) do + {:ok, zipper} -> + {:ok, zipper} + + _ -> + {:warning, + "Could not add installed extension #{inspect(extension)} to #{inspect(repo_name)}.installed_extensions/0"} + end + + _ -> + zipper = Sourceror.Zipper.rightmost(zipper) + + code = """ + def installed_extensions do + [#{inspect(extension)}] + end + """ + + {:ok, Igniter.Code.Common.add_code(zipper, code)} + end + end) + end + + def select_repo(igniter, opts \\ []) do + label = Keyword.get(opts, :label, "Which repo should be used?") + generate = Keyword.get(opts, :generate?, false) + + case list_repos(igniter) do + {igniter, []} -> + if generate do + repo = Igniter.Code.Module.module_name("Repo") + otp_app = Igniter.Project.Application.app_name() + + igniter = + Igniter.Code.Module.create_module(igniter, repo, default_repo_contents(otp_app)) + + {igniter, repo} + else + {igniter, nil} + end + + {igniter, [repo]} -> + {igniter, repo} + + {igniter, repos} -> + {igniter, Owl.IO.select(repos, label: label, render_as: &inspect/1)} + end + end + + def list_repos(igniter) do + Igniter.Code.Module.find_all_matching_modules(igniter, fn _mod, zipper -> + move_to_repo_use(zipper) != :error + end) + end + + defp move_to_repo_use(zipper) do + Igniter.Code.Function.move_to_function_call(zipper, :use, 2, fn zipper -> + Igniter.Code.Function.argument_equals?( + zipper, + 0, + AshPostgres.Repo + ) + end) + end +end diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 48d490c9..26127915 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -250,20 +250,10 @@ defmodule Mix.Tasks.AshPostgres.Install do end defp setup_repo_module(igniter, otp_app, repo) do - default_repo_contents = - """ - use AshPostgres.Repo, otp_app: #{inspect(otp_app)} - - def installed_extensions do - # Add extensions here, and the migration generator will install them. - ["ash-functions"] - end - """ - Igniter.Code.Module.find_and_update_or_create_module( igniter, repo, - default_repo_contents, + AshPostgres.Igniter.default_repo_contents(otp_app), fn zipper -> zipper |> set_otp_app(otp_app) From bc0cb6babdd434dac3253d146dadd99f6626cb7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 12:23:46 -0400 Subject: [PATCH 106/690] chore(deps): bump the production-dependencies group with 2 updates (#365) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.3.1 to 3.3.2 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.3.1...v3.3.2) Updates `igniter` from 0.3.14 to 0.3.16 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.3.14...v0.3.16) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 3108ce27..50de2aee 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.3.1", "fc67719590b3f3488f90b267666364f6ac364e7658bee3806c2739c9850d05d9", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "de8568f528194edd6d22f8941f5f67589788fe9a3868e900efac81e2ded25955"}, + "ash": {:hex, :ash, "3.3.2", "e5bb78f4fde87e3b445675e0d1691c81aecc3f5835bac625b6cc72ab8da13061", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "dd264da49cf737318506f8b6b3c3b1aeb925e5ad6ec8ca27786b341ef9566446"}, "ash_sql": {:hex, :ash_sql, "0.2.29", "d99a40818667d1843e61edae6b3eeeaedda62f34e6477e4dd29017f81fddbf07", [:mix], [{:ash, ">= 3.1.7 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", "1d3cc1c3a26cf87bb913fdf7bcbe9d901d35f260aac36225b8054541836e5752"}, "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"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.14", "9b93dce6b40a51306ce6f11e5951d81df7eb7cd4e119ba8a781ca3eeca8dd98e", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "d4cf3ca7cdad5e10cb9767e5947d4e358557ed310f1333db26892e96bf3950ff"}, + "igniter": {:hex, :igniter, "0.3.16", "5967e06e26379cb7531aa7c4fa9ab8a4899f75d12f00d5453565ca748c24e6ae", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "ccbce6aab2e0f1d1c34f7a19e025e8f66ed970b7ec6e35cc823164625afbf843"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 2d1c7d48ceb85d1d2d411f8e2e03e2bfa4f0ca5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20M=C3=A4nnchen?= Date: Wed, 7 Aug 2024 16:38:00 +0200 Subject: [PATCH 107/690] chore: Cleanup Test Output (#366) --- .../migration_generator.ex | 4 +- test/migration_generator_test.exs | 81 +++++++++---------- test/mix_squash_snapshots_test.exs | 14 +++- 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index a6138ebc..ff8f1d41 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -379,7 +379,7 @@ defmodule AshPostgres.MigrationGenerator do operations -> if opts.check do - IO.puts(""" + Mix.shell().error(""" Migrations would have been generated, but the --check flag was provided. To see what migration would have been generated, run with the `--dry-run` @@ -1028,7 +1028,7 @@ defmodule AshPostgres.MigrationGenerator do end rescue exception -> - IO.puts(""" + Mix.shell().error(""" Exception while formatting: #{inspect(exception)} diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index de8e12ae..a5648c43 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -4,7 +4,17 @@ defmodule AshPostgres.MigrationGeneratorTest do import ExUnit.CaptureLog - defmacrop defposts(mod \\ Post, do: body) do + setup do + current_shell = Mix.shell() + + :ok = Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(current_shell) + end) + end + + defmacrop defresource(mod, do: body) do quote do Code.compiler_options(ignore_module_conflict: true) @@ -13,6 +23,16 @@ defmodule AshPostgres.MigrationGeneratorTest do domain: nil, data_layer: AshPostgres.DataLayer + unquote(body) + end + + Code.compiler_options(ignore_module_conflict: false) + end + end + + defmacrop defposts(mod \\ Post, do: body) do + quote do + defresource unquote(mod) do postgres do table "posts" repo(AshPostgres.TestRepo) @@ -30,8 +50,23 @@ defmodule AshPostgres.MigrationGeneratorTest do unquote(body) end + end + end - Code.compiler_options(ignore_module_conflict: false) + defmacrop defcomments(mod \\ Comment, do: body) do + quote do + defresource unquote(mod) do + postgres do + table "comments" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + unquote(body) + end end end @@ -108,8 +143,6 @@ defmodule AshPostgres.MigrationGeneratorTest do defdomain([Post]) - Mix.shell(Mix.Shell.Process) - AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", @@ -208,8 +241,6 @@ defmodule AshPostgres.MigrationGeneratorTest do defdomain([Post]) - Mix.shell(Mix.Shell.Process) - {:ok, _} = Ecto.Adapters.SQL.query( AshPostgres.TestRepo, @@ -291,7 +322,6 @@ defmodule AshPostgres.MigrationGeneratorTest do end defdomain([Post]) - Mix.shell(Mix.Shell.Process) AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", @@ -336,7 +366,6 @@ defmodule AshPostgres.MigrationGeneratorTest do end defdomain([Post]) - Mix.shell(Mix.Shell.Process) AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", @@ -378,8 +407,6 @@ defmodule AshPostgres.MigrationGeneratorTest do defdomain([Post]) - Mix.shell(Mix.Shell.Process) - AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", @@ -470,8 +497,6 @@ defmodule AshPostgres.MigrationGeneratorTest do defdomain([Post]) - Mix.shell(Mix.Shell.Process) - AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", @@ -833,8 +858,6 @@ defmodule AshPostgres.MigrationGeneratorTest do defdomain([Post]) - Mix.shell(Mix.Shell.Process) - AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", @@ -1635,11 +1658,7 @@ defmodule AshPostgres.MigrationGeneratorTest do File.rm_rf!("test_migration_path") end) - defmodule Comment do - use Ash.Resource, - domain: nil, - data_layer: AshPostgres.DataLayer - + defcomments do postgres do polymorphic?(true) repo(AshPostgres.TestRepo) @@ -1832,16 +1851,7 @@ defmodule AshPostgres.MigrationGeneratorTest do end end - defmodule Comment do - use Ash.Resource, - domain: nil, - data_layer: AshPostgres.DataLayer - - postgres do - table "comments" - repo AshPostgres.TestRepo - end - + defcomments do attributes do uuid_primary_key(:id) end @@ -1855,8 +1865,6 @@ defmodule AshPostgres.MigrationGeneratorTest do defdomain([Post, Comment]) - Mix.shell(Mix.Shell.Process) - AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", @@ -1881,16 +1889,7 @@ defmodule AshPostgres.MigrationGeneratorTest do end end - defmodule Comment do - use Ash.Resource, - domain: nil, - data_layer: AshPostgres.DataLayer - - postgres do - table "comments" - repo AshPostgres.TestRepo - end - + defcomments do attributes do uuid_primary_key(:id) end diff --git a/test/mix_squash_snapshots_test.exs b/test/mix_squash_snapshots_test.exs index 5c934b27..f2827228 100644 --- a/test/mix_squash_snapshots_test.exs +++ b/test/mix_squash_snapshots_test.exs @@ -2,6 +2,16 @@ defmodule AshPostgres.MixSquashSnapshotsTest do use AshPostgres.RepoCase, async: false @moduletag :migration + setup do + current_shell = Mix.shell() + + :ok = Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(current_shell) + end) + end + defmacrop defposts(mod \\ Post, do: body) do quote do Code.compiler_options(ignore_module_conflict: true) @@ -67,8 +77,6 @@ defmodule AshPostgres.MixSquashSnapshotsTest do File.rm_rf!("test_migration_path") end) - Mix.shell(Mix.Shell.Process) - defposts do identities do identity(:title, [:title]) @@ -154,8 +162,6 @@ defmodule AshPostgres.MixSquashSnapshotsTest do File.rm_rf!("test_migration_path") end) - Mix.shell(Mix.Shell.Process) - defposts do identities do identity(:title, [:title]) From cdd94a8b930531f26369f5fc24dab8a41b4e94b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 08:53:03 -0400 Subject: [PATCH 108/690] chore(deps): bump the production-dependencies group with 3 updates (#367) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [igniter](https://github.com/ash-project/igniter) and [postgrex](https://github.com/elixir-ecto/postgrex). Updates `ash` from 3.3.2 to 3.3.3 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.3.2...v3.3.3) Updates `igniter` from 0.3.16 to 0.3.17 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.3.16...v0.3.17) Updates `postgrex` from 0.18.0 to 0.19.0 - [Release notes](https://github.com/elixir-ecto/postgrex/releases) - [Changelog](https://github.com/elixir-ecto/postgrex/blob/master/CHANGELOG.md) - [Commits](https://github.com/elixir-ecto/postgrex/compare/v0.18.0...v0.19.0) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: postgrex dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 50de2aee..07af5576 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.3.2", "e5bb78f4fde87e3b445675e0d1691c81aecc3f5835bac625b6cc72ab8da13061", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "dd264da49cf737318506f8b6b3c3b1aeb925e5ad6ec8ca27786b341ef9566446"}, + "ash": {:hex, :ash, "3.3.3", "1e4047c867e064fe5edabd86c7366dbf3e094a91a2f5269ee0169eb310931e7c", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "0486ec2185deeca68d617eb016d22e598af0e44e7512453f959124f4345ae9df"}, "ash_sql": {:hex, :ash_sql, "0.2.29", "d99a40818667d1843e61edae6b3eeeaedda62f34e6477e4dd29017f81fddbf07", [:mix], [{:ash, ">= 3.1.7 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", "1d3cc1c3a26cf87bb913fdf7bcbe9d901d35f260aac36225b8054541836e5752"}, "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"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.16", "5967e06e26379cb7531aa7c4fa9ab8a4899f75d12f00d5453565ca748c24e6ae", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "ccbce6aab2e0f1d1c34f7a19e025e8f66ed970b7ec6e35cc823164625afbf843"}, + "igniter": {:hex, :igniter, "0.3.17", "177d9c5d4895908b84021d274e6f12c1dd9ac81401a011157efe92a7c63a8196", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "f851584a9403a151a82809d5b1db7d5dda4b35dec5aff7829e75616917d9c9e2"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -33,7 +33,7 @@ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.11.0", "2cd46185d330aa2400f1c8c3cddf8d2ff6320baeff23321d1810e58127082cae", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "73f5783f0e963cc04a061be717a0dbb3e49ae0c4bfd55fb4b78ece8d33a65efe"}, - "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, + "postgrex": {:hex, :postgrex, "0.19.0", "f7d50e50cb42e0a185f5b9a6095125a9ab7e4abccfbe2ab820ab9aa92b71dbab", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "dba2d2a0a8637defbf2307e8629cb2526388ba7348f67d04ec77a5d6a72ecfae"}, "reactor": {:hex, :reactor, "0.9.0", "f48af9f300454b979a22d5a04b18b59e16959478ffa7f88d50b5e142b5d055dc", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c5ffd700ac669d0992a9e296978abe2110670b23addc0970fca9108d506489c"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, From cc7a7615125547786abb8badb497ee04aa6d12f7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 8 Aug 2024 10:01:33 -0400 Subject: [PATCH 109/690] chore: make test assertion clearer to debug CI --- test/aggregate_test.exs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 9c8c27d8..02d2add3 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -616,11 +616,12 @@ defmodule AshSql.AggregateTest do |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) |> Ash.create!() - assert %{first_comment_nils_first_include_nil: "match"} = + assert "match" == Post |> Ash.Query.filter(id == ^post.id) |> Ash.Query.load(:first_comment_nils_first_include_nil) |> Ash.read_one!() + |> Map.get(:first_comment_nils_first_include_nil) end test "it can be sorted on" do From 769f8bfccfda34d74b31ff7748e3915b3f71825e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 9 Aug 2024 16:09:49 -0400 Subject: [PATCH 110/690] fix: update ash_sql for exists aggregate fixes --- mix.exs | 2 +- mix.lock | 2 +- test/aggregate_test.exs | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index 917cc54b..42de7696 100644 --- a/mix.exs +++ b/mix.exs @@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.3")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.29")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.11 and >= 3.11.3"}, {:ecto, "~> 3.11 and >= 3.11.2"}, diff --git a/mix.lock b/mix.lock index 07af5576..cc085f2d 100644 --- a/mix.lock +++ b/mix.lock @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.17", "177d9c5d4895908b84021d274e6f12c1dd9ac81401a011157efe92a7c63a8196", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "f851584a9403a151a82809d5b1db7d5dda4b35dec5aff7829e75616917d9c9e2"}, + "igniter": {:hex, :igniter, "0.3.18", "da7a08eba965a89282c3a8642d7ccc718be65b09aef3d77312dbb27e3f288466", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "91c7b011cfa6b5036cd84757a3a8a8e009ef59c06956789f598ada3eb8be2fc4"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 02d2add3..62f2d81e 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -334,6 +334,24 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end + test "exists aggregates can be referenced in nested filters" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Logger.configure(level: :debug) + + assert Comment + |> Ash.Query.filter(post.has_comment_called_match) + |> Ash.read_one!() + end + test "exists aggregates can be used at the query level" do post = Post From 4db75671ed5f188ce084a77c6c292a50ffea61ac Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 9 Aug 2024 16:10:21 -0400 Subject: [PATCH 111/690] chore: release version v2.1.18 --- CHANGELOG.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7a67b47..ee30a3f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,65 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.18](https://github.com/ash-project/ash_postgres/compare/v2.1.17...v2.1.18) (2024-08-09) + + + + +### Bug Fixes: + +* update ash_sql for exists aggregate fixes + +* don't overwrite non-updated fields on update + +* ensure app is compiled before using repo modules + +* use a subquery if any exists aggregates are in play + +* properly convert tenant to string when building lateral join + +* update ash & ash_sql for fixes, test atomic alidations in destroys + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* dynamically select and allow setting a repo + +* update ash_sql for latest fixes + +* update ash & ash_sql for various fixes + +* update ash_sql for cleaner queries + +* update ash_sql dependencies for bug fixes + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.17](https://github.com/ash-project/ash_postgres/compare/v2.1.16...v2.1.17) (2024-07-27) diff --git a/mix.exs b/mix.exs index 42de7696..7137fd11 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.17" + @version "2.1.18" def project do [ From ed602671735db23788f05836e64004c9c55e3254 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 9 Aug 2024 16:10:39 -0400 Subject: [PATCH 112/690] chore: update mix.lock --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index cc085f2d..b9cf57bf 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.3.3", "1e4047c867e064fe5edabd86c7366dbf3e094a91a2f5269ee0169eb310931e7c", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "0486ec2185deeca68d617eb016d22e598af0e44e7512453f959124f4345ae9df"}, - "ash_sql": {:hex, :ash_sql, "0.2.29", "d99a40818667d1843e61edae6b3eeeaedda62f34e6477e4dd29017f81fddbf07", [:mix], [{:ash, ">= 3.1.7 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", "1d3cc1c3a26cf87bb913fdf7bcbe9d901d35f260aac36225b8054541836e5752"}, + "ash_sql": {:hex, :ash_sql, "0.2.30", "244a2071c7fdaec486a186136e52a635dc01f2c1db774d3c506562b339efcf1c", [:mix], [{:ash, ">= 3.1.7 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", "e93f704b5b29caf0793dd880ec10b1fd313cc0e0a385074955ca36d8af530e4e"}, "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"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, From 5e8ac4bf7e63a8151f96c36f3deb88e9587cf851 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 12 Aug 2024 14:22:21 -0400 Subject: [PATCH 113/690] fix: we missed a change when preparing for ecto 3.12 parameterized type changes --- lib/sql_implementation.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 7c556076..6a26291a 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -249,11 +249,13 @@ defmodule AshPostgres.SqlImplementation do new_returns = case new_returns do + {:parameterized, _} = parameterized -> parameterized {type, constraints} -> parameterized_type(type, constraints) other -> other end {Enum.map(types, fn + {:parameterized, _} = parameterized -> parameterized {type, constraints} -> parameterized_type(type, constraints) From 8f3005294473db3a854d5c13ac8faff9f73d609c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 12 Aug 2024 14:25:04 -0400 Subject: [PATCH 114/690] chore: update mix.lock --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index b9cf57bf..3bdcffe5 100644 --- a/mix.lock +++ b/mix.lock @@ -10,8 +10,8 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, - "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, + "ecto": {:hex, :ecto, "3.12.0", "9014a3ccac7f91e680b9d237d461ebe3d4e16d62ca8e355d540e2c6afdc28309", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "41e781a76e131093af8e1edf68b1319bf320878faff58da41ffa4b10fc6ff678"}, + "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, @@ -34,11 +34,11 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.11.0", "2cd46185d330aa2400f1c8c3cddf8d2ff6320baeff23321d1810e58127082cae", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "73f5783f0e963cc04a061be717a0dbb3e49ae0c4bfd55fb4b78ece8d33a65efe"}, "postgrex": {:hex, :postgrex, "0.19.0", "f7d50e50cb42e0a185f5b9a6095125a9ab7e4abccfbe2ab820ab9aa92b71dbab", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "dba2d2a0a8637defbf2307e8629cb2526388ba7348f67d04ec77a5d6a72ecfae"}, - "reactor": {:hex, :reactor, "0.9.0", "f48af9f300454b979a22d5a04b18b59e16959478ffa7f88d50b5e142b5d055dc", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c5ffd700ac669d0992a9e296978abe2110670b23addc0970fca9108d506489c"}, + "reactor": {:hex, :reactor, "0.9.1", "082f8e9b1fd7586c0a016c2fb533835fec7eaef5ffb0263abb4473106c20b1ca", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7191ddf95fdd2b65770a57a2e38dd502a94909e51ac8daf497330e67fc032dc3"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.5.0", "3e65d5fbb1a8e2864ad6411262c8018fee73474f5789dda12285c82999253d5d", [:mix], [], "hexpm", "4a32b5d189d8453f73278c15712f8731b89e9211e50726b798214b303b51bfc7"}, + "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, "spark": {:hex, :spark, "2.2.11", "6589ac0e50d69e5095871a5e8f3bb6107755b1cc71f05a31d7398902506dab9a", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "662d297d0ad49a5990a72cbf342d70e90894218062da2893f2df529f70ecc2b4"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, From e8027f6e9d7e41ecf341e589f6bf5dd2a5cc025f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 12 Aug 2024 14:25:42 -0400 Subject: [PATCH 115/690] chore: release version v2.1.19 --- CHANGELOG.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee30a3f4..0551a506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,67 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.1.19](https://github.com/ash-project/ash_postgres/compare/v2.1.18...v2.1.19) (2024-08-12) + + + + +### Bug Fixes: + +* we missed a change when preparing for ecto 3.12 parameterized type changes + +* update ash_sql for exists aggregate fixes + +* don't overwrite non-updated fields on update + +* ensure app is compiled before using repo modules + +* use a subquery if any exists aggregates are in play + +* properly convert tenant to string when building lateral join + +* update ash & ash_sql for fixes, test atomic alidations in destroys + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* dynamically select and allow setting a repo + +* update ash_sql for latest fixes + +* update ash & ash_sql for various fixes + +* update ash_sql for cleaner queries + +* update ash_sql dependencies for bug fixes + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.18](https://github.com/ash-project/ash_postgres/compare/v2.1.17...v2.1.18) (2024-08-09) diff --git a/mix.exs b/mix.exs index 7137fd11..77c1e3c9 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.18" + @version "2.1.19" def project do [ From 73c7a915e00b06e4119935bbedf674106687a668 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 12 Aug 2024 14:45:04 -0400 Subject: [PATCH 116/690] chore: format --- lib/sql_implementation.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 6a26291a..71ec3cf2 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -255,7 +255,9 @@ defmodule AshPostgres.SqlImplementation do end {Enum.map(types, fn - {:parameterized, _} = parameterized -> parameterized + {:parameterized, _} = parameterized -> + parameterized + {type, constraints} -> parameterized_type(type, constraints) From a539f6443ef52a601349c70cafbf0d91d42595d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20M=C3=A4nnchen?= Date: Mon, 12 Aug 2024 20:48:45 +0200 Subject: [PATCH 117/690] fix: handle filter condition on create (#368) --- lib/data_layer.ex | 22 +++++++++++++ test/bulk_create_test.exs | 44 ++++++++++++++++++++++++++ test/create_test.exs | 58 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 12 ++++++- test/test_helper.exs | 2 +- 5 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 test/create_test.exs diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 6f85e935..c56fbf9f 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -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} diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index f4edee0b..bdfdd497 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -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 diff --git a/test/create_test.exs b/test/create_test.exs new file mode 100644 index 00000000..0f461dfc --- /dev/null +++ b/test/create_test.exs @@ -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 diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 473a0103..468afe0f 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -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 diff --git a/test/test_helper.exs b/test/test_helper.exs index fd6fc1e0..6a184284 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,4 @@ -ExUnit.start() +ExUnit.start(capture_log: true) ExUnit.configure(stacktrace_depth: 100) AshPostgres.TestRepo.start_link() From 10cf60cdc1c69ea6e8044cacd3fba9fc83eb265d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 13 Aug 2024 09:57:31 -0400 Subject: [PATCH 118/690] fix: remove `Agent` "convenience" for determining min pg version We need to require that users provide this function. To that end we're adding a warning in a minor release branch telling users to define this. The agent was acting as a bottleneck that all queries must go through, causing nontrivial performance issues at scale. --- lib/data_layer/info.ex | 11 +++- lib/repo.ex | 106 +------------------------------------ lib/repo/before_compile.ex | 25 +++++++++ mix.lock | 2 +- test/aggregate_test.exs | 2 - test/support/test_repo.ex | 4 ++ 6 files changed, 40 insertions(+), 110 deletions(-) create mode 100644 lib/repo/before_compile.ex diff --git a/lib/data_layer/info.ex b/lib/data_layer/info.ex index 5dcec0ad..7f66ff2c 100644 --- a/lib/data_layer/info.ex +++ b/lib/data_layer/info.ex @@ -42,8 +42,15 @@ defmodule AshPostgres.DataLayer.Info do @doc "Gets the resource's repo's postgres version" def min_pg_version(resource) do case repo(resource, :read).min_pg_version() do - %Version{} = version -> version - string when is_binary(string) -> Version.parse!(string) + %Version{} = version -> + version + + string when is_binary(string) -> + IO.warn( + "Got a `string` for min_pg_version, expected a `Version` struct. Got: #{inspect(string)}. Please call `Version.parse!` before returning the value." + ) + + Version.parse!(string) end end diff --git a/lib/repo.ex b/lib/repo.ex index b6a49815..d46107bb 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -86,10 +86,10 @@ defmodule AshPostgres.Repo do otp_app: otp_app end - @agent __MODULE__.AshPgVersion @behaviour AshPostgres.Repo @warn_on_missing_ash_functions Keyword.get(opts, :warn_on_missing_ash_functions?, true) @after_compile __MODULE__ + @before_compile AshPostgres.Repo.BeforeCompile require Logger defoverridable insert: 2, insert: 1, insert!: 2, insert!: 1 @@ -123,18 +123,6 @@ defmodule AshPostgres.Repo do end def init(type, config) do - if type == :supervisor do - try do - Agent.stop(@agent) - rescue - _ -> - :ok - catch - _, _ -> - :ok - end - end - new_config = config |> Keyword.put(:installed_extensions, installed_extensions()) @@ -208,97 +196,6 @@ defmodule AshPostgres.Repo do end end - def min_pg_version do - if version = cached_version() do - version - else - lookup_version() - end - end - - defp cached_version do - if config()[:pool] == Ecto.Adapters.SQL.Sandbox do - Agent.start_link( - fn -> - nil - end, - name: @agent - ) - - case Agent.get(@agent, fn state -> state end) do - nil -> - version = lookup_version() - - Agent.update(@agent, fn _ -> - version - end) - - version - - version -> - version - end - else - Agent.start_link( - fn -> - lookup_version() - end, - name: @agent - ) - - Agent.get(@agent, fn state -> state end) - end - end - - defp lookup_version do - version_string = - try do - query!("SELECT version()").rows |> Enum.at(0) |> Enum.at(0) - rescue - error -> - reraise """ - Got an error while trying to read postgres version - - Error: - - #{inspect(error)} - """, - __STACKTRACE__ - end - - try do - version_string - |> String.split(" ") - |> Enum.at(1) - |> String.split(".") - |> case do - [major] -> - "#{major}.0.0" - - [major, minor] -> - "#{major}.#{minor}.0" - - other -> - Enum.join(other, ".") - end - |> Version.parse!() - rescue - error -> - reraise( - """ - Could not parse postgres version from version string: "#{version_string}" - - You may need to define the `min_version/0` callback yourself. - - Error: - - #{inspect(error)} - """, - __STACKTRACE__ - ) - end - end - def from_ecto(other), do: other def to_ecto(nil), do: nil @@ -336,7 +233,6 @@ defmodule AshPostgres.Repo do defoverridable init: 2, on_transaction_begin: 1, installed_extensions: 0, - min_pg_version: 0, all_tenants: 0, tenant_migrations_path: 0, default_prefix: 0, diff --git a/lib/repo/before_compile.ex b/lib/repo/before_compile.ex new file mode 100644 index 00000000..a53f96d0 --- /dev/null +++ b/lib/repo/before_compile.ex @@ -0,0 +1,25 @@ +defmodule AshPostgres.Repo.BeforeCompile do + @moduledoc false + + defmacro __before_compile__(_env) do + quote do + unless Module.defines?(__MODULE__, {:min_pg_version, 0}, :def) do + IO.warn(""" + Please define `min_pg_version/0` in repo module: #{inspect(__MODULE__)} + + For example: + + def min_pg_version do + %Version{major: 16, minor: 0, patch: 0} + end + + The lowest compatible version is being assumed. + """) + + def min_pg_version do + %Version{major: 13, minor: 0, patch: 0} + end + end + end + end +end diff --git a/mix.lock b/mix.lock index 3bdcffe5..7d50c371 100644 --- a/mix.lock +++ b/mix.lock @@ -39,7 +39,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.11", "6589ac0e50d69e5095871a5e8f3bb6107755b1cc71f05a31d7398902506dab9a", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "662d297d0ad49a5990a72cbf342d70e90894218062da2893f2df529f70ecc2b4"}, + "spark": {:hex, :spark, "2.2.16", "221f18b302f8b2df28ac5664c4a1abc8b9c1ba493676d9dc77234a8dbfcd07ae", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "143d3f78d717556041a1b89f523ba7f3004f90351a567e9ea9044f90afcd1085"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 62f2d81e..630aeaac 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -345,8 +345,6 @@ defmodule AshSql.AggregateTest do |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) |> Ash.create!() - Logger.configure(level: :debug) - assert Comment |> Ash.Query.filter(post.has_comment_called_match) |> Ash.read_one!() diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index 50d1b472..094b947a 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -12,6 +12,10 @@ defmodule AshPostgres.TestRepo do Application.get_env(:ash_postgres, :no_extensions, []) end + def min_pg_version do + %Version{major: 16, minor: 0, patch: 0} + end + def all_tenants do Code.ensure_compiled(AshPostgres.MultitenancyTest.Org) From 8244a203e0b60b0ce65c087259b8a356319715cf Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 13 Aug 2024 09:58:42 -0400 Subject: [PATCH 119/690] chore: release version v2.2.0 --- CHANGELOG.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0551a506..a006b836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,71 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.2.0](https://github.com/ash-project/ash_postgres/compare/v2.1.19...v2.2.0) (2024-08-13) + + + + +### Bug Fixes: + +* remove `Agent` "convenience" for determining min pg version + +* handle filter condition on create (#368) + +* we missed a change when preparing for ecto 3.12 parameterized type changes + +* update ash_sql for exists aggregate fixes + +* don't overwrite non-updated fields on update + +* ensure app is compiled before using repo modules + +* use a subquery if any exists aggregates are in play + +* properly convert tenant to string when building lateral join + +* update ash & ash_sql for fixes, test atomic alidations in destroys + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* dynamically select and allow setting a repo + +* update ash_sql for latest fixes + +* update ash & ash_sql for various fixes + +* update ash_sql for cleaner queries + +* update ash_sql dependencies for bug fixes + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.1.19](https://github.com/ash-project/ash_postgres/compare/v2.1.18...v2.1.19) (2024-08-12) diff --git a/mix.exs b/mix.exs index 77c1e3c9..856bedd3 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.1.19" + @version "2.2.0" def project do [ From 9ac8c02eccb2d2e232a6979c52595fe3d064d42e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 13 Aug 2024 10:03:37 -0400 Subject: [PATCH 120/690] chore: fix changelog --- CHANGELOG.md | 225 +++------------------------------------------------ 1 file changed, 10 insertions(+), 215 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a006b836..e3aca9cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,241 +7,36 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.2.0](https://github.com/ash-project/ash_postgres/compare/v2.1.19...v2.2.0) (2024-08-13) - - - ### Bug Fixes: -* remove `Agent` "convenience" for determining min pg version - -* handle filter condition on create (#368) - -* we missed a change when preparing for ecto 3.12 parameterized type changes - -* update ash_sql for exists aggregate fixes - -* don't overwrite non-updated fields on update - -* ensure app is compiled before using repo modules - -* use a subquery if any exists aggregates are in play - -* properly convert tenant to string when building lateral join - -* update ash & ash_sql for fixes, test atomic alidations in destroys - -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - -### Improvements: - -* dynamically select and allow setting a repo - -* update ash_sql for latest fixes - -* update ash & ash_sql for various fixes - -* update ash_sql for cleaner queries - -* update ash_sql dependencies for bug fixes - -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies +- [`AshPostgres.Repo`] remove `Agent` "convenience" for determining min pg version -* add `binding()` expression +We need to require that users provide this function. To that end we're +adding a warning in a minor release branch telling users to define this. +The agent was acting as a bottleneck that all queries must go through, +causing nontrivial performance issues at scale. -* use latest type casting code from ash - -* support new type determination code +- [upserts] handle filter condition on create (#368) ## [v2.1.19](https://github.com/ash-project/ash_postgres/compare/v2.1.18...v2.1.19) (2024-08-12) - - - ### Bug Fixes: -* we missed a change when preparing for ecto 3.12 parameterized type changes - -* update ash_sql for exists aggregate fixes - -* don't overwrite non-updated fields on update - -* ensure app is compiled before using repo modules - -* use a subquery if any exists aggregates are in play - -* properly convert tenant to string when building lateral join - -* update ash & ash_sql for fixes, test atomic alidations in destroys - -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - -### Improvements: - -* dynamically select and allow setting a repo - -* update ash_sql for latest fixes - -* update ash & ash_sql for various fixes - -* update ash_sql for cleaner queries - -* update ash_sql dependencies for bug fixes - -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies +- [ecto compatibility] we missed a change when preparing for ecto 3.12 parameterized type changes -* add `binding()` expression - -* use latest type casting code from ash - -* support new type determination code +- [exists aggregates] update ash_sql for exists aggregate fixes ## [v2.1.18](https://github.com/ash-project/ash_postgres/compare/v2.1.17...v2.1.18) (2024-08-09) - - - -### Bug Fixes: - -* update ash_sql for exists aggregate fixes - -* don't overwrite non-updated fields on update - -* ensure app is compiled before using repo modules - -* use a subquery if any exists aggregates are in play - -* properly convert tenant to string when building lateral join - -* update ash & ash_sql for fixes, test atomic alidations in destroys - -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - ### Improvements: -* dynamically select and allow setting a repo - -* update ash_sql for latest fixes - -* update ash & ash_sql for various fixes - -* update ash_sql for cleaner queries - -* update ash_sql dependencies for bug fixes - -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression - -* use latest type casting code from ash - -* support new type determination code +- [`ash_postgres.gen.migration`] dynamically select and allow setting a repo ## [v2.1.17](https://github.com/ash-project/ash_postgres/compare/v2.1.16...v2.1.17) (2024-07-27) - - - -### Bug Fixes: - -* don't overwrite non-updated fields on update - -* ensure app is compiled before using repo modules - -* use a subquery if any exists aggregates are in play - -* properly convert tenant to string when building lateral join - -* update ash & ash_sql for fixes, test atomic alidations in destroys - -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set - ### Improvements: -* update ash & ash_sql for various fixes - -* update ash_sql for cleaner queries - -* update ash_sql dependencies for bug fixes - -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression - -* use latest type casting code from ash - -* support new type determination code +- [`ash_sql`] update ash & ash_sql for various fixes ## [v2.1.16](https://github.com/ash-project/ash_postgres/compare/v2.1.15...v2.1.16) (2024-07-25) From 4f7b3cdcd02a85e5c76d702d8073f08af90e9abc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 06:23:08 -0400 Subject: [PATCH 121/690] chore(deps): bump the production-dependencies group with 4 updates (#371) --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 7d50c371..fa1f597c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.3.3", "1e4047c867e064fe5edabd86c7366dbf3e094a91a2f5269ee0169eb310931e7c", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "0486ec2185deeca68d617eb016d22e598af0e44e7512453f959124f4345ae9df"}, + "ash": {:hex, :ash, "3.4.1", "14bfccd4c1e7c17db5aed1ecb5062875f55b56b67f6fba911f3a8ef6739f3cfd", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "1e3127e0af0698e652a6bbfb4d4f1a3bb8a48fb42833f4e8f00eda8f1a93082b"}, "ash_sql": {:hex, :ash_sql, "0.2.30", "244a2071c7fdaec486a186136e52a635dc01f2c1db774d3c506562b339efcf1c", [:mix], [{:ash, ">= 3.1.7 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", "e93f704b5b29caf0793dd880ec10b1fd313cc0e0a385074955ca36d8af530e4e"}, "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"}, @@ -10,7 +10,7 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "ecto": {:hex, :ecto, "3.12.0", "9014a3ccac7f91e680b9d237d461ebe3d4e16d62ca8e355d540e2c6afdc28309", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "41e781a76e131093af8e1edf68b1319bf320878faff58da41ffa4b10fc6ff678"}, + "ecto": {:hex, :ecto, "3.12.1", "626765f7066589de6fa09e0876a253ff60c3d00870dd3a1cd696e2ba67bfceea", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "df0045ab9d87be947228e05a8d153f3e06e0d05ab10c3b3cc557d2f7243d1940"}, "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.18", "da7a08eba965a89282c3a8642d7ccc718be65b09aef3d77312dbb27e3f288466", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "91c7b011cfa6b5036cd84757a3a8a8e009ef59c06956789f598ada3eb8be2fc4"}, + "igniter": {:hex, :igniter, "0.3.19", "dfa4a05e94be72e9b75c9ce73b9ce408c9a5fe8f1f010eb36e711e70da698b46", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "f9b1ca6d11a7dcd1beb0bc0a1c08b8ce1fb4eb140a763037f3b79d9170cbf958"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -33,13 +33,13 @@ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.11.0", "2cd46185d330aa2400f1c8c3cddf8d2ff6320baeff23321d1810e58127082cae", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "73f5783f0e963cc04a061be717a0dbb3e49ae0c4bfd55fb4b78ece8d33a65efe"}, - "postgrex": {:hex, :postgrex, "0.19.0", "f7d50e50cb42e0a185f5b9a6095125a9ab7e4abccfbe2ab820ab9aa92b71dbab", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "dba2d2a0a8637defbf2307e8629cb2526388ba7348f67d04ec77a5d6a72ecfae"}, + "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, "reactor": {:hex, :reactor, "0.9.1", "082f8e9b1fd7586c0a016c2fb533835fec7eaef5ffb0263abb4473106c20b1ca", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7191ddf95fdd2b65770a57a2e38dd502a94909e51ac8daf497330e67fc032dc3"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.16", "221f18b302f8b2df28ac5664c4a1abc8b9c1ba493676d9dc77234a8dbfcd07ae", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "143d3f78d717556041a1b89f523ba7f3004f90351a567e9ea9044f90afcd1085"}, + "spark": {:hex, :spark, "2.2.21", "b343f3488b5a986ad38d15ac124b9111b8f63f953e3a6ef3fad44fe129b7fad6", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "45b05c52a1afe4858e10b5e6b8cd33bff3cf0098afc144146c5ff05002d75a9d"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 97ef1437ccc472a8f15cb2a7ea5193df72c56ca1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 15 Aug 2024 07:25:29 -0400 Subject: [PATCH 122/690] chore: CI/test/build fixes --- mix.exs | 4 ++-- test/calculation_test.exs | 28 ++++++++++++++++++++++++++++ test/support/resources/post.ex | 8 ++++++++ test/support/test_no_sandbox_repo.ex | 7 +++++++ test/support/test_repo.ex | 5 ++++- 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 856bedd3..2e7c5a7d 100644 --- a/mix.exs +++ b/mix.exs @@ -165,8 +165,8 @@ defmodule AshPostgres.MixProject do {:ash, ash_version("~> 3.3")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, {:igniter, "~> 0.3 and >= 0.3.6"}, - {:ecto_sql, "~> 3.11 and >= 3.11.3"}, - {:ecto, "~> 3.11 and >= 3.11.2"}, + {:ecto_sql, "~> 3.12"}, + {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, # dev/test dependencies diff --git a/test/calculation_test.exs b/test/calculation_test.exs index e15dbbc8..38cc70f8 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -814,6 +814,34 @@ defmodule AshPostgres.CalculationTest do |> Ash.read!() end + # This test will pass on Ash 3.4.2+ + test "using calculations with input as anonymous aggregate fields works" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "abcdef"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "abc"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "abcd"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "abcde"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert %{max_comment_similarity: 0.625} = + Post + |> Ash.Query.load(max_comment_similarity: %{to: "abcdef"}) + |> Ash.read_one!() + end + test "exists with a relationship that has a filtered read action works" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 468afe0f..399254fa 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -551,6 +551,14 @@ defmodule AshPostgres.Test.Post do expr(count(comments, query: [filter: expr(title == "baz")])) ) + calculate( + :max_comment_similarity, + :float, + expr(max(comments, expr_type: :float, expr: fragment("similarity(?, ?)", title, ^arg(:to)))) + ) do + argument(:to, :string, allow_nil?: false) + end + calculate( :agg_map, :map, diff --git a/test/support/test_no_sandbox_repo.ex b/test/support/test_no_sandbox_repo.ex index f1222459..201d3667 100644 --- a/test/support/test_no_sandbox_repo.ex +++ b/test/support/test_no_sandbox_repo.ex @@ -7,6 +7,13 @@ defmodule AshPostgres.TestNoSandboxRepo do send(self(), data) end + def min_pg_version do + case System.get_env("PG_VERSION") do + nil -> %Version{major: 16, minor: 0, patch: 0} + version -> Version.parse!(version) + end + end + def installed_extensions do ["ash-functions", "uuid-ossp", "pg_trgm", "citext", AshPostgres.TestCustomExtension] -- Application.get_env(:ash_postgres, :no_extensions, []) diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index 094b947a..c12dad79 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -13,7 +13,10 @@ defmodule AshPostgres.TestRepo do end def min_pg_version do - %Version{major: 16, minor: 0, patch: 0} + case System.get_env("PG_VERSION") do + nil -> %Version{major: 16, minor: 0, patch: 0} + version -> Version.parse!(version) + end end def all_tenants do From e7ea05edc6abf425e6bc4a6676ff80c98ece6b4b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 15 Aug 2024 07:48:29 -0400 Subject: [PATCH 123/690] chore: unlock deps --- mix.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/mix.lock b/mix.lock index fa1f597c..23427c91 100644 --- a/mix.lock +++ b/mix.lock @@ -3,7 +3,6 @@ "ash_sql": {:hex, :ash_sql, "0.2.30", "244a2071c7fdaec486a186136e52a635dc01f2c1db774d3c506562b339efcf1c", [:mix], [{:ash, ">= 3.1.7 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", "e93f704b5b29caf0793dd880ec10b1fd313cc0e0a385074955ca36d8af530e4e"}, "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"}, - "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, @@ -45,7 +44,6 @@ "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"}, "ucwidth": {:hex, :ucwidth, "0.2.0", "1f0a440f541d895dff142275b96355f7e91e15bca525d4a0cc788ea51f0e3441", [:mix], [], "hexpm", "c1efd1798b8eeb11fb2bec3cafa3dd9c0c3647bee020543f0340b996177355bf"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, From d2b73fc3c3ef6d2fbf017abd2f3ffd6f8c0f8b61 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 15 Aug 2024 10:43:22 -0400 Subject: [PATCH 124/690] fix: set a proper default for `skip_unique_indexes` --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index c56fbf9f..40bc5f52 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -331,7 +331,7 @@ defmodule AshPostgres.DataLayer do ], skip_unique_indexes: [ type: {:wrap_list, :atom}, - default: false, + default: [], doc: "Skip generating unique indexes when generating migrations" ], unique_index_names: [ From 8bf9864732f4937fc3ff493d8cf04fa343ea9b8c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 16 Aug 2024 15:39:53 -0400 Subject: [PATCH 125/690] improvement: include `min_pg_version` in new generators --- lib/igniter.ex | 5 +++++ lib/mix/tasks/ash_postgres.install.ex | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/igniter.ex b/lib/igniter.ex index cc99b05c..c7140277 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -6,6 +6,11 @@ defmodule AshPostgres.Igniter do """ use AshPostgres.Repo, otp_app: #{inspect(otp_app)} + def min_pg_version do + # Adjust this according to your postgres version + %Version{major: 16, minor: 0, patch: 0} + end + def installed_extensions do # Add extensions here, and the migration generator will install them. ["ash-functions"] diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 26127915..a310e905 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -341,4 +341,26 @@ defmodule Mix.Tasks.AshPostgres.Install do {:ok, zipper} end end + + defp configure_min_pg_version_function(zipper) do + case Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo) do + {:ok, zipper} -> + case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do + {:ok, zipper} -> + {:ok, zipper} + + _ -> + {:ok, + Igniter.Code.Common.add_code(zipper, """ + def min_pg_version do + # Adjust this according to your postgres version + %Version{major: 16, minor: 0, patch: 0} + end + """)} + end + + _ -> + {:ok, zipper} + end + end end From a94ee9823f35ea360657b8cb5837017c35cc9c0b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 16 Aug 2024 15:42:34 -0400 Subject: [PATCH 126/690] chore: release version v2.2.1 --- CHANGELOG.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3aca9cd..8df97c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,75 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.2.1](https://github.com/ash-project/ash_postgres/compare/v2.2.0...v2.2.1) (2024-08-16) + + + + +### Bug Fixes: + +* set a proper default for `skip_unique_indexes` + +* remove `Agent` "convenience" for determining min pg version + +* handle filter condition on create (#368) + +* we missed a change when preparing for ecto 3.12 parameterized type changes + +* update ash_sql for exists aggregate fixes + +* don't overwrite non-updated fields on update + +* ensure app is compiled before using repo modules + +* use a subquery if any exists aggregates are in play + +* properly convert tenant to string when building lateral join + +* update ash & ash_sql for fixes, test atomic alidations in destroys + +* properly add prod config in installer + +* properly perform or don't perform configuration modification code + +* allow non-unique has_many source_attributes (#355) + +* allow non-unique has_many source_attributes + +* update `ash_sql` for `parent_as` binding fix + +* update to latest ash version for aggregate fix + +* update ash_sql for include_nil? fix and test it + +* ensure synthesized query aggregates have context set + +### Improvements: + +* include `min_pg_version` in new generators + +* dynamically select and allow setting a repo + +* update ash_sql for latest fixes + +* update ash & ash_sql for various fixes + +* update ash_sql for cleaner queries + +* update ash_sql dependencies for bug fixes + +* prepend `:postgres` to section order + +* pluralize table name in extender + +* update ash/igniter dependencies + +* add `binding()` expression + +* use latest type casting code from ash + +* support new type determination code + ## [v2.2.0](https://github.com/ash-project/ash_postgres/compare/v2.1.19...v2.2.0) (2024-08-13) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 2e7c5a7d..4ac3c497 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.2.0" + @version "2.2.1" def project do [ From dda21bc6c4278d0c0e9a1b97740dc6f8e55c78cc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 16 Aug 2024 15:42:34 -0400 Subject: [PATCH 127/690] chore: release version v2.2.1 --- documentation/dsls/DSL:-AshPostgres.DataLayer.md | 2 +- lib/mix/tasks/ash_postgres.install.ex | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/dsls/DSL:-AshPostgres.DataLayer.md b/documentation/dsls/DSL:-AshPostgres.DataLayer.md index bc5f18c8..305a925f 100644 --- a/documentation/dsls/DSL:-AshPostgres.DataLayer.md +++ b/documentation/dsls/DSL:-AshPostgres.DataLayer.md @@ -47,7 +47,7 @@ end | [`identity_wheres_to_sql`](#postgres-identity_wheres_to_sql){: #postgres-identity_wheres_to_sql } | `keyword` | | A keyword list of identity names and the SQL representation of their `where` clause. Used when creating unique indexes for identities over calculations | | [`base_filter_sql`](#postgres-base_filter_sql){: #postgres-base_filter_sql } | `String.t` | | A raw sql version of the base_filter, e.g `representative = true`. Required if trying to create a unique constraint on a resource with a base_filter | | [`simple_join_first_aggregates`](#postgres-simple_join_first_aggregates){: #postgres-simple_join_first_aggregates } | `list(atom)` | `[]` | A list of `:first` type aggregate names that can be joined to using a simple join. Use when you have a `:first` aggregate that uses a to-many relationship , but your `filter` statement ensures that there is only one result. Optimizes the generated query. | -| [`skip_unique_indexes`](#postgres-skip_unique_indexes){: #postgres-skip_unique_indexes } | `atom \| list(atom)` | `false` | Skip generating unique indexes when generating migrations | +| [`skip_unique_indexes`](#postgres-skip_unique_indexes){: #postgres-skip_unique_indexes } | `atom \| list(atom)` | `[]` | Skip generating unique indexes when generating migrations | | [`unique_index_names`](#postgres-unique_index_names){: #postgres-unique_index_names } | `list({list(atom), String.t} \| {list(atom), String.t, String.t})` | `[]` | A list of unique index names that could raise errors that are not configured in identities, or an mfa to a function that takes a changeset and returns the list. In the format `{[:affected, :keys], "name_of_constraint"}` or `{[:affected, :keys], "name_of_constraint", "custom error message"}` | | [`exclusion_constraint_names`](#postgres-exclusion_constraint_names){: #postgres-exclusion_constraint_names } | `any` | `[]` | A list of exclusion constraint names that could raise errors. Must be in the format `{:affected_key, "name_of_constraint"}` or `{:affected_key, "name_of_constraint", "custom error message"}` | | [`identity_index_names`](#postgres-identity_index_names){: #postgres-identity_index_names } | `any` | `[]` | A keyword list of identity names to the unique index name that they should use when being managed by the migration generator. | diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index a310e905..ceba0621 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -263,6 +263,7 @@ defmodule Mix.Tasks.AshPostgres.Install do |> remove_adapter_option() |> Sourceror.Zipper.top() |> configure_installed_extensions_function() + |> configure_min_pg_version_function() end ) end From 3fbd5514e09e7199cc7969b7a0dff36ab5fe60af Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 16 Aug 2024 15:45:38 -0400 Subject: [PATCH 128/690] chore: update changelog --- CHANGELOG.md | 63 ++-------------------------------------------------- 1 file changed, 2 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8df97c1a..c8448f29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,72 +7,13 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.2.1](https://github.com/ash-project/ash_postgres/compare/v2.2.0...v2.2.1) (2024-08-16) - - - ### Bug Fixes: -* set a proper default for `skip_unique_indexes` - -* remove `Agent` "convenience" for determining min pg version - -* handle filter condition on create (#368) - -* we missed a change when preparing for ecto 3.12 parameterized type changes - -* update ash_sql for exists aggregate fixes - -* don't overwrite non-updated fields on update - -* ensure app is compiled before using repo modules - -* use a subquery if any exists aggregates are in play - -* properly convert tenant to string when building lateral join - -* update ash & ash_sql for fixes, test atomic alidations in destroys - -* properly add prod config in installer - -* properly perform or don't perform configuration modification code - -* allow non-unique has_many source_attributes (#355) - -* allow non-unique has_many source_attributes - -* update `ash_sql` for `parent_as` binding fix - -* update to latest ash version for aggregate fix - -* update ash_sql for include_nil? fix and test it - -* ensure synthesized query aggregates have context set +- [`AshPostgres.DataLayer`] set a proper default for `skip_unique_indexes` ### Improvements: -* include `min_pg_version` in new generators - -* dynamically select and allow setting a repo - -* update ash_sql for latest fixes - -* update ash & ash_sql for various fixes - -* update ash_sql for cleaner queries - -* update ash_sql dependencies for bug fixes - -* prepend `:postgres` to section order - -* pluralize table name in extender - -* update ash/igniter dependencies - -* add `binding()` expression - -* use latest type casting code from ash - -* support new type determination code +- [`mix ash_postgres.install`] include `min_pg_version` in new generators ## [v2.2.0](https://github.com/ash-project/ash_postgres/compare/v2.1.19...v2.2.0) (2024-08-13) From 59d1c3d6cc1a42151e6631a046cc6a7ea252414f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 17 Aug 2024 12:05:33 -0400 Subject: [PATCH 129/690] fix: properly handle new igniter installer functions --- lib/mix/tasks/ash_postgres.install.ex | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index ceba0621..959e6c47 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -255,17 +255,20 @@ defmodule Mix.Tasks.AshPostgres.Install do repo, AshPostgres.Igniter.default_repo_contents(otp_app), fn zipper -> - zipper - |> set_otp_app(otp_app) - |> Sourceror.Zipper.top() - |> use_ash_postgres_instead_of_ecto() - |> Sourceror.Zipper.top() - |> remove_adapter_option() - |> Sourceror.Zipper.top() - |> configure_installed_extensions_function() - |> configure_min_pg_version_function() + {:ok, + zipper + |> set_otp_app(otp_app) + |> Sourceror.Zipper.top() + |> use_ash_postgres_instead_of_ecto() + |> Sourceror.Zipper.top() + |> remove_adapter_option()} end ) + |> Igniter.Code.Module.find_and_update_module!( + repo, + &configure_installed_extensions_function/1 + ) + |> Igniter.Code.Module.find_and_update_module!(repo, &configure_min_pg_version_function/1) end defp use_ash_postgres_instead_of_ecto(zipper) do From 73a070e2feccc0969504c84ae552be5ce39b4e62 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 17 Aug 2024 12:09:09 -0400 Subject: [PATCH 130/690] chore: release version v2.2.2 --- CHANGELOG.md | 6 ++++++ mix.exs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8448f29..8a3cb2d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.2.2](https://github.com/ash-project/ash_postgres/compare/v2.2.1...v2.2.2) (2024-08-17) + +### Bug Fixes: + +- [`mix ash_postgres.install`] properly handle new igniter installer functions + ## [v2.2.1](https://github.com/ash-project/ash_postgres/compare/v2.2.0...v2.2.1) (2024-08-16) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 4ac3c497..dbf45eaa 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.2.1" + @version "2.2.2" def project do [ From b437e3f147fe56f517a259ad7b685c8db1e67129 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 18 Aug 2024 07:43:06 -0400 Subject: [PATCH 131/690] fix: `mix ash_postgres.install` not adding ash_functions/min_pg_version --- lib/mix/tasks/ash_postgres.install.ex | 57 +++++++++++---------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 959e6c47..66f2336e 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -319,52 +319,43 @@ defmodule Mix.Tasks.AshPostgres.Install do end defp configure_installed_extensions_function(zipper) do - case Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo) do + case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do {:ok, zipper} -> - case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do + case Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do {:ok, zipper} -> - case Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do - {:ok, zipper} -> - Igniter.Code.List.append_new_to_list(zipper, "ash-functions") + Igniter.Code.List.append_new_to_list(zipper, "ash-functions") - :error -> - {:error, "installed_extensions/0 doesn't return a list"} - end - - _ -> - {:ok, - Igniter.Code.Common.add_code(zipper, """ - def installed_extensions do - # Add extensions here, and the migration generator will install them. - ["ash-functions"] - end - """)} + :error -> + {:error, "installed_extensions/0 doesn't return a list"} end _ -> - {:ok, zipper} + IO.inspect("HERE!") + + {:ok, + Igniter.Code.Common.add_code(zipper, """ + def installed_extensions do + # Add extensions here, and the migration generator will install them. + ["ash-functions"] + end + """)} + |> IO.inspect() end end defp configure_min_pg_version_function(zipper) do - case Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo) do + case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do {:ok, zipper} -> - case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do - {:ok, zipper} -> - {:ok, zipper} - - _ -> - {:ok, - Igniter.Code.Common.add_code(zipper, """ - def min_pg_version do - # Adjust this according to your postgres version - %Version{major: 16, minor: 0, patch: 0} - end - """)} - end + {:ok, zipper} _ -> - {:ok, zipper} + {:ok, + Igniter.Code.Common.add_code(zipper, """ + def min_pg_version do + # Adjust this according to your postgres version + %Version{major: 16, minor: 0, patch: 0} + end + """)} end end end From 555063d2708544e9c05c9f0f4e191ff92ae2e55c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 18 Aug 2024 07:45:39 -0400 Subject: [PATCH 132/690] chore: release version v2.2.3 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a3cb2d8..d6056e26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.2.3](https://github.com/ash-project/ash_postgres/compare/v2.2.2...v2.2.3) (2024-08-18) + + + + +### Bug Fixes: + +* `mix ash_postgres.install` not adding ash_functions/min_pg_version + ## [v2.2.2](https://github.com/ash-project/ash_postgres/compare/v2.2.1...v2.2.2) (2024-08-17) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index dbf45eaa..0a49d43e 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.2.2" + @version "2.2.3" def project do [ From 2c5c759a20904ab7b214d66ad590895918d29a33 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 18 Aug 2024 07:46:11 -0400 Subject: [PATCH 133/690] docs: update readme --- CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6056e26..18547dc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,9 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.2.3](https://github.com/ash-project/ash_postgres/compare/v2.2.2...v2.2.3) (2024-08-18) - - - ### Bug Fixes: -* `mix ash_postgres.install` not adding ash_functions/min_pg_version +- [`mix ash_postgres.install`] was not adding ash_functions/min_pg_version ## [v2.2.2](https://github.com/ash-project/ash_postgres/compare/v2.2.1...v2.2.2) (2024-08-17) From cb172d274c564bb619e8ce56f1342eb7b2f91dfb Mon Sep 17 00:00:00 2001 From: Trond A Ekseth Date: Thu, 22 Aug 2024 15:05:53 +0200 Subject: [PATCH 134/690] docs: Output valid example code in ValidateIdentityIndexNames (#373) --- lib/verifiers/validate_identity_index_names.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/verifiers/validate_identity_index_names.ex b/lib/verifiers/validate_identity_index_names.ex index f09b95e9..269e881e 100644 --- a/lib/verifiers/validate_identity_index_names.ex +++ b/lib/verifiers/validate_identity_index_names.ex @@ -49,7 +49,7 @@ defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do Please configure an index name for this identity in the `identity_index_names` configuration. For example: postgres do - identity_index_names #{inspect(identity.name)}: "a_shorter_name" + identity_index_names #{identity.name}: "a_shorter_name" end """ end From 1d8c2ae0081dd612fc9ab443969e6f04ac578c48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:35:26 -0400 Subject: [PATCH 135/690] chore(deps): bump igniter in the production-dependencies group (#372) Bumps the production-dependencies group with 1 update: [igniter](https://github.com/ash-project/igniter). Updates `igniter` from 0.3.19 to 0.3.22 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.3.19...v0.3.22) --- updated-dependencies: - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 23427c91..ab1c1403 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.19", "dfa4a05e94be72e9b75c9ce73b9ce408c9a5fe8f1f010eb36e711e70da698b46", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "f9b1ca6d11a7dcd1beb0bc0a1c08b8ce1fb4eb140a763037f3b79d9170cbf958"}, + "igniter": {:hex, :igniter, "0.3.22", "342235c729ec7407ca9a7cf88cbaf7ea7568e5f0ec850e76a1b90c5e545d41d0", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "db1dd4551ff8cf357581e53d64b6bd3f60a96e9032fcde1e860e0f4c6cf2bdc0"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 1e286106e6788946ee500ee7badcf2f50075ef81 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 25 Aug 2024 17:41:05 -0400 Subject: [PATCH 136/690] fix: properly traverse newtypes when determining types closes #1406 --- lib/sql_implementation.ex | 33 ++++++++++++++++++++++----------- test/filter_test.exs | 8 ++++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 71ec3cf2..5b9a247b 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -191,6 +191,10 @@ defmodule AshPostgres.SqlImplementation do end end + # def parameterized_type(Ash.Type.NewType, new_type_constraints, no_maps?) do + # constraints = Ash.Type.NewType.constraints(new_type_constraints) + # end + def parameterized_type(Ash.Type.CiString, constraints, no_maps?) do parameterized_type(AshPostgres.Type.CiStringWrapper, constraints, no_maps?) end @@ -213,19 +217,26 @@ defmodule AshPostgres.SqlImplementation do def parameterized_type(type, constraints, no_maps?) do if Ash.Type.ash_type?(type) do - cast_in_query? = - if function_exported?(Ash.Type, :cast_in_query?, 2) do - Ash.Type.cast_in_query?(type, constraints) - else - Ash.Type.cast_in_query?(type) - end + if Ash.Type.NewType.new_type?(type) do + subtype = Ash.Type.NewType.subtype_of(type) + subtype_constraints = Ash.Type.NewType.constraints(type, constraints) - if cast_in_query? do - type = Ash.Type.ecto_type(type) - - parameterized_type(type, constraints, no_maps?) + parameterized_type(subtype, subtype_constraints, no_maps?) else - nil + cast_in_query? = + if function_exported?(Ash.Type, :cast_in_query?, 2) do + Ash.Type.cast_in_query?(type, constraints) + else + Ash.Type.cast_in_query?(type) + end + + if cast_in_query? do + type = Ash.Type.ecto_type(type) + + parameterized_type(type, constraints, no_maps?) + else + nil + end end else if is_atom(type) && :erlang.function_exported(type, :type, 1) do diff --git a/test/filter_test.exs b/test/filter_test.exs index cff2dae4..fb36933c 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -21,6 +21,14 @@ defmodule AshPostgres.FilterTest do end end + describe "ci_string argument casting" do + test "it properly casts" do + Post + |> Ash.Query.for_read(:category_matches, %{category: "category"}) + |> Ash.read!() + end + end + describe "invalid uuid" do test "with an invalid uuid, an invalid error is raised" do assert_raise Ash.Error.Invalid, fn -> From 6b3961e5db298c682c2eefa6910cfcae0d8b1fd4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 25 Aug 2024 17:42:32 -0400 Subject: [PATCH 137/690] chore: fix tests --- test/support/resources/post.ex | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 399254fa..86b17273 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -49,6 +49,12 @@ defmodule HasNoComments do end end +defmodule CiCategory do + use Ash.Type.NewType, + subtype_of: :ci_string, + constraints: [casing: :upper] +end + defmodule AshPostgres.Test.Post do @moduledoc false use Ash.Resource, @@ -231,6 +237,11 @@ defmodule AshPostgres.Test.Post do filter(expr(title == "foo")) end + read :category_matches do + argument(:category, CiCategory) + filter(expr(category == ^arg(:category))) + end + read :keyset do pagination do keyset?(true) @@ -317,7 +328,7 @@ defmodule AshPostgres.Test.Post do attribute(:datetime, AshPostgres.TimestamptzUsec, public?: true) attribute(:score, :integer, public?: true) attribute(:public, :boolean, public?: true) - attribute(:category, :ci_string, public?: true) + attribute(:category, CiCategory, public?: true) attribute(:type, :atom, default: :sponsored, writable?: false, public?: false) attribute(:price, :integer, public?: true) attribute(:decimal, :decimal, default: Decimal.new(0), public?: true) From 65adf04ee0951c5c684ba21161ddba643c650c04 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 Aug 2024 10:04:12 -0400 Subject: [PATCH 138/690] fix: ensure default bindings are present on data layer --- lib/data_layer.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 40bc5f52..a62d49d2 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -750,7 +750,9 @@ defmodule AshPostgres.DataLayer do @impl true def return_query(query, resource) do - AshSql.Query.return_query(query, resource) + query + |> AshSql.Bindings.default_bindings(resource, AshPostgres.SqlImplementation) + |> AshSql.Query.return_query(query, resource) end @impl true From 1c18bc6227f28f795ccc87e2d16bb7458d77651f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 Aug 2024 10:45:33 -0400 Subject: [PATCH 139/690] chore: fix ash_sql call --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index a62d49d2..57243028 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -752,7 +752,7 @@ defmodule AshPostgres.DataLayer do def return_query(query, resource) do query |> AshSql.Bindings.default_bindings(resource, AshPostgres.SqlImplementation) - |> AshSql.Query.return_query(query, resource) + |> AshSql.Query.return_query(resource) end @impl true From cf1207dd60df66e0db6cef632d5e3ea6bee7dce0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 Aug 2024 11:10:54 -0400 Subject: [PATCH 140/690] chore: fix recent type casting logic change --- lib/sql_implementation.ex | 56 ++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 5b9a247b..67819a40 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -191,10 +191,6 @@ defmodule AshPostgres.SqlImplementation do end end - # def parameterized_type(Ash.Type.NewType, new_type_constraints, no_maps?) do - # constraints = Ash.Type.NewType.constraints(new_type_constraints) - # end - def parameterized_type(Ash.Type.CiString, constraints, no_maps?) do parameterized_type(AshPostgres.Type.CiStringWrapper, constraints, no_maps?) end @@ -217,39 +213,39 @@ defmodule AshPostgres.SqlImplementation do def parameterized_type(type, constraints, no_maps?) do if Ash.Type.ash_type?(type) do - if Ash.Type.NewType.new_type?(type) do - subtype = Ash.Type.NewType.subtype_of(type) - subtype_constraints = Ash.Type.NewType.constraints(type, constraints) - - parameterized_type(subtype, subtype_constraints, no_maps?) - else - cast_in_query? = - if function_exported?(Ash.Type, :cast_in_query?, 2) do - Ash.Type.cast_in_query?(type, constraints) - else - Ash.Type.cast_in_query?(type) - end - - if cast_in_query? do - type = Ash.Type.ecto_type(type) - - parameterized_type(type, constraints, no_maps?) + cast_in_query? = + if function_exported?(Ash.Type, :cast_in_query?, 2) do + Ash.Type.cast_in_query?(type, constraints) else - nil + Ash.Type.cast_in_query?(type) end + + if cast_in_query? do + type = Ash.Type.ecto_type(type) + + parameterized_type(type, constraints, no_maps?) + else + nil end else if is_atom(type) && :erlang.function_exported(type, :type, 1) do - type = - if type == :ci_string do - :citext - else - type - end + if type == :ci_string do + :citext + else + case type.type(constraints || []) do + :ci_string -> + parameterized_type(AshPostgres.Type.CiStringWrapper, constraints, no_maps?) - Ecto.ParameterizedType.init(type, constraints || []) + _ -> + Ecto.ParameterizedType.init(type, constraints || []) + end + end else - type + if type == :ci_string do + :citext + else + type + end end end end From 4ccdc7b0b60f4af1fc7189841c65ce8c1e31e35f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 Aug 2024 11:16:40 -0400 Subject: [PATCH 141/690] chore: update deps, fix tests --- mix.lock | 6 +++--- test/support/resources/post.ex | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index ab1c1403..c88e2304 100644 --- a/mix.lock +++ b/mix.lock @@ -9,7 +9,7 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "ecto": {:hex, :ecto, "3.12.1", "626765f7066589de6fa09e0876a253ff60c3d00870dd3a1cd696e2ba67bfceea", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "df0045ab9d87be947228e05a8d153f3e06e0d05ab10c3b3cc557d2f7243d1940"}, + "ecto": {:hex, :ecto, "3.12.2", "bae2094f038e9664ce5f089e5f3b6132a535d8b018bd280a485c2f33df5c0ce1", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "492e67c70f3a71c6afe80d946d3ced52ecc57c53c9829791bfff1830ff5a1f0c"}, "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, @@ -38,12 +38,12 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.21", "b343f3488b5a986ad38d15ac124b9111b8f63f953e3a6ef3fad44fe129b7fad6", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "45b05c52a1afe4858e10b5e6b8cd33bff3cf0098afc144146c5ff05002d75a9d"}, + "spark": {:hex, :spark, "2.2.22", "abb5ba74ed8b8a69f8d3112fe0d74a1dea261664d9a3bcaf2d0f94f9ee7102f6", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "98b6ea8c19fe97b2b7b20be034ae6cf34e98b03ecba8b7d5a4cc2449f60f3f5e"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"}, - "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "ucwidth": {:hex, :ucwidth, "0.2.0", "1f0a440f541d895dff142275b96355f7e91e15bca525d4a0cc788ea51f0e3441", [:mix], [], "hexpm", "c1efd1798b8eeb11fb2bec3cafa3dd9c0c3647bee020543f0340b996177355bf"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 86b17273..8b7fff09 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -51,8 +51,7 @@ end defmodule CiCategory do use Ash.Type.NewType, - subtype_of: :ci_string, - constraints: [casing: :upper] + subtype_of: :ci_string end defmodule AshPostgres.Test.Post do From 725e14ab62229b6f34673102e15e5dc525351249 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 Aug 2024 12:14:13 -0400 Subject: [PATCH 142/690] test: add tests for filter input parsing --- test/rel_with_parent_filter_test.exs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/rel_with_parent_filter_test.exs b/test/rel_with_parent_filter_test.exs index ef8a3846..20a4082e 100644 --- a/test/rel_with_parent_filter_test.exs +++ b/test/rel_with_parent_filter_test.exs @@ -24,6 +24,34 @@ defmodule AshPostgres.RelWithParentFilterTest do |> Ash.read_one!() end + test "filter constructed from input on relationship using parent works as expected" do + %{id: author_id} = + Author + |> Ash.Changeset.for_create(:create, %{first_name: "John", last_name: "Doe"}) + |> Ash.create!() + + %{id: author2_id} = + Author + |> Ash.Changeset.for_create(:create, %{first_name: "John"}) + |> Ash.create!() + + filter = + Ash.Filter.parse_input!(Author, %{ + "authors_with_same_first_name" => %{ + "id" => %{ + "eq" => author_id + } + } + }) + + # here we get the expected result of 1 because it is done in the same query + assert %{id: ^author2_id} = + Author + |> Ash.Query.for_read(:read) + |> Ash.Query.do_filter(filter) + |> Ash.read_one!(authorize?: true) + end + test "filter on relationship using parent works as expected when loading relationship" do %{id: author_id} = Author From fe1651169b1d9a48b9e3f27e18582187ad88d6ae Mon Sep 17 00:00:00 2001 From: Shankar Dhanasekaran Date: Wed, 28 Aug 2024 17:35:18 +0530 Subject: [PATCH 143/690] Remove IO.inspect (#376) --- lib/mix/tasks/ash_postgres.install.ex | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 66f2336e..e7a44ed8 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -330,8 +330,6 @@ defmodule Mix.Tasks.AshPostgres.Install do end _ -> - IO.inspect("HERE!") - {:ok, Igniter.Code.Common.add_code(zipper, """ def installed_extensions do @@ -339,7 +337,6 @@ defmodule Mix.Tasks.AshPostgres.Install do ["ash-functions"] end """)} - |> IO.inspect() end end From c104e6a2ba0608c318f15c3bf57ce3a33ccb386d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:01:42 -0400 Subject: [PATCH 144/690] chore(deps): bump the production-dependencies group with 2 updates (#377) --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index c88e2304..be006432 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.1", "14bfccd4c1e7c17db5aed1ecb5062875f55b56b67f6fba911f3a8ef6739f3cfd", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "1e3127e0af0698e652a6bbfb4d4f1a3bb8a48fb42833f4e8f00eda8f1a93082b"}, - "ash_sql": {:hex, :ash_sql, "0.2.30", "244a2071c7fdaec486a186136e52a635dc01f2c1db774d3c506562b339efcf1c", [:mix], [{:ash, ">= 3.1.7 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", "e93f704b5b29caf0793dd880ec10b1fd313cc0e0a385074955ca36d8af530e4e"}, + "ash_sql": {:hex, :ash_sql, "0.2.31", "721521e073d706169ebb0e68535422c1920580b29829fe949fb679c8674a9691", [:mix], [{:ash, ">= 3.1.7 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", "e5f578be31f5fa5af8dd1cb27b01b7b1864ef1414472293ce3a4851290cb69b1"}, "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.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.22", "342235c729ec7407ca9a7cf88cbaf7ea7568e5f0ec850e76a1b90c5e545d41d0", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "db1dd4551ff8cf357581e53d64b6bd3f60a96e9032fcde1e860e0f4c6cf2bdc0"}, + "igniter": {:hex, :igniter, "0.3.24", "791a91650ffab9d66b9a3011c66491f767577ad55c363f820cc188554207ee6f", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "2e1d336534c6129bae0db043fae650303b96974c0488c290191d6d4c61ec9a9f"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 06c0c328df447053f3346e0c1029e5ec49505bdb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 30 Aug 2024 18:13:15 -0400 Subject: [PATCH 145/690] test: add test for bugfix in ash --- test/bulk_update_test.exs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index e0bb1737..afe8fbd8 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -106,6 +106,8 @@ defmodule AshPostgres.BulkUpdateTest do test "bulk updates honor update action filters when streaming" do Ash.bulk_create!([%{title: "fred"}, %{title: "george"}], Post, :create) + Logger.configure(level: :debug) + Post |> Ash.bulk_update!(:update_only_freds, %{}, strategy: :stream, @@ -113,9 +115,18 @@ defmodule AshPostgres.BulkUpdateTest do atomic_update: %{title: Ash.Expr.expr(title <> "_stuff")} ) - titles = + posts = Post |> Ash.read!() + + fred = + posts + |> Enum.find(&(&1.title == "fred_stuff")) + + assert fred.created_at != fred.updated_at + + titles = + posts |> Enum.map(& &1.title) |> Enum.sort() From 96508522380e217f6bb33c53d36b08e2b45aac97 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 31 Aug 2024 16:44:05 -0400 Subject: [PATCH 146/690] test: additional tests for bulk updates --- test/bulk_update_test.exs | 2 -- test/update_test.exs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 test/update_test.exs diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index afe8fbd8..6ed482df 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -106,8 +106,6 @@ defmodule AshPostgres.BulkUpdateTest do test "bulk updates honor update action filters when streaming" do Ash.bulk_create!([%{title: "fred"}, %{title: "george"}], Post, :create) - Logger.configure(level: :debug) - Post |> Ash.bulk_update!(:update_only_freds, %{}, strategy: :stream, diff --git a/test/update_test.exs b/test/update_test.exs new file mode 100644 index 00000000..59897db3 --- /dev/null +++ b/test/update_test.exs @@ -0,0 +1,37 @@ +defmodule AshPostgres.UpdateTest do + use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Post + require Ash.Query + + test "can update with nested maps" do + Post + |> Ash.Changeset.for_create(:create, %{stuff: %{foo: %{bar: :baz}}}) + |> Ash.create!() + |> then(fn record -> + Ash.Query.filter(Post, id == ^record.id) + end) + |> Ash.bulk_update( + :update, + %{ + stuff: %{ + summary: %{ + chat_history: [ + %{"content" => "Default system prompt", "role" => "system"}, + %{ + "content" => + "Here's a collection of tweets from the Twitter list 'Web 3 Mid':\nTweet by KhanAbbas201 (2024-08-26 19:40:13.000000Z):\n@Rahatcodes told me I look good wearing the Eth shirt. https://t.co/xBugAt2tDi\nTweet by Rahatcodes (2024-08-26 19:42:55.000000Z):\n@KhanAbbas201 I dont recall saying this\nTweet by KhanAbbas201 (2024-08-26 19:44:08.000000Z):\n@Rahatcodes Damn what happened to your memory bruv?\nTweet by angelinarusse (2024-08-26 19:56:05.000000Z):\n@dabit3 Real degens call it Twitter\nTweet by angelinarusse (2024-08-26 20:13:58.000000Z):\n@hamseth They tried the same in Afghanistan and it didn’t go well for them.\nTweet by KhanAbbas201 (2024-08-26 20:39:53.000000Z):\nTweet by Osh_mahajan (2024-08-26 21:34:08.000000Z):\n@FedericoNoemie 🐾🐾🦘\nTweet by developer_dao (2024-08-26 21:39:59.000000Z):\n@ZwigoZwitscher @ArweaveEco @k4yls Wildly high praise, ty ty. @k4yls is 🔥 with a 🐶\nTweet by developer_dao (2024-08-26 21:41:17.000000Z):\nRT @ZwigoZwitscher : I've been into @ArweaveEco for years – as an interested outsider – and still learned new things in that course 👇. Thanks…\nTweet by angelin...eet by developer_dao (2024-08-26 22:18:09.000000Z):\nRT @jeremykauffman: BREAKING: France has arrested Gonzalve Bich, the CEO of Bic\nTweet by PatrickAlphaC (2024-08-26 22:26:16.000000Z):\n@oxfav @ar_io_network\n", + "role" => "user" + }, + %{"content" => "test", "role" => "user"}, + %{ + "content" => + "It looks like you're testing the feature. How can I assist you further?", + "role" => "assistant" + } + ] + } + } + } + ) + end +end From 7285b3382eb0fb905385326de13a096e20f43f3f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Sep 2024 01:57:31 -0400 Subject: [PATCH 147/690] chore: release version v2.2.4 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18547dc7..275c7b75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.2.4](https://github.com/ash-project/ash_postgres/compare/v2.2.3...v2.2.4) (2024-09-03) + + + + +### Bug Fixes: + +* ensure default bindings are present on data layer + +* properly traverse newtypes when determining types + ## [v2.2.3](https://github.com/ash-project/ash_postgres/compare/v2.2.2...v2.2.3) (2024-08-18) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 0a49d43e..267dace4 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.2.3" + @version "2.2.4" def project do [ From 2015aa658cacfbac181ef8f8fbd9ae81a9a9f02b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Sep 2024 18:02:14 -0400 Subject: [PATCH 148/690] improvement: support ash main upsert_condition logic --- lib/data_layer.ex | 3 ++- lib/sql_implementation.ex | 27 +++++++++++++++++++ test/bulk_create_test.exs | 47 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 6 +++++ 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 57243028..200ee3af 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -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 diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 67819a40..d01c134e 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -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( diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index bdfdd497..d7a2c544 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -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 diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 8b7fff09..e4f64c23 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -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 From 6e0b8fb0358d53fe8e1cb331d7da4d14be940507 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Sep 2024 22:26:46 -0400 Subject: [PATCH 149/690] chore: release version v2.2.5 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 275c7b75..c63f6d5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.2.5](https://github.com/ash-project/ash_postgres/compare/v2.2.4...v2.2.5) (2024-09-04) + + + + +### Improvements: + +* support ash main upsert_condition logic + ## [v2.2.4](https://github.com/ash-project/ash_postgres/compare/v2.2.3...v2.2.4) (2024-09-03) diff --git a/mix.exs b/mix.exs index 267dace4..974223c3 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.2.4" + @version "2.2.5" def project do [ From 607254d3184e39ab255b2ccd75cecf6e8cc2850d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Sep 2024 22:27:30 -0400 Subject: [PATCH 150/690] chore: update changelog --- CHANGELOG.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c63f6d5e..be827fc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,23 +7,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.2.5](https://github.com/ash-project/ash_postgres/compare/v2.2.4...v2.2.5) (2024-09-04) - - - ### Improvements: -* support ash main upsert_condition logic +- [`AshPostgres.DataLayer`] support ash main upsert_condition logic ## [v2.2.4](https://github.com/ash-project/ash_postgres/compare/v2.2.3...v2.2.4) (2024-09-03) - - - ### Bug Fixes: -* ensure default bindings are present on data layer +- [`AshPostgres.DataLayer`] ensure default bindings are present on data layer -* properly traverse newtypes when determining types +- [`AshPostgres.DataLayer`] properly traverse newtypes when determining types ## [v2.2.3](https://github.com/ash-project/ash_postgres/compare/v2.2.2...v2.2.3) (2024-08-18) From 0ccb35a713b9097c4aac6fde996dbb4d1c00cccb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Sep 2024 22:42:57 -0400 Subject: [PATCH 151/690] chore: update ash --- mix.exs | 2 +- mix.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 974223c3..63d080c4 100644 --- a/mix.exs +++ b/mix.exs @@ -162,7 +162,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.3")}, + {:ash, ash_version("~> 3.4 and >= 3.4.2")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.12"}, diff --git a/mix.lock b/mix.lock index be006432..ea609ef7 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.1", "14bfccd4c1e7c17db5aed1ecb5062875f55b56b67f6fba911f3a8ef6739f3cfd", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "1e3127e0af0698e652a6bbfb4d4f1a3bb8a48fb42833f4e8f00eda8f1a93082b"}, + "ash": {:hex, :ash, "3.4.2", "17544d04a1ed5fdc7fc61e9fbb491418c322c73c9cb0c00836c0f80070d4e09a", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "df5a851797a82a7fa9a1348a0c79bf206f77ce1e3047ec00ce4bfdf733e9459d"}, "ash_sql": {:hex, :ash_sql, "0.2.31", "721521e073d706169ebb0e68535422c1920580b29829fe949fb679c8674a9691", [:mix], [{:ash, ">= 3.1.7 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", "e5f578be31f5fa5af8dd1cb27b01b7b1864ef1414472293ce3a4851290cb69b1"}, "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"}, @@ -38,7 +38,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.22", "abb5ba74ed8b8a69f8d3112fe0d74a1dea261664d9a3bcaf2d0f94f9ee7102f6", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "98b6ea8c19fe97b2b7b20be034ae6cf34e98b03ecba8b7d5a4cc2449f60f3f5e"}, + "spark": {:hex, :spark, "2.2.23", "78f0a1b0b713a91ad556fe9dc19ec92d977aaa0803cce2e255d90e58b9045c2a", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "a354b5cd7c3f021e3cd1da5a033b7643fe7b3c71c96b96d9f500a742f40c94db"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 133be5094b9946ade9d1f8c8b905456f7227f81a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Sep 2024 20:28:45 -0400 Subject: [PATCH 152/690] feat: `mix ash_postgres.gen.resources` --- .../set-up-with-existing-database.md | 33 + lib/igniter.ex | 24 + .../migration_generator.ex | 1 + lib/mix/tasks/ash_postgres.gen.resources.ex | 137 +++ .../tasks/ash_postgres.generate_migrations.ex | 6 +- lib/resource_generator/resource_generator.ex | 658 +++++++++++ lib/resource_generator/sensitive_data.ex | 73 ++ lib/resource_generator/spec.ex | 1026 +++++++++++++++++ mix.exs | 2 + mix.lock | 12 +- .../schematic_groups/20240821213522.json | 29 + test/support/domain.ex | 9 + 12 files changed, 2002 insertions(+), 8 deletions(-) create mode 100644 documentation/tutorials/set-up-with-existing-database.md create mode 100644 lib/mix/tasks/ash_postgres.gen.resources.ex create mode 100644 lib/resource_generator/resource_generator.ex create mode 100644 lib/resource_generator/sensitive_data.ex create mode 100644 lib/resource_generator/spec.ex create mode 100644 priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json diff --git a/documentation/tutorials/set-up-with-existing-database.md b/documentation/tutorials/set-up-with-existing-database.md new file mode 100644 index 00000000..0c5d92c0 --- /dev/null +++ b/documentation/tutorials/set-up-with-existing-database.md @@ -0,0 +1,33 @@ +# Setting AshPostgres up with an existing database + +If you already have a postgres database and you'd like to get +started quickly, you can scaffold resources directly from your +database. + +First, create an application with AshPostgres if you haven't already: + +```bash +mix igniter.new my_app + --install ash,ash_postgres + --with phx.new # add this if you will be using phoenix too +``` + +Then, go into your `config/dev.exs` and configure your repo to use +your existing database. + +Finally, run: + +```bash +mix ash_postgres.gen.resources MyApp.MyDomain --tables table1,table2,table3 +``` + +## More fine grained control + +You may want to do multiple passes to separate your application into multiple domains. For example: + +```bash +mix ash_postgres.gen.resources MyApp.Accounts --tables users,roles,tokens +mix ash_postgres.gen.resources MyApp.Blog --tables posts,comments +``` + +See the docs for `mix ash_postgres.gen.resources` for more information. diff --git a/lib/igniter.ex b/lib/igniter.ex index c7140277..662418e0 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -18,6 +18,30 @@ defmodule AshPostgres.Igniter do """ end + def table(igniter, resource) do + igniter + |> Spark.Igniter.get_option(resource, [:postgres, :table]) + |> case do + {igniter, {:ok, value}} when is_binary(value) or is_nil(value) -> + {:ok, igniter, value} + + _ -> + :error + end + end + + def repo(igniter, resource) do + igniter + |> Spark.Igniter.get_option(resource, [:postgres, :repo]) + |> case do + {igniter, {:ok, value}} when is_atom(value) -> + {:ok, igniter, value} + + _ -> + :error + end + end + def add_postgres_extension(igniter, repo_name, extension) do Igniter.Code.Module.find_and_update_module!(igniter, repo_name, fn zipper -> case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index ff8f1d41..7b9de7a2 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -18,6 +18,7 @@ defmodule AshPostgres.MigrationGenerator do format: true, dry_run: false, check: false, + snapshots_only: false, dont_drop_columns: false def generate(domains, opts \\ []) do diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex new file mode 100644 index 00000000..4bb2cd05 --- /dev/null +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -0,0 +1,137 @@ +defmodule Mix.Tasks.AshPostgres.Gen.Resources do + use Igniter.Mix.Task + + @example "mix ash_postgres.gen.resource MyApp.MyDomain" + + @shortdoc "Generates or updates resources based on a database schema" + + @doc """ + #{@shortdoc} + + ## Example + + `#{@example}` + + ## Domain + + The domain will be generated if it does not exist. If you aren't sure, + we suggest using something like `MyApp.App`. + + ## Options + + - `repo`, `r` - The repo or repos to generate resources for, comma separated. Can be specified multiple times. Defaults to all repos. + - `tables`, `t` - Defaults to `public.*`. The tables to generate resources for, comma separated. Can be specified multiple times. See the section on tables for more. + - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. + - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. + + ## Tables + + When specifying tables to include with `--tables`, you can specify the table name, or the schema and table name separated by a period. + For example, `users` will generate resources for the `users` table in the `public` schema, but `accounts.users` will generate resources for the `users` table in the `accounts` schema. + + To include all tables in a given schema, add a period only with no table name, i.e `schema.`, i.e `accounts.`. + + When skipping tables with `--skip-tables`, the same rules apply, except that the `schema.` format is not supported. + """ + + @impl Igniter.Mix.Task + def info(_argv, _parent) do + %Igniter.Mix.Task.Info{ + positional: [:domain], + example: @example, + schema: [ + repo: :keep, + tables: :keep, + skip_tables: :keep, + snapshots_only: :boolean, + domain: :keep + ], + aliases: [ + t: :tables, + r: :repo, + d: :domain, + s: :skip_tables + ] + } + end + + @impl Igniter.Mix.Task + def igniter(igniter, argv) do + Mix.Task.run("compile") + + {%{domain: domain}, argv} = positional_args!(argv) + + domain = Igniter.Code.Module.parse(domain) + + options = options!(argv) + + repos = + options[:repo] || + Mix.Project.config()[:app] + |> Application.get_env(:ecto_repos, []) + + case repos do + [] -> + igniter + |> Igniter.add_warning("No ecto repos configured.") + + repos -> + Mix.shell().info("Generating resources from #{inspect(repos)}") + + prompt = + """ + + Would you like to generate migrations for the current structure? (recommended) + + If #{IO.ANSI.green()}yes#{IO.ANSI.reset()}: + We will generate migrations based on the generated resources. + You should then change your database name in your config, and + run `mix ash.setup`. + + If you already have ecto migrations you'd like to use, run + this command with `--snapshots-only`, in which case only resource + snapshots will be generated. + #{IO.ANSI.green()} + Going forward, your resources will be the source of truth.#{IO.ANSI.reset()} + #{IO.ANSI.red()} + *WARNING* + + If you run `mix ash.reset` after this command without updating + your config, you will be *deleting the database you just used to + generate these resources*!#{IO.ANSI.reset()} + + If #{IO.ANSI.red()}no#{IO.ANSI.reset()}: + + We will not generate any migrations. This means you have migrations already that + can get you from zero to the current starting point. + #{IO.ANSI.yellow()} + You will have to hand-write migrations from this point on.#{IO.ANSI.reset()} + """ + + options = + if Mix.shell().yes?(prompt) do + Keyword.put(options, :no_migrations, false) + else + Keyword.put(options, :no_migrations, true) + end + + migration_opts = + if options[:snapshots_only] do + ["--snapshots-only"] + else + [] + end + + igniter + |> Igniter.compose_task("ash.gen.domain", [inspect(domain), "--ignore-if-exists"]) + |> AshPostgres.ResourceGenerator.generate(repos, domain, options) + |> then(fn igniter -> + if options[:no_migrations] do + igniter + else + Igniter.add_task(igniter, "ash_postgres.generate_migrations", migration_opts) + end + end) + end + end +end diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index 2c31d0f7..68f92b55 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -21,6 +21,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do * `no-format` - files that are created will not be formatted with the code formatter * `dry-run` - no files are created, instead the new migration is printed * `check` - no files are created, returns an exit(1) code if the current snapshots and resources don't fit + * `snapshots-only` - no migrations are generated, only snapshots are stored #### Snapshots @@ -90,6 +91,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do migration_path: :string, tenant_migration_path: :string, quiet: :boolean, + snapshots_only: :boolean, name: :string, no_format: :boolean, dry_run: :boolean, @@ -100,7 +102,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do domains = AshPostgres.Mix.Helpers.domains!(opts, args, false) - if Enum.empty?(domains) do + if Enum.empty?(domains) && !opts[:snapshots_only] do IO.warn(""" No domains found, so no resource-related migrations will be generated. Pass the `--domains` option or configure `config :your_app, ash_domains: [...]` @@ -113,7 +115,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do |> Keyword.delete(:no_format) |> Keyword.put_new(:name, name) - if !opts[:name] && !opts[:dry_run] && !opts[:check] do + if !opts[:name] && !opts[:dry_run] && !opts[:check] && !opts[:snapshots_only] do IO.warn(""" Name must be provided when generating migrations, unless `--dry-run` or `--check` is also provided. Using an autogenerated name will be deprecated in a future release. diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex new file mode 100644 index 00000000..9ba9586f --- /dev/null +++ b/lib/resource_generator/resource_generator.ex @@ -0,0 +1,658 @@ +defmodule AshPostgres.ResourceGenerator do + alias AshPostgres.ResourceGenerator.Spec + + require Logger + + def generate(igniter, repos, domain, opts \\ []) do + {igniter, resources} = Ash.Resource.Igniter.list_resources(igniter) + + resources = + Task.async_stream(resources, fn resource -> + {resource, AshPostgres.Igniter.repo(igniter, resource), + AshPostgres.Igniter.table(igniter, resource)} + end) + |> Enum.map(fn {:ok, {resource, repo, table}} -> + repo = + case repo do + {:ok, _igniter, repo} -> repo + _ -> nil + end + + table = + case table do + {:ok, _igniter, table} -> table + _ -> nil + end + + {resource, repo, table} + end) + + igniter = Igniter.include_all_elixir_files(igniter) + + opts = + if opts[:tables] do + Keyword.put( + opts, + :tables, + opts[:tables] + |> List.wrap() + |> Enum.join(",") + |> String.split(",") + ) + else + opts + end + + opts = + if opts[:skip_tables] do + Keyword.put( + opts, + :skip_tables, + opts[:skip_tables] + |> List.wrap() + |> Enum.join(",") + |> String.split(",") + ) + else + opts + end + + specs = + repos + |> Enum.flat_map(&Spec.tables(&1, skip_tables: opts[:skip_tables], tables: opts[:tables])) + |> Enum.map(fn %{table_name: table} = spec -> + resource = + table + |> Macro.camelize() + |> then(&Module.concat([domain, &1])) + + %{spec | resource: resource} + end) + |> Enum.group_by(& &1.resource) + |> Enum.map(fn + {_resource, [single]} -> + single + + {resource, specs} -> + raise """ + Duplicate resource names detected across multiple repos: #{inspect(resource)} + + #{inspect(Enum.map(specs, & &1.repo))} + + To address this, run this command separately for each repo and specify the + `--domain` option to put the resources into a separate domain, or omit the table + with `--tables` or `--skip-tables` + """ + end) + |> Spec.add_relationships(resources) + + Enum.reduce(specs, igniter, fn table_spec, igniter -> + table_to_resource(igniter, table_spec, domain, opts) + end) + end + + defp table_to_resource( + igniter, + %AshPostgres.ResourceGenerator.Spec{} = table_spec, + domain, + opts + ) do + no_migrate_flag = + if opts[:no_migrations] do + "migrate? false" + end + + resource = + """ + use Ash.Resource, + domain: #{inspect(domain)}, + data_layer: AshPostgres.DataLayer + + postgres do + table #{inspect(table_spec.table_name)} + repo #{inspect(table_spec.repo)} + #{no_migrate_flag} + #{references(table_spec, opts[:no_migrations])} + #{custom_indexes(table_spec, opts[:no_migrations])} + #{check_constraints(table_spec, opts[:no_migrations])} + #{skip_unique_indexes(table_spec)} + #{identity_index_names(table_spec)} + end + + attributes do + #{attributes(table_spec)} + end + """ + |> add_identities(table_spec) + |> add_relationships(table_spec) + + igniter + |> Ash.Domain.Igniter.add_resource_reference(domain, table_spec.resource) + |> Igniter.Code.Module.create_module(table_spec.resource, resource) + end + + defp check_constraints(%{check_constraints: _check_constraints}, true) do + "" + end + + defp check_constraints(%{check_constraints: []}, _) do + "" + end + + defp check_constraints(%{check_constraints: check_constraints}, _) do + IO.inspect(check_constraints) + + check_constraints = + Enum.map_join(check_constraints, "\n", fn check_constraint -> + """ + check_constraint :#{check_constraint.column}, "#{check_constraint.name}", check: "#{check_constraint.expression}", message: "is invalid" + """ + end) + + """ + check_constraints do + #{check_constraints} + end + """ + end + + defp skip_unique_indexes(%{indexes: indexes}) do + indexes + |> Enum.filter(& &1.unique?) + |> Enum.filter(fn %{columns: columns} -> + Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end) + |> Enum.reject(&index_as_identity?/1) + |> case do + [] -> + "" + + indexes -> + """ + skip_unique_indexes [#{Enum.map_join(indexes, ",", &":#{&1.name}")}] + """ + end + end + + defp identity_index_names(%{indexes: indexes}) do + indexes + |> Enum.filter(& &1.unique?) + |> Enum.filter(fn %{columns: columns} -> + Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end) + |> case do + [] -> + [] + + indexes -> + indexes + |> Enum.map_join(", ", fn index -> + "#{index.name}: \"#{index.name}\"" + end) + |> then(&"identity_index_names [#{&1}]") + end + end + + defp add_identities(str, %{indexes: indexes}) do + indexes + |> Enum.filter(& &1.unique?) + |> Enum.filter(fn %{columns: columns} -> + Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end) + |> Enum.map(fn index -> + name = index.name + + fields = "[" <> Enum.map_join(index.columns, ", ", &":#{&1}") <> "]" + + case identity_options(index) do + "" -> + "identity :#{name}, #{fields}" + + options -> + """ + identity :#{name}, #{fields} do + #{options} + end + """ + end + end) + |> case do + [] -> + str + + identities -> + """ + #{str} + + identities do + #{Enum.join(identities, "\n")} + end + """ + end + end + + defp identity_options(index) do + "" + |> add_identity_where(index) + |> add_nils_distinct?(index) + end + + defp add_identity_where(str, %{where_clause: nil}), do: str + + defp add_identity_where(str, %{name: name, where_clause: where_clause}) do + Logger.warning(""" + Index #{name} has been left commented out in its resource + Manual conversion of `#{where_clause}` to an Ash expression is required. + """) + + """ + #{str} + # Express `#{where_clause}` as an Ash expression + # where expr(...) + """ + end + + defp add_nils_distinct?(str, %{nils_distinct?: false}) do + "#{str}\n nils_distinct? false" + end + + defp add_nils_distinct?(str, _), do: str + + defp add_relationships(str, %{relationships: []}) do + str + end + + defp add_relationships(str, %{relationships: relationships} = spec) do + relationships + |> Enum.map_join("\n", fn relationship -> + case relationship_options(spec, relationship) do + "" -> + "#{relationship.type} :#{relationship.name}, #{inspect(relationship.destination)}" + + options -> + """ + #{relationship.type} :#{relationship.name}, #{inspect(relationship.destination)} do + #{options} + end + """ + end + end) + |> then(fn rels -> + """ + #{str} + + relationships do + #{rels} + end + """ + end) + end + + defp relationship_options(spec, %{type: :belongs_to} = rel) do + case Enum.find(spec.attributes, fn attribute -> + attribute.name == rel.source_attribute + end) do + %{ + default: default, + generated?: generated?, + source: source, + name: name + } + when not is_nil(default) or generated? or source != name -> + "define_attribute? false" + |> add_destination_attribute(rel, "id") + |> add_source_attribute(rel, "#{rel.name}_id") + |> add_allow_nil(rel) + |> add_filter(rel) + + attribute -> + "" + |> add_destination_attribute(rel, "id") + |> add_source_attribute(rel, "#{rel.name}_id") + |> add_allow_nil(rel) + |> add_primary_key(attribute.primary_key?) + |> add_attribute_type(attribute) + |> add_filter(rel) + end + end + + defp relationship_options(_spec, rel) do + default_destination_attribute = + rel.source + |> Module.split() + |> List.last() + |> Macro.underscore() + |> Kernel.<>("_id") + + "" + |> add_destination_attribute(rel, default_destination_attribute) + |> add_source_attribute(rel, "id") + |> add_filter(rel) + end + + defp add_filter(str, %{match_with: []}), do: str + + defp add_filter(str, %{match_with: match_with}) do + filter = + Enum.map_join(match_with, " and ", fn {source, dest} -> + "parent(#{source}) == #{dest}" + end) + + "#{str}\n filter expr(#{filter})" + end + + defp add_attribute_type(str, %{attr_type: :uuid}), do: str + + defp add_attribute_type(str, %{attr_type: attr_type}) do + "#{str}\n attribute_type :#{attr_type}" + end + + defp add_destination_attribute(str, rel, default) do + if rel.destination_attribute == default do + str + else + "#{str}\n destination_attribute :#{rel.destination_attribute}" + end + end + + defp add_source_attribute(str, rel, default) do + if rel.source_attribute == default do + str + else + "#{str}\n source_attribute :#{rel.source_attribute}" + end + end + + defp references(_table_spec, true) do + "" + end + + defp references(table_spec, _) do + table_spec.foreign_keys + |> Enum.flat_map(fn %Spec.ForeignKey{} = foreign_key -> + default_name = "#{table_spec.table_name}_#{foreign_key.column}_fkey" + + if default_name == foreign_key.constraint_name and + foreign_key.on_update == "NO ACTION" and + foreign_key.on_delete == "NO ACTION" and + foreign_key.match_type in ["SIMPLE", "NONE"] do + [] + else + relationship = + Enum.find(table_spec.relationships, fn relationship -> + relationship.type == :belongs_to and + relationship.constraint_name == foreign_key.constraint_name + end).name + + options = + "" + |> add_on(:update, foreign_key.on_update) + |> add_on(:delete, foreign_key.on_delete) + |> add_match_with(foreign_key.match_with) + |> add_match_type(foreign_key.match_type) + + [ + """ + reference :#{relationship} do + #{options} + end + """ + ] + end + |> Enum.join("\n") + |> String.trim() + |> then( + &[ + """ + references do + #{&1} + end + """ + ] + ) + end) + end + + defp add_match_with(str, empty) when empty in [[], nil], do: str + + defp add_match_with(str, keyval), + do: str <> "\nmatch_with [#{Enum.map_join(keyval, fn {key, val} -> "#{key}: :#{val}" end)}]" + + defp add_match_type(str, type) when type in ["SIMPLE", "NONE"], do: str + + defp add_match_type(str, "FULL"), do: str <> "\nmatch_type :full" + defp add_match_type(str, "PARTIAL"), do: str <> "\nmatch_type :partial" + + defp add_on(str, type, "RESTRICT"), do: str <> "\non_#{type} :restrict" + defp add_on(str, type, "CASCADE"), do: str <> "\non_#{type} :#{type}" + defp add_on(str, type, "SET NULL"), do: str <> "\non_#{type} :nilify" + defp add_on(str, _type, _), do: str + + defp custom_indexes(table_spec, true) do + table_spec.indexes + |> Enum.reject(fn index -> + !index.unique? || (&index_as_identity?/1) + end) + |> Enum.reject(fn index -> + Enum.any?(index.columns, &String.contains?(&1, "(")) + end) + |> case do + [] -> + "" + + indexes -> + indexes + |> Enum.map_join(", ", fn %{index: name, columns: columns} -> + columns = Enum.map_join(columns, ", ", &":#{&1}") + "{[#{columns}], #{inspect(name)}}" + end) + |> then(fn index_names -> + "unique_index_names [#{index_names}]" + end) + end + end + + defp custom_indexes(table_spec, _) do + table_spec.indexes + |> Enum.reject(&index_as_identity?/1) + |> case do + [] -> + "" + + indexes -> + indexes + |> Enum.map_join("\n", fn index -> + columns = + index.columns + |> Enum.map_join(", ", fn thing -> + if String.contains?(thing, "(") do + inspect(thing) + else + ":#{thing}" + end + end) + + case index_options(table_spec, index) do + "" -> + "index [#{columns}]" + + options -> + """ + index [#{columns}] do + #{options} + end + """ + end + end) + |> then(fn indexes -> + """ + custom_indexes do + #{indexes} + end + """ + end) + end + end + + defp index_as_identity?(index) do + is_nil(index.where_clause) and index.using == "btree" and index.include in [nil, []] and + Enum.all?(index.columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end + + defp index_options(spec, index) do + default_name = + if Enum.all?(index.columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) do + AshPostgres.CustomIndex.name(spec.table_name, %{fields: index.columns}) + end + + "" + |> add_index_name(index.name, default_name) + |> add_unique(index.unique?) + |> add_using(index.using) + |> add_where(index.where_clause) + |> add_include(index.include) + |> add_nulls_distinct(index.nulls_distinct) + end + + defp add_index_name(str, default, default), do: str + defp add_index_name(str, name, _), do: str <> "\nname #{inspect(name)}" + + defp add_unique(str, false), do: str + defp add_unique(str, true), do: str <> "\nunique true" + + defp add_nulls_distinct(str, true), do: str + defp add_nulls_distinct(str, false), do: str <> "\nnulls_distinct false" + + defp add_using(str, "btree"), do: str + defp add_using(str, using), do: str <> "\nusing #{inspect(using)}" + + defp add_where(str, empty) when empty in [nil, ""], do: str + defp add_where(str, where), do: str <> "\nwhere #{inspect(where)}" + + defp add_include(str, empty) when empty in [nil, []], do: str + + defp add_include(str, include), + do: str <> "\ninclude [#{Enum.map_join(include, ", ", &inspect/1)}]" + + defp attributes(table_spec) do + table_spec.attributes + |> Enum.split_with(& &1.default) + |> then(fn {l, r} -> r ++ l end) + |> Enum.split_with(& &1.primary_key?) + |> then(fn {l, r} -> l ++ r end) + |> Enum.filter(fn attribute -> + if not is_nil(attribute.default) or !!attribute.generated? or + attribute.source != attribute.name do + true + else + not Enum.any?(table_spec.relationships, fn relationship -> + relationship.type == :belongs_to and relationship.source_attribute == attribute.name + end) + end + end) + |> Enum.map_join("\n", &attribute(&1)) + end + + defp attribute(attribute) do + now_default = &DateTime.utc_now/0 + uuid_default = &Ash.UUID.generate/0 + + {constructor, attribute, type?, type_option?} = + case attribute do + %{name: "updated_at", attr_type: attr_type} -> + {"update_timestamp", %{attribute | default: nil, generated?: false}, false, + attr_type != :utc_datetime_usec} + + %{default: default, attr_type: attr_type} + when default == now_default -> + {"create_timestamp", %{attribute | default: nil, generated?: false}, false, + attr_type != :utc_datetime_usec} + + %{default: default, attr_type: attr_type, primary_key?: true} + when default == uuid_default -> + {"uuid_primary_key", + %{attribute | default: nil, primary_key?: false, generated?: false, allow_nil?: true}, + false, attr_type != :uuid} + + _ -> + {"attribute", attribute, true, false} + end + + case String.trim(options(attribute, type_option?)) do + "" -> + if type? do + "#{constructor} :#{attribute.name}, #{inspect(attribute.attr_type)}" + else + "#{constructor} :#{attribute.name}" + end + + options -> + if type? do + """ + #{constructor} :#{attribute.name}, #{inspect(attribute.attr_type)} do + #{options} + end + """ + else + """ + #{constructor} :#{attribute.name} do + #{options} + end + """ + end + end + end + + defp options(attribute, type_option?) do + "" + |> add_primary_key(attribute) + |> add_allow_nil(attribute) + |> add_sensitive(attribute) + |> add_default(attribute) + |> add_type(attribute, type_option?) + |> add_generated(attribute) + |> add_source(attribute) + end + + defp add_type(str, %{attr_type: attr_type}, true) do + str <> "\n type #{inspect(attr_type)}" + end + + defp add_type(str, _, _), do: str + + defp add_generated(str, %{generated?: true}) do + str <> "\n generated? true" + end + + defp add_generated(str, _), do: str + + defp add_source(str, %{name: name, source: source}) when name != source do + str <> "\n source :#{source}" + end + + defp add_source(str, _), do: str + + defp add_primary_key(str, %{primary_key?: true}) do + str <> "\n primary_key? true" + end + + defp add_primary_key(str, _), do: str + + defp add_allow_nil(str, %{allow_nil?: false}) do + str <> "\n allow_nil? false" + end + + defp add_allow_nil(str, _), do: str + + defp add_sensitive(str, %{sensitive?: true}) do + str <> "\n sensitive? true" + end + + defp add_sensitive(str, _), do: str + + defp add_default(str, %{default: default}) when not is_nil(default) do + str <> "\n default #{inspect(default)}" + end + + defp add_default(str, _), do: str +end diff --git a/lib/resource_generator/sensitive_data.ex b/lib/resource_generator/sensitive_data.ex new file mode 100644 index 00000000..10fa3691 --- /dev/null +++ b/lib/resource_generator/sensitive_data.ex @@ -0,0 +1,73 @@ +defmodule AshPostgres.ResourceGenerator.SensitiveData do + # I got this from ChatGPT, but this is a best effort transformation + # anyway. + @sensitive_patterns [ + # Password-related + ~r/password/i, + ~r/passwd/i, + ~r/pass/i, + ~r/pwd/i, + ~r/hash(ed)?(_password)?/i, + + # Authentication-related + ~r/auth(_key)?/i, + ~r/token/i, + ~r/secret(_key)?/i, + ~r/api_key/i, + + # Personal Information + ~r/ssn/i, + ~r/social(_security)?(_number)?/i, + ~r/(credit_?card|cc)(_number)?/i, + ~r/passport(_number)?/i, + ~r/driver_?licen(s|c)e(_number)?/i, + ~r/national_id/i, + + # Financial Information + ~r/account(_number)?/i, + ~r/routing(_number)?/i, + ~r/iban/i, + ~r/swift(_code)?/i, + ~r/tax_id/i, + + # Contact Information + ~r/phone(_number)?/i, + ~r/email(_address)?/i, + ~r/address/i, + + # Health Information + ~r/medical(_record)?/i, + ~r/health(_data)?/i, + ~r/diagnosis/i, + ~r/treatment/i, + + # Biometric Data + ~r/fingerprint/i, + ~r/retina_scan/i, + ~r/face_id/i, + ~r/dna/i, + + # Encrypted or Encoded Data + ~r/encrypt(ed)?/i, + ~r/encoded/i, + ~r/cipher/i, + + # Other Potentially Sensitive Data + ~r/private(_key)?/i, + ~r/confidential/i, + ~r/restricted/i, + ~r/sensitive/i, + + # General patterns + ~r/.*_salt/i, + ~r/.*_secret/i, + ~r/.*_key/i, + ~r/.*_token/i + ] + + def is_sensitive?(column_name) do + Enum.any?(@sensitive_patterns, fn pattern -> + Regex.match?(pattern, column_name) + end) + end +end diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex new file mode 100644 index 00000000..1b73fc41 --- /dev/null +++ b/lib/resource_generator/spec.ex @@ -0,0 +1,1026 @@ +defmodule AshPostgres.ResourceGenerator.Spec do + require Logger + + defstruct [ + :attributes, + :table_name, + :repo, + :resource, + :schema, + check_constraints: [], + foreign_keys: [], + indexes: [], + identities: [], + relationships: [] + ] + + defmodule Attribute do + defstruct [ + :name, + :type, + :attr_type, + :default, + :migration_default, + :size, + :source, + generated?: false, + primary_key?: false, + sensitive?: false, + allow_nil?: true + ] + end + + defmodule ForeignKey do + defstruct [ + :constraint_name, + :match_type, + :column, + :references, + :destination_field, + :on_delete, + :on_update, + :match_with + ] + end + + defmodule Index do + defstruct [:name, :columns, :unique?, :nulls_distinct, :where_clause, :using, :include] + end + + defmodule CheckConstraint do + defstruct [:name, :column, :expression] + end + + defmodule Relationship do + defstruct [ + :name, + :type, + :destination, + :match_with, + :source, + :source_attribute, + :constraint_name, + :destination_attribute, + :allow_nil?, + :foreign_key + ] + end + + def tables(repo, opts \\ []) do + {:ok, result, _} = + Ecto.Migrator.with_repo(repo, fn repo -> + repo + |> table_specs(opts) + |> verify_found_tables(opts) + |> Enum.group_by(&Enum.take(&1, 2), fn [_, _, field, type, default, size, allow_nil?] -> + name = Macro.underscore(field) + + %Attribute{ + name: name, + source: field, + type: type, + migration_default: default, + size: size, + allow_nil?: allow_nil? + } + end) + |> Enum.map(fn {[table_name, table_schema], attributes} -> + attributes = build_attributes(attributes, table_name, table_schema, repo) + + %__MODULE__{ + table_name: table_name, + schema: table_schema, + repo: repo, + attributes: attributes + } + end) + |> Enum.map(fn spec -> + spec + |> add_foreign_keys() + |> add_indexes() + |> add_check_constraints() + end) + end) + + result + end + + defp add_foreign_keys(spec) do + %Postgrex.Result{rows: fkey_rows} = + spec.repo.query!( + """ + SELECT + tc.constraint_name, + rc.match_option AS match_type, + rc.update_rule AS on_update, + rc.delete_rule AS on_delete, + array_agg(DISTINCT kcu.column_name) AS referencing_columns, + array_agg(DISTINCT ccu.column_name) AS referenced_columns, + ccu.table_name AS foreign_table_name + FROM + information_schema.table_constraints AS tc + JOIN information_schema.key_column_usage AS kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_schema = kcu.table_schema + JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name + AND ccu.table_schema = tc.table_schema + JOIN information_schema.referential_constraints AS rc + ON tc.constraint_name = rc.constraint_name + AND tc.table_schema = rc.constraint_schema + WHERE + tc.constraint_type = 'FOREIGN KEY' + AND tc.table_name = $1 + AND tc.table_schema = $2 + GROUP BY + tc.constraint_name, + ccu.table_name, + rc.match_option, + rc.update_rule, + rc.delete_rule; + """, + [spec.table_name, spec.schema], + log: false + ) + + %{ + spec + | foreign_keys: + Enum.map( + fkey_rows, + fn [ + constraint_name, + match_type, + on_update, + on_delete, + referencing_columns, + referenced_columns, + destination + ] -> + {[column_name], match_with_source} = + Enum.split(referencing_columns, 1) + + {[destination_field], match_with_destination} = + Enum.split(referenced_columns, 1) + + %ForeignKey{ + constraint_name: constraint_name, + column: column_name, + references: destination, + destination_field: destination_field, + on_delete: on_delete, + on_update: on_update, + match_type: match_type, + match_with: Enum.zip(match_with_source, match_with_destination) + } + end + ) + } + end + + defp add_check_constraints(spec) do + %Postgrex.Result{rows: check_constraint_rows} = + spec.repo.query!( + """ + SELECT + conname AS constraint_name, + pg_get_constraintdef(oid) AS constraint_definition + FROM + pg_constraint + WHERE + contype = 'c' + AND conrelid::regclass::text = $1 + """, + [spec.table_name] + ) + + attribute = Enum.find(spec.attributes, & &1.primary_key?) || Enum.at(spec.attributes, 0) + + spec + |> Map.put( + :check_constraints, + Enum.flat_map(check_constraint_rows, fn + [name, "CHECK " <> expr] -> + [ + %CheckConstraint{ + name: name, + column: attribute.source, + expression: expr + } + ] + + _ -> + [] + end) + ) + end + + defp add_indexes(spec) do + %Postgrex.Result{rows: index_rows} = + spec.repo.query!( + """ + SELECT + i.relname AS index_name, + ix.indisunique AS is_unique, + NOT(ix.indnullsnotdistinct) AS nulls_distinct, + pg_get_expr(ix.indpred, ix.indrelid) AS where_clause, + am.amname AS using_method, + idx.indexdef + FROM + pg_index ix + JOIN + pg_class i ON ix.indexrelid = i.oid + JOIN + pg_class t ON ix.indrelid = t.oid + JOIN + pg_am am ON i.relam = am.oid + LEFT JOIN + pg_constraint c ON c.conindid = ix.indexrelid AND c.contype = 'p' + JOIN + pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = 'public' -- Adjust schema name if necessary + JOIN information_schema.tables ta + ON ta.table_name = t.relname + WHERE + t.relname = $1 + AND ta.table_schema = $2 + AND c.conindid IS NULL + GROUP BY + i.relname, ix.indisunique, ix.indnullsnotdistinct, pg_get_expr(ix.indpred, ix.indrelid), am.amname, idx.indexdef; + """, + [spec.table_name, spec.schema], + log: false + ) + + %{ + spec + | indexes: + index_rows + |> Enum.flat_map(fn [ + index_name, + is_unique, + nulls_distinct, + where_clause, + using, + index_def + ] -> + index_name = String.slice(index_name, 0..63) + + case parse_columns_from_index_def(index_def, using) do + {:ok, columns} -> + include = + case String.split(index_def, "INCLUDE ") do + [_, included_cols] -> + try do + parse_columns(included_cols) + catch + :error -> + Logger.warning( + "Failed to parse includs from index definition: #{index_def}" + ) + + nil + end + + _ -> + nil + end + + [ + %Index{ + name: index_name, + columns: Enum.uniq(columns), + unique?: is_unique, + include: include, + using: using, + nulls_distinct: nulls_distinct, + where_clause: where_clause + } + ] + + :error -> + Logger.warning("Failed to parse index definition: #{index_def}") + [] + end + end) + } + end + + # CREATE INDEX users_lower_email_idx ON public.users USING btree (lower((email)::text)) + # CREATE INDEX unique_email_com3 ON public.users USING btree (email, id) WHERE (email ~~ '%.com'::citext) + defp parse_columns_from_index_def(string, using) do + string + |> String.trim_leading("CREATE ") + |> String.trim_leading("UNIQUE ") + |> String.trim_leading("INDEX ") + |> String.replace(~r/^[a-zA-Z0-9_\.]+\s/, "") + |> String.trim_leading("ON ") + |> String.replace(~r/^[\S]+/, "") + |> String.trim_leading() + |> String.trim_leading("USING #{using} ") + |> do_parse_columns() + |> then(&{:ok, &1}) + catch + :error -> :error + end + + def parse_columns(char) do + do_parse_columns(char) + end + + defp do_parse_columns(char, state \\ [], field \\ "", acc \\ []) + + defp do_parse_columns("(" <> rest, [], field, acc) do + do_parse_columns(rest, [:outer], field, acc) + end + + defp do_parse_columns(")" <> _rest, [:outer], field, acc) do + if field == "" do + Enum.reverse(acc) + else + Enum.reverse([field | acc]) + end + end + + defp do_parse_columns("(" <> rest, [:outer], field, acc) do + do_parse_columns(rest, [:in_paren, :in_field, :outer], field, acc) + end + + defp do_parse_columns(", " <> rest, [:in_field, :outer], field, acc) do + do_parse_columns(rest, [:in_field, :outer], "", [field | acc]) + end + + defp do_parse_columns(<> <> rest, [:outer], field, acc) do + do_parse_columns(rest, [:in_field, :outer], field <> str, acc) + end + + defp do_parse_columns("''" <> rest, [:in_quote | stack], field, acc) do + do_parse_columns(rest, [:in_quote | stack], field <> "'", acc) + end + + defp do_parse_columns("'" <> rest, [:in_quote | stack], field, acc) do + do_parse_columns(rest, stack, field <> "'", acc) + end + + defp do_parse_columns(<> <> rest, [:in_quote | stack], field, acc) do + do_parse_columns(rest, [:in_quote | stack], field <> str, acc) + end + + defp do_parse_columns("'" <> rest, stack, field, acc) do + do_parse_columns(rest, [:in_quote | stack], field <> "'", acc) + end + + defp do_parse_columns("(" <> rest, stack, field, acc) do + do_parse_columns(rest, [:in_paren | stack], field <> "(", acc) + end + + defp do_parse_columns(")" <> rest, [:in_paren | stack], field, acc) do + do_parse_columns(rest, stack, field <> ")", acc) + end + + defp do_parse_columns("), " <> rest, [:in_field | stack], field, acc) do + do_parse_columns(rest, [:in_field | stack], "", [field | acc]) + end + + defp do_parse_columns(")" <> _rest, [:in_field | _stack], field, acc) do + Enum.reverse([field | acc]) + end + + defp do_parse_columns(<> <> rest, [:in_paren | stack], field, acc) do + do_parse_columns(rest, [:in_paren | stack], field <> str, acc) + end + + defp do_parse_columns(<> <> rest, [:outer], field, acc) do + do_parse_columns(rest, [:in_field, :outer], field <> str, acc) + end + + defp do_parse_columns(<> <> rest, [:in_field | stack], field, acc) do + do_parse_columns(rest, [:in_field | stack], field <> str, acc) + end + + defp do_parse_columns(", " <> rest, [:in_field | stack], field, acc) do + do_parse_columns(rest, stack, "", [field | acc]) + end + + defp do_parse_columns(")" <> _rest, [:outer], field, acc) do + Enum.reverse([field | acc]) + end + + defp do_parse_columns("", [:in_field | _stack], field, acc) do + Enum.reverse([field | acc]) + end + + defp do_parse_columns("", [:outer], field, acc) do + if field == "" do + Enum.reverse(acc) + else + Enum.reverse([field | acc]) + end + end + + defp do_parse_columns(other, stack, field, acc) do + raise "Unexpected character: #{inspect(other)} at #{inspect(stack)} with #{inspect(field)} - #{inspect(acc)}" + end + + defp verify_found_tables(specs, opts) do + if opts[:tables] do + not_found = + Enum.reject(opts[:tables], fn table -> + if String.ends_with?(table, ".") do + true + else + case String.split(table, ".") do + [schema, table] -> + Enum.any?(specs, fn spec -> + Enum.at(spec, 0) == table and Enum.at(spec, 1) == schema + end) + + [table] -> + Enum.any?(specs, fn spec -> + Enum.at(spec, 0) == table + end) + end + end + end) + + case not_found do + [] -> + specs + + tables -> + raise "The following tables did not exist: #{inspect(tables)}" + end + else + specs + end + end + + defp build_attributes(attributes, table_name, schema, repo) do + attributes + |> set_primary_key(table_name, schema, repo) + |> set_sensitive() + |> set_types() + |> set_defaults_and_generated() + end + + defp set_defaults_and_generated(attributes) do + Enum.map(attributes, fn attribute -> + attribute = + if attribute.migration_default do + %{attribute | generated?: true} + else + attribute + end + + case attribute do + %{migration_default: nil} -> + attribute + + %{migration_default: "CURRENT_TIMESTAMP"} -> + %{attribute | default: &DateTime.utc_now/0} + + %{migration_default: "now()"} -> + %{attribute | default: &DateTime.utc_now/0} + + %{migration_default: "(now() AT TIME ZONE 'utc'::text)"} -> + %{attribute | default: &DateTime.utc_now/0} + + %{migration_default: "gen_random_uuid()"} -> + %{attribute | default: &Ash.UUID.generate/0} + + %{migration_default: "uuid_generate_v4()"} -> + %{attribute | default: &Ash.UUID.generate/0} + + %{attr_type: :integer, migration_default: value} -> + case Integer.parse(value) do + {value, ""} -> + %{attribute | default: value} + + _ -> + attribute + end + + %{attr_type: :decimal, migration_default: value} -> + case Decimal.parse(value) do + {value, ""} -> + %{attribute | default: Decimal.new(value)} + + _ -> + attribute + end + + %{attr_type: :map, migration_default: value} -> + case Jason.decode(String.trim_trailing(value, "::json")) do + {:ok, value} -> + %{attribute | default: value} + + _ -> + attribute + end + + %{attr_type: type, migration_default: "'" <> value} + when type in [:string, :ci_string, :atom] -> + case String.trim_trailing(value, "'::text") do + ^value -> + attribute + + trimmed -> + # This is very likely too naive + attribute = %{attribute | default: String.replace(trimmed, "''", "'")} + + if type == :atom do + %{attribute | default: String.to_atom(attribute.default)} + else + attribute + end + end + + _ -> + attribute + end + end) + end + + def add_relationships(specs, resources) do + specs + |> Enum.group_by(& &1.repo) + |> Enum.flat_map(fn {repo, specs} -> + do_add_relationships( + specs, + Enum.flat_map(resources, fn {resource, resource_repo, table} -> + if resource_repo == repo do + [{resource, table}] + else + [] + end + end) + ) + end) + end + + defp do_add_relationships(specs, resources) do + specs = + Enum.map(specs, fn spec -> + belongs_to_relationships = + Enum.flat_map( + spec.foreign_keys, + fn %ForeignKey{ + constraint_name: constraint_name, + column: column_name, + references: references, + destination_field: destination_field, + match_with: match_with + } -> + case find_destination_and_field( + specs, + spec, + references, + destination_field, + resources, + match_with + ) do + nil -> + [] + + {destination, destination_attribute, match_with} -> + source_attr = + Enum.find(spec.attributes, fn attribute -> + attribute.source == column_name + end) + + [ + %Relationship{ + type: :belongs_to, + name: Inflex.singularize(references), + source: spec.resource, + constraint_name: constraint_name, + match_with: match_with, + destination: destination, + source_attribute: source_attr.name, + allow_nil?: source_attr.allow_nil?, + destination_attribute: destination_attribute + } + ] + end + end + ) + |> Enum.group_by(& &1.name) + |> Enum.flat_map(fn + {_name, [relationship]} -> + [relationship] + + {name, relationships} -> + name_all_relationships(:belongs_to, spec, name, relationships) + end) + + %{spec | relationships: belongs_to_relationships} + end) + + Enum.map(specs, fn spec -> + relationships_to_me = + Enum.flat_map(specs, fn other_spec -> + Enum.flat_map(other_spec.relationships, fn relationship -> + if relationship.destination == spec.resource do + [{other_spec.table_name, other_spec.resource, relationship}] + else + [] + end + end) + end) + |> Enum.map(fn {table, resource, relationship} -> + destination_field = + Enum.find(spec.attributes, fn attribute -> + attribute.name == relationship.destination_attribute + end).source + + has_unique_index? = + Enum.any?(spec.indexes, fn index -> + index.unique? and is_nil(index.where_clause) and + index.columns == [destination_field] + end) + + {name, type} = + if has_unique_index? do + if Inflex.pluralize(table) == table do + {Inflex.singularize(table), :has_one} + else + {table, :has_one} + end + else + if Inflex.pluralize(table) == table do + {table, :has_many} + else + {Inflex.pluralize(table), :has_many} + end + end + + %Relationship{ + type: type, + name: name, + destination: resource, + source: spec.resource, + match_with: + Enum.map(relationship.match_with, fn {source, dest} -> + {dest, source} + end), + constraint_name: relationship.constraint_name, + source_attribute: relationship.destination_attribute, + destination_attribute: relationship.source_attribute + } + end) + |> Enum.group_by(& &1.name) + |> Enum.flat_map(fn + {_name, [relationship]} -> + [relationship] + + {name, relationships} -> + name_all_relationships(:has, spec, name, relationships) + end) + + %{spec | relationships: spec.relationships ++ relationships_to_me} + end) + end + + defp name_all_relationships(type, spec, name, relationships, acc \\ []) + defp name_all_relationships(_type, _spec, _name, [], acc), do: acc + + defp name_all_relationships(type, spec, name, [relationship | rest], acc) do + label = + case type do + :belongs_to -> + """ + Multiple foreign keys found from `#{inspect(spec.resource)}` to `#{inspect(relationship.destination)}` with the guessed name `#{name}`. + + Provide a relationship name for the one with the following info: + + Resource: `#{inspect(spec.resource)}` + Relationship Type: :belongs_to + Guessed Name: `:#{name}` + Relationship Destination: `#{inspect(relationship.destination)}` + Constraint Name: `#{inspect(relationship.constraint_name)}`. + + Leave empty to skip adding this relationship. + + Name: + """ + |> String.trim_trailing() + + _ -> + """ + Multiple foreign keys found from `#{inspect(relationship.source)}` to `#{inspect(spec.resource)}` with the guessed name `#{name}`. + + Provide a relationship name for the one with the following info: + + Resource: `#{inspect(relationship.source)}` + Relationship Type: :#{relationship.type} + Guessed Name: `:#{name}` + Relationship Destination: `#{inspect(spec.resource)}` + Constraint Name: `#{inspect(relationship.constraint_name)}`. + + Leave empty to skip adding this relationship. + + Name: + """ + |> String.trim_trailing() + end + + Owl.IO.input(label: label) + |> String.trim() + # common typo + |> String.trim_leading(":") + |> case do + "" -> + name_all_relationships(type, spec, name, rest, acc) + + new_name -> + name_all_relationships(type, spec, name, rest, [%{relationship | name: new_name} | acc]) + end + end + + defp find_destination_and_field( + specs, + spec, + destination, + destination_field, + resources, + match_with + ) do + case Enum.find(specs, fn other_spec -> + other_spec.table_name == destination + end) do + nil -> + case Enum.find(resources, fn {_resource, table} -> + table == destination + end) do + nil -> + nil + + {resource, _table} -> + # this is cheating. We should be making sure the app is compiled + # before our task is composed or pulling from source code + attributes = + resource + |> Ash.Resource.Info.attributes() + + case Enum.reduce_while(match_with, {:ok, []}, fn {source, dest}, {:ok, acc} -> + with source_attr when not is_nil(source_attr) <- + Enum.find(spec.attributes, &(&1.source == source)), + dest_attr when not is_nil(dest_attr) <- + Enum.find(attributes, &(to_string(&1.source) == dest)) do + {:cont, {:ok, acc ++ [{source_attr.name, to_string(dest_attr.name)}]}} + else + _ -> + {:halt, :error} + end + end) do + {:ok, match_with} -> + Enum.find_value(attributes, fn attribute -> + if to_string(attribute.source) == destination_field do + {resource, to_string(attribute.name), match_with} + end + end) + + _ -> + nil + end + end + + %__MODULE__{} = other_spec -> + case Enum.reduce_while(match_with, {:ok, []}, fn {source, dest}, {:ok, acc} -> + with source_attr when not is_nil(source_attr) <- + Enum.find(spec.attributes, &(&1.source == source)), + dest_attr when not is_nil(dest_attr) <- + Enum.find(other_spec.attributes, &(&1.source == dest)) do + {:cont, {:ok, acc ++ [{source_attr.name, dest_attr.name}]}} + else + _ -> + {:halt, :error} + end + end) do + {:ok, match_with} -> + other_spec.attributes + |> Enum.find_value(fn %Attribute{} = attr -> + if attr.source == destination_field do + {other_spec.resource, attr.name, match_with} + end + end) + + _ -> + nil + end + end + end + + def set_types(attributes) do + attributes + |> Enum.map(fn attribute -> + case Process.get({:type_cache, attribute.type}) do + nil -> + case type(attribute.type) do + {:ok, type} -> + %{attribute | attr_type: type} + + :error -> + get_type(attribute) + end + + type -> + %{attribute | attr_type: type} + end + end) + end + + defp get_type(attribute) do + case Mix.shell().prompt(""" + Unknown type: #{attribute.type}. What should we use as the type? + + Provide the value as literal source code that should be placed into the + generated file, i.e + + - :string + - MyApp.Types.CustomType + - {:array, :string} + + Use `skip` to skip ignore this attribute. + """) do + skip when skip in ["skip", "skip\n"] -> + attribute + + new_type -> + case String.trim(new_type) do + ":" <> type -> + new_type = String.to_atom(type) + Process.put({:type_cache, attribute.type}, new_type) + %{attribute | attr_type: new_type} + + type -> + try do + Code.eval_string(type) + Process.put({:type_cache, attribute.type}, new_type) + %{attribute | attr_type: new_type} + rescue + e -> + IO.puts(Exception.format(:error, e, __STACKTRACE__)) + + get_type(attribute) + end + end + end + end + + defp type("ARRAY of " <> rest) do + case type(rest) do + {:ok, type} -> {:ok, {:array, type}} + :error -> :error + end + end + + defp type("bigint"), do: {:ok, :integer} + defp type("bigserial"), do: {:ok, :integer} + defp type("boolean"), do: {:ok, :boolean} + defp type("bytea"), do: {:ok, :binary} + defp type("varchar"), do: {:ok, :string} + defp type("character varying"), do: {:ok, :string} + defp type("date"), do: {:ok, :date} + defp type("double precision"), do: {:ok, :decimal} + defp type("int"), do: {:ok, :integer} + defp type("integer"), do: {:ok, :integer} + defp type("json"), do: {:ok, :map} + defp type("jsonb"), do: {:ok, :map} + defp type("numeric"), do: {:ok, :decimal} + defp type("decimal"), do: {:ok, :decimal} + defp type("smallint"), do: {:ok, :integer} + defp type("smallserial"), do: {:ok, :ineger} + defp type("serial"), do: {:ok, :integer} + defp type("text"), do: {:ok, :string} + defp type("time"), do: {:ok, :time} + defp type("time without time zone"), do: {:ok, :time} + defp type("time with time zone"), do: {:ok, :time} + defp type("timestamp"), do: {:ok, :utc_datetime_usec} + defp type("timestamp without time zone"), do: {:ok, :utc_datetime_usec} + defp type("timestamp with time zone"), do: {:ok, :utc_datetime_usec} + defp type("tsquery"), do: {:ok, AshPostgres.Tsquery} + defp type("tsvector"), do: {:ok, AshPostgres.Tsvector} + defp type("uuid"), do: {:ok, :uuid} + defp type("citext"), do: {:ok, :ci_string} + defp type(_), do: :error + + defp set_sensitive(attributes) do + Enum.map(attributes, fn attribute -> + %{ + attribute + | sensitive?: AshPostgres.ResourceGenerator.SensitiveData.is_sensitive?(attribute.name) + } + end) + end + + defp set_primary_key(attributes, table_name, schema, repo) do + %Postgrex.Result{rows: pkey_rows} = + repo.query!( + """ + SELECT c.column_name + FROM information_schema.table_constraints tc + JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) + JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema + AND tc.table_name = c.table_name AND ccu.column_name = c.column_name + WHERE constraint_type = 'PRIMARY KEY' and tc.table_name = $1 AND tc.table_schema = $2; + """, + [table_name, schema], + log: false + ) + + Enum.map(attributes, fn %Attribute{name: name} = attribute -> + %{attribute | primary_key?: [name] in pkey_rows} + end) + end + + defp table_specs(repo, opts) do + Enum.flat_map(opts[:tables] || ["public."], fn table -> + {schema, table} = + case String.split(table, ".") do + [schema, table] -> + {schema, table} + + [table] -> + {"public", table} + end + + %{rows: rows} = + if table == "" do + repo.query!( + """ + SELECT + t.table_name, + t.table_schema, + c.column_name, + CASE WHEN c.data_type = 'ARRAY' THEN + repeat('ARRAY of ', a.attndims) || REPLACE(c.udt_name, '_', '') + WHEN c.data_type = 'USER-DEFINED' THEN + c.udt_name + ELSE + c.data_type + END as data_type, + c.column_default, + c.character_maximum_length, + c.is_nullable = 'YES' + FROM + information_schema.tables t + JOIN + information_schema.columns c + ON t.table_name = c.table_name + JOIN pg_attribute a + ON a.attrelid = (SELECT oid FROM pg_class WHERE relname = t.table_name AND relkind = 'r') + AND a.attname = c.column_name + AND a.attnum > 0 + WHERE + t.table_name NOT LIKE 'pg_%' + AND t.table_name NOT LIKE '_pg_%' + AND t.table_schema = $1 + ORDER BY + t.table_name, + c.ordinal_position; + """, + [schema], + log: false + ) + else + repo.query!( + """ + SELECT + t.table_name, + t.table_schema, + c.column_name, + CASE WHEN c.data_type = 'ARRAY' THEN + repeat('ARRAY of ', a.attndims) || REPLACE(c.udt_name, '_', '') + WHEN c.data_type = 'USER-DEFINED' THEN + c.udt_name + ELSE + c.data_type + END as data_type, + c.column_default, + c.character_maximum_length, + c.is_nullable = 'YES' + FROM + information_schema.tables t + JOIN + information_schema.columns c + ON t.table_name = c.table_name + JOIN pg_attribute a + ON a.attrelid = (SELECT oid FROM pg_class WHERE relname = t.table_name AND relkind = 'r') + AND a.attname = c.column_name + AND a.attnum > 0 + WHERE + t.table_schema = $1 + AND t.table_name = $2 + ORDER BY + t.table_name, + c.ordinal_position; + """, + [schema, table], + log: false + ) + end + + rows + end) + end +end diff --git a/mix.exs b/mix.exs index 63d080c4..d4b8e368 100644 --- a/mix.exs +++ b/mix.exs @@ -169,6 +169,8 @@ defmodule AshPostgres.MixProject do {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, + {:inflex, "~> 2.1"}, + {:owl, "~> 0.11"}, # dev/test dependencies {:eflame, "~> 1.0", only: [:dev, :test]}, {:simple_sat, "~> 0.1", only: [:dev, :test]}, diff --git a/mix.lock b/mix.lock index ea609ef7..6410f216 100644 --- a/mix.lock +++ b/mix.lock @@ -8,15 +8,15 @@ "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, "ecto": {:hex, :ecto, "3.12.2", "bae2094f038e9664ce5f089e5f3b6132a535d8b018bd280a485c2f33df5c0ce1", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "492e67c70f3a71c6afe80d946d3ced52ecc57c53c9829791bfff1830ff5a1f0c"}, "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "a663c13478a49d29ae0267b6e45badb803267cf0", []}, - "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "d571628fd829a510d219bcb7162400baff50977f", []}, + "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, @@ -25,9 +25,9 @@ "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, + "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, diff --git a/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json b/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json new file mode 100644 index 00000000..06016f77 --- /dev/null +++ b/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json @@ -0,0 +1,29 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "F24673A4219DEC6873571CCF68B8F0CC34B5843DAA2D7B71A16EFE576C385C1C", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "schematic_groups" +} \ No newline at end of file diff --git a/test/support/domain.ex b/test/support/domain.ex index a1037a47..5fefbd37 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -21,6 +21,15 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Record) resource(AshPostgres.Test.PostFollower) resource(AshPostgres.Test.StatefulPostFollower) + resource(CalcDependency.Dependency) + resource(CalcDependency.Element) + resource(CalcDependency.ElementContext) + resource(CalcDependency.Location) + resource(CalcDependency.Operation) + resource(CalcDependency.OperationVersion) + resource(CalcDependency.SchematicGroup) + resource(CalcDependency.Segment) + resource(CalcDependency.Verb) end authorization do From efa4ef03f14de04b5747ed16e2da85599b669ca3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Sep 2024 20:28:45 -0400 Subject: [PATCH 153/690] feat: `mix ash_postgres.gen.resources` --- lib/mix/tasks/ash_postgres.gen.resources.ex | 5 +- lib/resource_generator/resource_generator.ex | 2 +- lib/resource_generator/spec.ex | 62 ++++++++++++-------- test/resource_generator_test.exs | 27 +++++++++ 4 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 test/resource_generator_test.exs diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 4bb2cd05..73605422 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -23,6 +23,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do - `tables`, `t` - Defaults to `public.*`. The tables to generate resources for, comma separated. Can be specified multiple times. See the section on tables for more. - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. + - `yes`, `y` - Answer yes (or skip) to all questions. ## Tables @@ -41,6 +42,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do example: @example, schema: [ repo: :keep, + yes: :boolean, tables: :keep, skip_tables: :keep, snapshots_only: :boolean, @@ -48,6 +50,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do ], aliases: [ t: :tables, + y: :boolean, r: :repo, d: :domain, s: :skip_tables @@ -109,7 +112,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do """ options = - if Mix.shell().yes?(prompt) do + if options[:yes] || Mix.shell().yes?(prompt) do Keyword.put(options, :no_migrations, false) else Keyword.put(options, :no_migrations, true) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 9ba9586f..2b4b395c 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -84,7 +84,7 @@ defmodule AshPostgres.ResourceGenerator do with `--tables` or `--skip-tables` """ end) - |> Spec.add_relationships(resources) + |> Spec.add_relationships(resources, opts) Enum.reduce(specs, igniter, fn table_spec, igniter -> table_to_resource(igniter, table_spec, domain, opts) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 1b73fc41..4a20c1bc 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -85,7 +85,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do } end) |> Enum.map(fn {[table_name, table_schema], attributes} -> - attributes = build_attributes(attributes, table_name, table_schema, repo) + attributes = build_attributes(attributes, table_name, table_schema, repo, opts) %__MODULE__{ table_name: table_name, @@ -454,11 +454,11 @@ defmodule AshPostgres.ResourceGenerator.Spec do end end - defp build_attributes(attributes, table_name, schema, repo) do + defp build_attributes(attributes, table_name, schema, repo, opts) do attributes |> set_primary_key(table_name, schema, repo) |> set_sensitive() - |> set_types() + |> set_types(opts) |> set_defaults_and_generated() end @@ -540,7 +540,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do end) end - def add_relationships(specs, resources) do + def add_relationships(specs, resources, opts) do specs |> Enum.group_by(& &1.repo) |> Enum.flat_map(fn {repo, specs} -> @@ -552,12 +552,13 @@ defmodule AshPostgres.ResourceGenerator.Spec do else [] end - end) + end), + opts ) end) end - defp do_add_relationships(specs, resources) do + defp do_add_relationships(specs, resources, opts) do specs = Enum.map(specs, fn spec -> belongs_to_relationships = @@ -609,7 +610,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do [relationship] {name, relationships} -> - name_all_relationships(:belongs_to, spec, name, relationships) + name_all_relationships(:belongs_to, opts, spec, name, relationships) end) %{spec | relationships: belongs_to_relationships} @@ -673,17 +674,17 @@ defmodule AshPostgres.ResourceGenerator.Spec do [relationship] {name, relationships} -> - name_all_relationships(:has, spec, name, relationships) + name_all_relationships(:has, opts, spec, name, relationships) end) %{spec | relationships: spec.relationships ++ relationships_to_me} end) end - defp name_all_relationships(type, spec, name, relationships, acc \\ []) - defp name_all_relationships(_type, _spec, _name, [], acc), do: acc + defp name_all_relationships(type, opts, spec, name, relationships, acc \\ []) + defp name_all_relationships(_type, _opts, _spec, _name, [], acc), do: acc - defp name_all_relationships(type, spec, name, [relationship | rest], acc) do + defp name_all_relationships(type, opts, spec, name, [relationship | rest], acc) do label = case type do :belongs_to -> @@ -729,10 +730,12 @@ defmodule AshPostgres.ResourceGenerator.Spec do |> String.trim_leading(":") |> case do "" -> - name_all_relationships(type, spec, name, rest, acc) + name_all_relationships(type, opts, spec, name, rest, acc) new_name -> - name_all_relationships(type, spec, name, rest, [%{relationship | name: new_name} | acc]) + name_all_relationships(type, opts, spec, name, rest, [ + %{relationship | name: new_name} | acc + ]) end end @@ -810,7 +813,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do end end - def set_types(attributes) do + def set_types(attributes, opts) do attributes |> Enum.map(fn attribute -> case Process.get({:type_cache, attribute.type}) do @@ -820,7 +823,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do %{attribute | attr_type: type} :error -> - get_type(attribute) + get_type(attribute, opts) end type -> @@ -829,19 +832,26 @@ defmodule AshPostgres.ResourceGenerator.Spec do end) end - defp get_type(attribute) do - case Mix.shell().prompt(""" - Unknown type: #{attribute.type}. What should we use as the type? + defp get_type(attribute, opts) do + result = + if opts[:yes?] do + "skip" + else + Mix.shell().prompt(""" + Unknown type: #{attribute.type}. What should we use as the type? + + Provide the value as literal source code that should be placed into the + generated file, i.e - Provide the value as literal source code that should be placed into the - generated file, i.e + - :string + - MyApp.Types.CustomType + - {:array, :string} - - :string - - MyApp.Types.CustomType - - {:array, :string} + Use `skip` to skip ignore this attribute. + """) + end - Use `skip` to skip ignore this attribute. - """) do + case result do skip when skip in ["skip", "skip\n"] -> attribute @@ -861,7 +871,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do e -> IO.puts(Exception.format(:error, e, __STACKTRACE__)) - get_type(attribute) + get_type(attribute, opts) end end end diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs new file mode 100644 index 00000000..f501d26b --- /dev/null +++ b/test/resource_generator_test.exs @@ -0,0 +1,27 @@ +defmodule AshPostgres.RelWithParentFilterTest do + use AshPostgres.RepoCase, async: false + + setup do + AshPostgres.TestRepo.query!("DROP TABLE IF EXISTS example_table") + AshPostgres.TestRepo.query!("CREATE TABLE example_table ( + id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, + name VARCHAR(255), + age INTEGER, + email VARCHAR(255) + )") + + on_exit(fn -> + AshPostgres.TestRepo.query!("DROP TABLE IF EXISTS example_table") + end) + end + + test "a resource is generated from a table" do + Igniter.new() + |> Igniter.compose_task("ash_postgres.gen.resources", [ + "MyApp.Accounts", + "--tables", + "example_table", + "--yes" + ]) + end +end From 3fece442301a0c70f2a9d3d28198a55fbdaf5775 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Sep 2024 22:58:36 -0400 Subject: [PATCH 154/690] chore: add the new guide to the docs in mix.exs --- mix.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/mix.exs b/mix.exs index d4b8e368..700bfabf 100644 --- a/mix.exs +++ b/mix.exs @@ -87,6 +87,7 @@ defmodule AshPostgres.MixProject do extras: [ {"README.md", title: "Home"}, "documentation/tutorials/get-started-with-ash-postgres.md", + "documentation/tutorials/set-up-with-existing-database.md", "documentation/topics/about-ash-postgres/what-is-ash-postgres.md", "documentation/topics/resources/references.md", "documentation/topics/resources/polymorphic-resources.md", From f80b157d067b70b77d681d81e2cbcbbdd7636a16 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Sep 2024 23:02:03 -0400 Subject: [PATCH 155/690] chore: remove testing modules not in use --- test/support/domain.ex | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/support/domain.ex b/test/support/domain.ex index 5fefbd37..a1037a47 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -21,15 +21,6 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Record) resource(AshPostgres.Test.PostFollower) resource(AshPostgres.Test.StatefulPostFollower) - resource(CalcDependency.Dependency) - resource(CalcDependency.Element) - resource(CalcDependency.ElementContext) - resource(CalcDependency.Location) - resource(CalcDependency.Operation) - resource(CalcDependency.OperationVersion) - resource(CalcDependency.SchematicGroup) - resource(CalcDependency.Segment) - resource(CalcDependency.Verb) end authorization do From 9191bd32696216508314c8c451c4fda57e1fa536 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Sep 2024 00:31:38 -0400 Subject: [PATCH 156/690] chore: perf fixes, build, and test --- lib/igniter.ex | 8 ++-- lib/mix/tasks/ash_postgres.gen.resources.ex | 2 +- lib/resource_generator/resource_generator.ex | 47 +++++-------------- lib/resource_generator/sensitive_data.ex | 3 +- lib/resource_generator/spec.ex | 48 ++++---------------- test/resource_generator_test.exs | 48 ++++++++++++++++---- test/support/resources/post.ex | 1 + 7 files changed, 68 insertions(+), 89 deletions(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index 662418e0..63fe886d 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -25,8 +25,8 @@ defmodule AshPostgres.Igniter do {igniter, {:ok, value}} when is_binary(value) or is_nil(value) -> {:ok, igniter, value} - _ -> - :error + {igniter, _} -> + {:error, igniter} end end @@ -37,8 +37,8 @@ defmodule AshPostgres.Igniter do {igniter, {:ok, value}} when is_atom(value) -> {:ok, igniter, value} - _ -> - :error + {igniter, _} -> + {:error, igniter} end end diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 73605422..346bbdac 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -5,7 +5,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do @shortdoc "Generates or updates resources based on a database schema" - @doc """ + @moduledoc """ #{@shortdoc} ## Example diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 2b4b395c..81ef6afb 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -1,4 +1,5 @@ defmodule AshPostgres.ResourceGenerator do + @moduledoc false alias AshPostgres.ResourceGenerator.Spec require Logger @@ -6,26 +7,9 @@ defmodule AshPostgres.ResourceGenerator do def generate(igniter, repos, domain, opts \\ []) do {igniter, resources} = Ash.Resource.Igniter.list_resources(igniter) - resources = - Task.async_stream(resources, fn resource -> - {resource, AshPostgres.Igniter.repo(igniter, resource), - AshPostgres.Igniter.table(igniter, resource)} - end) - |> Enum.map(fn {:ok, {resource, repo, table}} -> - repo = - case repo do - {:ok, _igniter, repo} -> repo - _ -> nil - end - - table = - case table do - {:ok, _igniter, table} -> table - _ -> nil - end - - {resource, repo, table} - end) + # This is a hack. We should be looking at compiled resources + # unlikely to ever matter given how this task will be used though. + resources = Enum.filter(resources, &Code.ensure_loaded?/1) igniter = Igniter.include_all_elixir_files(igniter) @@ -140,8 +124,6 @@ defmodule AshPostgres.ResourceGenerator do end defp check_constraints(%{check_constraints: check_constraints}, _) do - IO.inspect(check_constraints) - check_constraints = Enum.map_join(check_constraints, "\n", fn check_constraint -> """ @@ -158,9 +140,8 @@ defmodule AshPostgres.ResourceGenerator do defp skip_unique_indexes(%{indexes: indexes}) do indexes - |> Enum.filter(& &1.unique?) - |> Enum.filter(fn %{columns: columns} -> - Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + |> Enum.filter(fn %{unique?: unique?, columns: columns} -> + unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) end) |> Enum.reject(&index_as_identity?/1) |> case do @@ -176,9 +157,8 @@ defmodule AshPostgres.ResourceGenerator do defp identity_index_names(%{indexes: indexes}) do indexes - |> Enum.filter(& &1.unique?) - |> Enum.filter(fn %{columns: columns} -> - Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + |> Enum.filter(fn %{unique?: unique?, columns: columns} -> + unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) end) |> case do [] -> @@ -195,9 +175,8 @@ defmodule AshPostgres.ResourceGenerator do defp add_identities(str, %{indexes: indexes}) do indexes - |> Enum.filter(& &1.unique?) - |> Enum.filter(fn %{columns: columns} -> - Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + |> Enum.filter(fn %{unique?: unique?, columns: columns} -> + unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) end) |> Enum.map(fn index -> name = index.name @@ -431,10 +410,8 @@ defmodule AshPostgres.ResourceGenerator do defp custom_indexes(table_spec, true) do table_spec.indexes |> Enum.reject(fn index -> - !index.unique? || (&index_as_identity?/1) - end) - |> Enum.reject(fn index -> - Enum.any?(index.columns, &String.contains?(&1, "(")) + !index.unique? || (&index_as_identity?/1) || + Enum.any?(index.columns, &String.contains?(&1, "(")) end) |> case do [] -> diff --git a/lib/resource_generator/sensitive_data.ex b/lib/resource_generator/sensitive_data.ex index 10fa3691..77b0e45b 100644 --- a/lib/resource_generator/sensitive_data.ex +++ b/lib/resource_generator/sensitive_data.ex @@ -1,4 +1,5 @@ defmodule AshPostgres.ResourceGenerator.SensitiveData do + @moduledoc false # I got this from ChatGPT, but this is a best effort transformation # anyway. @sensitive_patterns [ @@ -65,7 +66,7 @@ defmodule AshPostgres.ResourceGenerator.SensitiveData do ~r/.*_token/i ] - def is_sensitive?(column_name) do + def sensitive?(column_name) do Enum.any?(@sensitive_patterns, fn pattern -> Regex.match?(pattern, column_name) end) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 4a20c1bc..fe9fa24c 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -1,4 +1,5 @@ defmodule AshPostgres.ResourceGenerator.Spec do + @moduledoc false require Logger defstruct [ @@ -15,6 +16,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do ] defmodule Attribute do + @moduledoc false defstruct [ :name, :type, @@ -31,6 +33,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do end defmodule ForeignKey do + @moduledoc false defstruct [ :constraint_name, :match_type, @@ -44,14 +47,17 @@ defmodule AshPostgres.ResourceGenerator.Spec do end defmodule Index do + @moduledoc false defstruct [:name, :columns, :unique?, :nulls_distinct, :where_clause, :using, :include] end defmodule CheckConstraint do + @moduledoc false defstruct [:name, :column, :expression] end defmodule Relationship do + @moduledoc false defstruct [ :name, :type, @@ -71,7 +77,6 @@ defmodule AshPostgres.ResourceGenerator.Spec do Ecto.Migrator.with_repo(repo, fn repo -> repo |> table_specs(opts) - |> verify_found_tables(opts) |> Enum.group_by(&Enum.take(&1, 2), fn [_, _, field, type, default, size, allow_nil?] -> name = Macro.underscore(field) @@ -421,39 +426,6 @@ defmodule AshPostgres.ResourceGenerator.Spec do raise "Unexpected character: #{inspect(other)} at #{inspect(stack)} with #{inspect(field)} - #{inspect(acc)}" end - defp verify_found_tables(specs, opts) do - if opts[:tables] do - not_found = - Enum.reject(opts[:tables], fn table -> - if String.ends_with?(table, ".") do - true - else - case String.split(table, ".") do - [schema, table] -> - Enum.any?(specs, fn spec -> - Enum.at(spec, 0) == table and Enum.at(spec, 1) == schema - end) - - [table] -> - Enum.any?(specs, fn spec -> - Enum.at(spec, 0) == table - end) - end - end - end) - - case not_found do - [] -> - specs - - tables -> - raise "The following tables did not exist: #{inspect(tables)}" - end - else - specs - end - end - defp build_attributes(attributes, table_name, schema, repo, opts) do attributes |> set_primary_key(table_name, schema, repo) @@ -546,9 +518,9 @@ defmodule AshPostgres.ResourceGenerator.Spec do |> Enum.flat_map(fn {repo, specs} -> do_add_relationships( specs, - Enum.flat_map(resources, fn {resource, resource_repo, table} -> - if resource_repo == repo do - [{resource, table}] + Enum.flat_map(resources, fn resource -> + if AshPostgres.DataLayer.Info.repo(resource) == repo do + [{resource, AshPostgres.DataLayer.Info.table(resource)}] else [] end @@ -918,7 +890,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do Enum.map(attributes, fn attribute -> %{ attribute - | sensitive?: AshPostgres.ResourceGenerator.SensitiveData.is_sensitive?(attribute.name) + | sensitive?: AshPostgres.ResourceGenerator.SensitiveData.sensitive?(attribute.name) } end) end diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index f501d26b..50bfa7db 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -3,6 +3,7 @@ defmodule AshPostgres.RelWithParentFilterTest do setup do AshPostgres.TestRepo.query!("DROP TABLE IF EXISTS example_table") + AshPostgres.TestRepo.query!("CREATE TABLE example_table ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, name VARCHAR(255), @@ -10,18 +11,45 @@ defmodule AshPostgres.RelWithParentFilterTest do email VARCHAR(255) )") - on_exit(fn -> - AshPostgres.TestRepo.query!("DROP TABLE IF EXISTS example_table") - end) + :ok end test "a resource is generated from a table" do - Igniter.new() - |> Igniter.compose_task("ash_postgres.gen.resources", [ - "MyApp.Accounts", - "--tables", - "example_table", - "--yes" - ]) + resource = + Igniter.new() + |> Igniter.compose_task("ash_postgres.gen.resources", [ + "MyApp.Accounts", + "--tables", + "example_table", + "--yes" + ]) + |> Igniter.prepare_for_write() + |> Map.get(:rewrite) + |> Rewrite.source!("lib/my_app/accounts/example_table.ex") + |> Rewrite.Source.get(:content) + + assert String.trim(resource) == + String.trim(""" + defmodule MyApp.Accounts.ExampleTable do + use Ash.Resource, + domain: MyApp.Accounts, + data_layer: AshPostgres.DataLayer + + postgres do + table "example_table" + repo AshPostgres.TestRepo + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string) + attribute(:age, :integer) + + attribute :email, :string do + sensitive?(true) + end + end + end + """) end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index e4f64c23..fabbdc6d 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -50,6 +50,7 @@ defmodule HasNoComments do end defmodule CiCategory do + @moduledoc false use Ash.Type.NewType, subtype_of: :ci_string end From 5395aba898c3e01eb51b59d654918775040324df Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Sep 2024 01:21:09 -0400 Subject: [PATCH 157/690] chore: release version v2.3.0 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be827fc1..ae1e8191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.3.0](https://github.com/ash-project/ash_postgres/compare/v2.2.5...v2.3.0) (2024-09-05) + + + + +### Features: + +* `mix ash_postgres.gen.resources` + +* `mix ash_postgres.gen.resources` + ## [v2.2.5](https://github.com/ash-project/ash_postgres/compare/v2.2.4...v2.2.5) (2024-09-04) ### Improvements: diff --git a/mix.exs b/mix.exs index 700bfabf..bc665a66 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.2.5" + @version "2.3.0" def project do [ From a9913a699999e7f98a5472c33921f223a8743831 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Sep 2024 12:54:13 -0400 Subject: [PATCH 158/690] improvement: better imported index names improvement: add `--extend` option, forwarded to generated resource --- lib/mix/tasks/ash_postgres.gen.resources.ex | 3 + lib/resource_generator/resource_generator.ex | 66 ++++++++++---------- lib/resource_generator/spec.ex | 23 ++++++- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 346bbdac..5e270f8e 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -23,6 +23,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do - `tables`, `t` - Defaults to `public.*`. The tables to generate resources for, comma separated. Can be specified multiple times. See the section on tables for more. - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. + - `extend`, `e` - Extension or extensions to apply to the generated resources. See `mix ash.patch.extend` for more. - `yes`, `y` - Answer yes (or skip) to all questions. ## Tables @@ -45,6 +46,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do yes: :boolean, tables: :keep, skip_tables: :keep, + extend: :keep, snapshots_only: :boolean, domain: :keep ], @@ -52,6 +54,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do t: :tables, y: :boolean, r: :repo, + e: :extend, d: :domain, s: :skip_tables ] diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 81ef6afb..d29b5800 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -13,33 +13,7 @@ defmodule AshPostgres.ResourceGenerator do igniter = Igniter.include_all_elixir_files(igniter) - opts = - if opts[:tables] do - Keyword.put( - opts, - :tables, - opts[:tables] - |> List.wrap() - |> Enum.join(",") - |> String.split(",") - ) - else - opts - end - - opts = - if opts[:skip_tables] do - Keyword.put( - opts, - :skip_tables, - opts[:skip_tables] - |> List.wrap() - |> Enum.join(",") - |> String.split(",") - ) - else - opts - end + opts = handle_csv_opts(opts, [:tables, :skip_tables, :extend]) specs = repos @@ -75,6 +49,23 @@ defmodule AshPostgres.ResourceGenerator do end) end + defp handle_csv_opts(opts, keys) do + Enum.reduce(keys, opts, fn key, opts -> + opts + |> Keyword.get_values(key) + |> case do + [] -> + opts + + values -> + values + |> Enum.join(",") + |> String.split(",", trim: true) + |> then(&Keyword.put(opts, key, &1)) + end + end) + end + defp table_to_resource( igniter, %AshPostgres.ResourceGenerator.Spec{} = table_spec, @@ -113,6 +104,15 @@ defmodule AshPostgres.ResourceGenerator do igniter |> Ash.Domain.Igniter.add_resource_reference(domain, table_spec.resource) |> Igniter.Code.Module.create_module(table_spec.resource, resource) + |> then(fn igniter -> + if opts[:extend] do + Igniter.compose_task(igniter, "ash.patch.extend", [ + table_spec.resource | opts[:extend] || [] + ]) + else + igniter + end + end) end defp check_constraints(%{check_constraints: _check_constraints}, true) do @@ -138,7 +138,7 @@ defmodule AshPostgres.ResourceGenerator do """ end - defp skip_unique_indexes(%{indexes: indexes}) do + defp skip_unique_indexes(%{table_name: table_name, indexes: indexes}) do indexes |> Enum.filter(fn %{unique?: unique?, columns: columns} -> unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) @@ -150,12 +150,12 @@ defmodule AshPostgres.ResourceGenerator do indexes -> """ - skip_unique_indexes [#{Enum.map_join(indexes, ",", &":#{&1.name}")}] + skip_unique_indexes [#{Enum.map_join(indexes, ",", &":#{&1.identity_name}")}] """ end end - defp identity_index_names(%{indexes: indexes}) do + defp identity_index_names(%{table_name: table_name, indexes: indexes}) do indexes |> Enum.filter(fn %{unique?: unique?, columns: columns} -> unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) @@ -167,19 +167,19 @@ defmodule AshPostgres.ResourceGenerator do indexes -> indexes |> Enum.map_join(", ", fn index -> - "#{index.name}: \"#{index.name}\"" + "#{index.identity_name}: \"#{index.name}\"" end) |> then(&"identity_index_names [#{&1}]") end end - defp add_identities(str, %{indexes: indexes}) do + defp add_identities(str, %{table_name: table_name, indexes: indexes}) do indexes |> Enum.filter(fn %{unique?: unique?, columns: columns} -> unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) end) |> Enum.map(fn index -> - name = index.name + name = index.identity_name fields = "[" <> Enum.map_join(index.columns, ", ", &":#{&1}") <> "]" diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index fe9fa24c..607e2ae5 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -48,7 +48,16 @@ defmodule AshPostgres.ResourceGenerator.Spec do defmodule Index do @moduledoc false - defstruct [:name, :columns, :unique?, :nulls_distinct, :where_clause, :using, :include] + defstruct [ + :name, + :columns, + :unique?, + :nulls_distinct, + :where_clause, + :using, + :include, + :identity_name + ] end defmodule CheckConstraint do @@ -196,7 +205,8 @@ defmodule AshPostgres.ResourceGenerator.Spec do contype = 'c' AND conrelid::regclass::text = $1 """, - [spec.table_name] + [spec.table_name], + log: false ) attribute = Enum.find(spec.attributes, & &1.primary_key?) || Enum.at(spec.attributes, 0) @@ -290,9 +300,18 @@ defmodule AshPostgres.ResourceGenerator.Spec do nil end + identity_name = + index_name + |> String.trim_leading(spec.table_name <> "_") + |> String.trim_leading("unique_") + |> String.replace("_unique_", "_") + |> String.trim_trailing("_index") + |> String.replace("_index_", "_") + [ %Index{ name: index_name, + identity_name: identity_name, columns: Enum.uniq(columns), unique?: is_unique, include: include, From 088bf9d11289cfcdbcfcccc3b59f81cd7b686e1b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Sep 2024 12:54:43 -0400 Subject: [PATCH 159/690] chore: release version v2.3.1 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae1e8191..b3d07dbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.3.1](https://github.com/ash-project/ash_postgres/compare/v2.3.0...v2.3.1) (2024-09-05) + + + + +### Improvements: + +* better imported index names + +* add `--extend` option, forwarded to generated resource + ## [v2.3.0](https://github.com/ash-project/ash_postgres/compare/v2.2.5...v2.3.0) (2024-09-05) diff --git a/mix.exs b/mix.exs index bc665a66..6227db81 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.3.0" + @version "2.3.1" def project do [ From 20486d19681ded546740d393c05222bbdc89fd15 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Sep 2024 12:55:37 -0400 Subject: [PATCH 160/690] chore: update changelog --- CHANGELOG.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d07dbf..8f8f5e4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,25 +7,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.3.1](https://github.com/ash-project/ash_postgres/compare/v2.3.0...v2.3.1) (2024-09-05) - - - ### Improvements: -* better imported index names +- [`mix ash_postgres.gen.migrations`] better imported index names -* add `--extend` option, forwarded to generated resource +- [`mix ash_postgres.gen.migrations`] add `--extend` option, forwarded to generated resource ## [v2.3.0](https://github.com/ash-project/ash_postgres/compare/v2.2.5...v2.3.0) (2024-09-05) - - - ### Features: -* `mix ash_postgres.gen.resources` - -* `mix ash_postgres.gen.resources` +- [`mix ash_postgres.gen.resources`] Add `mix ash_postgres.gen.resources` for importing tables from an existing database as resources ## [v2.2.5](https://github.com/ash-project/ash_postgres/compare/v2.2.4...v2.2.5) (2024-09-04) From 845c6bbdaa554ebc8047d33dabca8aff815f842f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Sep 2024 12:57:15 -0400 Subject: [PATCH 161/690] chore: fix build --- lib/resource_generator/resource_generator.ex | 6 +++--- test/resource_generator_test.exs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index d29b5800..294ff1d1 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -138,7 +138,7 @@ defmodule AshPostgres.ResourceGenerator do """ end - defp skip_unique_indexes(%{table_name: table_name, indexes: indexes}) do + defp skip_unique_indexes(%{indexes: indexes}) do indexes |> Enum.filter(fn %{unique?: unique?, columns: columns} -> unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) @@ -155,7 +155,7 @@ defmodule AshPostgres.ResourceGenerator do end end - defp identity_index_names(%{table_name: table_name, indexes: indexes}) do + defp identity_index_names(%{indexes: indexes}) do indexes |> Enum.filter(fn %{unique?: unique?, columns: columns} -> unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) @@ -173,7 +173,7 @@ defmodule AshPostgres.ResourceGenerator do end end - defp add_identities(str, %{table_name: table_name, indexes: indexes}) do + defp add_identities(str, %{indexes: indexes}) do indexes |> Enum.filter(fn %{unique?: unique?, columns: columns} -> unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index 50bfa7db..0a9b755a 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -1,4 +1,4 @@ -defmodule AshPostgres.RelWithParentFilterTest do +defmodule AshPostgres.ResourceGeenratorTests do use AshPostgres.RepoCase, async: false setup do From 8d22e6ed65380a7a31923c718ac6ee8e3d900ca2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:04:44 -0400 Subject: [PATCH 162/690] chore(deps): bump the production-dependencies group with 2 updates (#379) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash` from 3.4.2 to 3.4.4 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.2...v3.4.4) Updates `ash_sql` from 0.2.31 to 0.2.32 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.31...v0.2.32) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 6410f216..d8e97c6b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.2", "17544d04a1ed5fdc7fc61e9fbb491418c322c73c9cb0c00836c0f80070d4e09a", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, 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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "df5a851797a82a7fa9a1348a0c79bf206f77ce1e3047ec00ce4bfdf733e9459d"}, - "ash_sql": {:hex, :ash_sql, "0.2.31", "721521e073d706169ebb0e68535422c1920580b29829fe949fb679c8674a9691", [:mix], [{:ash, ">= 3.1.7 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", "e5f578be31f5fa5af8dd1cb27b01b7b1864ef1414472293ce3a4851290cb69b1"}, + "ash": {:hex, :ash, "3.4.4", "1745bf9ee2eb4351540a60e14c85ca4ac6afb3924a5625f0b1a4dfdeeed30512", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "38484f04dd19cb985e767bed30a99e5cbb83642db26cc81d8f7e6d0e6ed31e9c"}, + "ash_sql": {:hex, :ash_sql, "0.2.32", "de99255becfb9daa7991c18c870e9f276bb372acda7eda3e05c3e2ff2ca8922e", [:mix], [{:ash, ">= 3.1.7 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", "43773bcd33d21319c11804d76fe11f1a1b7c8faba7aaedeab6f55fde3d2405db"}, "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.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, From 2d7879ff151e09cc37aea347c0fa3c411b558947 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Sep 2024 13:17:07 -0400 Subject: [PATCH 163/690] chore: singularize resource name --- lib/resource_generator/resource_generator.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 294ff1d1..d6772ba2 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -21,6 +21,7 @@ defmodule AshPostgres.ResourceGenerator do |> Enum.map(fn %{table_name: table} = spec -> resource = table + |> Inflex.singularize() |> Macro.camelize() |> then(&Module.concat([domain, &1])) From ba29ed7c70df3a751daf69547a36ac42f40bbe5d Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Fri, 6 Sep 2024 21:19:48 +0200 Subject: [PATCH 164/690] chore: fix PG_VERSION parsing in tests (#382) Allow passing a bare integer as PG_VERSION, which will be interpreted as a major version --- test/support/test_repo.ex | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index c12dad79..4f01c091 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -14,8 +14,14 @@ defmodule AshPostgres.TestRepo do def min_pg_version do case System.get_env("PG_VERSION") do - nil -> %Version{major: 16, minor: 0, patch: 0} - version -> Version.parse!(version) + nil -> + %Version{major: 16, minor: 0, patch: 0} + + version -> + case Integer.parse(version) do + {major, ""} -> %Version{major: major, minor: 0, patch: 0} + _ -> Version.parse!(version) + end end end From 68fff263916b617962592c056587807656e10c56 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Fri, 6 Sep 2024 21:20:50 +0200 Subject: [PATCH 165/690] chore: failing test for constraint violation with stream strategy (#381) This is probably a problem in Ash but I didn't know a simple way to make the ETS data layer fail similarly to a constraint violation --- .../post_permalinks/20240906170759.json | 58 +++++++++++++++++++ .../20240906170759_migrate_resources38.exs | 33 +++++++++++ test/bulk_destroy_test.exs | 36 ++++++++++++ test/support/domain.ex | 1 + test/support/resources/permalink.ex | 33 +++++++++++ test/support/resources/post.ex | 2 + 6 files changed, 163 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json create mode 100644 priv/test_repo/migrations/20240906170759_migrate_resources38.exs create mode 100644 test/support/resources/permalink.ex diff --git a/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json new file mode 100644 index 00000000..6a4201eb --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json @@ -0,0 +1,58 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "post_permalinks_post_id_fkey", + "on_delete": "nothing", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "post_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "2B9B1A4022280ABA644CD2AEB55F765ECC0DFAD3E41F247BFA953ECCB0DCB2F9", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "post_permalinks" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240906170759_migrate_resources38.exs b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs new file mode 100644 index 00000000..f1211140 --- /dev/null +++ b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs @@ -0,0 +1,33 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources38 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:post_permalinks, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + + add( + :post_id, + references(:posts, + column: :id, + name: "post_permalinks_post_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :nothing + ), + null: false + ) + end + end + + def down do + drop(constraint(:post_permalinks, "post_permalinks_post_id_fkey")) + + drop(table(:post_permalinks)) + end +end diff --git a/test/bulk_destroy_test.exs b/test/bulk_destroy_test.exs index dafc2926..e30b62de 100644 --- a/test/bulk_destroy_test.exs +++ b/test/bulk_destroy_test.exs @@ -1,5 +1,6 @@ defmodule AshPostgres.BulkDestroyTest do use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Permalink alias AshPostgres.Test.Post require Ash.Expr @@ -68,4 +69,39 @@ defmodule AshPostgres.BulkDestroyTest do assert [] = Ash.read!(Post) end + + test "bulk destroys errors on constraint violation" do + post = Ash.create!(Post, %{title: "fred"}) + Ash.create!(Permalink, %{post_id: post.id}) + + assert %Ash.BulkResult{ + status: :error, + error_count: 1, + errors: [%Ash.Error.Invalid{}] + } = + Post + |> Ash.read!() + |> Ash.bulk_destroy(:destroy, %{}, + return_records?: true, + return_errors?: true + ) + end + + test "bulk destroys returns error on constraint violation with strategy stream" do + post = Ash.create!(Post, %{title: "fred"}) + Ash.create!(Permalink, %{post_id: post.id}) + + assert %Ash.BulkResult{ + status: :error, + error_count: 1, + errors: [%Ash.Error.Invalid{}] + } = + Post + |> Ash.read!() + |> Ash.bulk_destroy(:destroy, %{}, + strategy: :stream, + return_records?: true, + return_errors?: true + ) + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index a1037a47..353ca4d6 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -18,6 +18,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Manager) resource(AshPostgres.Test.Entity) resource(AshPostgres.Test.TempEntity) + resource(AshPostgres.Test.Permalink) resource(AshPostgres.Test.Record) resource(AshPostgres.Test.PostFollower) resource(AshPostgres.Test.StatefulPostFollower) diff --git a/test/support/resources/permalink.ex b/test/support/resources/permalink.ex new file mode 100644 index 00000000..21df7959 --- /dev/null +++ b/test/support/resources/permalink.ex @@ -0,0 +1,33 @@ +defmodule AshPostgres.Test.Permalink do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + actions do + default_accept(:*) + + defaults([:create, :read]) + end + + attributes do + uuid_primary_key(:id) + end + + relationships do + belongs_to :post, AshPostgres.Test.Post do + public?(true) + allow_nil?(false) + attribute_writable?(true) + end + end + + postgres do + table "post_permalinks" + repo AshPostgres.TestRepo + + references do + reference :post, on_delete: :nothing + end + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index fabbdc6d..31b22721 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -504,6 +504,8 @@ defmodule AshPostgres.Test.Post do has_many(:views, AshPostgres.Test.PostView) do public?(true) end + + has_many(:permalinks, AshPostgres.Test.Permalink) end validations do From b144ee193753feaa51b5423006c174e9de9bba11 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Sep 2024 13:40:21 -0400 Subject: [PATCH 166/690] improvement: ensure `Repo` is started after telemetry improvement: update to latest igniter functions --- lib/data_layer.ex | 2 +- lib/igniter.ex | 4 ++-- lib/mix/tasks/ash_postgres.install.ex | 21 ++++++++++++++------- mix.lock | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 200ee3af..53e3967e 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2984,7 +2984,7 @@ defmodule AshPostgres.DataLayer do repo = case options[:repo] do nil -> - Igniter.Code.Module.module_name("Repo") + Igniter.Code.Module.module_name(igniter, "Repo") repo -> Igniter.Code.Module.parse(repo) diff --git a/lib/igniter.ex b/lib/igniter.ex index 63fe886d..8ac3f29e 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -76,8 +76,8 @@ defmodule AshPostgres.Igniter do case list_repos(igniter) do {igniter, []} -> if generate do - repo = Igniter.Code.Module.module_name("Repo") - otp_app = Igniter.Project.Application.app_name() + repo = Igniter.Code.Module.module_name(igniter, "Repo") + otp_app = Igniter.Project.Application.app_name(igniter) igniter = Igniter.Code.Module.create_module(igniter, repo, default_repo_contents(otp_app)) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index e7a44ed8..d8b93fc8 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -6,8 +6,8 @@ defmodule Mix.Tasks.AshPostgres.Install do use Igniter.Mix.Task def igniter(igniter, _argv) do - repo = Igniter.Code.Module.module_name("Repo") - otp_app = Igniter.Project.Application.app_name() + repo = Igniter.Code.Module.module_name(igniter, "Repo") + otp_app = Igniter.Project.Application.app_name(igniter) igniter |> Igniter.Project.Formatter.import_dep(:ash_postgres) @@ -17,7 +17,14 @@ defmodule Mix.Tasks.AshPostgres.Install do |> configure_runtime(otp_app, repo) |> configure_test(otp_app, repo) |> setup_data_case() - |> Igniter.Project.Application.add_new_child(repo) + |> Igniter.Project.Application.add_new_child(repo, + after: fn mod -> + case Module.split(mod) do + [_, "Telemetry"] -> true + _ -> false + end + end + ) |> Spark.Igniter.prepend_to_section_order(:"Ash.Resource", [:postgres]) |> Ash.Igniter.codegen("initialize") end @@ -221,23 +228,23 @@ defmodule Mix.Tasks.AshPostgres.Install do using do quote do - alias #{inspect(Igniter.Code.Module.module_name("Repo"))} + alias #{inspect(Igniter.Code.Module.module_name(igniter, "Repo"))} import Ecto import Ecto.Changeset import Ecto.Query - import #{inspect(Igniter.Code.Module.module_name("DataCase"))} + import #{inspect(Igniter.Code.Module.module_name(igniter, "DataCase"))} end end setup tags do - pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(Igniter.Code.Module.module_name("Repo"))}, shared: not tags[:async]) + pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(Igniter.Code.Module.module_name(igniter, "Repo"))}, shared: not tags[:async]) on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) :ok end | - module_name = Igniter.Code.Module.module_name("DataCase") + module_name = Igniter.Code.Module.module_name(igniter, "DataCase") igniter |> Igniter.Code.Module.find_and_update_or_create_module( diff --git a/mix.lock b/mix.lock index d8e97c6b..aa2e8729 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.24", "791a91650ffab9d66b9a3011c66491f767577ad55c363f820cc188554207ee6f", [: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]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "2e1d336534c6129bae0db043fae650303b96974c0488c290191d6d4c61ec9a9f"}, + "igniter": {:hex, :igniter, "0.3.30", "89c414e4e3d3d58a29133ad2480d9037abf8881a83e6aa5a753307e5db5f74b5", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "072e441e1bf5102b2516fe75113174c35c381ea3674e389eb6e9f0fb476bbc70"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From b35b97654763bf2a7040208168d1195fc3d24a38 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Sep 2024 20:09:32 -0400 Subject: [PATCH 167/690] improvement: support upcoming `action_select` options --- lib/data_layer.ex | 43 +- mix.lock | 8 +- .../test_repo/posts/20240910180107.json | 459 ++++++++++++++++++ .../20240910180107_migrate_resources39.exs | 21 + test/bulk_create_test.exs | 15 + test/select_test.exs | 8 + test/support/resources/post.ex | 18 + test/test_helper.exs | 2 +- 8 files changed, 560 insertions(+), 14 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/posts/20240910180107.json create mode 100644 priv/test_repo/migrations/20240910180107_migrate_resources39.exs diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 53e3967e..ef61be85 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1368,10 +1368,17 @@ defmodule AshPostgres.DataLayer do query = if options[:return_records?] do {:ok, query} = - query - |> Ecto.Query.exclude(:select) - |> Ecto.Query.select([row], row) - |> add_calculations(options[:calculations] || [], resource) + if options[:action_select] do + query + |> Ecto.Query.exclude(:select) + |> Ecto.Query.select([row], struct(row, ^options[:action_select])) + |> add_calculations(options[:calculations] || [], resource) + else + query + |> Ecto.Query.exclude(:select) + |> Ecto.Query.select([row], row) + |> add_calculations(options[:calculations] || [], resource) + end query else @@ -1626,10 +1633,19 @@ defmodule AshPostgres.DataLayer do query = if options[:return_records?] do {:ok, query} = - query - |> Ecto.Query.exclude(:select) - |> Ecto.Query.select([row], row) - |> add_calculations(options[:calculations] || [], resource) + case options[:action_select] do + nil -> + query + |> Ecto.Query.exclude(:select) + |> Ecto.Query.select([row], row) + |> add_calculations(options[:calculations] || [], resource) + + action_select -> + query + |> Ecto.Query.exclude(:select) + |> Ecto.Query.select([row], struct(row, ^action_select)) + |> add_calculations(options[:calculations] || [], resource) + end query else @@ -1717,7 +1733,13 @@ defmodule AshPostgres.DataLayer do opts = if options.return_records? do - Keyword.put(opts, :returning, true) + returning = + case options[:action_select] do + nil -> true + fields -> fields + end + + Keyword.put(opts, :returning, returning) else opts end @@ -1956,6 +1978,7 @@ defmodule AshPostgres.DataLayer do case bulk_create(resource, [changeset], %{ single?: true, tenant: Map.get(changeset, :to_tenant, changeset.tenant), + action_select: changeset.action_select, return_records?: true }) do {:ok, [result]} -> @@ -2539,6 +2562,7 @@ defmodule AshPostgres.DataLayer do tenant: changeset.tenant, identity: identity, upsert_keys: keys, + action_select: changeset.action_select, upsert_fields: upsert_fields, return_records?: true }) do @@ -2733,6 +2757,7 @@ defmodule AshPostgres.DataLayer do case update_query(query, changeset, resource, %{ return_records?: true, + action_select: changeset.action_select, calculations: [] }) do {:ok, []} -> diff --git a/mix.lock b/mix.lock index aa2e8729..ee8fc935 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.4", "1745bf9ee2eb4351540a60e14c85ca4ac6afb3924a5625f0b1a4dfdeeed30512", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "38484f04dd19cb985e767bed30a99e5cbb83642db26cc81d8f7e6d0e6ed31e9c"}, + "ash": {:hex, :ash, "3.4.8", "8c35c1e401044d05474c0e1a3209c74afb7ac955243085489242cade24d31906", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "e8dd3eb1f3aa45a75265c784df95ce261a3fad7f0d07400d316e981e14ed10f0"}, "ash_sql": {:hex, :ash_sql, "0.2.32", "de99255becfb9daa7991c18c870e9f276bb372acda7eda3e05c3e2ff2ca8922e", [:mix], [{:ash, ">= 3.1.7 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", "43773bcd33d21319c11804d76fe11f1a1b7c8faba7aaedeab6f55fde3d2405db"}, "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"}, @@ -9,7 +9,7 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, - "ecto": {:hex, :ecto, "3.12.2", "bae2094f038e9664ce5f089e5f3b6132a535d8b018bd280a485c2f33df5c0ce1", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "492e67c70f3a71c6afe80d946d3ced52ecc57c53c9829791bfff1830ff5a1f0c"}, + "ecto": {:hex, :ecto, "3.12.3", "1a9111560731f6c3606924c81c870a68a34c819f6d4f03822f370ea31a582208", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9efd91506ae722f95e48dc49e70d0cb632ede3b7a23896252a60a14ac6d59165"}, "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.30", "89c414e4e3d3d58a29133ad2480d9037abf8881a83e6aa5a753307e5db5f74b5", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "072e441e1bf5102b2516fe75113174c35c381ea3674e389eb6e9f0fb476bbc70"}, + "igniter": {:hex, :igniter, "0.3.35", "edd8db6234db7639eb2f954b45ab23db98b1fd0a940850f58db8900912a908bf", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "d2826d94d8c851e2bc8b920766815b3df4b184cab05eae8423e965363a2e02b1"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -38,7 +38,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.23", "78f0a1b0b713a91ad556fe9dc19ec92d977aaa0803cce2e255d90e58b9045c2a", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "a354b5cd7c3f021e3cd1da5a033b7643fe7b3c71c96b96d9f500a742f40c94db"}, + "spark": {:hex, :spark, "2.2.26", "1701f388a9cfb2e27cd037b6f4b72a999e49bdb2d2f946bdbde8a991ce42c499", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "7a57860e4d15ab2e395dffeac617f3ee64d371b47f7b3d718a8d535d75cc7556"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/priv/resource_snapshots/test_repo/posts/20240910180107.json b/priv/resource_snapshots/test_repo/posts/20240910180107.json new file mode 100644 index 00000000..065dc1e9 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240910180107.json @@ -0,0 +1,459 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "702922F4C474FB9294FE47B61DF92D6A5D2D6586F696B7F5B05493CEA4C485D0", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240910180107_migrate_resources39.exs b/priv/test_repo/migrations/20240910180107_migrate_resources39.exs new file mode 100644 index 00000000..adf27660 --- /dev/null +++ b/priv/test_repo/migrations/20240910180107_migrate_resources39.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources39 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:not_selected_by_default, :text) + end + end + + def down do + alter table(:posts) do + remove(:not_selected_by_default) + end + end +end diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index d7a2c544..f4e7ceb6 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -14,6 +14,21 @@ defmodule AshPostgres.BulkCreateTest do |> Ash.read!() end + test "bulk creates perform before action hooks" do + Ash.bulk_create!( + [%{title: "before_action"}, %{title: "before_action"}], + Post, + :create_with_before_action, + return_errors?: true, + return_records?: true + ) + + assert [%{title: "before_action"}, %{title: "before_action"}] = + Post + |> Ash.Query.sort(:title) + |> Ash.read!() + end + test "bulk creates can be streamed" do assert [{:ok, %{title: "fred"}}, {:ok, %{title: "george"}}] = Ash.bulk_create!([%{title: "fred"}, %{title: "george"}], Post, :create, diff --git a/test/select_test.exs b/test/select_test.exs index 1d30aaea..219fdc77 100644 --- a/test/select_test.exs +++ b/test/select_test.exs @@ -12,4 +12,12 @@ defmodule AshPostgres.SelectTest do assert [%{title: %Ash.NotLoaded{}}] = Ash.read!(Ash.Query.select(Post, :id)) end + + test "values not selected in a changeset are not present in the response" do + assert %{title: %Ash.NotLoaded{}} = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.Changeset.select([]) + |> Ash.create!() + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 31b22721..f727dfc7 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -269,6 +269,20 @@ defmodule AshPostgres.Test.Post do ) end + defmodule HasBeforeAction do + use Ash.Resource.Change + + def change(changeset, _, _) do + Ash.Changeset.before_action(changeset, fn changeset -> + Ash.Changeset.force_change_attribute(changeset, :title, "before_action") + end) + end + end + + create :create_with_before_action do + change(HasBeforeAction) + end + create :upsert_with_filter do upsert?(true) upsert_identity(:uniq_if_contains_foo) @@ -331,6 +345,10 @@ defmodule AshPostgres.Test.Post do source(:title_column) end + attribute :not_selected_by_default, :string do + select_by_default?(false) + end + attribute(:datetime, AshPostgres.TimestamptzUsec, public?: true) attribute(:score, :integer, public?: true) attribute(:public, :boolean, public?: true) diff --git a/test/test_helper.exs b/test/test_helper.exs index 6a184284..10ae3340 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,4 @@ -ExUnit.start(capture_log: true) +# ExUnit.start(capture_log: true) ExUnit.configure(stacktrace_depth: 100) AshPostgres.TestRepo.start_link() From 8779250fdea3e1cd58639734d273addba6bb1a44 Mon Sep 17 00:00:00 2001 From: Ahmed Kamal Date: Wed, 11 Sep 2024 22:57:22 +1000 Subject: [PATCH 168/690] docs: fix typo in timestamptz (#384) --- lib/types/timestamptz.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/types/timestamptz.ex b/lib/types/timestamptz.ex index 6388b2fb..dfac2d4f 100644 --- a/lib/types/timestamptz.ex +++ b/lib/types/timestamptz.ex @@ -6,7 +6,7 @@ defmodule AshPostgres.Timestamptz do The basic reason `timestamptz` exists is to guarantee that the precise moment in time is stored as microseconds since January 1st, 2000 in UTC. This guarantee eliminates many time arithmetic problems, and ensures portability. - It does not actually store a timezone, in spite of the name. As far as Elixir/Ecto is concerned, it it always of type `DateTime` and set to UTC. Using this type ensures Postgres internally uses the same contract as Ecto's `:utc_datetime`, which is to always store `DateTime` in UTC. This is especially helpful if you need to do complex time arithmetic in SQL fragments, or build reports/materialized views that use localized time formatting. + It does not actually store a timezone, in spite of the name. As far as Elixir/Ecto is concerned, it is always of type `DateTime` and set to UTC. Using this type ensures Postgres internally uses the same contract as Ecto's `:utc_datetime`, which is to always store `DateTime` in UTC. This is especially helpful if you need to do complex time arithmetic in SQL fragments, or build reports/materialized views that use localized time formatting. Using this type ubiquitously in your schemas is particularly beneficial for consistency, and this is currently [under consideration](https://github.com/ash-project/ash_postgres/issues/264) as a configuration option for the default datetime storage type. From ec3273f1638a1c41133409531e842566022eb3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20M=C3=A4nnchen?= Date: Thu, 12 Sep 2024 15:11:26 +0200 Subject: [PATCH 169/690] feat: Implement Ltree Type (#385) --- lib/resource_generator/spec.ex | 1 + lib/types/ltree.ex | 221 ++++++++ mix.exs | 1 + .../test_repo/extensions.json | 7 +- .../test_repo/posts/20240911225320.json | 479 ++++++++++++++++++ .../20240911225319_install_1_extensions.exs | 19 + .../20240911225320_migrate_resources40.exs | 23 + test/ltree_test.exs | 176 +++++++ test/support/resources/post.ex | 7 + test/support/test_repo.ex | 2 +- 10 files changed, 932 insertions(+), 4 deletions(-) create mode 100644 lib/types/ltree.ex create mode 100644 priv/resource_snapshots/test_repo/posts/20240911225320.json create mode 100644 priv/test_repo/migrations/20240911225319_install_1_extensions.exs create mode 100644 priv/test_repo/migrations/20240911225320_migrate_resources40.exs create mode 100644 test/ltree_test.exs diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 607e2ae5..ee1c3194 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -903,6 +903,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do defp type("tsvector"), do: {:ok, AshPostgres.Tsvector} defp type("uuid"), do: {:ok, :uuid} defp type("citext"), do: {:ok, :ci_string} + defp type("ltree"), do: {:ok, AshPostgres.Ltree} defp type(_), do: :error defp set_sensitive(attributes) do diff --git a/lib/types/ltree.ex b/lib/types/ltree.ex new file mode 100644 index 00000000..0d6ad79e --- /dev/null +++ b/lib/types/ltree.ex @@ -0,0 +1,221 @@ +defmodule AshPostgres.Ltree do + @constraints [ + escape?: [ + type: :boolean, + doc: """ + Escape the ltree segments to make it possible to include characters that + are either `.` (the separation character) or any other unsupported + character like `-` (Postgres <= 15). + + If the option is enabled, any characters besides `[0-9a-zA-Z]` will be + replaced with `_[HEX Ascii Code]`. + + Additionally the type will no longer take strings as user input since + it's impossible to decide between `.` being a separator or part of a + segment. + + If the option is disabled, any string will be relayed directly to + postgres. If the segments are provided as a list, they can't contain `.` + since postgres would split the segment. + """ + ], + min_length: [ + type: :non_neg_integer, + doc: "A minimum length for the tree segments." + ], + max_length: [ + type: :non_neg_integer, + doc: "A maximum length for the tree segments." + ] + ] + + @moduledoc """ + Ash Type for [postgres `ltree`](https://www.postgresql.org/docs/current/ltree.html), + a hierarchical tree-like data type. + + ## Postgres Extension + + To be able to use the `ltree` type, you'll have to enable the postgres `ltree` + extension first. + + See `m:AshPostgres.Repo#module-installed-extensions` + + ## Constraints + + #{Spark.Options.docs(@constraints)} + """ + + use Ash.Type + + @type t() :: [segment()] + @type segment() :: String.t() + + @impl Ash.Type + def storage_type(_constraints), do: :ltree + + @impl Ash.Type + def constraints, do: @constraints + + @impl Ash.Type + def matches_type?(list, _constraints) when is_list(list), do: true + + def matches_type?(binary, constraints) when is_binary(binary), + do: not Keyword.get(constraints, :escape?, false) + + def matches_type?(_ltree, _constraints), do: false + + @impl Ash.Type + def generator(constraints) do + segment = + if constraints[:escape?], + do: StreamData.string(:utf8, min_length: 1), + else: StreamData.string(:alphanumeric, min_length: 1) + + StreamData.list_of(segment, Keyword.take(constraints, [:min_length, :max_length])) + end + + @impl Ash.Type + def apply_constraints(nil, _constraints), do: {:ok, nil} + + def apply_constraints(ltree, constraints) do + segment_validation = + Enum.reduce_while(ltree, :ok, fn segment, :ok -> + cond do + segment == "" -> + {:halt, {:error, message: "Ltree segments can't be empty.", value: segment}} + + not String.valid?(segment) -> + {:halt, + {:error, message: "Ltree segments must be valid UTF-8 strings.", value: segment}} + + String.contains?(segment, ".") and !constraints[:escape?] -> + {:halt, + {:error, + message: ~S|Ltree segments can't contain "." if :escape? is not enabled.|, + value: segment}} + + true -> + {:cont, :ok} + end + end) + + with :ok <- segment_validation do + cond do + constraints[:min_length] && length(ltree) < constraints[:min_length] -> + {:error, message: "must have %{min} or more items", min: constraints[:min_length]} + + constraints[:max_length] && length(ltree) > constraints[:max_length] -> + {:error, message: "must have %{max} or less items", max: constraints[:max_length]} + + true -> + :ok + end + end + end + + @impl Ash.Type + def cast_input(nil, _constraints), do: {:ok, nil} + + def cast_input(string, constraints) when is_binary(string) do + if constraints[:escape?] do + {:error, "String input casting is not supported when the :escape? constraint is enabled"} + else + string |> String.split(".") |> cast_input(constraints) + end + end + + def cast_input(list, _constraints) when is_list(list) do + if Enum.all?(list, &is_binary/1) do + {:ok, list} + else + {:error, "Ltree segments must be strings. #{inspect(list)} provided."} + end + end + + def cast_input(_ltree, _constraints), do: :error + + @impl Ash.Type + def cast_stored(nil, _constraints), do: {:ok, nil} + + def cast_stored(ltree, constraints) when is_binary(ltree) do + segments = + ltree + |> String.split(".", trim: true) + |> then( + if constraints[:escape?] do + fn segments -> Enum.map(segments, &unescape_segment/1) end + else + & &1 + end + ) + + {:ok, segments} + end + + def cast_stored(_ltree, _constraints), do: :error + + @impl Ash.Type + def dump_to_native(nil, _constraints), do: {:ok, nil} + + def dump_to_native(ltree, constraints) when is_list(ltree) do + if constraints[:escape?] do + {:ok, Enum.map_join(ltree, ".", &escape_segment/1)} + else + {:ok, Enum.join(ltree, ".")} + end + end + + def dump_to_native(_ltree, _constraints), do: :error + + @doc """ + Get shared root of given ltrees. + + ## Examples + + iex> Ltree.shared_root(["1", "2"], ["1", "1"]) + ["1"] + + iex> Ltree.shared_root(["1", "2"], ["2", "1"]) + [] + + """ + @spec shared_root(ltree1 :: t(), ltree2 :: t()) :: t() + def shared_root(ltree1, ltree2) do + ltree1 + |> List.myers_difference(ltree2) + |> case do + [{:eq, shared} | _] -> shared + _other -> [] + end + end + + @spec escape_segment(segment :: String.t()) :: String.t() + defp escape_segment(segment) + defp escape_segment(<<>>), do: <<>> + + defp escape_segment(<>) + when letter in ?0..?9 + when letter in ?a..?z + when letter in ?A..?Z, + do: <> + + defp escape_segment(<>) do + escape_code = letter |> Integer.to_string(16) |> String.pad_leading(2, "0") + <> + end + + @spec unescape_segment(segment :: String.t()) :: String.t() + defp unescape_segment(segment) + defp unescape_segment(<<>>), do: <<>> + + defp unescape_segment(<>) + when letter in ?0..?9 + when letter in ?a..?z + when letter in ?A..?Z, + do: <> + + defp unescape_segment(<>) do + {letter, ""} = Integer.parse(<>, 16) + <> + end +end diff --git a/mix.exs b/mix.exs index 6227db81..f0ce841c 100644 --- a/mix.exs +++ b/mix.exs @@ -134,6 +134,7 @@ defmodule AshPostgres.MixProject do AshPostgres.Statement ], Types: [ + AshPostgres.Ltree, AshPostgres.Type, AshPostgres.Tsquery, AshPostgres.Tsvector, diff --git a/priv/resource_snapshots/test_repo/extensions.json b/priv/resource_snapshots/test_repo/extensions.json index 08191fb2..557d0ea8 100644 --- a/priv/resource_snapshots/test_repo/extensions.json +++ b/priv/resource_snapshots/test_repo/extensions.json @@ -1,10 +1,11 @@ { + "ash_functions_version": 4, "installed": [ "ash-functions", "uuid-ossp", "pg_trgm", "citext", - "demo-functions_v1" - ], - "ash_functions_version": 4 + "demo-functions_v1", + "ltree" + ] } \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/posts/20240911225320.json b/priv/resource_snapshots/test_repo/posts/20240911225320.json new file mode 100644 index 00000000..0eb03ca9 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240911225320.json @@ -0,0 +1,479 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "1CCE2AC7D78FB347E152BE62184DF908C651671C1BDF9EC9AACB6CFA44264451", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240911225319_install_1_extensions.exs b/priv/test_repo/migrations/20240911225319_install_1_extensions.exs new file mode 100644 index 00000000..0f2eb12b --- /dev/null +++ b/priv/test_repo/migrations/20240911225319_install_1_extensions.exs @@ -0,0 +1,19 @@ +defmodule AshPostgres.TestRepo.Migrations.Install1Extensions20240911225317 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute("CREATE EXTENSION IF NOT EXISTS \"ltree\"") + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + # execute("DROP EXTENSION IF EXISTS \"ltree\"") + end +end diff --git a/priv/test_repo/migrations/20240911225320_migrate_resources40.exs b/priv/test_repo/migrations/20240911225320_migrate_resources40.exs new file mode 100644 index 00000000..1e1cd754 --- /dev/null +++ b/priv/test_repo/migrations/20240911225320_migrate_resources40.exs @@ -0,0 +1,23 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources40 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:ltree_unescaped, :ltree) + add(:ltree_escaped, :ltree) + end + end + + def down do + alter table(:posts) do + remove(:ltree_escaped) + remove(:ltree_unescaped) + end + end +end diff --git a/test/ltree_test.exs b/test/ltree_test.exs new file mode 100644 index 00000000..cbd54ab1 --- /dev/null +++ b/test/ltree_test.exs @@ -0,0 +1,176 @@ +defmodule AshPostgres.LtreeTest do + use AshPostgres.RepoCase, async: true + use ExUnitProperties + + alias AshPostgres.Ltree + alias AshPostgres.Test.Post + + require Ash.Query + + doctest AshPostgres.Ltree + + describe inspect(&Ltree.storage_type/1) do + test "correct" do + assert :ltree = Ltree.storage_type([]) + end + end + + describe inspect(&Ltree.matches_type?/2) do + test "correct" do + assert Ltree.matches_type?(["1", "2"], []) + assert Ltree.matches_type?("1.2", []) + refute Ltree.matches_type?("1.2", escape?: true) + end + end + + describe inspect(&Ltee.generator/1) do + property "generates valid ltrees" do + check all( + constraints <- constraints_generator(), + ltree <- Ltree.generator(constraints) + ) do + assert :ok = Ltree.apply_constraints(ltree, constraints) + end + end + end + + describe inspect(&Ltree.apply_constraints/2) do + test "checks min length" do + assert :ok = Ltree.apply_constraints(["1", "2"], min_length: 2) + + assert {:error, [message: "must have %{min} or more items", min: 2]} = + Ltree.apply_constraints(["1"], min_length: 2) + end + + test "checks max length" do + assert :ok = Ltree.apply_constraints(["1", "2"], max_length: 2) + + assert {:error, [message: "must have %{max} or less items", max: 1]} = + Ltree.apply_constraints(["1", "2"], max_length: 1) + end + + test "checks UTF-8" do + assert :ok = Ltree.apply_constraints(["1", "2"], []) + + assert {:error, + [message: "Ltree segments must be valid UTF-8 strings.", value: <<0xFFFF::16>>]} = + Ltree.apply_constraints([<<0xFFFF::16>>, "2"], []) + end + + test "checks empty string" do + assert {:error, [message: "Ltree segments can't be empty.", value: ""]} = + Ltree.apply_constraints(["", "2"], []) + end + + test ~S|can't contain "." when escape? is not enabled| do + assert :ok = Ltree.apply_constraints(["1", "2"], []) + + assert {:error, + [ + message: ~S|Ltree segments can't contain "." if :escape? is not enabled.|, + value: "1.2" + ]} = Ltree.apply_constraints(["1.2"], []) + + assert :ok = Ltree.apply_constraints(["1.2"], escape?: true) + end + end + + describe inspect(&Ltree.cast_input/2) do + test "casts nil" do + assert {:ok, nil} = Ltree.cast_input(nil, []) + end + + test "casts list" do + assert {:ok, ["1", "2"]} = Ltree.cast_input(["1", "2"], []) + end + + test "casts binary if escaped?" do + assert {:ok, ["1", "2"]} = Ltree.cast_input("1.2", []) + + assert {:error, + "String input casting is not supported when the :escape? constraint is enabled"} = + Ltree.cast_input("1.2", escape?: true) + end + end + + describe inspect(&Ltree.cast_stored/2) do + test "casts nil" do + assert {:ok, nil} = Ltree.cast_stored(nil, []) + end + + test "casts binary" do + assert {:ok, ["1", "2"]} = Ltree.cast_stored("1.2", []) + end + + test "unescapes segments" do + assert {:ok, ["1.", "2"]} = Ltree.cast_stored("1_2E.2", escape?: true) + end + end + + describe inspect(&Ltree.dump_to_native/2) do + test "dumps nil" do + assert {:ok, nil} = Ltree.dump_to_native(nil, []) + end + + test "dumps list" do + assert {:ok, "1.2"} = Ltree.dump_to_native(["1", "2"], []) + end + + test "escapes segments" do + assert {:ok, "1_2E.2"} = Ltree.dump_to_native(["1.", "2"], escape?: true) + end + end + + describe inspect(&Ltree.shared_root/2) do + test "works when they share a root" do + assert ["1"] = Ltree.shared_root(["1", "1"], ["1", "2"]) + end + + test "returns empty list if they do not share a root" do + assert [] = Ltree.shared_root(["1", "2"], ["2", "1"]) + end + end + + describe "escape/unescape" do + property "escape |> unescape results in same value" do + check all(ltree <- Ltree.generator(escape?: true)) do + assert {:ok, stored} = Ltree.dump_to_native(ltree, escape?: true) + assert {:ok, loaded} = Ltree.cast_stored(stored, escape?: true) + + assert loaded == ltree + end + end + end + + describe "integration" do + test "can serialize / underialize to db" do + post = + Post + |> Ash.Changeset.for_create(:create, %{ + title: "title", + ltree_unescaped: ["1", "2"], + ltree_escaped: ["1.", "2"] + }) + |> Ash.create!() + + assert %Post{id: id, ltree_unescaped: ["1", "2"], ltree_escaped: ["1.", "2"]} = post + + assert %Post{id: ^id} = + Post |> Ash.Query.filter(ltree_unescaped == ["1", "2"]) |> Ash.read_one!() + + assert %Post{id: ^id} = + Post |> Ash.Query.filter(ltree_escaped == ["1.", "2"]) |> Ash.read_one!() + end + end + + defp constraints_generator do + [ + StreamData.tuple({StreamData.constant(:escape?), StreamData.boolean()}), + StreamData.tuple({StreamData.constant(:min_length), StreamData.non_negative_integer()}), + StreamData.tuple({StreamData.constant(:max_length), StreamData.positive_integer()}) + ] + |> StreamData.one_of() + |> StreamData.list_of(max_length: 3) + |> StreamData.filter(&(not (&1[:min_length] > &1[:max_length]))) + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index f727dfc7..cbef1c10 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -387,6 +387,13 @@ defmodule AshPostgres.Test.Post do constraints(nil_items?: true) end + attribute(:ltree_unescaped, AshPostgres.Ltree, + constraints: [min_length: 1, max_length: 10], + public?: true + ) + + attribute(:ltree_escaped, AshPostgres.Ltree, constraints: [escape?: true], public?: true) + create_timestamp(:created_at, writable?: true, public?: true) update_timestamp(:updated_at, diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index 4f01c091..c272a2e5 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -8,7 +8,7 @@ defmodule AshPostgres.TestRepo do end def installed_extensions do - ["ash-functions", "uuid-ossp", "pg_trgm", "citext", AshPostgres.TestCustomExtension] -- + ["ash-functions", "uuid-ossp", "pg_trgm", "citext", AshPostgres.TestCustomExtension, "ltree"] -- Application.get_env(:ash_postgres, :no_extensions, []) end From e2b648a9e47bb41b4e6d1bb970b0928ede5cc043 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 13 Sep 2024 09:37:12 -0400 Subject: [PATCH 170/690] improvement: remove LEAKPROOF from function to prevent migration issues chore: add some tests to show calculation w/ fragment --- lib/migration_generator/ash_functions.ex | 2 +- test/calculation_test.exs | 4 ++++ test/support/resources/post.ex | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index 609bb487..369173cb 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -230,7 +230,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); $$ LANGUAGE SQL - IMMUTABLE PARALLEL SAFE STRICT LEAKPROOF; + IMMUTABLE PARALLEL SAFE STRICT; \"\"\") """ end diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 38cc70f8..0301868d 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -312,6 +312,10 @@ defmodule AshPostgres.CalculationTest do refute Ash.calculate!(Post, :author_has_post_with_follower_named_fred, refs: %{id: post.id}) end + test "calculation works with simple fragments" do + Post.upper_title!("example") + end + test "calculations that refer to aggregates can be authorized" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index cbef1c10..615d1c31 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -409,6 +409,8 @@ defmodule AshPostgres.Test.Post do define(:increment_score, args: [{:optional, :amount}]) define(:destroy) define(:update_constrained_int, args: [:amount]) + + define_calculation(:upper_title, args: [:title]) end relationships do @@ -542,6 +544,8 @@ defmodule AshPostgres.Test.Post do calculations do calculate(:upper_thing, :string, expr(fragment("UPPER(?)", uniq_on_upper))) + calculate(:upper_title, :string, expr(fragment("UPPER(?)", title))) + calculate( :author_has_post_with_follower_named_fred, :boolean, From 045796f91688e87aa21cbc666e58629686666596 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 13 Sep 2024 15:01:21 -0400 Subject: [PATCH 171/690] improvement: update ash to latest version chore: add some tests, use new `Igniter.Test` --- mix.exs | 2 +- mix.lock | 4 +- test/bulk_destroy_test.exs | 2 +- test/resource_generator_test.exs | 67 +++++++++++++++----------------- 4 files changed, 35 insertions(+), 40 deletions(-) diff --git a/mix.exs b/mix.exs index f0ce841c..7f4c9a85 100644 --- a/mix.exs +++ b/mix.exs @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.2")}, + {:ash, ash_version("~> 3.4 and >= 3.4.9")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, {:igniter, "~> 0.3 and >= 0.3.6"}, {:ecto_sql, "~> 3.12"}, diff --git a/mix.lock b/mix.lock index ee8fc935..6ac7b8d0 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.8", "8c35c1e401044d05474c0e1a3209c74afb7ac955243085489242cade24d31906", [: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.3.11 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "e8dd3eb1f3aa45a75265c784df95ce261a3fad7f0d07400d316e981e14ed10f0"}, + "ash": {:hex, :ash, "3.4.9", "17ad3a8a37d17f1d5db93f26a53fa979fa19046b741140afef526cf22b306f56", [: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.3.35 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "e3c24fd0a249356abc5da8deb4265e40906f75f0aadec779767fb828712d446d"}, "ash_sql": {:hex, :ash_sql, "0.2.32", "de99255becfb9daa7991c18c870e9f276bb372acda7eda3e05c3e2ff2ca8922e", [:mix], [{:ash, ">= 3.1.7 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", "43773bcd33d21319c11804d76fe11f1a1b7c8faba7aaedeab6f55fde3d2405db"}, "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"}, @@ -38,7 +38,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.26", "1701f388a9cfb2e27cd037b6f4b72a999e49bdb2d2f946bdbde8a991ce42c499", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "7a57860e4d15ab2e395dffeac617f3ee64d371b47f7b3d718a8d535d75cc7556"}, + "spark": {:hex, :spark, "2.2.27", "213447d22c5ccdfa9d77bc4c58ba2f5ace99dadd9b974e52a374fa58320ab9e4", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "59ca9129fe707dcfec768591d1d2582c6cc8062fb6329df4837cba8a88392b0b"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/bulk_destroy_test.exs b/test/bulk_destroy_test.exs index e30b62de..ddc9b65a 100644 --- a/test/bulk_destroy_test.exs +++ b/test/bulk_destroy_test.exs @@ -13,7 +13,7 @@ defmodule AshPostgres.BulkDestroyTest do test "bulk destroys destroy everything pertaining to the query" do Ash.bulk_create!([%{title: "fred"}, %{title: "george"}], Post, :create) - Ash.bulk_destroy!(Post, :destroy, %{}) + Ash.bulk_destroy!(Post, :destroy, %{}, return_records?: true) assert Ash.read!(Post) == [] end diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index 0a9b755a..e2b655ed 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -1,6 +1,8 @@ defmodule AshPostgres.ResourceGeenratorTests do use AshPostgres.RepoCase, async: false + import Igniter.Test + setup do AshPostgres.TestRepo.query!("DROP TABLE IF EXISTS example_table") @@ -15,41 +17,34 @@ defmodule AshPostgres.ResourceGeenratorTests do end test "a resource is generated from a table" do - resource = - Igniter.new() - |> Igniter.compose_task("ash_postgres.gen.resources", [ - "MyApp.Accounts", - "--tables", - "example_table", - "--yes" - ]) - |> Igniter.prepare_for_write() - |> Map.get(:rewrite) - |> Rewrite.source!("lib/my_app/accounts/example_table.ex") - |> Rewrite.Source.get(:content) - - assert String.trim(resource) == - String.trim(""" - defmodule MyApp.Accounts.ExampleTable do - use Ash.Resource, - domain: MyApp.Accounts, - data_layer: AshPostgres.DataLayer - - postgres do - table "example_table" - repo AshPostgres.TestRepo - end - - attributes do - uuid_primary_key(:id) - attribute(:name, :string) - attribute(:age, :integer) - - attribute :email, :string do - sensitive?(true) - end - end - end - """) + test_project() + |> Igniter.compose_task("ash_postgres.gen.resources", [ + "MyApp.Accounts", + "--tables", + "example_table", + "--yes" + ]) + |> assert_creates("lib/my_app/accounts/example_table.ex", """ + defmodule MyApp.Accounts.ExampleTable do + use Ash.Resource, + domain: MyApp.Accounts, + data_layer: AshPostgres.DataLayer + + postgres do + table("example_table") + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string) + attribute(:age, :integer) + + attribute :email, :string do + sensitive?(true) + end + end + end + """) end end From 43f6880308cb93f5bf222fa85f6da2bbfa1d979a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 13 Sep 2024 15:11:25 -0400 Subject: [PATCH 172/690] chore: fix build --- lib/resource_generator/spec.ex | 2 ++ mix.lock | 2 -- test/support/resources/post.ex | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index ee1c3194..9c67d3fc 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -453,6 +453,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do |> set_defaults_and_generated() end + # sobelow_skip ["DOS.StringToAtom"] defp set_defaults_and_generated(attributes) do Enum.map(attributes, fn attribute -> attribute = @@ -823,6 +824,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do end) end + # sobelow_skip ["RCE.CodeModule", "DOS.StringToAtom"] defp get_type(attribute, opts) do result = if opts[:yes?] do diff --git a/mix.lock b/mix.lock index 6ac7b8d0..f94861bc 100644 --- a/mix.lock +++ b/mix.lock @@ -29,7 +29,6 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, - "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.11.0", "2cd46185d330aa2400f1c8c3cddf8d2ff6320baeff23321d1810e58127082cae", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "73f5783f0e963cc04a061be717a0dbb3e49ae0c4bfd55fb4b78ece8d33a65efe"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, @@ -44,7 +43,6 @@ "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, - "ucwidth": {:hex, :ucwidth, "0.2.0", "1f0a440f541d895dff142275b96355f7e91e15bca525d4a0cc788ea51f0e3441", [:mix], [], "hexpm", "c1efd1798b8eeb11fb2bec3cafa3dd9c0c3647bee020543f0340b996177355bf"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, } diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 615d1c31..7f1385a9 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -270,6 +270,7 @@ defmodule AshPostgres.Test.Post do end defmodule HasBeforeAction do + @moduledoc false use Ash.Resource.Change def change(changeset, _, _) do From ad636fcbfdb948b5753025a0f71e9c425b9bec31 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 13 Sep 2024 15:11:36 -0400 Subject: [PATCH 173/690] chore: release version v2.4.0 --- CHANGELOG.md | 21 +++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f8f5e4c..25520753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,27 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.0](https://github.com/ash-project/ash_postgres/compare/v2.3.1...v2.4.0) (2024-09-13) + + + + +### Features: + +* Implement Ltree Type (#385) + +### Improvements: + +* update ash to latest version + +* remove LEAKPROOF from function to prevent migration issues + +* support upcoming `action_select` options + +* ensure `Repo` is started after telemetry + +* update to latest igniter functions + ## [v2.3.1](https://github.com/ash-project/ash_postgres/compare/v2.3.0...v2.3.1) (2024-09-05) ### Improvements: diff --git a/mix.exs b/mix.exs index 7f4c9a85..9fdb63a0 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.3.1" + @version "2.4.0" def project do [ From d7a8083ff95081ba074eaf8b128e5d3a05148646 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 13 Sep 2024 15:12:00 -0400 Subject: [PATCH 174/690] chore: update changelog --- CHANGELOG.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25520753..4587e3ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,24 +7,21 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline ## [v2.4.0](https://github.com/ash-project/ash_postgres/compare/v2.3.1...v2.4.0) (2024-09-13) - - - ### Features: -* Implement Ltree Type (#385) +- Implement Ltree Type (#385) ### Improvements: -* update ash to latest version +- update ash to latest version -* remove LEAKPROOF from function to prevent migration issues +- remove LEAKPROOF from function to prevent migration issues -* support upcoming `action_select` options +- support upcoming `action_select` options -* ensure `Repo` is started after telemetry +- ensure `Repo` is started after telemetry in igniter installer -* update to latest igniter functions +- update to latest igniter functions ## [v2.3.1](https://github.com/ash-project/ash_postgres/compare/v2.3.0...v2.3.1) (2024-09-05) From eb3329b4f300203aff2bc7302f72f85a947de489 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 13 Sep 2024 15:51:59 -0400 Subject: [PATCH 175/690] fix: match on table schema as well as table name --- lib/resource_generator/spec.ex | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 9c67d3fc..fffaf97e 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -972,7 +972,14 @@ defmodule AshPostgres.ResourceGenerator.Spec do information_schema.columns c ON t.table_name = c.table_name JOIN pg_attribute a - ON a.attrelid = (SELECT oid FROM pg_class WHERE relname = t.table_name AND relkind = 'r') + ON a.attrelid = ( + SELECT c.oid + FROM pg_class c + JOIN pg_namespace n ON c.relnamespace = n.oid + WHERE c.relname = t.table_name + AND n.nspname = t.table_schema + AND c.relkind = 'r' + ) AND a.attname = c.column_name AND a.attnum > 0 WHERE @@ -1009,7 +1016,14 @@ defmodule AshPostgres.ResourceGenerator.Spec do information_schema.columns c ON t.table_name = c.table_name JOIN pg_attribute a - ON a.attrelid = (SELECT oid FROM pg_class WHERE relname = t.table_name AND relkind = 'r') + ON a.attrelid = ( + SELECT c.oid + FROM pg_class c + JOIN pg_namespace n ON c.relnamespace = n.oid + WHERE c.relname = t.table_name + AND n.nspname = t.table_schema + AND c.relkind = 'r' + ) AND a.attname = c.column_name AND a.attnum > 0 WHERE From 3c0872ab94c9b3290df438bb769cbcd3f55e6d22 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 13 Sep 2024 19:10:54 -0400 Subject: [PATCH 176/690] chore: update igniter and fix deprecation warning --- lib/mix/tasks/ash_postgres.install.ex | 2 +- mix.exs | 2 +- mix.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index d8b93fc8..5126c6d4 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -252,7 +252,7 @@ defmodule Mix.Tasks.AshPostgres.Install do default_data_case_contents, # do nothing if already exists fn zipper -> {:ok, zipper} end, - path: Igniter.Code.Module.proper_location(module_name, "test/support") + path: Igniter.Project.Module.proper_location(igniter, module_name, "test/support") ) end diff --git a/mix.exs b/mix.exs index 9fdb63a0..5da440dc 100644 --- a/mix.exs +++ b/mix.exs @@ -166,7 +166,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.4 and >= 3.4.9")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, - {:igniter, "~> 0.3 and >= 0.3.6"}, + {:igniter, "~> 0.3 and >= 0.3.36"}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index f94861bc..32e44fbd 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.35", "edd8db6234db7639eb2f954b45ab23db98b1fd0a940850f58db8900912a908bf", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "d2826d94d8c851e2bc8b920766815b3df4b184cab05eae8423e965363a2e02b1"}, + "igniter": {:hex, :igniter, "0.3.36", "7dffb41e8c25dac3de8a0947c4973dc3db3cd25f394fd87ac334fe18a725f291", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "5a493222cbf4e3cf0106cd090c93a1f61fa4df958b7d00e03a836e8a67a4bab2"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 3afbae2c806ac94529ba49c123ed7ef384bb0e9b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 15 Sep 2024 20:56:51 -0400 Subject: [PATCH 177/690] fix: ensure that returning is not an empty list --- lib/data_layer.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index ef61be85..79052e73 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1736,6 +1736,7 @@ defmodule AshPostgres.DataLayer do returning = case options[:action_select] do nil -> true + [] -> Ash.Resource.Info.primary_key(resource) fields -> fields end From 448237d8d1f283d9d63d9253deefcecbf672c7f9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Sep 2024 08:39:56 -0400 Subject: [PATCH 178/690] test: add test for data seeding --- mix.lock | 6 +++--- test/create_test.exs | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 32e44fbd..8695e923 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.36", "7dffb41e8c25dac3de8a0947c4973dc3db3cd25f394fd87ac334fe18a725f291", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "5a493222cbf4e3cf0106cd090c93a1f61fa4df958b7d00e03a836e8a67a4bab2"}, + "igniter": {:hex, :igniter, "0.3.37", "ad4ec1c0d73dedf5514ac52c5e93d5daa64bf4037a17088a9a7f4d44133a5846", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "727b74a67df63cbe4c21a99707e02c50f4b7740c93cd3431fa9184a863eb064c"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -32,12 +32,12 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.11.0", "2cd46185d330aa2400f1c8c3cddf8d2ff6320baeff23321d1810e58127082cae", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "73f5783f0e963cc04a061be717a0dbb3e49ae0c4bfd55fb4b78ece8d33a65efe"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, - "reactor": {:hex, :reactor, "0.9.1", "082f8e9b1fd7586c0a016c2fb533835fec7eaef5ffb0263abb4473106c20b1ca", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7191ddf95fdd2b65770a57a2e38dd502a94909e51ac8daf497330e67fc032dc3"}, + "reactor": {:hex, :reactor, "0.10.0", "1206113c21ba69b889e072b2c189c05a7aced523b9c3cb8dbe2dab7062cb699a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4003c33e4c8b10b38897badea395e404d74d59a31beb30469a220f2b1ffe6457"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.27", "213447d22c5ccdfa9d77bc4c58ba2f5ace99dadd9b974e52a374fa58320ab9e4", [:mix], [{:igniter, ">= 0.2.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "59ca9129fe707dcfec768591d1d2582c6cc8062fb6329df4837cba8a88392b0b"}, + "spark": {:hex, :spark, "2.2.29", "a52733ff72b05a674e48d3ca7a4172fe7bec81e9116069da8b4db19030d581d9", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "111a0dadbb27537c7629bc03ac56fcab15056ab0b9ad985084b9adcdb48836c8"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/create_test.exs b/test/create_test.exs index 0f461dfc..23fe3533 100644 --- a/test/create_test.exs +++ b/test/create_test.exs @@ -2,6 +2,10 @@ defmodule AshPostgres.CreateTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post + test "seeding data works" do + Ash.Seed.seed!(%Post{title: "fred"}) + end + test "creates insert" do assert {:ok, %Post{}} = Post From d472f622f910ec6b14b1e03cbb2c7775e207d0cb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Sep 2024 08:55:32 -0400 Subject: [PATCH 179/690] chore: fix ash_postgres igniter --- lib/mix/tasks/ash_postgres.install.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 5126c6d4..e0af615b 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -252,7 +252,7 @@ defmodule Mix.Tasks.AshPostgres.Install do default_data_case_contents, # do nothing if already exists fn zipper -> {:ok, zipper} end, - path: Igniter.Project.Module.proper_location(igniter, module_name, "test/support") + path: Igniter.Project.Module.proper_location(igniter, module_name, :test_support) ) end From 2101ab3cd9a60314791e67e4ff260e03600ec559 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Sep 2024 10:20:27 -0400 Subject: [PATCH 180/690] chore: add basic tests for install task --- test/mix/tasks/ash_postgres.install_test.exs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test/mix/tasks/ash_postgres.install_test.exs diff --git a/test/mix/tasks/ash_postgres.install_test.exs b/test/mix/tasks/ash_postgres.install_test.exs new file mode 100644 index 00000000..eb687a0d --- /dev/null +++ b/test/mix/tasks/ash_postgres.install_test.exs @@ -0,0 +1,13 @@ +defmodule Mix.Tasks.AshPostgres.InstallTest do + use ExUnit.Case + + import Igniter.Test + + # This is a simple test to ensure that the installation doesnt have + # any errors. We should add better tests here, though. + test "installation does not fail" do + test_project() + |> Igniter.compose_task("ash_postgres.install") + |> assert_creates("lib/test/repo.ex") + end +end From 873a1f8983a16de89ebb6a669b141e3f1cbe52c1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Sep 2024 10:21:50 -0400 Subject: [PATCH 181/690] chore: release version v2.4.1 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4587e3ea..da0eeb29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.1](https://github.com/ash-project/ash_postgres/compare/v2.4.0...v2.4.1) (2024-09-16) + + + + +### Bug Fixes: + +* ensure that returning is not an empty list + +* match on table schema as well as table name + ## [v2.4.0](https://github.com/ash-project/ash_postgres/compare/v2.3.1...v2.4.0) (2024-09-13) ### Features: diff --git a/mix.exs b/mix.exs index 5da440dc..5ea543be 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.0" + @version "2.4.1" def project do [ From ee0c2a0f452b8cf8b5f379ad993f7ed7546ab064 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Sep 2024 17:04:15 -0400 Subject: [PATCH 182/690] test: add test for behavior fixed in ash --- test/calculation_test.exs | 39 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 1 + 2 files changed, 40 insertions(+) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 0301868d..8c0f2678 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -5,6 +5,45 @@ defmodule AshPostgres.CalculationTest do require Ash.Query import Ash.Expr + test "a calculation that references a first optimizable aggregate can be sorted on" do + author1 = + Author + |> Ash.Changeset.for_create(:create, %{ + first_name: "abc" + }) + |> Ash.create!() + + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "match", author_id: author1.id}) + |> Ash.create!() + + author2 = + Author + |> Ash.Changeset.for_create(:create, %{ + first_name: "def" + }) + |> Ash.create!() + + post2 = + Post + |> Ash.Changeset.for_create(:create, %{title: "match", author_id: author2.id}) + |> Ash.create!() + + post1_id = post.id + post2_id = post2.id + + assert [%{id: ^post2_id}, %{id: ^post1_id}] = + Post + |> Ash.Query.sort(author_first_name_ref_agg_calc: :desc) + |> Ash.read!() + + assert [%{id: ^post1_id}, %{id: ^post2_id}] = + Post + |> Ash.Query.sort(author_first_name_ref_agg_calc: :asc) + |> Ash.read!() + end + test "an expression calculation can be filtered on" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 7f1385a9..d6b8e745 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -692,6 +692,7 @@ defmodule AshPostgres.Test.Post do ) calculate(:author_first_name_calc, :string, expr(author.first_name)) + calculate(:author_first_name_ref_agg_calc, :string, expr(author_first_name)) calculate(:author_profile_description_from_agg, :string, expr(author_profile_description)) end From bc26951c41fa1c2484742de912ac97b46182f084 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 18 Sep 2024 06:52:21 -0400 Subject: [PATCH 183/690] test: add test for optimistic lock --- .../test_repo/posts/20240918104740.json | 489 ++++++++++++++++++ .../20240918104740_migrate_resources41.exs | 21 + test/support/resources/post.ex | 7 + test/update_test.exs | 28 + 4 files changed, 545 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/posts/20240918104740.json create mode 100644 priv/test_repo/migrations/20240918104740_migrate_resources41.exs diff --git a/priv/resource_snapshots/test_repo/posts/20240918104740.json b/priv/resource_snapshots/test_repo/posts/20240918104740.json new file mode 100644 index 00000000..9b2de037 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240918104740.json @@ -0,0 +1,489 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "AB47CA6F1EB3D500856075592A4D436CC4F323885E1D49E35089C07877F069DF", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240918104740_migrate_resources41.exs b/priv/test_repo/migrations/20240918104740_migrate_resources41.exs new file mode 100644 index 00000000..118fe8fc --- /dev/null +++ b/priv/test_repo/migrations/20240918104740_migrate_resources41.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources41 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:version, :bigint, null: false, default: 1) + end + end + + def down do + alter table(:posts) do + remove(:version) + end + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index d6b8e745..aadcee06 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -327,6 +327,11 @@ defmodule AshPostgres.Test.Post do message: "You cannot select less than two." ) end + + update :optimistic_lock do + accept([:title]) + change(optimistic_lock(:version)) + end end identities do @@ -341,6 +346,8 @@ defmodule AshPostgres.Test.Post do attributes do uuid_primary_key(:id, writable?: true) + attribute(:version, :integer, allow_nil?: false, default: 1) + attribute(:title, :string) do public?(true) source(:title_column) diff --git a/test/update_test.exs b/test/update_test.exs index 59897db3..9afb32ab 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -34,4 +34,32 @@ defmodule AshPostgres.UpdateTest do } ) end + + test "can optimist lock" do + Logger.configure(level: :debug) + + Post + |> Ash.Changeset.for_create(:create, %{title: "fred"}) + |> Ash.create!() + |> then(fn record -> + Ash.Query.filter(Post, id == ^record.id) + end) + |> Ash.bulk_update( + :optimistic_lock, + %{ + title: "george" + } + ) + + Post + |> Ash.Changeset.for_create(:create, %{title: "fred"}) + |> Ash.create!() + |> Ash.Changeset.for_update( + :optimistic_lock, + %{ + title: "george" + } + ) + |> Ash.update!() + end end From 6eda5fae9c13ae553215e9442e1cfa69184e3b03 Mon Sep 17 00:00:00 2001 From: James Harton Date: Thu, 19 Sep 2024 11:56:28 +1200 Subject: [PATCH 184/690] fix: trim input before passing to `String.to_integer/1`. (#389) --- lib/migration_generator/migration_generator.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 7b9de7a2..f75670cb 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -727,6 +727,7 @@ defmodule AshPostgres.MigrationGenerator do opts |> prompt(message) + |> String.trim() |> String.to_integer() end From ebd7a71d51a119b9794fbaa08db2368ff15f977f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:33:46 -0400 Subject: [PATCH 185/690] chore(deps): bump the production-dependencies group with 2 updates (#390) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.4.9 to 3.4.17 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.9...v3.4.17) Updates `igniter` from 0.3.37 to 0.3.39 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.3.37...v0.3.39) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 8695e923..2596b036 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.9", "17ad3a8a37d17f1d5db93f26a53fa979fa19046b741140afef526cf22b306f56", [: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.3.35 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.22 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [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", "e3c24fd0a249356abc5da8deb4265e40906f75f0aadec779767fb828712d446d"}, + "ash": {:hex, :ash, "3.4.17", "2f2b817a9ea88ae68c4845b27a9ac0fc60f507cf4cc7ad3a3b614b1bdd619783", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "54eba5f478b7d1f4570479cdf747fa65e993acebb8d6bf2a7e8a48b4e0519ae2"}, "ash_sql": {:hex, :ash_sql, "0.2.32", "de99255becfb9daa7991c18c870e9f276bb372acda7eda3e05c3e2ff2ca8922e", [:mix], [{:ash, ">= 3.1.7 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", "43773bcd33d21319c11804d76fe11f1a1b7c8faba7aaedeab6f55fde3d2405db"}, "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"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.37", "ad4ec1c0d73dedf5514ac52c5e93d5daa64bf4037a17088a9a7f4d44133a5846", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "727b74a67df63cbe4c21a99707e02c50f4b7740c93cd3431fa9184a863eb064c"}, + "igniter": {:hex, :igniter, "0.3.39", "e59b56836b9b22c6b76b1b9661c60a996eca7bbb3b0a22f7a888cd1c77d43419", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "0e794a273b53442a6fb223a65cd9800648d6e2f8fdf8556bcf74d0af793f4bd4"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 103158829fb8af9f7e08a954118de3ad13718824 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 19 Sep 2024 13:50:43 -0400 Subject: [PATCH 186/690] improvement: set a name for generated migrations --- lib/mix/tasks/ash_postgres.gen.resources.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 5e270f8e..097a45fe 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -135,7 +135,9 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do if options[:no_migrations] do igniter else - Igniter.add_task(igniter, "ash_postgres.generate_migrations", migration_opts) + Igniter.add_task(igniter, "ash_postgres.generate_migrations", [ + "import_resources" | migration_opts + ]) end end) end From 6219e8ba71096072ee10c76396ac3dfd8c9c539c Mon Sep 17 00:00:00 2001 From: James Harton Date: Mon, 23 Sep 2024 09:47:20 +1200 Subject: [PATCH 187/690] fix(installer): use correct module name in the `DataCase` moduledocs. (#393) --- lib/mix/tasks/ash_postgres.install.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index e0af615b..c5c71fe3 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -208,6 +208,8 @@ defmodule Mix.Tasks.AshPostgres.Install do end defp setup_data_case(igniter) do + module_name = Igniter.Code.Module.module_name(igniter, "DataCase") + default_data_case_contents = ~s| @moduledoc """ This module defines the setup for tests requiring @@ -220,7 +222,7 @@ defmodule Mix.Tasks.AshPostgres.Install do we enable the SQL sandbox, so changes done to the database are reverted at the end of every test. If you are using PostgreSQL, you can even run database tests asynchronously - by setting `use AshHq.DataCase, async: true`, although + by setting `use #{inspect(module_name)}, async: true`, although this option is not recommended for other databases. """ @@ -244,8 +246,6 @@ defmodule Mix.Tasks.AshPostgres.Install do end | - module_name = Igniter.Code.Module.module_name(igniter, "DataCase") - igniter |> Igniter.Code.Module.find_and_update_or_create_module( module_name, From 0351f52211ca0969fdc4713b94b81864d3017f7d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 23 Sep 2024 14:27:52 -0400 Subject: [PATCH 188/690] improvement: prompt for minimum pg version improvement: adjust mix task aliases to be used with `ash_postgres` closes #391 --- lib/igniter.ex | 60 +++++++++- lib/mix/helpers.ex | 8 +- .../tasks/ash_postgres.generate_migrations.ex | 2 +- lib/mix/tasks/ash_postgres.install.ex | 110 ++++++++++++++---- mix.exs | 2 +- mix.lock | 2 +- test/mix/tasks/ash_postgres.install_test.exs | 2 +- 7 files changed, 152 insertions(+), 34 deletions(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index 8ac3f29e..5d0a0053 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -2,13 +2,14 @@ defmodule AshPostgres.Igniter do @moduledoc "Codemods and utilities for working with AshPostgres & Igniter" @doc false - def default_repo_contents(otp_app) do + def default_repo_contents(otp_app, name, opts \\ []) do + min_pg_version = get_min_pg_version(name, opts) + """ use AshPostgres.Repo, otp_app: #{inspect(otp_app)} def min_pg_version do - # Adjust this according to your postgres version - %Version{major: 16, minor: 0, patch: 0} + %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor || 0}, patch: #{min_pg_version.patch || 0}} end def installed_extensions do @@ -80,7 +81,12 @@ defmodule AshPostgres.Igniter do otp_app = Igniter.Project.Application.app_name(igniter) igniter = - Igniter.Code.Module.create_module(igniter, repo, default_repo_contents(otp_app)) + Igniter.Code.Module.create_module( + igniter, + repo, + default_repo_contents(otp_app, repo), + opts + ) {igniter, repo} else @@ -110,4 +116,50 @@ defmodule AshPostgres.Igniter do ) end) end + + @doc false + def get_min_pg_version(name, opts) do + if opts[:yes] do + %Version{major: 16, minor: 0, patch: 0} + else + lead_in = """ + Generating #{inspect(name)} + + What is the minimum postgres version you will be using? + + AshPostgres uses this information when generating queries and migrations + to choose the best available features for your version of postgres. + """ + + format_request = + """ + Please enter the version in the format major.minor.patch (e.g. 13.4.0) + + Default: 16.0.0 + + ❯ + """ + + prompt = + if opts[:invalid_loop?] do + format_request + else + "#{lead_in}\n\n#{format_request}" + end + + prompt + |> String.trim_trailing() + |> Mix.shell().prompt() + |> String.trim() + |> case do + "" -> "16.0.0" + input -> input + end + |> Version.parse() + |> case do + {:ok, version} -> version + :error -> get_min_pg_version(name, Keyword.put(opts, :invalid_loop?, true)) + end + end + end end diff --git a/lib/mix/helpers.ex b/lib/mix/helpers.ex index 9168165b..6858ec47 100644 --- a/lib/mix/helpers.ex +++ b/lib/mix/helpers.ex @@ -1,6 +1,6 @@ defmodule AshPostgres.Mix.Helpers do @moduledoc false - def domains!(opts, args, error_on_no_domains? \\ true) do + def domains!(opts, args) do apps = if apps_paths = Mix.Project.apps_paths() do apps_paths |> Map.keys() |> Enum.sort() @@ -30,11 +30,7 @@ defmodule AshPostgres.Mix.Helpers do |> Enum.map(&ensure_compiled(&1, args)) |> case do [] -> - if error_on_no_domains? do - raise "must supply the --domains argument, or set `config :my_app, ash_domains: [...]` in config" - else - [] - end + [] domains -> domains diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index 68f92b55..eedaf280 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -100,7 +100,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do ] ) - domains = AshPostgres.Mix.Helpers.domains!(opts, args, false) + domains = AshPostgres.Mix.Helpers.domains!(opts, args) if Enum.empty?(domains) && !opts[:snapshots_only] do IO.warn(""" diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index c5c71fe3..a33986c2 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -5,13 +5,29 @@ defmodule Mix.Tasks.AshPostgres.Install do require Igniter.Code.Function use Igniter.Mix.Task - def igniter(igniter, _argv) do + @impl true + def info(_argv, _source) do + %Igniter.Mix.Task.Info{ + schema: [ + yes: :boolean + ], + aliases: [ + y: :yes + ] + } + end + + @impl true + def igniter(igniter, argv) do repo = Igniter.Code.Module.module_name(igniter, "Repo") otp_app = Igniter.Project.Application.app_name(igniter) + opts = options!(argv) + igniter |> Igniter.Project.Formatter.import_dep(:ash_postgres) - |> setup_repo_module(otp_app, repo) + |> setup_aliases() + |> setup_repo_module(otp_app, repo, opts) |> configure_config(otp_app, repo) |> configure_dev(otp_app, repo) |> configure_runtime(otp_app, repo) @@ -29,6 +45,47 @@ defmodule Mix.Tasks.AshPostgres.Install do |> Ash.Igniter.codegen("initialize") end + defp setup_aliases(igniter) do + is_ecto_setup = &Igniter.Code.Common.nodes_equal?(&1, "ecto.setup") + + is_ecto_create_or_migrate = + fn zipper -> + Igniter.Code.Common.nodes_equal?(zipper, "ecto.create --quiet") or + Igniter.Code.Common.nodes_equal?(zipper, "ecto.create") or + Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate --quiet") or + Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate") + end + + igniter + |> Igniter.Project.TaskAliases.modify_existing_alias( + "test", + &Igniter.Code.List.remove_from_list(&1, is_ecto_create_or_migrate) + ) + |> Igniter.Project.TaskAliases.modify_existing_alias( + "test", + &Igniter.Code.List.replace_in_list( + &1, + is_ecto_setup, + "ash.setup" + ) + ) + |> Igniter.Project.TaskAliases.add_alias("test", ["ash.setup --quiet", "test"], + if_exists: {:prepend, "ash.setup --quiet"} + ) + |> run_seeds_on_setup() + end + + defp run_seeds_on_setup(igniter) do + if Igniter.exists?(igniter, "priv/repo/seeds.exs") do + Igniter.Project.TaskAliases.add_alias(igniter, "ash.setup", [ + "ash.setup", + "run priv/repo/seeds.exs" + ]) + else + igniter + end + end + defp configure_config(igniter, otp_app, repo) do Igniter.Project.Config.configure( igniter, @@ -256,26 +313,38 @@ defmodule Mix.Tasks.AshPostgres.Install do ) end - defp setup_repo_module(igniter, otp_app, repo) do - Igniter.Code.Module.find_and_update_or_create_module( - igniter, + defp setup_repo_module(igniter, otp_app, repo, opts) do + {exists?, igniter} = Igniter.Project.Module.module_exists?(igniter, repo) + + if exists? do + Igniter.Project.Module.find_and_update_module!( + igniter, + repo, + fn zipper -> + {:ok, + zipper + |> set_otp_app(otp_app) + |> Sourceror.Zipper.top() + |> use_ash_postgres_instead_of_ecto() + |> Sourceror.Zipper.top() + |> remove_adapter_option()} + end + ) + else + Igniter.Project.Module.create_module( + igniter, + repo, + AshPostgres.Igniter.default_repo_contents(otp_app, repo, opts) + ) + end + |> Igniter.Project.Module.find_and_update_module!( repo, - AshPostgres.Igniter.default_repo_contents(otp_app), - fn zipper -> - {:ok, - zipper - |> set_otp_app(otp_app) - |> Sourceror.Zipper.top() - |> use_ash_postgres_instead_of_ecto() - |> Sourceror.Zipper.top() - |> remove_adapter_option()} - end + &configure_installed_extensions_function/1 ) |> Igniter.Code.Module.find_and_update_module!( repo, - &configure_installed_extensions_function/1 + &configure_min_pg_version_function(&1, repo, opts) ) - |> Igniter.Code.Module.find_and_update_module!(repo, &configure_min_pg_version_function/1) end defp use_ash_postgres_instead_of_ecto(zipper) do @@ -347,17 +416,18 @@ defmodule Mix.Tasks.AshPostgres.Install do end end - defp configure_min_pg_version_function(zipper) do + defp configure_min_pg_version_function(zipper, repo, opts) do case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do {:ok, zipper} -> {:ok, zipper} _ -> + min_pg_version = AshPostgres.Igniter.get_min_pg_version(repo, opts) + {:ok, Igniter.Code.Common.add_code(zipper, """ def min_pg_version do - # Adjust this according to your postgres version - %Version{major: 16, minor: 0, patch: 0} + %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor || 0}, patch: #{min_pg_version.patch || 0}} end """)} end diff --git a/mix.exs b/mix.exs index 5ea543be..f402e868 100644 --- a/mix.exs +++ b/mix.exs @@ -166,7 +166,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.4 and >= 3.4.9")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, - {:igniter, "~> 0.3 and >= 0.3.36"}, + {:igniter, "~> 0.3 and >= 0.3.42"}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index 2596b036..82a4c6ef 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.39", "e59b56836b9b22c6b76b1b9661c60a996eca7bbb3b0a22f7a888cd1c77d43419", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "0e794a273b53442a6fb223a65cd9800648d6e2f8fdf8556bcf74d0af793f4bd4"}, + "igniter": {:hex, :igniter, "0.3.42", "29ab08de9ba4316a6eb0ac73cd4481b3d2c4e799a647b667faafe5c988487e1b", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "d6bb222d7c6f29a9fb2461a93109da5787e4354928feea2b7a14827c27129115"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, diff --git a/test/mix/tasks/ash_postgres.install_test.exs b/test/mix/tasks/ash_postgres.install_test.exs index eb687a0d..e90b69ee 100644 --- a/test/mix/tasks/ash_postgres.install_test.exs +++ b/test/mix/tasks/ash_postgres.install_test.exs @@ -7,7 +7,7 @@ defmodule Mix.Tasks.AshPostgres.InstallTest do # any errors. We should add better tests here, though. test "installation does not fail" do test_project() - |> Igniter.compose_task("ash_postgres.install") + |> Igniter.compose_task("ash_postgres.install", ["--yes"]) |> assert_creates("lib/test/repo.ex") end end From 5642e0f96d6c64c3bf5991aaa9fd90474dfe723d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 23 Sep 2024 14:38:33 -0400 Subject: [PATCH 189/690] chore: fix dialyzer --- lib/igniter.ex | 2 +- lib/mix/tasks/ash_postgres.install.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index 5d0a0053..9b37d0d0 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -9,7 +9,7 @@ defmodule AshPostgres.Igniter do use AshPostgres.Repo, otp_app: #{inspect(otp_app)} def min_pg_version do - %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor || 0}, patch: #{min_pg_version.patch || 0}} + %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} end def installed_extensions do diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index a33986c2..dee5368c 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -427,7 +427,7 @@ defmodule Mix.Tasks.AshPostgres.Install do {:ok, Igniter.Code.Common.add_code(zipper, """ def min_pg_version do - %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor || 0}, patch: #{min_pg_version.patch || 0}} + %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} end """)} end From a87d9b4c81e7254cc145f31b630e3928ee315e50 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 23 Sep 2024 15:12:45 -0400 Subject: [PATCH 190/690] improvement: add `--repo` option to installer, and warn on clashing existing repo --- lib/mix/tasks/ash_postgres.install.ex | 51 ++++++++++++++++++++------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index dee5368c..f75a7b86 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -9,21 +9,31 @@ defmodule Mix.Tasks.AshPostgres.Install do def info(_argv, _source) do %Igniter.Mix.Task.Info{ schema: [ - yes: :boolean + yes: :boolean, + repo: :string ], aliases: [ - y: :yes + y: :yes, + r: :repo ] } end @impl true def igniter(igniter, argv) do - repo = Igniter.Code.Module.module_name(igniter, "Repo") - otp_app = Igniter.Project.Application.app_name(igniter) - opts = options!(argv) + repo = + case opts[:repo] do + nil -> + Igniter.Code.Module.module_name(igniter, "Repo") + + repo -> + Igniter.Code.Module.parse(repo) + end + + otp_app = Igniter.Project.Application.app_name(igniter) + igniter |> Igniter.Project.Formatter.import_dep(:ash_postgres) |> setup_aliases() @@ -321,13 +331,30 @@ defmodule Mix.Tasks.AshPostgres.Install do igniter, repo, fn zipper -> - {:ok, - zipper - |> set_otp_app(otp_app) - |> Sourceror.Zipper.top() - |> use_ash_postgres_instead_of_ecto() - |> Sourceror.Zipper.top() - |> remove_adapter_option()} + case Igniter.Code.Module.move_to_use(zipper, Ecto.Repo) do + {:ok, _} -> + {:ok, + zipper + |> set_otp_app(otp_app) + |> Sourceror.Zipper.top() + |> use_ash_postgres_instead_of_ecto() + |> Sourceror.Zipper.top() + |> remove_adapter_option()} + + _ -> + case Igniter.Code.Module.move_to_use(zipper, AshPostgres.Repo) do + {:ok, _} -> + {:ok, zipper} + + _ -> + {:error, + """ + Repo module #{inspect(repo)} existed, but was not an `Ecto.Repo` or an `AshPostgres.Repo`. + + Please rerun the ash_postgresql installer with the `--repo` option to specify a repo. + """} + end + end end ) else From 10c95086d5a428d806b38656a811173257b5548f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 24 Sep 2024 14:52:55 -0400 Subject: [PATCH 191/690] fix: typo of `biging` -> `bigint` fix: altering attributes not properly generating foreign keys in some cases --- .../migration_generator.ex | 52 ++++++++++++------- lib/migration_generator/operation.ex | 2 +- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index f75670cb..5118b4f4 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2199,12 +2199,10 @@ defmodule AshPostgres.MigrationGenerator do [] end - if has_reference?(old_snapshot.multitenancy, old_attribute) and - Map.get(old_attribute, :references) != Map.get(new_attribute, :references) do + if Map.get(old_attribute, :references) != Map.get(new_attribute, :references) do redo_deferrability = - if differently_deferrable?(new_attribute, old_attribute) do - [] - else + if has_reference?(old_snapshot.multitenancy, old_attribute) and + differently_deferrable?(new_attribute, old_attribute) do [ %Operation.AlterDeferrability{ table: snapshot.table, @@ -2213,24 +2211,38 @@ defmodule AshPostgres.MigrationGenerator do direction: :up } ] + else + [] end old_and_alter = - [ - %Operation.DropForeignKey{ - attribute: old_attribute, - table: snapshot.table, - schema: snapshot.schema, - multitenancy: old_snapshot.multitenancy, - direction: :up - }, - %Operation.AlterAttribute{ - new_attribute: new_attribute, - old_attribute: old_attribute, - schema: snapshot.schema, - table: snapshot.table - } - ] ++ redo_deferrability + if has_reference?(old_snapshot.multitenancy, old_attribute) do + [ + %Operation.DropForeignKey{ + attribute: old_attribute, + table: snapshot.table, + schema: snapshot.schema, + multitenancy: old_snapshot.multitenancy, + direction: :up + }, + %Operation.AlterAttribute{ + new_attribute: new_attribute, + old_attribute: old_attribute, + schema: snapshot.schema, + table: snapshot.table + } + ] + else + [ + %Operation.AlterAttribute{ + new_attribute: new_attribute, + old_attribute: old_attribute, + schema: snapshot.schema, + table: snapshot.table + } + ] + end ++ + redo_deferrability if has_reference?(snapshot.multitenancy, new_attribute) do reference_ops = [ diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 4198baa3..930a375b 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -501,7 +501,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do Map.get(old_attribute, :references) != Map.get(attribute, :references) do reference(multitenancy, attribute, schema) else - if attribute.type == :biging and attribute.default == "nil" and attribute.generated? do + if attribute.type == :bigint and attribute.default == "nil" and attribute.generated? do ":bigserial" else inspect(attribute.type) From 6e94a2580ccf6c806ba4423fe7234bdb2b4f5a3e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 24 Sep 2024 14:59:46 -0400 Subject: [PATCH 192/690] chore: release version v2.4.2 --- CHANGELOG.md | 25 +++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da0eeb29..0fc6628e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,31 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.2](https://github.com/ash-project/ash_postgres/compare/v2.4.1...v2.4.2) (2024-09-24) + + + + +### Bug Fixes: + +* typo of `biging` -> `bigint` + +* altering attributes not properly generating foreign keys in some cases + +* installer: use correct module name in the `DataCase` moduledocs. (#393) + +* trim input before passing to `String.to_integer/1`. (#389) + +### Improvements: + +* add `--repo` option to installer, and warn on clashing existing repo + +* prompt for minimum pg version + +* adjust mix task aliases to be used with `ash_postgres` + +* set a name for generated migrations + ## [v2.4.1](https://github.com/ash-project/ash_postgres/compare/v2.4.0...v2.4.1) (2024-09-16) diff --git a/mix.exs b/mix.exs index f402e868..49bf272f 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.1" + @version "2.4.2" def project do [ From 610b894ac0bf9f45e92ff7035941994359a5b5c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:24:21 -0400 Subject: [PATCH 193/690] chore(deps): bump the production-dependencies group with 2 updates (#394) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.4.17 to 3.4.21 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.17...v3.4.21) Updates `igniter` from 0.3.42 to 0.3.45 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.3.42...v0.3.45) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 82a4c6ef..d841c49e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.17", "2f2b817a9ea88ae68c4845b27a9ac0fc60f507cf4cc7ad3a3b614b1bdd619783", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "54eba5f478b7d1f4570479cdf747fa65e993acebb8d6bf2a7e8a48b4e0519ae2"}, + "ash": {:hex, :ash, "3.4.21", "d97b060c64084613ca8317272864be908d591aaa30671d1b04de41f82f8ce368", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "1fedea9b994c4b1d18722d49333fd8f30db4af058c9d56cd8cc438b420e6a6a8"}, "ash_sql": {:hex, :ash_sql, "0.2.32", "de99255becfb9daa7991c18c870e9f276bb372acda7eda3e05c3e2ff2ca8922e", [:mix], [{:ash, ">= 3.1.7 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", "43773bcd33d21319c11804d76fe11f1a1b7c8faba7aaedeab6f55fde3d2405db"}, "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"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, - "igniter": {:hex, :igniter, "0.3.42", "29ab08de9ba4316a6eb0ac73cd4481b3d2c4e799a647b667faafe5c988487e1b", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "d6bb222d7c6f29a9fb2461a93109da5787e4354928feea2b7a14827c27129115"}, + "igniter": {:hex, :igniter, "0.3.45", "f487138ed0c5cbf8f1bdd53360cdc2ac40c18ff379c8a575a7a34e526b4ba846", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "fbe663e3f4566fb358c64bdddf0ceb05cf9175cea34cccf45a9aa5532ea967f8"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -37,7 +37,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.29", "a52733ff72b05a674e48d3ca7a4172fe7bec81e9116069da8b4db19030d581d9", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "111a0dadbb27537c7629bc03ac56fcab15056ab0b9ad985084b9adcdb48836c8"}, + "spark": {:hex, :spark, "2.2.30", "811977b274cdad9d7668f934d44e8a013d7d9a059b63bcb6f2afb434dfcec458", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "476f2d463463ae14734f1e0c48cd642090cf3fb4082b8e73ea08118ad0da24ce"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 9c69ed15953d168bdfec31fe8360777c25c555de Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Sep 2024 08:24:35 -0400 Subject: [PATCH 194/690] chore: clean up test name & remove logger --- test/update_test.exs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/update_test.exs b/test/update_test.exs index 9afb32ab..e67db4ae 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -35,9 +35,7 @@ defmodule AshPostgres.UpdateTest do ) end - test "can optimist lock" do - Logger.configure(level: :debug) - + test "can optimistic lock" do Post |> Ash.Changeset.for_create(:create, %{title: "fred"}) |> Ash.create!() From fd7b9015e8b74d419dd207b62985ffcd469b9583 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Sep 2024 11:12:49 -0400 Subject: [PATCH 195/690] docs: clarify getting started guide --- .../get-started-with-ash-postgres.md | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/documentation/tutorials/get-started-with-ash-postgres.md b/documentation/tutorials/get-started-with-ash-postgres.md index db8e1c15..4ad0c498 100644 --- a/documentation/tutorials/get-started-with-ash-postgres.md +++ b/documentation/tutorials/get-started-with-ash-postgres.md @@ -148,9 +148,24 @@ And finally, add the repo to your application ... ``` -#### Add AshPostgres to our resources + + +## Adding AshPostgres to your resources + + + +### With Igniter + +You can add `AshPostgres` to a resource with `mix ash.patch.extend Your.Resource.Name postgres`. For example: + +```sh +mix ash.patch.extend Helpdesk.Support.Ticket postgres +mix ash.patch.extend Helpdesk.Support.Representative postgres +``` + +### Manually -Now we can add the data layer to our resources. The basic configuration for a resource requires the `d:AshPostgres.postgres|table` and the `d:AshPostgres.postgres|repo`. +The basic configuration for a resource requires the `d:AshPostgres.postgres|table` and the `d:AshPostgres.postgres|repo`. ```elixir # in lib/helpdesk/support/ticket.ex @@ -178,12 +193,16 @@ Now we can add the data layer to our resources. The basic configuration for a re end ``` + + #### Create the database and tables First, we'll create the database with `mix ash.setup`. Then we will generate database migrations. This is one of the many ways that AshPostgres can save time and reduce complexity. +For example: + ```bash mix ash.codegen add_tickets_and_representatives ``` @@ -200,8 +219,6 @@ Finally, we will create the local database and apply the generated migrations: mix ash.setup ``` - - ### Try it out This is based on the [Getting Started](https://hexdocs.pm/ash/getting_started.html) guide. From c46f896600f5ffb0fd003da75a7d38d705fe98c6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Sep 2024 13:13:00 -0400 Subject: [PATCH 196/690] fix: support pg <= 14 in resource generator, and update tests --- lib/resource_generator/spec.ex | 102 ++++++++++++++++++++++----------- test/aggregate_test.exs | 2 + test/test_helper.exs | 23 +++++++- 3 files changed, 92 insertions(+), 35 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index fffaf97e..8114a780 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -232,39 +232,75 @@ defmodule AshPostgres.ResourceGenerator.Spec do defp add_indexes(spec) do %Postgrex.Result{rows: index_rows} = - spec.repo.query!( - """ - SELECT - i.relname AS index_name, - ix.indisunique AS is_unique, - NOT(ix.indnullsnotdistinct) AS nulls_distinct, - pg_get_expr(ix.indpred, ix.indrelid) AS where_clause, - am.amname AS using_method, - idx.indexdef - FROM - pg_index ix - JOIN - pg_class i ON ix.indexrelid = i.oid - JOIN - pg_class t ON ix.indrelid = t.oid - JOIN - pg_am am ON i.relam = am.oid - LEFT JOIN - pg_constraint c ON c.conindid = ix.indexrelid AND c.contype = 'p' - JOIN - pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = 'public' -- Adjust schema name if necessary - JOIN information_schema.tables ta - ON ta.table_name = t.relname - WHERE - t.relname = $1 - AND ta.table_schema = $2 - AND c.conindid IS NULL - GROUP BY - i.relname, ix.indisunique, ix.indnullsnotdistinct, pg_get_expr(ix.indpred, ix.indrelid), am.amname, idx.indexdef; - """, - [spec.table_name, spec.schema], - log: false - ) + if Version.match?(spec.repo.min_pg_version(), ">= 15.0") do + spec.repo.query!( + """ + SELECT + i.relname AS index_name, + ix.indisunique AS is_unique, + NOT(ix.indnullsnotdistinct) AS nulls_distinct, + pg_get_expr(ix.indpred, ix.indrelid) AS where_clause, + am.amname AS using_method, + idx.indexdef + FROM + pg_index ix + JOIN + pg_class i ON ix.indexrelid = i.oid + JOIN + pg_class t ON ix.indrelid = t.oid + JOIN + pg_am am ON i.relam = am.oid + LEFT JOIN + pg_constraint c ON c.conindid = ix.indexrelid AND c.contype = 'p' + JOIN + pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = 'public' -- Adjust schema name if necessary + JOIN information_schema.tables ta + ON ta.table_name = t.relname + WHERE + t.relname = $1 + AND ta.table_schema = $2 + AND c.conindid IS NULL + GROUP BY + i.relname, ix.indisunique, ix.indnullsnotdistinct, pg_get_expr(ix.indpred, ix.indrelid), am.amname, idx.indexdef; + """, + [spec.table_name, spec.schema], + log: false + ) + else + spec.repo.query!( + """ + SELECT + i.relname AS index_name, + ix.indisunique AS is_unique, + TRUE AS nulls_distinct, + pg_get_expr(ix.indpred, ix.indrelid) AS where_clause, + am.amname AS using_method, + idx.indexdef + FROM + pg_index ix + JOIN + pg_class i ON ix.indexrelid = i.oid + JOIN + pg_class t ON ix.indrelid = t.oid + JOIN + pg_am am ON i.relam = am.oid + LEFT JOIN + pg_constraint c ON c.conindid = ix.indexrelid AND c.contype = 'p' + JOIN + pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = 'public' -- Adjust schema name if necessary + JOIN information_schema.tables ta + ON ta.table_name = t.relname + WHERE + t.relname = $1 + AND ta.table_schema = $2 + AND c.conindid IS NULL + GROUP BY + i.relname, ix.indisunique, pg_get_expr(ix.indpred, ix.indrelid), am.amname, idx.indexdef; + """, + [spec.table_name, spec.schema], + log: false + ) + end %{ spec diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 630aeaac..257f2f26 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -422,6 +422,7 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end + @tag :postgres_16 test "returns nil values if `include_nil?` is set to `true`" do post = Post @@ -616,6 +617,7 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end + @tag :postgres_16 test "it returns `nil` values when `include_nil?` is `true`" do post = Post diff --git a/test/test_helper.exs b/test/test_helper.exs index 10ae3340..5b02474b 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,5 +1,24 @@ -# ExUnit.start(capture_log: true) -ExUnit.configure(stacktrace_depth: 100) +ExUnit.start(capture_log: true) + +exclude_tags = + case System.get_env("PG_VERSION") do + "13" -> + [:postgres_14, :postgres_15, :postgres_16] + + "14" -> + [:postgres_15, :postgres_16] + + "15" -> + [:postgres_16] + + "16" -> + [] + + _ -> + [] + end + +ExUnit.configure(stacktrace_depth: 100, exclude: exclude_tags) AshPostgres.TestRepo.start_link() AshPostgres.TestNoSandboxRepo.start_link() From 2644585104c6c70df89aecf6aa48812d659ef185 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Sep 2024 13:27:25 -0400 Subject: [PATCH 197/690] chore: fix version matcher --- lib/resource_generator/spec.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 8114a780..a2eaa83a 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -232,7 +232,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do defp add_indexes(spec) do %Postgrex.Result{rows: index_rows} = - if Version.match?(spec.repo.min_pg_version(), ">= 15.0") do + if Version.match?(spec.repo.min_pg_version(), ">= 15.0.0") do spec.repo.query!( """ SELECT From ea1f57ef49d4e9f418a956d08763ac39d923ac7f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 27 Sep 2024 09:01:10 -0400 Subject: [PATCH 198/690] chore: add tests for ash_sql fixes --- lib/data_layer.ex | 2 ++ test/calculation_test.exs | 38 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 8 +++++++ 3 files changed, 48 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 79052e73..90be9bb1 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -609,6 +609,8 @@ defmodule AshPostgres.DataLayer do def can?(_, :async_engine), do: true def can?(_, :bulk_create), do: true + def can?(_, :action_select), do: true + def can?(resource, :update_query) do # We can't currently support updating a record from a query # if that record manages a tenant on update diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 8c0f2678..fd0ab43f 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -44,6 +44,44 @@ defmodule AshPostgres.CalculationTest do |> Ash.read!() end + @tag :regression + test "an expression calculation that requires a left join & distinct doesn't raise errors on out of order params" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "_"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "_"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "_"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Post + |> Ash.Query.load([ + :comment_title, + :category_label, + score_plus: %{amount: 10}, + max_comment_similarity: %{to: "foobar"} + ]) + |> Ash.Query.load_calculation_as(:comment_title, {:some, :example}) + |> Ash.Query.load_calculation_as(:max_comment_similarity, {:some, :other_thing_again}, %{ + to: "foobar" + }) + |> Ash.Query.load_calculation_as(:category_label, {:some, :other_thing}) + |> Ash.Query.sort(:title) + |> Ash.read!() + end + test "an expression calculation can be filtered on" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index aadcee06..14bd29eb 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -569,6 +569,10 @@ defmodule AshPostgres.Test.Post do calculate(:has_comments, :boolean, expr(exists(comments, true == true))) + # DONT DO THIS. USE SOMETHING LIKE `first(comments.name)` + # We're doing this to test a specific breakage + calculate(:comment_title, :string, expr(comments.title)) + calculate( :has_no_followers, :boolean, @@ -635,6 +639,10 @@ defmodule AshPostgres.Test.Post do argument(:search, AshPostgres.Tsquery, allow_expr?: true, allow_nil?: false) end + calculate :score_plus, :integer, expr(score + ^arg(:amount)) do + argument(:amount, :integer, allow_nil?: false) + end + calculate :query, AshPostgres.Tsquery, expr(fragment("to_tsquery(?)", ^arg(:search))) do argument(:search, :string, allow_expr?: true, allow_nil?: false) end From 73190a3649c77864ec632feb8fddf37304cfbfcf Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 27 Sep 2024 09:02:05 -0400 Subject: [PATCH 199/690] chore: update deps --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index d841c49e..6ce23950 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.21", "d97b060c64084613ca8317272864be908d591aaa30671d1b04de41f82f8ce368", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "1fedea9b994c4b1d18722d49333fd8f30db4af058c9d56cd8cc438b420e6a6a8"}, - "ash_sql": {:hex, :ash_sql, "0.2.32", "de99255becfb9daa7991c18c870e9f276bb372acda7eda3e05c3e2ff2ca8922e", [:mix], [{:ash, ">= 3.1.7 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", "43773bcd33d21319c11804d76fe11f1a1b7c8faba7aaedeab6f55fde3d2405db"}, + "ash_sql": {:hex, :ash_sql, "0.2.33", "bb0c53fb2920903d04a1997f6ad2efd923b90c5d47023b8c426ad79a34d4c8a0", [:mix], [{:ash, ">= 3.1.7 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", "c3dcd4ad90b7b0c73123debd59c838f7694b819723c48ed968b00f487de0ce30"}, "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.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, From 085a9f74bf466ecf31eae4b9e0e8c7fb6141ab8c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 27 Sep 2024 09:02:20 -0400 Subject: [PATCH 200/690] chore: release version v2.4.3 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fc6628e..1579a5c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.3](https://github.com/ash-project/ash_postgres/compare/v2.4.2...v2.4.3) (2024-09-27) + + + + +### Bug Fixes: + +* support pg <= 14 in resource generator, and update tests + ## [v2.4.2](https://github.com/ash-project/ash_postgres/compare/v2.4.1...v2.4.2) (2024-09-24) diff --git a/mix.exs b/mix.exs index 49bf272f..f5899a47 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.2" + @version "2.4.3" def project do [ From a119ba29af07017d15fcd9406770c88688d78b50 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 29 Sep 2024 09:37:34 -0400 Subject: [PATCH 201/690] fix: handle atomic array operations --- lib/sql_implementation.ex | 8 + .../test_repo/posts/20240929121224.json | 499 ++++++++++++++++++ .../test_repo/users/20240929124728.json | 130 +++++ .../20240929121224_migrate_resources42.exs | 21 + .../20240929124728_migrate_resources43.exs | 21 + test/atomics_test.exs | 24 + test/support/resources/post.ex | 7 + test/support/resources/user.ex | 24 + 8 files changed, 734 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/posts/20240929121224.json create mode 100644 priv/resource_snapshots/test_repo/users/20240929124728.json create mode 100644 priv/test_repo/migrations/20240929121224_migrate_resources42.exs create mode 100644 priv/test_repo/migrations/20240929124728_migrate_resources43.exs diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index d01c134e..c5a13c0d 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -239,6 +239,10 @@ defmodule AshPostgres.SqlImplementation do do: nil def parameterized_type(type, constraints, no_maps?) do + if type == :array do + raise "WHAT" + end + if Ash.Type.ash_type?(type) do cast_in_query? = if function_exported?(Ash.Type, :cast_in_query?, 2) do @@ -284,6 +288,7 @@ defmodule AshPostgres.SqlImplementation do new_returns = case new_returns do {:parameterized, _} = parameterized -> parameterized + {:array, _} = type -> parameterized_type(type, []) {type, constraints} -> parameterized_type(type, constraints) other -> other end @@ -292,6 +297,9 @@ defmodule AshPostgres.SqlImplementation do {:parameterized, _} = parameterized -> parameterized + {:array, _} = type -> + parameterized_type(type, []) + {type, constraints} -> parameterized_type(type, constraints) diff --git a/priv/resource_snapshots/test_repo/posts/20240929121224.json b/priv/resource_snapshots/test_repo/posts/20240929121224.json new file mode 100644 index 00000000..02103002 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240929121224.json @@ -0,0 +1,499 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "limited_score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "75F7ADAAFDA2EFE1592C479941632CC8B29A1158A4A2268B9B9F5B43BD64AD7C", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/users/20240929124728.json b/priv/resource_snapshots/test_repo/users/20240929124728.json new file mode 100644 index 00000000..1a4c5eac --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20240929124728.json @@ -0,0 +1,130 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "is_active", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "\"user\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role", + "type": "text" + }, + { + "allow_nil?": true, + "default": "[]", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role_list", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "users_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "name": "users_org_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_orgs" + }, + "size": null, + "source": "org_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "1259CA2EDC7624799344ADE60ACA1745688666D00D18450A22430683754B425F", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "users" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240929121224_migrate_resources42.exs b/priv/test_repo/migrations/20240929121224_migrate_resources42.exs new file mode 100644 index 00000000..529a2338 --- /dev/null +++ b/priv/test_repo/migrations/20240929121224_migrate_resources42.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources42 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:limited_score, :bigint) + end + end + + def down do + alter table(:posts) do + remove(:limited_score) + end + end +end diff --git a/priv/test_repo/migrations/20240929124728_migrate_resources43.exs b/priv/test_repo/migrations/20240929124728_migrate_resources43.exs new file mode 100644 index 00000000..31e815f9 --- /dev/null +++ b/priv/test_repo/migrations/20240929124728_migrate_resources43.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources43 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:users) do + add(:role_list, {:array, :text}, default: []) + end + end + + def down do + alter table(:users) do + remove(:role_list) + end + end +end diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 2ab42b6c..2cf5e6b6 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -39,6 +39,30 @@ defmodule AshPostgres.AtomicsTest do |> Ash.update!() end + test "an atomic works on a constrained integer" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "foo", price: 1}) + |> Ash.create!() + + assert %{limited_score: 6} = + post + |> Ash.Changeset.for_update(:add_to_limited_score, %{amount: 6}) + |> Ash.update!() + end + + test "an atomic works on an array attribute" do + user = + User + |> Ash.Changeset.for_create(:create, %{}) + |> Ash.create!() + + assert %{role_list: [:admin]} = + user + |> Ash.Changeset.for_update(:add_role, %{role: :admin}) + |> Ash.update!() + end + test "a basic atomic works with enum/allow_nil? false" do user = User diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 14bd29eb..531fb486 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -130,6 +130,11 @@ defmodule AshPostgres.Test.Post do defaults([:read, :destroy]) + update :add_to_limited_score do + argument(:amount, :integer, allow_nil?: false) + change(atomic_update(:limited_score, expr((limited_score || 0) + ^arg(:amount)))) + end + destroy :destroy_only_freds do change(filter(expr(title == "fred"))) end @@ -359,6 +364,8 @@ defmodule AshPostgres.Test.Post do attribute(:datetime, AshPostgres.TimestamptzUsec, public?: true) attribute(:score, :integer, public?: true) + attribute(:limited_score, :integer, public?: true, constraints: [min: 0, max: 100]) + attribute(:public, :boolean, public?: true) attribute(:category, CiCategory, public?: true) attribute(:type, :atom, default: :sponsored, writable?: false, public?: false) diff --git a/test/support/resources/user.ex b/test/support/resources/user.ex index 25a99f18..b07b3e7c 100644 --- a/test/support/resources/user.ex +++ b/test/support/resources/user.ex @@ -14,6 +14,24 @@ defmodule AshPostgres.Test.User do change(atomic_update(:role, expr(invite.role))) end + update :add_role do + argument(:role, AshPostgres.Test.Role, allow_nil?: false) + + change( + atomic_update( + :role_list, + expr( + fragment( + "array(select distinct unnest(array_append(?, ?)))", + ^atomic_ref(:role_list), + ^arg(:role) + ) + ), + cast_atomic?: false + ) + ) + end + read :active do filter(expr(active)) @@ -43,6 +61,12 @@ defmodule AshPostgres.Test.User do attribute(:is_active, :boolean, public?: true) attribute(:name, :string, public?: true) attribute(:role, AshPostgres.Test.Role, allow_nil?: false, default: :user, public?: true) + + attribute(:role_list, {:array, AshPostgres.Test.Role}, + allow_nil?: false, + default: [], + public?: true + ) end postgres do From 12196cf7a11003dab1923c21dea353ca0b4e236a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 29 Sep 2024 09:39:16 -0400 Subject: [PATCH 202/690] chore: release version v2.4.4 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1579a5c0..cf961fc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.4](https://github.com/ash-project/ash_postgres/compare/v2.4.3...v2.4.4) (2024-09-29) + + + + +### Bug Fixes: + +* handle atomic array operations + ## [v2.4.3](https://github.com/ash-project/ash_postgres/compare/v2.4.2...v2.4.3) (2024-09-27) diff --git a/mix.exs b/mix.exs index f5899a47..cbeb0eb9 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.3" + @version "2.4.4" def project do [ From af32acde466154a4e16a86e32ab183bd8ed8669b Mon Sep 17 00:00:00 2001 From: Ahmed Kamal Date: Tue, 1 Oct 2024 13:49:52 +1000 Subject: [PATCH 203/690] improvement: support to_ecto(%Ecto.Changeset{}) and from_ecto(%Ecto.Changeset{}) (#395) --- lib/repo.ex | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/repo.ex b/lib/repo.ex index d46107bb..b9b2290f 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -176,6 +176,10 @@ defmodule AshPostgres.Repo do Enum.map(value, &from_ecto/1) end + def from_ecto(%Ecto.Changeset{} = changeset) do + Map.put(changeset, :data, from_ecto(changeset.data)) + end + def from_ecto(%resource{} = record) do if Spark.Dsl.is?(resource, Ash.Resource) do empty = struct(resource) @@ -204,6 +208,10 @@ defmodule AshPostgres.Repo do Enum.map(value, &to_ecto/1) end + def to_ecto(%Ecto.Changeset{} = changeset) do + Map.put(changeset, :data, to_ecto(changeset.data)) + end + def to_ecto(%resource{} = record) do if Spark.Dsl.is?(resource, Ash.Resource) do resource From 02104860f38d0cc41dfbbd0dcf5f7741318f4322 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 1 Oct 2024 11:53:15 -0400 Subject: [PATCH 204/690] fix: ensure upsert fields are uniq --- lib/data_layer.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 90be9bb1..9607e447 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1918,7 +1918,9 @@ defmodule AshPostgres.DataLayer do upsert_fields -- Keyword.keys(Enum.at(changesets, 0).atomics) - Enum.map(fields_to_upsert, fn upsert_field -> + fields_to_upsert + |> Enum.uniq() + |> Enum.map(fn upsert_field -> # for safety, we check once more at the end that all values in # upsert_fields are names of attributes. This is because # below we use `literal/1` to bring them into the query From c9e66b15e6647acf1064a1d102c0fd0768a593fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:33:19 -0400 Subject: [PATCH 205/690] chore(deps): bump the production-dependencies group with 2 updates (#397) --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 6ce23950..34ad4f56 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.21", "d97b060c64084613ca8317272864be908d591aaa30671d1b04de41f82f8ce368", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "1fedea9b994c4b1d18722d49333fd8f30db4af058c9d56cd8cc438b420e6a6a8"}, - "ash_sql": {:hex, :ash_sql, "0.2.33", "bb0c53fb2920903d04a1997f6ad2efd923b90c5d47023b8c426ad79a34d4c8a0", [:mix], [{:ash, ">= 3.1.7 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", "c3dcd4ad90b7b0c73123debd59c838f7694b819723c48ed968b00f487de0ce30"}, + "ash": {:hex, :ash, "3.4.22", "e292e40cae558c486bb23da656b564c3bb5fb551dbd2aeae54c879b408c91844", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "6ca9be81d06ab07cb2f4d14132b085dc421f3f400b7aa0148b9fd7d575499efc"}, + "ash_sql": {:hex, :ash_sql, "0.2.34", "8b4761979284733d1c40f478af623c59bd09d67c38955f243ff88912f5c5bee8", [:mix], [{:ash, ">= 3.1.7 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", "bc993e532aa6346231521c1c743e0660cf09344d9ffafe9e42faf59f9523743b"}, "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.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, @@ -19,7 +19,7 @@ "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, - "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, + "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, "igniter": {:hex, :igniter, "0.3.45", "f487138ed0c5cbf8f1bdd53360cdc2ac40c18ff379c8a575a7a34e526b4ba846", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "fbe663e3f4566fb358c64bdddf0ceb05cf9175cea34cccf45a9aa5532ea967f8"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, @@ -37,7 +37,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.30", "811977b274cdad9d7668f934d44e8a013d7d9a059b63bcb6f2afb434dfcec458", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "476f2d463463ae14734f1e0c48cd642090cf3fb4082b8e73ea08118ad0da24ce"}, + "spark": {:hex, :spark, "2.2.31", "ce58988f5b34b96bb01cfc5399a5ddc24a7a5bcf0ae7003503678f3466d7779a", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "1b4fdf2e0bba79a2e6417428f79dc8b7f7b01f02cdb632526071052d6cbfdfec"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 714dbf8f4d35ed882a2c0b66e541518e250e3fcf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:33:57 -0400 Subject: [PATCH 206/690] chore(deps-dev): bump the dev-dependencies group with 2 updates (#398) --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 34ad4f56..56218cb9 100644 --- a/mix.lock +++ b/mix.lock @@ -3,11 +3,11 @@ "ash_sql": {:hex, :ash_sql, "0.2.34", "8b4761979284733d1c40f478af623c59bd09d67c38955f243ff88912f5c5bee8", [:mix], [{:ash, ">= 3.1.7 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", "bc993e532aa6346231521c1c743e0660cf09344d9ffafe9e42faf59f9523743b"}, "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.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, + "credo": {:hex, :credo, "1.7.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [: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", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, + "dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, "ecto": {:hex, :ecto, "3.12.3", "1a9111560731f6c3606924c81c870a68a34c819f6d4f03822f370ea31a582208", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9efd91506ae722f95e48dc49e70d0cb632ede3b7a23896252a60a14ac6d59165"}, "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, From 58392165a568f198b01945e2d83b99b3e9f78ca8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 4 Oct 2024 17:54:29 -0400 Subject: [PATCH 207/690] improvement: detect 1 arg repo use in installer --- lib/igniter.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index 9b37d0d0..b005e1d5 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -108,7 +108,7 @@ defmodule AshPostgres.Igniter do end defp move_to_repo_use(zipper) do - Igniter.Code.Function.move_to_function_call(zipper, :use, 2, fn zipper -> + Igniter.Code.Function.move_to_function_call(zipper, :use, [1, 2], fn zipper -> Igniter.Code.Function.argument_equals?( zipper, 0, From 45503d22b5a94c788abd1cf603f195cebdc21902 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 6 Oct 2024 11:50:10 -0400 Subject: [PATCH 208/690] chore: pass `yes` option to generate a repo --- lib/igniter.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index b005e1d5..f1bbd558 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -84,7 +84,7 @@ defmodule AshPostgres.Igniter do Igniter.Code.Module.create_module( igniter, repo, - default_repo_contents(otp_app, repo), + default_repo_contents(otp_app, repo, opts), opts ) From d37ebd8f00380331f7359bcc6d79fdb0aa6cf8b1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 6 Oct 2024 11:52:32 -0400 Subject: [PATCH 209/690] chore: release version v2.4.5 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf961fc7..5adce0e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.5](https://github.com/ash-project/ash_postgres/compare/v2.4.4...v2.4.5) (2024-10-06) + + + + +### Bug Fixes: + +* ensure upsert fields are uniq + +### Improvements: + +* detect 1 arg repo use in installer + +* support to_ecto(%Ecto.Changeset{}) and from_ecto(%Ecto.Changeset{}) (#395) + ## [v2.4.4](https://github.com/ash-project/ash_postgres/compare/v2.4.3...v2.4.4) (2024-09-29) diff --git a/mix.exs b/mix.exs index cbeb0eb9..053b2930 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.4" + @version "2.4.5" def project do [ From 77e3dfb7ad53b597e7491525059bd1ff3d965dac Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 7 Oct 2024 11:01:22 -0400 Subject: [PATCH 210/690] chore: update ash_sql and tests --- mix.lock | 14 +++++++------- test/aggregate_test.exs | 26 ++++++++++++++++++++++++++ test/support/resources/post.ex | 5 +++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/mix.lock b/mix.lock index 56218cb9..d1652007 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.22", "e292e40cae558c486bb23da656b564c3bb5fb551dbd2aeae54c879b408c91844", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "6ca9be81d06ab07cb2f4d14132b085dc421f3f400b7aa0148b9fd7d575499efc"}, + "ash": {:hex, :ash, "3.4.24", "a631bef823e42e204e82bf4040cf437b3c8c286a62a4913615c970e73a2fa741", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "c1d7f10b34b298a6848eb8d2a88c4ff974a67a0d38ce3aa08caa7c8cd1bd665b"}, "ash_sql": {:hex, :ash_sql, "0.2.34", "8b4761979284733d1c40f478af623c59bd09d67c38955f243ff88912f5c5bee8", [:mix], [{:ash, ">= 3.1.7 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", "bc993e532aa6346231521c1c743e0660cf09344d9ffafe9e42faf59f9523743b"}, "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"}, @@ -9,8 +9,8 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, - "ecto": {:hex, :ecto, "3.12.3", "1a9111560731f6c3606924c81c870a68a34c819f6d4f03822f370ea31a582208", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9efd91506ae722f95e48dc49e70d0cb632ede3b7a23896252a60a14ac6d59165"}, - "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, + "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"}, + "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, - "igniter": {:hex, :igniter, "0.3.45", "f487138ed0c5cbf8f1bdd53360cdc2ac40c18ff379c8a575a7a34e526b4ba846", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "fbe663e3f4566fb358c64bdddf0ceb05cf9175cea34cccf45a9aa5532ea967f8"}, + "igniter": {:hex, :igniter, "0.3.49", "da3ce1ff42a8ba61cda462cbd46aafad9ac09be9b6fe92cbcd9a25ebf914f32f", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "4b2693347fdf51da6e921a5bc067fefb22698bd92c1597d06a27dc06ec686b26"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -30,18 +30,18 @@ "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, - "owl": {:hex, :owl, "0.11.0", "2cd46185d330aa2400f1c8c3cddf8d2ff6320baeff23321d1810e58127082cae", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "73f5783f0e963cc04a061be717a0dbb3e49ae0c4bfd55fb4b78ece8d33a65efe"}, + "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, "reactor": {:hex, :reactor, "0.10.0", "1206113c21ba69b889e072b2c189c05a7aced523b9c3cb8dbe2dab7062cb699a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4003c33e4c8b10b38897badea395e404d74d59a31beb30469a220f2b1ffe6457"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.31", "ce58988f5b34b96bb01cfc5399a5ddc24a7a5bcf0ae7003503678f3466d7779a", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "1b4fdf2e0bba79a2e6417428f79dc8b7f7b01f02cdb632526071052d6cbfdfec"}, + "spark": {:hex, :spark, "2.2.32", "cb84983c56e57670dd87a7a008a860d6e69626c814b0b5e25194b495ce56c7ba", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "ee5a0a4ddb16ad8f5a792a7b1883498d3090c60101af77a866f76d54962478e8"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, - "stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"}, + "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 257f2f26..bc2ac0b3 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -617,6 +617,32 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end + test "it does not return `nil` values when filtered" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: nil}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "stuff"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert %{first_comment_nils_first_called_stuff: "stuff"} = + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.load([ + :first_comment_nils_first_called_stuff, + :first_comment_nils_first + ]) + |> Ash.read_one!() + end + @tag :postgres_16 test "it returns `nil` values when `include_nil?` is `true`" do post = diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 531fb486..7d2764cb 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -742,6 +742,11 @@ defmodule AshPostgres.Test.Post do sort(title: :asc_nils_first) end + first :first_comment_nils_first_called_stuff, :comments, :title do + sort(title: :asc_nils_first) + filter(expr(title == "stuff")) + end + first :first_comment_nils_first_include_nil, :comments, :title do include_nil?(true) sort(title: :asc_nils_first) From 21b923e32d902515b4418d1a139cd850de4985bc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 7 Oct 2024 11:04:25 -0400 Subject: [PATCH 211/690] chore: fix deprecation warnings from igniter --- lib/data_layer.ex | 2 +- lib/igniter.ex | 8 ++++---- lib/mix/tasks/ash_postgres.install.ex | 16 ++++++++-------- lib/resource_generator/resource_generator.ex | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 9607e447..76997e3f 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3014,7 +3014,7 @@ defmodule AshPostgres.DataLayer do repo = case options[:repo] do nil -> - Igniter.Code.Module.module_name(igniter, "Repo") + Igniter.Project.Module.module_name(igniter, "Repo") repo -> Igniter.Code.Module.parse(repo) diff --git a/lib/igniter.ex b/lib/igniter.ex index f1bbd558..868383bf 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -44,7 +44,7 @@ defmodule AshPostgres.Igniter do end def add_postgres_extension(igniter, repo_name, extension) do - Igniter.Code.Module.find_and_update_module!(igniter, repo_name, fn zipper -> + Igniter.Project.Module.find_and_update_module!(igniter, repo_name, fn zipper -> case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do {:ok, zipper} -> case Igniter.Code.List.append_new_to_list(zipper, extension) do @@ -77,11 +77,11 @@ defmodule AshPostgres.Igniter do case list_repos(igniter) do {igniter, []} -> if generate do - repo = Igniter.Code.Module.module_name(igniter, "Repo") + repo = Igniter.Project.Module.module_name(igniter, "Repo") otp_app = Igniter.Project.Application.app_name(igniter) igniter = - Igniter.Code.Module.create_module( + Igniter.Project.Module.create_module( igniter, repo, default_repo_contents(otp_app, repo, opts), @@ -102,7 +102,7 @@ defmodule AshPostgres.Igniter do end def list_repos(igniter) do - Igniter.Code.Module.find_all_matching_modules(igniter, fn _mod, zipper -> + Igniter.Project.Module.find_all_matching_modules(igniter, fn _mod, zipper -> move_to_repo_use(zipper) != :error end) end diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index f75a7b86..3171929a 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -26,7 +26,7 @@ defmodule Mix.Tasks.AshPostgres.Install do repo = case opts[:repo] do nil -> - Igniter.Code.Module.module_name(igniter, "Repo") + Igniter.Project.Module.module_name(igniter, "Repo") repo -> Igniter.Code.Module.parse(repo) @@ -275,7 +275,7 @@ defmodule Mix.Tasks.AshPostgres.Install do end defp setup_data_case(igniter) do - module_name = Igniter.Code.Module.module_name(igniter, "DataCase") + module_name = Igniter.Project.Module.module_name(igniter, "DataCase") default_data_case_contents = ~s| @moduledoc """ @@ -297,24 +297,24 @@ defmodule Mix.Tasks.AshPostgres.Install do using do quote do - alias #{inspect(Igniter.Code.Module.module_name(igniter, "Repo"))} + alias #{inspect(Igniter.Project.Module.module_name(igniter, "Repo"))} import Ecto import Ecto.Changeset import Ecto.Query - import #{inspect(Igniter.Code.Module.module_name(igniter, "DataCase"))} + import #{inspect(Igniter.Project.Module.module_name(igniter, "DataCase"))} end end setup tags do - pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(Igniter.Code.Module.module_name(igniter, "Repo"))}, shared: not tags[:async]) + pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(Igniter.Project.Module.module_name(igniter, "Repo"))}, shared: not tags[:async]) on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) :ok end | igniter - |> Igniter.Code.Module.find_and_update_or_create_module( + |> Igniter.Project.Module.find_and_update_or_create_module( module_name, default_data_case_contents, # do nothing if already exists @@ -324,7 +324,7 @@ defmodule Mix.Tasks.AshPostgres.Install do end defp setup_repo_module(igniter, otp_app, repo, opts) do - {exists?, igniter} = Igniter.Project.Module.module_exists?(igniter, repo) + {exists?, igniter} = Igniter.Project.Module.module_exists(igniter, repo) if exists? do Igniter.Project.Module.find_and_update_module!( @@ -368,7 +368,7 @@ defmodule Mix.Tasks.AshPostgres.Install do repo, &configure_installed_extensions_function/1 ) - |> Igniter.Code.Module.find_and_update_module!( + |> Igniter.Project.Module.find_and_update_module!( repo, &configure_min_pg_version_function(&1, repo, opts) ) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index d6772ba2..103305cb 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -104,7 +104,7 @@ defmodule AshPostgres.ResourceGenerator do igniter |> Ash.Domain.Igniter.add_resource_reference(domain, table_spec.resource) - |> Igniter.Code.Module.create_module(table_spec.resource, resource) + |> Igniter.Project.Module.create_module(table_spec.resource, resource) |> then(fn igniter -> if opts[:extend] do Igniter.compose_task(igniter, "ash.patch.extend", [ From 9fe09559305db6d86ead79bad19dfdef7b35e5a4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 7 Oct 2024 15:14:57 -0400 Subject: [PATCH 212/690] improvement: with `--yes` assume oldest version --- lib/igniter.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index 868383bf..70d190fe 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -120,7 +120,7 @@ defmodule AshPostgres.Igniter do @doc false def get_min_pg_version(name, opts) do if opts[:yes] do - %Version{major: 16, minor: 0, patch: 0} + %Version{major: 13, minor: 0, patch: 0} else lead_in = """ Generating #{inspect(name)} From 764ecb66cdae7b34056b87f1a8073f8b23e36dda Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 7 Oct 2024 15:16:29 -0400 Subject: [PATCH 213/690] chore: release version v2.4.6 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5adce0e1..1ce02035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.6](https://github.com/ash-project/ash_postgres/compare/v2.4.5...v2.4.6) (2024-10-07) + + + + +### Improvements: + +* with `--yes` assume oldest version + ## [v2.4.5](https://github.com/ash-project/ash_postgres/compare/v2.4.4...v2.4.5) (2024-10-06) diff --git a/mix.exs b/mix.exs index 053b2930..a111fc03 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.5" + @version "2.4.6" def project do [ From 53694a9e2b8e9cd30d3704294d9a0e4f0ba6da83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:55:01 -0400 Subject: [PATCH 214/690] chore(deps): bump the production-dependencies group with 3 updates (#401) --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index d1652007..a583ea11 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.24", "a631bef823e42e204e82bf4040cf437b3c8c286a62a4913615c970e73a2fa741", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "c1d7f10b34b298a6848eb8d2a88c4ff974a67a0d38ce3aa08caa7c8cd1bd665b"}, - "ash_sql": {:hex, :ash_sql, "0.2.34", "8b4761979284733d1c40f478af623c59bd09d67c38955f243ff88912f5c5bee8", [:mix], [{:ash, ">= 3.1.7 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", "bc993e532aa6346231521c1c743e0660cf09344d9ffafe9e42faf59f9523743b"}, + "ash": {:hex, :ash, "3.4.27", "8a7f8102a053c5238654a1089bbd6330f400386eb5ef5201755b6332fc4c7566", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "55d2c70f23b51bc97abb414729ced315995f502f98e8cbfad2298c2ed083b8c9"}, + "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, "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.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [: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", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, - "igniter": {:hex, :igniter, "0.3.49", "da3ce1ff42a8ba61cda462cbd46aafad9ac09be9b6fe92cbcd9a25ebf914f32f", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "4b2693347fdf51da6e921a5bc067fefb22698bd92c1597d06a27dc06ec686b26"}, + "igniter": {:hex, :igniter, "0.3.52", "b2260226c278cb11864ac2c7d171869aa5fed5a1b350ccedb7ff7020414b04f4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "98682760abca84b87588dfd578db04f575458726a3dbfef09cb2fc24c14cc4ec"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From c5c9575f3e5e344284a71a6d9d9a998a8a16ca2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:55:11 -0400 Subject: [PATCH 215/690] chore(deps-dev): bump git_ops in the dev-dependencies group (#402) --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index a583ea11..87d3f33b 100644 --- a/mix.lock +++ b/mix.lock @@ -18,7 +18,7 @@ "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "d571628fd829a510d219bcb7162400baff50977f", []}, "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, - "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, + "git_ops": {:hex, :git_ops, "2.6.2", "1e03e44d1b41e91cf39b47d214d515a0d67d44a7fda13ef131bb70bd706dd398", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fc0200fbc6d2784e2f3b9be200ce63e523d0d9ff527c6308490c3d6d325d5e6f"}, "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, "igniter": {:hex, :igniter, "0.3.52", "b2260226c278cb11864ac2c7d171869aa5fed5a1b350ccedb7ff7020414b04f4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "98682760abca84b87588dfd578db04f575458726a3dbfef09cb2fc24c14cc4ec"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, From bd91615f4913050126a4fb58cfbd8d6742010fd8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 10 Oct 2024 11:22:51 -0400 Subject: [PATCH 216/690] improvement: adapt to fixes and optimizations around skipped upserts in ash core test: update tests correspondingly --- lib/data_layer.ex | 12 ++++++++---- mix.exs | 2 +- mix.lock | 2 +- test/create_test.exs | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 76997e3f..34c17d9f 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2588,10 +2588,14 @@ defmodule AshPostgres.DataLayer do 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, + {:upsert_skipped, ash_query, + fn -> + 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 + end}} {:ok, [result]} -> {:ok, result} diff --git a/mix.exs b/mix.exs index a111fc03..a43aed41 100644 --- a/mix.exs +++ b/mix.exs @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.9")}, + {:ash, ash_version("~> 3.4 and >= 3.4.28")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, {:igniter, "~> 0.3 and >= 0.3.42"}, {:ecto_sql, "~> 3.12"}, diff --git a/mix.lock b/mix.lock index 87d3f33b..020e7b3d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.27", "8a7f8102a053c5238654a1089bbd6330f400386eb5ef5201755b6332fc4c7566", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "55d2c70f23b51bc97abb414729ced315995f502f98e8cbfad2298c2ed083b8c9"}, "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, + "ash": {:hex, :ash, "3.4.28", "499c8cf49e406cc5a9b7c6e8e0daae616d2cbd5a02ad421db7932b2972e8badf", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "7faafca1f6b70bf2e72dbabef0d667ee2108923df465878e94f03b2ea8c24fe8"}, "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.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [: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", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, diff --git a/test/create_test.exs b/test/create_test.exs index 23fe3533..84607880 100644 --- a/test/create_test.exs +++ b/test/create_test.exs @@ -55,7 +55,7 @@ defmodule AshPostgres.CreateTest do uniq_if_contains_foo: "foo", price: 10 }) - |> Ash.create() + |> Ash.create(return_skipped_upsert?: true) assert Ash.Resource.get_metadata(post, :upsert_skipped) end From dacc4f960e28bc02f87c0e296ff93f71a830b233 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 10 Oct 2024 11:26:31 -0400 Subject: [PATCH 217/690] chore: release version v2.4.7 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce02035..e20f57ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.7](https://github.com/ash-project/ash_postgres/compare/v2.4.6...v2.4.7) (2024-10-10) + + + + +### Improvements: + +* adapt to fixes and optimizations around skipped upserts in ash core + ## [v2.4.6](https://github.com/ash-project/ash_postgres/compare/v2.4.5...v2.4.6) (2024-10-07) diff --git a/mix.exs b/mix.exs index a43aed41..58c14c80 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.6" + @version "2.4.7" def project do [ From 95fe5829aab1bb9f21b807e162372da6542a4e26 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 11 Oct 2024 08:34:12 -0400 Subject: [PATCH 218/690] improvement: use the `name` parameter when generating migrations --- .../migration_generator.ex | 62 ++++++++++++++++--- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 5118b4f4..03337583 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -233,13 +233,61 @@ defmodule AshPostgres.MigrationGenerator do {"install_#{ext_name}_v#{version}_#{timestamp(true)}", "#{timestamp(true)}_install_#{ext_name}_v#{version}_extension"} - ["ash-functions" = single] -> - {"install_#{single}_extension_#{AshPostgres.MigrationGenerator.AshFunctions.latest_version()}_#{timestamp(true)}", - "#{timestamp(true)}_install_#{single}_extension_#{AshPostgres.MigrationGenerator.AshFunctions.latest_version()}"} - - multiple -> - {"install_#{Enum.count(multiple)}_extensions_#{timestamp(true)}", - "#{timestamp(true)}_install_#{Enum.count(multiple)}_extensions"} + ["ash_functions"] -> + {"install_ash_functions_extension_#{AshPostgres.MigrationGenerator.AshFunctions.latest_version()}_#{timestamp(true)}", + "#{timestamp(true)}_install_ash_functions_extension_#{AshPostgres.MigrationGenerator.AshFunctions.latest_version()}"} + + _multiple -> + migration_path = migration_path(opts, repo, false) + + if opts.name do + count = + migration_path + |> Path.join("*_#{opts.name}_extensions*") + |> Path.wildcard() + |> Enum.map(fn path -> + path + |> Path.basename() + |> String.split("_#{opts.name}_extensions", parts: 2) + |> Enum.at(1) + |> Integer.parse() + |> case do + {integer, _} -> + integer + + _ -> + 0 + end + end) + |> Enum.max(fn -> 0 end) + |> Kernel.+(1) + + {"#{opts.name}_extensions", "#{timestamp(true)}_#{opts.name}_extensions"} + else + count = + migration_path + |> Path.join("*_migrate_resources_extensions*") + |> Path.wildcard() + |> Enum.map(fn path -> + path + |> Path.basename() + |> String.split("_migrate_resources_extensions", parts: 2) + |> Enum.at(1) + |> Integer.parse() + |> case do + {integer, _} -> + integer + + _ -> + 0 + end + end) + |> Enum.max(fn -> 0 end) + |> Kernel.+(1) + + {"migrate_resources_extensions_#{count}", + "#{timestamp(true)}_migrate_resources_extensions_#{count}"} + end end migration_file = From 733647ac65c1e0196b86ab572a5f1d75d21d8942 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 11 Oct 2024 09:19:52 -0400 Subject: [PATCH 219/690] chore: remove often-confusing warning --- lib/mix/tasks/ash_postgres.generate_migrations.ex | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index eedaf280..08f46528 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -102,13 +102,6 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do domains = AshPostgres.Mix.Helpers.domains!(opts, args) - if Enum.empty?(domains) && !opts[:snapshots_only] do - IO.warn(""" - No domains found, so no resource-related migrations will be generated. - Pass the `--domains` option or configure `config :your_app, ash_domains: [...]` - """) - end - opts = opts |> Keyword.put(:format, !opts[:no_format]) From cb801701f140a90614f062cb374d56b2d0f01f80 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 11 Oct 2024 09:20:08 -0400 Subject: [PATCH 220/690] chore: release version v2.4.8 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e20f57ca..6bfb0a7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.8](https://github.com/ash-project/ash_postgres/compare/v2.4.7...v2.4.8) (2024-10-11) + + + + +### Improvements: + +* use the `name` parameter when generating migrations + ## [v2.4.7](https://github.com/ash-project/ash_postgres/compare/v2.4.6...v2.4.7) (2024-10-10) diff --git a/mix.exs b/mix.exs index 58c14c80..c148b7af 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.7" + @version "2.4.8" def project do [ From da61fa8535d1202cb678634487eadafa80d87ac3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 11 Oct 2024 09:20:38 -0400 Subject: [PATCH 221/690] chore: use `count` --- lib/migration_generator/migration_generator.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 03337583..779538e7 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -262,7 +262,8 @@ defmodule AshPostgres.MigrationGenerator do |> Enum.max(fn -> 0 end) |> Kernel.+(1) - {"#{opts.name}_extensions", "#{timestamp(true)}_#{opts.name}_extensions"} + {"#{opts.name}_extensions_#{count}", + "#{timestamp(true)}_#{opts.name}_extensions_#{count}"} else count = migration_path From a1ffa1ca274b2598e3b04fbb6b809f9ab90f7b2c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 13 Oct 2024 18:42:11 -0400 Subject: [PATCH 222/690] chore: fix migration generator tests --- test/migration_generator_test.exs | 79 +++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index a5648c43..fd0e9045 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -158,7 +158,9 @@ defmodule AshPostgres.MigrationGeneratorTest do assert File.read!(Path.wildcard("test_snapshots_path/test_repo/posts/*.json")) |> Jason.decode!(keys: :atoms!) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) file_contents = File.read!(file) @@ -264,7 +266,9 @@ defmodule AshPostgres.MigrationGeneratorTest do assert File.read!(Path.wildcard("test_snapshots_path/test_repo/example.posts/*.json")) |> Jason.decode!(keys: :atoms!) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) file_contents = File.read!(file) @@ -334,6 +338,7 @@ defmodule AshPostgres.MigrationGeneratorTest do test "it creates multiple migration files" do assert [_, custom_index_migration] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) file = File.read!(custom_index_migration) @@ -378,6 +383,7 @@ defmodule AshPostgres.MigrationGeneratorTest do test "it adds nulls_distinct option to create index migration" do assert [custom_index_migration] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) file = File.read!(custom_index_migration) @@ -442,6 +448,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[rename table(:posts, prefix: "example"), :title, to: :name] end @@ -471,6 +478,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[rename table(:posts, prefix: "example"), :title, to: :name] assert File.read!(file2) =~ ~S[modify :title, :text, null: true, default: nil] @@ -534,6 +542,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[ALTER INDEX posts_title_index RENAME TO titles_r_unique_dawg] @@ -566,6 +575,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert [file_before, _] = String.split( @@ -601,6 +611,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[add :name, :text, null: false] @@ -627,6 +638,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[rename table(:posts), :title, to: :name] end @@ -652,6 +664,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[add :name, :text, null: false] @@ -680,6 +693,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) # Up migration assert File.read!(file2) =~ ~S[rename table(:posts), :title, to: :subject] @@ -710,6 +724,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[add :subject, :text, null: false] @@ -742,6 +757,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[add :foobar, :text] @@ -784,6 +800,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) file1_content = File.read!(file1) @@ -828,6 +845,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file2) =~ ~S[add :example, :text] <> "\n" @@ -869,7 +887,9 @@ defmodule AshPostgres.MigrationGeneratorTest do end test "when an integer is generated and default nil, it is a bigserial" do - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S[add :id, :bigserial, null: false, primary_key: true] @@ -944,7 +964,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S[references(:posts, column: :id, name: "posts_post_id_fkey", type: :uuid, prefix: "public")] @@ -979,7 +1001,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S[references(:posts, column: :id, name: "posts_post_id_fkey", type: :text, prefix: "public")] @@ -1023,7 +1047,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S{references(:posts, column: :id, with: [related_key_id: :key_id], match: :partial, name: "posts_post_id_fkey", type: :uuid, prefix: "public")} @@ -1067,7 +1093,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S{create index(:posts, [:post_id])} end @@ -1142,7 +1170,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S{create index(:posts, [:org_id, :post_id])} end @@ -1218,7 +1248,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S{references(:users, column: :secondary_id, with: [related_key_id: :key_id, org_id: :org_id], match: :full, name: "user_things_user_id_fkey", type: :uuid, prefix: "public")} @@ -1271,7 +1303,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S{create unique_index(:users, [:name], name: "users_unique_name_index")} @@ -1337,6 +1371,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert file = "test_migration_path/**/*_migrate_resources*.exs" |> Path.wildcard() + |> Enum.reject(&String.contains?(&1, "extensions")) |> Enum.sort() |> Enum.at(1) |> File.read!() @@ -1439,7 +1474,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S{references(:users, column: :secondary_id, with: [org_id: :org_id], match: :full, name: "user_things1_user_id_fkey", type: :uuid, prefix: "public")} @@ -1517,7 +1554,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S @@ -1558,6 +1597,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert file = "test_migration_path/**/*_migrate_resources*.exs" |> Path.wildcard() + |> Enum.reject(&String.contains?(&1, "extensions")) |> Enum.sort() |> Enum.at(0) |> File.read!() @@ -1590,6 +1630,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert file = "test_migration_path/**/*_migrate_resources*.exs" |> Path.wildcard() + |> Enum.reject(&String.contains?(&1, "extensions")) |> Enum.sort() |> Enum.at(1) |> File.read!() @@ -1643,6 +1684,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert file = "test_migration_path/**/*_migrate_resources*.exs" |> Path.wildcard() + |> Enum.reject(&String.contains?(&1, "extensions")) |> Enum.sort() |> Enum.at(1) @@ -1720,7 +1762,9 @@ defmodule AshPostgres.MigrationGeneratorTest do end test "it uses the relationship's table context if it is set" do - assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) assert File.read!(file) =~ ~S[references(:post_comments, column: :id, name: "posts_best_comment_id_fkey", type: :uuid, prefix: "public")] @@ -1771,7 +1815,9 @@ defmodule AshPostgres.MigrationGeneratorTest do format: false ) - assert [file1] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + assert [file1] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) file = File.read!(file1) @@ -1828,7 +1874,9 @@ defmodule AshPostgres.MigrationGeneratorTest do assert log =~ "`{\"xyz\"}`" - assert [file1] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + assert [file1] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) file = File.read!(file1) @@ -1912,6 +1960,7 @@ defmodule AshPostgres.MigrationGeneratorTest do assert [_file1, file2] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) file = File.read!(file2) From e05df6949ae7f40952b24661581f3568275ae7da Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 16 Oct 2024 08:50:03 -0400 Subject: [PATCH 223/690] chore: update tests/deps --- mix.lock | 6 +++--- test/update_test.exs | 31 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 020e7b3d..82b6fa4d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, "ash": {:hex, :ash, "3.4.28", "499c8cf49e406cc5a9b7c6e8e0daae616d2cbd5a02ad421db7932b2972e8badf", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "7faafca1f6b70bf2e72dbabef0d667ee2108923df465878e94f03b2ea8c24fe8"}, + "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, "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.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [: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", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.2", "1e03e44d1b41e91cf39b47d214d515a0d67d44a7fda13ef131bb70bd706dd398", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fc0200fbc6d2784e2f3b9be200ce63e523d0d9ff527c6308490c3d6d325d5e6f"}, "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, - "igniter": {:hex, :igniter, "0.3.52", "b2260226c278cb11864ac2c7d171869aa5fed5a1b350ccedb7ff7020414b04f4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "98682760abca84b87588dfd578db04f575458726a3dbfef09cb2fc24c14cc4ec"}, + "igniter": {:hex, :igniter, "0.3.62", "254ce459354443cf2134c7dc110010b5f46f945fd976c3e529a7f0e38410b89b", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "f64ddad8f66feb6389b4cccde3fa971aed701127ce25aba2db43752a786d364c"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -37,7 +37,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.32", "cb84983c56e57670dd87a7a008a860d6e69626c814b0b5e25194b495ce56c7ba", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "ee5a0a4ddb16ad8f5a792a7b1883498d3090c60101af77a866f76d54962478e8"}, + "spark": {:hex, :spark, "2.2.33", "221e4e3f94296e4aedfc63ba4371328f0cfcbf884c6348eaa8ed636003d0c5c2", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "663bc54574c55d6bfaf40eaa2732a197b42715020cca73a5b1737a4b398997d3"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/update_test.exs b/test/update_test.exs index e67db4ae..4a3ad58c 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -18,8 +18,7 @@ defmodule AshPostgres.UpdateTest do chat_history: [ %{"content" => "Default system prompt", "role" => "system"}, %{ - "content" => - "Here's a collection of tweets from the Twitter list 'Web 3 Mid':\nTweet by KhanAbbas201 (2024-08-26 19:40:13.000000Z):\n@Rahatcodes told me I look good wearing the Eth shirt. https://t.co/xBugAt2tDi\nTweet by Rahatcodes (2024-08-26 19:42:55.000000Z):\n@KhanAbbas201 I dont recall saying this\nTweet by KhanAbbas201 (2024-08-26 19:44:08.000000Z):\n@Rahatcodes Damn what happened to your memory bruv?\nTweet by angelinarusse (2024-08-26 19:56:05.000000Z):\n@dabit3 Real degens call it Twitter\nTweet by angelinarusse (2024-08-26 20:13:58.000000Z):\n@hamseth They tried the same in Afghanistan and it didn’t go well for them.\nTweet by KhanAbbas201 (2024-08-26 20:39:53.000000Z):\nTweet by Osh_mahajan (2024-08-26 21:34:08.000000Z):\n@FedericoNoemie 🐾🐾🦘\nTweet by developer_dao (2024-08-26 21:39:59.000000Z):\n@ZwigoZwitscher @ArweaveEco @k4yls Wildly high praise, ty ty. @k4yls is 🔥 with a 🐶\nTweet by developer_dao (2024-08-26 21:41:17.000000Z):\nRT @ZwigoZwitscher : I've been into @ArweaveEco for years – as an interested outsider – and still learned new things in that course 👇. Thanks…\nTweet by angelin...eet by developer_dao (2024-08-26 22:18:09.000000Z):\nRT @jeremykauffman: BREAKING: France has arrested Gonzalve Bich, the CEO of Bic\nTweet by PatrickAlphaC (2024-08-26 22:26:16.000000Z):\n@oxfav @ar_io_network\n", + "content" => "stuff", "role" => "user" }, %{"content" => "test", "role" => "user"}, @@ -60,4 +59,32 @@ defmodule AshPostgres.UpdateTest do ) |> Ash.update!() end + + test "can unrelate belongs_to" do + author = + AshPostgres.Test.Author + |> Ash.Changeset.for_create(:create, %{first_name: "is", last_name: "match"}) + |> Ash.create!() + + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + assert is_nil(post.author) == false + + post = + post + |> Ash.Changeset.for_update(:update) + |> Ash.Changeset.manage_relationship(:author, author, type: :remove) + |> Ash.update!() + + post + |> Ash.load!(:author) + |> Map.get(:author) + |> IO.inspect() + + assert is_nil(post.author) + end end From bdee388d4c2696d92598c282db92c3fbe460ce04 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 16 Oct 2024 08:55:17 -0400 Subject: [PATCH 224/690] fix: fix resource generator task & tests --- lib/mix/tasks/ash_postgres.gen.resources.ex | 11 +++++++++++ lib/resource_generator/resource_generator.ex | 2 +- test/resource_generator_test.exs | 4 +++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 097a45fe..9cc885ff 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -76,6 +76,17 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do Mix.Project.config()[:app] |> Application.get_env(:ecto_repos, []) + repos = + repos + |> List.wrap() + |> Enum.map(fn v -> + if is_binary(v) do + Igniter.Code.Module.parse(v) + else + v + end + end) + case repos do [] -> igniter diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 103305cb..a4fbdeb4 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -106,7 +106,7 @@ defmodule AshPostgres.ResourceGenerator do |> Ash.Domain.Igniter.add_resource_reference(domain, table_spec.resource) |> Igniter.Project.Module.create_module(table_spec.resource, resource) |> then(fn igniter -> - if opts[:extend] do + if opts[:extend] && opts[:extend] != [] do Igniter.compose_task(igniter, "ash.patch.extend", [ table_spec.resource | opts[:extend] || [] ]) diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index e2b655ed..30a14a1a 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -22,7 +22,9 @@ defmodule AshPostgres.ResourceGeenratorTests do "MyApp.Accounts", "--tables", "example_table", - "--yes" + "--yes", + "--repo", + "AshPostgres.TestRepo" ]) |> assert_creates("lib/my_app/accounts/example_table.ex", """ defmodule MyApp.Accounts.ExampleTable do From 2ea4a0d6c720775c2a71679de81b0ce22a41f9fd Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 16 Oct 2024 08:55:44 -0400 Subject: [PATCH 225/690] chore: release version v2.4.9 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bfb0a7a..01c0576a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline +## [v2.4.9](https://github.com/ash-project/ash_postgres/compare/v2.4.8...v2.4.9) (2024-10-16) + + + + +### Bug Fixes: + +* fix resource generator task & tests + ## [v2.4.8](https://github.com/ash-project/ash_postgres/compare/v2.4.7...v2.4.8) (2024-10-11) diff --git a/mix.exs b/mix.exs index c148b7af..2558ae19 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.8" + @version "2.4.9" def project do [ From af64faa82d81628f479650dbf0df7ef8afc5683e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 16 Oct 2024 08:56:19 -0400 Subject: [PATCH 226/690] chore: remove IO.inspect --- test/update_test.exs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/update_test.exs b/test/update_test.exs index 4a3ad58c..953a55d9 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -83,7 +83,6 @@ defmodule AshPostgres.UpdateTest do post |> Ash.load!(:author) |> Map.get(:author) - |> IO.inspect() assert is_nil(post.author) end From 971295921295c53c17f0bf9ac8a266299a231e3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:09:17 -0400 Subject: [PATCH 227/690] chore(deps): bump the production-dependencies group with 2 updates (#404) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.4.28 to 3.4.32 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.28...v3.4.32) Updates `igniter` from 0.3.62 to 0.3.63 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.3.62...v0.3.63) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 82b6fa4d..b499d628 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.28", "499c8cf49e406cc5a9b7c6e8e0daae616d2cbd5a02ad421db7932b2972e8badf", [: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.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "7faafca1f6b70bf2e72dbabef0d667ee2108923df465878e94f03b2ea8c24fe8"}, + "ash": {:hex, :ash, "3.4.32", "7445f6876491acecf1621ad97434540a360f82fbfeb7c8c4f7971c92c9ae5f91", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "a20224455a842f792d3aeb1fe313dedf619e4ad3d60a583f863b7417f8dc1991"}, "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, "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"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.2", "1e03e44d1b41e91cf39b47d214d515a0d67d44a7fda13ef131bb70bd706dd398", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fc0200fbc6d2784e2f3b9be200ce63e523d0d9ff527c6308490c3d6d325d5e6f"}, "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, - "igniter": {:hex, :igniter, "0.3.62", "254ce459354443cf2134c7dc110010b5f46f945fd976c3e529a7f0e38410b89b", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "f64ddad8f66feb6389b4cccde3fa971aed701127ce25aba2db43752a786d364c"}, + "igniter": {:hex, :igniter, "0.3.63", "ac27c466e6f779cf5f39d200a7d433cd91c8d465277e001661dc9b4680ca9eb3", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "5e24f71479cfd3575f79a767db51de0b38a633f05107b05d94ef1a54fde9093f"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -37,7 +37,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.33", "221e4e3f94296e4aedfc63ba4371328f0cfcbf884c6348eaa8ed636003d0c5c2", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "663bc54574c55d6bfaf40eaa2732a197b42715020cca73a5b1737a4b398997d3"}, + "spark": {:hex, :spark, "2.2.34", "1f0a3bd86d37f86a1d26db4a34d6b0e5fb091940aee25cd40041dab1397c8ada", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "93f94b8f511a72f8764465ea32ff2e5376695f70e747884de2ce64bb6ac22a59"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From c4cc32961612adc9546e8c185f369c572fd9388f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:09:40 -0400 Subject: [PATCH 228/690] chore(deps-dev): bump git_ops in the dev-dependencies group (#405) Bumps the dev-dependencies group with 1 update: [git_ops](https://github.com/zachdaniel/git_ops). Updates `git_ops` from 2.6.2 to 2.6.3 - [Changelog](https://github.com/zachdaniel/git_ops/blob/master/CHANGELOG.md) - [Commits](https://github.com/zachdaniel/git_ops/commits/v2.6.3) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index b499d628..814808be 100644 --- a/mix.lock +++ b/mix.lock @@ -18,7 +18,7 @@ "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "d571628fd829a510d219bcb7162400baff50977f", []}, "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, - "git_ops": {:hex, :git_ops, "2.6.2", "1e03e44d1b41e91cf39b47d214d515a0d67d44a7fda13ef131bb70bd706dd398", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fc0200fbc6d2784e2f3b9be200ce63e523d0d9ff527c6308490c3d6d325d5e6f"}, + "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, "igniter": {:hex, :igniter, "0.3.63", "ac27c466e6f779cf5f39d200a7d433cd91c8d465277e001661dc9b4680ca9eb3", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "5e24f71479cfd3575f79a767db51de0b38a633f05107b05d94ef1a54fde9093f"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, From a9f1a00316def8e2f30ca652a5a074c29ddf7d91 Mon Sep 17 00:00:00 2001 From: skrioify Date: Fri, 18 Oct 2024 13:04:00 +0200 Subject: [PATCH 229/690] fix: race condition compiling migrations when concurrently creating new tenants (#406) --- lib/migration_compile_cache.ex | 38 ++++++++++++++++++++++++++++++++++ lib/multitenancy.ex | 7 ++++++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 lib/migration_compile_cache.ex diff --git a/lib/migration_compile_cache.ex b/lib/migration_compile_cache.ex new file mode 100644 index 00000000..7c79dcc2 --- /dev/null +++ b/lib/migration_compile_cache.ex @@ -0,0 +1,38 @@ +defmodule AshPostgres.MigrationCompileCache do + @moduledoc """ + A cache for the compiled migrations. + + This is used to avoid recompiling the migration files + every time a migration is run, as well as ensuring that + migrations are compiled sequentially. + + This is important because otherwise there is a race condition + where two invocations could be compiling the same migration at + once, which would error out. + """ + + def start_link(opts \\ %{}) do + Agent.start_link(fn -> opts end, name: __MODULE__) + end + + @doc """ + Compile a file, caching the result for future calls. + """ + def compile_file(file) do + Agent.get_and_update(__MODULE__, fn state -> + new_state = ensure_compiled(state, file) + {Map.get(new_state, file), new_state} + end) + end + + defp ensure_compiled(state, file) do + case Map.get(state, file) do + nil -> + compiled = Code.compile_file(file) + Map.put(state, file, compiled) + _ -> + state + end + end + +end diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index ad4bbfbb..2f7fd0db 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -61,7 +61,7 @@ defmodule AshPostgres.MultiTenancy do end defp load_migration!({version, _, file}) when is_binary(file) do - loaded_modules = file |> Code.compile_file() |> Enum.map(&elem(&1, 0)) + loaded_modules = file |> compile_file() |> Enum.map(&elem(&1, 0)) if mod = Enum.find(loaded_modules, &migration?/1) do {version, mod} @@ -70,6 +70,11 @@ defmodule AshPostgres.MultiTenancy do "file #{Path.relative_to_cwd(file)} does not define an Ecto.Migration" end end + + defp compile_file(file) do + AshPostgres.MigrationCompileCache.start_link() + AshPostgres.MigrationCompileCache.compile_file(file) + end defp migration?(mod) do function_exported?(mod, :__migration__, 0) From e3b4e04769594ef57e2742b4123a1f03b0e2a169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Almir=20Saraj=C4=8Di=C4=87?= Date: Fri, 18 Oct 2024 17:38:50 +0200 Subject: [PATCH 230/690] docs: Fix links in documentation (#408) --- CHANGELOG.md | 24 +++++++++---------- README.md | 2 +- .../topics/advanced/manual-relationships.md | 2 +- .../get-started-with-ash-postgres.md | 2 +- lib/functions/trigram_similarity.ex | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01c0576a..ae5bfd73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Change Log All notable changes to this project will be documented in this file. -See [Conventional Commits](Https://conventionalcommits.org) for commit guidelines. +See [Conventional Commits](https://www.conventionalcommits.org) for commit guidelines. @@ -205,13 +205,13 @@ causing nontrivial performance issues at scale. - [`ash_postgres.gen.migration`] dynamically select and allow setting a repo -## [v2.1.17](https://github.com/ash-project/ash_postgres/compare/v2.1.16...v2.1.17) (2024-07-27) +## v2.1.17 (2024-07-27) ### Improvements: - [`ash_sql`] update ash & ash_sql for various fixes -## [v2.1.16](https://github.com/ash-project/ash_postgres/compare/v2.1.15...v2.1.16) (2024-07-25) +## v2.1.16 (2024-07-25) ### Bug Fixes: @@ -273,7 +273,7 @@ causing nontrivial performance issues at scale. - [`mix ash.gen.resource`] pluralize table name in extender -## [v2.1.8](https://github.com/ash-project/ash_postgres/compare/v2.1.7...v2.1.8) (2024-07-17) +## v2.1.8 (2024-07-17) ### Bug Fixes: @@ -287,7 +287,7 @@ causing nontrivial performance issues at scale. - [expressions] add `binding()` expression, for referring to the current table -## [v2.1.7](https://github.com/ash-project/ash_postgres/compare/v2.1.6...v2.1.7) (2024-07-17) +## v2.1.7 (2024-07-17) ### Bug Fixes: @@ -351,13 +351,13 @@ causing nontrivial performance issues at scale. - [query builder] update ash & improve type casting behavior -## [v2.1.1](https://github.com/ash-project/ash_postgres/compare/v2.1.0...v2.1.1) (2024-07-10) +## v2.1.1 (2024-07-10) ### Bug Fixes: - [mix ash_postgres.install] properly interpolate module names in installer -## [v2.1.0](https://github.com/ash-project/ash_postgres/compare/v2.0.12...v2.1.0) (2024-07-10) +## v2.1.0 (2024-07-10) ### Features: @@ -432,7 +432,7 @@ causing nontrivial performance issues at scale. ## [v2.0.8](https://github.com/ash-project/ash_postgres/compare/v2.0.7...v2.0.8) (2024-06-06) -## [v2.0.7](https://github.com/ash-project/ash_postgres/compare/v2.0.6...v2.0.7) (2024-06-06) +## v2.0.7 (2024-06-06) ### Bug Fixes: @@ -440,7 +440,7 @@ causing nontrivial performance issues at scale. - [fix] ensure that all current attribute values are selected on bulk update shifted root query -## [v2.0.6](https://github.com/ash-project/ash_postgres/compare/v2.0.5...v2.0.6) (2024-05-29) +## v2.0.6 (2024-05-29) ### Bug Fixes: @@ -458,7 +458,7 @@ causing nontrivial performance issues at scale. - [mix ash_postgres.squash_snapshots] add `ash_postgres.squash_snapshots` mix task (#302) -## [v2.0.5](https://github.com/ash-project/ash_postgres/compare/v2.0.4...v2.0.5) (2024-05-24) +## v2.0.5 (2024-05-24) ### Improvements: @@ -498,13 +498,13 @@ causing nontrivial performance issues at scale. - [AshPostgres.MigrationGenerator] properly parse previous version from migration generation -## [v2.0.1](https://github.com/ash-project/ash_postgres/compare/v2.0.0...v2.0.1) (2024-05-12) +## v2.0.1 (2024-05-12) ### Bug Fixes: - [AshPostgres.MigrationGenerator] properly parse previous version of custom extensions when generating migrations -## [v2.0.0](https://github.com/ash-project/ash_postgres/compare/v2.0.0...2.0) +## v2.0.0 The changelog is starting over. Please see `/documentation/1.0-CHANGELOG.md` in GitHub for previous changelogs. diff --git a/README.md b/README.md index 2d9bb79d..2e019bde 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![Logo](https://github.com/ash-project/ash/blob/main/logos/cropped-for-header-white-text.png?raw=true#gh-dark-mode-only) ![Elixir CI](https://github.com/ash-project/ash_postgres/workflows/CI/badge.svg) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/MIT) [![Hex version badge](https://img.shields.io/hexpm/v/ash_postgres.svg)](https://hex.pm/packages/ash_postgres) [![Hexdocs badge](https://img.shields.io/badge/docs-hexdocs-purple)](https://hexdocs.pm/ash_postgres) diff --git a/documentation/topics/advanced/manual-relationships.md b/documentation/topics/advanced/manual-relationships.md index ef261c5d..f3b57df4 100644 --- a/documentation/topics/advanced/manual-relationships.md +++ b/documentation/topics/advanced/manual-relationships.md @@ -1,6 +1,6 @@ # Manual Relationships -See [Defining Manual Relationships](https://hexdocs.pm/ash/defining-manual-relationships.html) for an idea of manual relationships in general. +See [Manual Relationships](https://hexdocs.pm/ash/relationships.html#manual-relationships) for an idea of manual relationships in general. Manual relationships allow for expressing complex/non-typical relationships between resources in a standard way. Individual data layers may interact with manual relationships in their own way, so see their corresponding guides. diff --git a/documentation/tutorials/get-started-with-ash-postgres.md b/documentation/tutorials/get-started-with-ash-postgres.md index 4ad0c498..12d88328 100644 --- a/documentation/tutorials/get-started-with-ash-postgres.md +++ b/documentation/tutorials/get-started-with-ash-postgres.md @@ -221,7 +221,7 @@ mix ash.setup ### Try it out -This is based on the [Getting Started](https://hexdocs.pm/ash/getting_started.html) guide. +This is based on the [Get Started](https://hexdocs.pm/ash/get-started.html) guide. If you haven't already, you should read that first. And now we're ready to try it out! Run the following in iex: diff --git a/lib/functions/trigram_similarity.ex b/lib/functions/trigram_similarity.ex index 7987f430..97177ae6 100644 --- a/lib/functions/trigram_similarity.ex +++ b/lib/functions/trigram_similarity.ex @@ -2,7 +2,7 @@ defmodule AshPostgres.Functions.TrigramSimilarity do @moduledoc """ Maps to the builtin postgres trigram similarity function. Requires `pgtrgm` extension to be installed. - See the postgres docs on [trigram](https://www.postgresql.org/docs/9.6/pgtrgm.html]) for more information. + See the postgres docs on [trigram](https://www.postgresql.org/docs/9.6/pgtrgm.html) for more information. Requires the pg_trgm extension. Configure which extensions you have installed in your `AshPostgres.Repo` From d6999d4e80cf0c93607fa62f1eb5fec1ba374dc5 Mon Sep 17 00:00:00 2001 From: Ethan Dang Date: Sun, 20 Oct 2024 16:39:43 +0700 Subject: [PATCH 231/690] doc: Fix migration path for tenant migration (#409) --- .../topics/development/migrations-and-tasks.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/documentation/topics/development/migrations-and-tasks.md b/documentation/topics/development/migrations-and-tasks.md index 619dded2..a9d6b951 100644 --- a/documentation/topics/development/migrations-and-tasks.md +++ b/documentation/topics/development/migrations-and-tasks.md @@ -68,13 +68,8 @@ Tasks that need to be executed in the released application (because mix is not p load_app() for repo <- repos() do - repo_name = repo |> Module.split() |> List.last() |> Macro.underscore() - - path = - "priv/" - |> Path.join(repo_name) - |> Path.join("tenant_migrations") - # This may be different for you if you are not using the default tenant migrations + path = Ecto.Migrator.migrations_path(repo, "tenant_migrations") + # This may be different for you if you are not using the default tenant migrations {:ok, _, _} = Ecto.Migrator.with_repo( @@ -103,13 +98,9 @@ Tasks that need to be executed in the released application (because mix is not p # only needed if you are using postgres multitenancy def rollback_tenants(repo, version) do load_app() - repo_name = repo |> Module.split() |> List.last() |> Macro.underscore() - path = - "priv/" - |> Path.join(repo_name) - |> Path.join("tenant_migrations") - # This may be different for you if you are not using the default tenant migrations + path = Ecto.Migrator.migrations_path(repo, "tenant_migrations") + # This may be different for you if you are not using the default tenant migrations for tenant <- repo.all_tenants() do {:ok, _, _} = From 1228fcd851f29a68609e236f7d6a2622a4b5c4ba Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 22 Oct 2024 22:11:13 -0400 Subject: [PATCH 232/690] fix: run any query that could produce errors when performing atomic upgrade --- lib/data_layer.ex | 12 +++++++++++- lib/mix/tasks/ash_postgres.gen.resources.ex | 4 ++-- lib/mix/tasks/ash_postgres.install.ex | 2 +- mix.lock | 8 ++++---- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 34c17d9f..06c05037 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1358,6 +1358,16 @@ defmodule AshPostgres.DataLayer do :empty -> if options[:return_records?] do if changeset.context[:data_layer][:use_atomic_update_data?] do + case query.__ash_bindings__ do + %{expression_accumulator: %AshSql.Expr.ExprInfo{has_error?: true}} -> + # if the query could produce an error + # we must run it even if we will just be returning the original data. + repo.all(query) + + _ -> + :ok + end + {:ok, [changeset.data]} else {:ok, repo.all(query)} @@ -3021,7 +3031,7 @@ defmodule AshPostgres.DataLayer do Igniter.Project.Module.module_name(igniter, "Repo") repo -> - Igniter.Code.Module.parse(repo) + Igniter.Project.Module.parse(repo) end igniter diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 9cc885ff..6816117a 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -67,7 +67,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do {%{domain: domain}, argv} = positional_args!(argv) - domain = Igniter.Code.Module.parse(domain) + domain = Igniter.Project.Module.parse(domain) options = options!(argv) @@ -81,7 +81,7 @@ defmodule Mix.Tasks.AshPostgres.Gen.Resources do |> List.wrap() |> Enum.map(fn v -> if is_binary(v) do - Igniter.Code.Module.parse(v) + Igniter.Project.Module.parse(v) else v end diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 3171929a..280e7f20 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -29,7 +29,7 @@ defmodule Mix.Tasks.AshPostgres.Install do Igniter.Project.Module.module_name(igniter, "Repo") repo -> - Igniter.Code.Module.parse(repo) + Igniter.Project.Module.parse(repo) end otp_app = Igniter.Project.Application.app_name(igniter) diff --git a/mix.lock b/mix.lock index 814808be..ec6f2170 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.32", "7445f6876491acecf1621ad97434540a360f82fbfeb7c8c4f7971c92c9ae5f91", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "a20224455a842f792d3aeb1fe313dedf619e4ad3d60a583f863b7417f8dc1991"}, + "ash": {:hex, :ash, "3.4.35", "0e27cd577809e4fda01df86c0e48e93ba6d02618b6b173b1d182d557f693358c", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "77b091ba74a7a788348716f1dcaa350c18439b2d714926a6f8a5c394c2015751"}, "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, "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"}, @@ -19,8 +19,8 @@ "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, - "glob_ex": {:hex, :glob_ex, "0.1.9", "b97a25392f5339e49f587e5b24c468c6a4f38299febd5ec85c5f8bb2e42b5c1e", [:mix], [], "hexpm", "be72e584ad1d8776a4d134d4b6da1bac8b80b515cdadf0120e0920b9978d7f01"}, - "igniter": {:hex, :igniter, "0.3.63", "ac27c466e6f779cf5f39d200a7d433cd91c8d465277e001661dc9b4680ca9eb3", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "5e24f71479cfd3575f79a767db51de0b38a633f05107b05d94ef1a54fde9093f"}, + "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, + "igniter": {:hex, :igniter, "0.3.72", "f7c4ddeb369c5cba2725ac28b20a00202186415d0176f7727422d98d093e7004", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "2fbe74116ed9e539901f0255cb9ebffdc11411620851d2a933e3ee18c68df62c"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -37,7 +37,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, - "spark": {:hex, :spark, "2.2.34", "1f0a3bd86d37f86a1d26db4a34d6b0e5fb091940aee25cd40041dab1397c8ada", [:mix], [{:igniter, ">= 0.3.36 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "93f94b8f511a72f8764465ea32ff2e5376695f70e747884de2ce64bb6ac22a59"}, + "spark": {:hex, :spark, "2.2.35", "1c0bb30f340151eca24164885935de39e6ada4010555f444c813d0488990f8f3", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "f242d6385c287389034a0e146d8f025b5c9ab777f1ae5cf0fdfc9209db6ae748"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 0570dccd5fd183eb24dfe21e6cb24402da018ac9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 22 Oct 2024 22:18:00 -0400 Subject: [PATCH 233/690] fix: when an atomic update is fully skipped, run the query if it could produce errors --- README.md | 2 +- ...-AshPostgres.DataLayer.md => DSL-AshPostgres.DataLayer.md} | 0 lib/migration_compile_cache.ex | 4 ++-- lib/multitenancy.ex | 2 +- mix.exs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename documentation/dsls/{DSL:-AshPostgres.DataLayer.md => DSL-AshPostgres.DataLayer.md} (100%) diff --git a/README.md b/README.md index 2e019bde..da0136ae 100644 --- a/README.md +++ b/README.md @@ -37,4 +37,4 @@ Welcome! `AshPostgres` is the PostgreSQL data layer for [Ash Framework](https:// ## Reference -- [AshPostgres.DataLayer DSL](documentation/dsls/DSL:-AshPostgres.DataLayer.md) +- [AshPostgres.DataLayer DSL](documentation/dsls/DSL-AshPostgres.DataLayer.md) diff --git a/documentation/dsls/DSL:-AshPostgres.DataLayer.md b/documentation/dsls/DSL-AshPostgres.DataLayer.md similarity index 100% rename from documentation/dsls/DSL:-AshPostgres.DataLayer.md rename to documentation/dsls/DSL-AshPostgres.DataLayer.md diff --git a/lib/migration_compile_cache.ex b/lib/migration_compile_cache.ex index 7c79dcc2..c8f9108a 100644 --- a/lib/migration_compile_cache.ex +++ b/lib/migration_compile_cache.ex @@ -19,7 +19,7 @@ defmodule AshPostgres.MigrationCompileCache do Compile a file, caching the result for future calls. """ def compile_file(file) do - Agent.get_and_update(__MODULE__, fn state -> + Agent.get_and_update(__MODULE__, fn state -> new_state = ensure_compiled(state, file) {Map.get(new_state, file), new_state} end) @@ -30,9 +30,9 @@ defmodule AshPostgres.MigrationCompileCache do nil -> compiled = Code.compile_file(file) Map.put(state, file, compiled) + _ -> state end end - end diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 2f7fd0db..fbae77fe 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -70,7 +70,7 @@ defmodule AshPostgres.MultiTenancy do "file #{Path.relative_to_cwd(file)} does not define an Ecto.Migration" end end - + defp compile_file(file) do AshPostgres.MigrationCompileCache.start_link() AshPostgres.MigrationCompileCache.compile_file(file) diff --git a/mix.exs b/mix.exs index 2558ae19..9826789a 100644 --- a/mix.exs +++ b/mix.exs @@ -97,7 +97,7 @@ defmodule AshPostgres.MixProject do "documentation/topics/advanced/expressions.md", "documentation/topics/advanced/schema-based-multitenancy.md", "documentation/topics/advanced/manual-relationships.md", - "documentation/dsls/DSL:-AshPostgres.DataLayer.md", + "documentation/dsls/DSL-AshPostgres.DataLayer.md", "CHANGELOG.md" ], groups_for_extras: [ From fe62a09d7bd77f84ada3edd2e8978432ee0bbebb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 22 Oct 2024 22:19:13 -0400 Subject: [PATCH 234/690] chore: release version v2.4.10 --- CHANGELOG.md | 13 +++++++++++++ mix.exs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae5bfd73..17d611ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.10](https://github.com/ash-project/ash_postgres/compare/v2.4.9...v2.4.10) (2024-10-23) + + + + +### Bug Fixes: + +* when an atomic update is fully skipped, run the query if it could produce errors + +* run any query that could produce errors when performing atomic upgrade + +* race condition compiling migrations when concurrently creating new tenants (#406) + ## [v2.4.9](https://github.com/ash-project/ash_postgres/compare/v2.4.8...v2.4.9) (2024-10-16) diff --git a/mix.exs b/mix.exs index 9826789a..54405e26 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.9" + @version "2.4.10" def project do [ From c7aa5f6a1b583436bb671b4064e5759cf57ada21 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 23 Oct 2024 09:19:40 -0400 Subject: [PATCH 235/690] fix: ensure repo_opts is passed through to `repo.all/2` --- lib/data_layer.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 06c05037..5c7acead 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1362,7 +1362,7 @@ defmodule AshPostgres.DataLayer do %{expression_accumulator: %AshSql.Expr.ExprInfo{has_error?: true}} -> # if the query could produce an error # we must run it even if we will just be returning the original data. - repo.all(query) + repo.all(query, repo_opts) _ -> :ok @@ -1370,7 +1370,7 @@ defmodule AshPostgres.DataLayer do {:ok, [changeset.data]} else - {:ok, repo.all(query)} + {:ok, repo.all(query, repo_opts)} end else :ok From b49bc8f3aebb4223f5a2a076a5f2d397e0dc3801 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 23 Oct 2024 09:19:59 -0400 Subject: [PATCH 236/690] chore: release version v2.4.11 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17d611ac..ec27bf6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.11](https://github.com/ash-project/ash_postgres/compare/v2.4.10...v2.4.11) (2024-10-23) + + + + +### Bug Fixes: + +* ensure repo_opts is passed through to `repo.all/2` + ## [v2.4.10](https://github.com/ash-project/ash_postgres/compare/v2.4.9...v2.4.10) (2024-10-23) diff --git a/mix.exs b/mix.exs index 54405e26..fed5bde9 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.10" + @version "2.4.11" def project do [ From 48a80297601416c2f0988203819e97ae1a5a3c2f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 23 Oct 2024 09:22:55 -0400 Subject: [PATCH 237/690] Create SECURITY.md --- SECURITY.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..87d03b8b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +This is a copy of the security policy in the core Ash repo. That is the authoritative source. + +[![OpenSSF Vulnerability Disclosure](https://img.shields.io/badge/OpenSSF-Vulnerability_Disclosure-green)](https://github.com/ossf/oss-vulnerability-guide/blob/main/finder-guide.md) +[![GitHub Report](https://img.shields.io/badge/GitHub-Security_Advisories-blue)](https://github.com/ash-project/ash/security/advisories/new) +[![Email Report](https://img.shields.io/badge/Email-security%40ash--hq.org-blue)](mailto:security@ash-hq.org) + +This repository follows the [OpenSSF Vulnerability Disclosure guide](https://github.com/ossf/oss-vulnerability-guide/tree/main). You can learn more about it in the [Finders Guide](https://github.com/ossf/oss-vulnerability-guide/blob/main/finder-guide.md). + +Please report vulnerabilities via the [GitHub Security Vulnerability Reporting](https://github.com/ash-project/ash/security/advisories/new) +or via email to [`security@ash-hq.org`](mailto:security@ash-hq.org) if this does not work for you. + +Someone from the core team respond within 3 working days of your +report. If the issue is confirmed as a vulnerability, we will open a Security +Advisory. This project follows a 90 day disclosure timeline. + +If you have questions about reporting security issues, email the vulnerability +management team: [`security@erlef.org`](mailto:security@erlef.org) From 802d5b2b2769f062ac003414ee4b49ebb463f581 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 23 Oct 2024 11:42:23 -0400 Subject: [PATCH 238/690] test: add test confirming fix for GHSA-hf59-7rwq-785m docs: illustrate where the fix occurred in the changelog --- CHANGELOG.md | 79 ++++++------------- ...ic_non_bulk_actions_policy_bypass_test.exs | 27 +++++++ test/support/domain.ex | 1 + .../resources/post_with_empty_update.ex | 41 ++++++++++ 4 files changed, 94 insertions(+), 54 deletions(-) create mode 100644 test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs create mode 100644 test/support/resources/post_with_empty_update.ex diff --git a/CHANGELOG.md b/CHANGELOG.md index ec27bf6a..bbd0d4d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,130 +7,101 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide ## [v2.4.11](https://github.com/ash-project/ash_postgres/compare/v2.4.10...v2.4.11) (2024-10-23) - - - ### Bug Fixes: -* ensure repo_opts is passed through to `repo.all/2` +- ensure repo_opts is passed through to `repo.all/2` ## [v2.4.10](https://github.com/ash-project/ash_postgres/compare/v2.4.9...v2.4.10) (2024-10-23) +## Security - +- Patch of [GHSA-hf59-7rwq-785m](https://github.com/ash-project/ash_postgres/security/advisories/GHSA-hf59-7rwq-785m) Empty, atomic, non-bulk actions, policy bypass for side-effects vulnerability. ### Bug Fixes: -* when an atomic update is fully skipped, run the query if it could produce errors +- when an atomic update is fully skipped, run the query if it could produce errors -* run any query that could produce errors when performing atomic upgrade +- run any query that could produce errors when performing atomic upgrade -* race condition compiling migrations when concurrently creating new tenants (#406) +- race condition compiling migrations when concurrently creating new tenants (#406) ## [v2.4.9](https://github.com/ash-project/ash_postgres/compare/v2.4.8...v2.4.9) (2024-10-16) - - - ### Bug Fixes: -* fix resource generator task & tests +- fix resource generator task & tests ## [v2.4.8](https://github.com/ash-project/ash_postgres/compare/v2.4.7...v2.4.8) (2024-10-11) - - - ### Improvements: -* use the `name` parameter when generating migrations +- use the `name` parameter when generating migrations ## [v2.4.7](https://github.com/ash-project/ash_postgres/compare/v2.4.6...v2.4.7) (2024-10-10) - - - ### Improvements: -* adapt to fixes and optimizations around skipped upserts in ash core +- adapt to fixes and optimizations around skipped upserts in ash core ## [v2.4.6](https://github.com/ash-project/ash_postgres/compare/v2.4.5...v2.4.6) (2024-10-07) - - - ### Improvements: -* with `--yes` assume oldest version +- with `--yes` assume oldest version ## [v2.4.5](https://github.com/ash-project/ash_postgres/compare/v2.4.4...v2.4.5) (2024-10-06) - - - ### Bug Fixes: -* ensure upsert fields are uniq +- ensure upsert fields are uniq ### Improvements: -* detect 1 arg repo use in installer +- detect 1 arg repo use in installer -* support to_ecto(%Ecto.Changeset{}) and from_ecto(%Ecto.Changeset{}) (#395) +- support to_ecto(%Ecto.Changeset{}) and from_ecto(%Ecto.Changeset{}) (#395) ## [v2.4.4](https://github.com/ash-project/ash_postgres/compare/v2.4.3...v2.4.4) (2024-09-29) - - - ### Bug Fixes: -* handle atomic array operations +- handle atomic array operations ## [v2.4.3](https://github.com/ash-project/ash_postgres/compare/v2.4.2...v2.4.3) (2024-09-27) - - - ### Bug Fixes: -* support pg <= 14 in resource generator, and update tests +- support pg <= 14 in resource generator, and update tests ## [v2.4.2](https://github.com/ash-project/ash_postgres/compare/v2.4.1...v2.4.2) (2024-09-24) - - - ### Bug Fixes: -* typo of `biging` -> `bigint` +- typo of `biging` -> `bigint` -* altering attributes not properly generating foreign keys in some cases +- altering attributes not properly generating foreign keys in some cases -* installer: use correct module name in the `DataCase` moduledocs. (#393) +- installer: use correct module name in the `DataCase` moduledocs. (#393) -* trim input before passing to `String.to_integer/1`. (#389) +- trim input before passing to `String.to_integer/1`. (#389) ### Improvements: -* add `--repo` option to installer, and warn on clashing existing repo +- add `--repo` option to installer, and warn on clashing existing repo -* prompt for minimum pg version +- prompt for minimum pg version -* adjust mix task aliases to be used with `ash_postgres` +- adjust mix task aliases to be used with `ash_postgres` -* set a name for generated migrations +- set a name for generated migrations ## [v2.4.1](https://github.com/ash-project/ash_postgres/compare/v2.4.0...v2.4.1) (2024-09-16) - - - ### Bug Fixes: -* ensure that returning is not an empty list +- ensure that returning is not an empty list -* match on table schema as well as table name +- match on table schema as well as table name ## [v2.4.0](https://github.com/ash-project/ash_postgres/compare/v2.3.1...v2.4.0) (2024-09-13) diff --git a/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs new file mode 100644 index 00000000..5863f499 --- /dev/null +++ b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs @@ -0,0 +1,27 @@ +defmodule AshPostgres.EmptyAtomicNonBulkActionsPolicyBypassTest do + @moduledoc """ + This is test verifies the fix for the following CVE: + + https://github.com/ash-project/ash_postgres/security/advisories/GHSA-hf59-7rwq-785m + """ + use AshPostgres.RepoCase, async: false + + alias AshPostgres.Test.PostWithEmptyUpdate + + require Ash.Query + + test "a forbidden error is appropriately raised on atomic upgraded, empty, non-bulk actions" do + post = + PostWithEmptyUpdate + |> Ash.Changeset.for_create(:create, %{}) + |> Ash.create!() + + Logger.configure(level: :debug) + + assert_raise Ash.Error.Forbidden, fn -> + post + |> Ash.Changeset.for_update(:empty_update, %{}, authorize?: true) + |> Ash.update!() + end + end +end diff --git a/test/support/domain.ex b/test/support/domain.ex index 353ca4d6..a571efb9 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -22,6 +22,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Record) resource(AshPostgres.Test.PostFollower) resource(AshPostgres.Test.StatefulPostFollower) + resource(AshPostgres.Test.PostWithEmptyUpdate) end authorization do diff --git a/test/support/resources/post_with_empty_update.ex b/test/support/resources/post_with_empty_update.ex new file mode 100644 index 00000000..fcc1bace --- /dev/null +++ b/test/support/resources/post_with_empty_update.ex @@ -0,0 +1,41 @@ +defmodule AshPostgres.Test.PostWithEmptyUpdate do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [ + Ash.Policy.Authorizer + ] + + require Ash.Sort + + policies do + policy action(:empty_update) do + # force visiting the database + authorize_if(expr(fragment("TRUE = FALSE"))) + end + end + + postgres do + table("posts") + repo(AshPostgres.TestRepo) + migrate? false + end + + actions do + defaults([:create, :read]) + + update :empty_update do + accept([]) + end + end + + attributes do + uuid_primary_key(:id, writable?: true) + + attribute(:title, :string) do + public?(true) + source(:title_column) + end + end +end From 4b939b5ec8a3fe65ccbb08ab17d3f65e281a2c58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 08:52:22 -0400 Subject: [PATCH 239/690] chore(deps): bump the production-dependencies group with 3 updates (#410) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [igniter](https://github.com/ash-project/igniter) and [postgrex](https://github.com/elixir-ecto/postgrex). Updates `ash` from 3.4.35 to 3.4.36 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.35...v3.4.36) Updates `igniter` from 0.3.72 to 0.3.73 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.3.72...v0.3.73) Updates `postgrex` from 0.19.1 to 0.19.2 - [Release notes](https://github.com/elixir-ecto/postgrex/releases) - [Changelog](https://github.com/elixir-ecto/postgrex/blob/master/CHANGELOG.md) - [Commits](https://github.com/elixir-ecto/postgrex/compare/v0.19.1...v0.19.2) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: postgrex dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index ec6f2170..d4f89a6c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.35", "0e27cd577809e4fda01df86c0e48e93ba6d02618b6b173b1d182d557f693358c", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "77b091ba74a7a788348716f1dcaa350c18439b2d714926a6f8a5c394c2015751"}, + "ash": {:hex, :ash, "3.4.36", "a5987bbdc86e8e7dbe28cf470ad0a33d6240869e842101471da2ffb7b84c8a27", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "22075b11e1873c4a7cc8548bc477187143bbae3cbcc1e890bfc3aecf4ca493a4"}, "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, "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"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, - "igniter": {:hex, :igniter, "0.3.72", "f7c4ddeb369c5cba2725ac28b20a00202186415d0176f7727422d98d093e7004", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "2fbe74116ed9e539901f0255cb9ebffdc11411620851d2a933e3ee18c68df62c"}, + "igniter": {:hex, :igniter, "0.3.73", "4ce625f586fc793067fd2bb7c96a422833fb5b5a6a4f836372054ac607cdc858", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "304baa473923f27834c8c7542e624341d2baac66ba5c5d26b57239ee9bc54032"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -31,7 +31,7 @@ "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, - "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, + "postgrex": {:hex, :postgrex, "0.19.2", "34d6884a332c7bf1e367fc8b9a849d23b43f7da5c6e263def92784d03f9da468", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "618988886ab7ae8561ebed9a3c7469034bf6a88b8995785a3378746a4b9835ec"}, "reactor": {:hex, :reactor, "0.10.0", "1206113c21ba69b889e072b2c189c05a7aced523b9c3cb8dbe2dab7062cb699a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4003c33e4c8b10b38897badea395e404d74d59a31beb30469a220f2b1ffe6457"}, "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, From aff40b05178e1ee88c37732d0662250ed7e05e1e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 26 Oct 2024 09:59:14 -0400 Subject: [PATCH 240/690] docs: add example of recursive relationship --- .../topics/advanced/manual-relationships.md | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/documentation/topics/advanced/manual-relationships.md b/documentation/topics/advanced/manual-relationships.md index f3b57df4..47e90e54 100644 --- a/documentation/topics/advanced/manual-relationships.md +++ b/documentation/topics/advanced/manual-relationships.md @@ -85,3 +85,187 @@ defmodule Helpdesk.Support.Ticket.Relationships.TicketsAboveThreshold do end end ``` + +## Recursive Relationships + +Manual relationships can be _very_ powerful, as they can leverage the full power of Ecto to do arbitrarily complex things. +Here is an example of a recursive relationship that loads all employees under the purview of a given manager using a recursive CTE. + +> ### Use ltree {: .info} +> +> While the below is very powerful, if at all possible we suggest using ltree for hierarchical data. Its built in to postgres +> and AshPostgres has built in support for it. For more, see: `AshPostgres.Ltree`. + +Keep in mind this is an example of a very advanced use case, _not_ something you'd typically need to do. + +```elixir +defmodule MyApp.Employee.ManagedEmployees do + @moduledoc """ + A manual relationship which uses a recursive CTE to find all employees managed by a given employee. + """ + + use Ash.Resource.ManualRelationship + use AshPostgres.ManualRelationship + alias MyApp.Employee + alias MyApp.Repo + import Ecto.Query + + @doc false + @impl true + @spec load([Employee.t()], keyword, map) :: + {:ok, %{Ash.UUID.t() => [Employee.t()]}} | {:error, any} + def load(employees, _opts, _context) do + employee_ids = Enum.map(employees, & &1.id) + + all_descendants = + Employee + |> where([l], l.manager_id in ^employee_ids) + |> recursive_cte_query("employee_tree", Employee) + |> Repo.all() + + employees + |> with_descendants(all_descendants) + |> Map.new(&{&1.id, &1.descendants}) + |> then(&{:ok, &1}) + end + + defp with_descendants([], _), do: [] + + defp with_descendants(employees, all_descendants) do + Enum.map(employees, fn employee -> + descendants = Map.get(all_descendants, employee.id, []) + + %{employee | descendants: with_descendants(descendants, all_descendants)} + end) + end + + @doc false + @impl true + @spec ash_postgres_join( + Ecto.Query.t(), + opts :: keyword, + current_binding :: any, + as_binding :: any, + :inner | :left, + Ecto.Query.t() + ) :: + {:ok, Ecto.Query.t()} | {:error, any} + # Add a join from some binding in the query, producing *as_binding*. + def ash_postgres_join(query, _opts, current_binding, as_binding, join_type, destination_query) do + immediate_parents = + from(destination in destination_query, + where: parent_as(^current_binding).manager_id == destination.id + ) + + cte_name = "employees_#{as_binding}" + + descendant_query = + recursive_cte_query_for_join( + immediate_parents, + cte_name, + destination_query + ) + + case join_type do + :inner -> + {:ok, + from(row in query, + inner_lateral_join: descendant in subquery(descendant_query), + on: true, + as: ^as_binding + )} + + :left -> + {:ok, + from(row in query, + left_lateral_join: descendant in subquery(descendant_query), + on: true, + as: ^as_binding + )} + end + end + + @impl true + @spec ash_postgres_subquery(keyword, any, any, Ecto.Query.t()) :: + {:ok, Ecto.Query.t()} | {:error, any} + # Produce a subquery using which will use the given binding and will be + def ash_postgres_subquery(_opts, current_binding, as_binding, destination_query) do + immediate_descendants = + from(destination in Employee, + where: parent_as(^current_binding).id == destination.manager_id + ) + + cte_name = "employees_#{as_binding}" + + recursive_cte_query = + recursive_cte_query_for_join( + immediate_descendants, + cte_name, + Employee + ) + + other_query = + from(row in subquery(recursive_cte_query), + where: + row.id in subquery( + from(row in Ecto.Query.exclude(destination_query, :select), select: row.id) + ) + ) + + {:ok, other_query} + end + + defp recursive_cte_query(immediate_parents, cte_name, query) do + recursion_query = + query + |> join(:inner, [l], lt in ^cte_name, on: l.manager_id == lt.id) + + descendants_query = + immediate_parents + |> union(^recursion_query) + + {cte_name, Employee} + |> recursive_ctes(true) + |> with_cte(^cte_name, as: ^descendants_query) + end + + defp recursive_cte_query_for_join(immediate_parents, cte_name, query) do + # This is due to limitations in ecto's recursive CTE implementation + # For more, see here: + # https://elixirforum.com/t/ecto-cte-queries-without-a-prefix/33148/2 + # https://stackoverflow.com/questions/39458572/ecto-declare-schema-for-a-query + employee_keys = Employee.__schema__(:fields) + + cte_name = + from(cte in fragment("?", literal(^cte_name)), select: map(cte, ^employee_keys)) + + recursion_query = + query + |> join(:inner, [l], lt in ^cte_name, on: l.manager_id == lt.id) + + descendants_query = + immediate_parents + |> union(^recursion_query) + + cte_name + |> recursive_ctes(true) + |> with_cte(^cte_name, as: ^descendants_query) + end +end +``` + +With the above definition, employees could have a relationship like this: + +```elixir +has_many :managed_employees, MyApp.Employee do + manual MyApp.Employee.ManagedEmployees +end +``` + +And you could then use it in calculations and aggregates! For example, to see the count of employees managed by each employee: + +```elixir +aggregates do + count :count_of_managed_employees, :managed_employees +end +``` From 879c8f1e27e39b8899475d7d4dfcb811eae6b873 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 26 Oct 2024 10:14:26 -0400 Subject: [PATCH 241/690] fix: don't use `cast` for changes --- lib/data_layer.ex | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 5c7acead..1941398a 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2078,7 +2078,8 @@ defmodule AshPostgres.DataLayer do record |> to_ecto() |> set_table(changeset, type, table_error?) - |> Ecto.Changeset.change(Map.take(changeset.attributes, attributes_to_change)) + |> Ecto.Changeset.cast(%{}, []) + |> force_changes(Map.take(changeset.attributes, attributes_to_change)) |> add_configured_foreign_key_constraints(record.__struct__) |> add_unique_indexes(record.__struct__, changeset) |> add_check_constraints(record.__struct__) @@ -2100,6 +2101,12 @@ defmodule AshPostgres.DataLayer do end end + defp force_changes(changeset, changes) do + Enum.reduce(changes, changeset, fn {key, value}, changeset -> + Ecto.Changeset.force_change(changeset, key, value) + end) + end + defp handle_raised_error( %Ecto.StaleEntryError{changeset: %{data: %resource{}, filters: filters}}, stacktrace, From d861ce0c7720b0edc1e10110d929f3dc396d0689 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 27 Oct 2024 14:59:21 -0400 Subject: [PATCH 242/690] improvement: support prefer_transaction? --- lib/data_layer.ex | 22 +++++++++++++++---- lib/repo.ex | 7 ++++++ ...ic_non_bulk_actions_policy_bypass_test.exs | 2 -- test/support/test_repo.ex | 2 ++ test/test_helper.exs | 2 +- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 1941398a..a16267ea 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -605,6 +605,11 @@ defmodule AshPostgres.DataLayer do import Ecto.Query, only: [from: 2, subquery: 1] + @impl true + def prefer_transaction?(resource) do + AshPostgres.DataLayer.Info.repo(resource, :mutate).prefer_transaction?() + end + @impl true def can?(_, :async_engine), do: true def can?(_, :bulk_create), do: true @@ -1773,7 +1778,12 @@ defmodule AshPostgres.DataLayer do |> AshSql.Bindings.default_bindings(resource, AshPostgres.SqlImplementation) upsert_set = - upsert_set(resource, changesets, options) + upsert_set( + resource, + changesets, + options[:upsert_keys] || Ash.Resource.Info.primary_key(resource), + options + ) on_conflict = case AshSql.Atomics.query_with_atomics( @@ -1785,7 +1795,11 @@ defmodule AshPostgres.DataLayer do upsert_set ) do :empty -> - {:replace, options[:upsert_keys] || Ash.Resource.Info.primary_key(resource)} + if options[:return_records?] do + {:replace, options[:upsert_keys] || Ash.Resource.Info.primary_key(resource)} + else + :nothing + end {:ok, query} -> query @@ -1913,7 +1927,7 @@ defmodule AshPostgres.DataLayer do fun.() end - defp upsert_set(resource, changesets, options) do + defp upsert_set(resource, changesets, keys, options) do attributes_changing_anywhere = changesets |> Enum.flat_map(&Map.keys(&1.attributes)) |> Enum.uniq() @@ -1926,7 +1940,7 @@ defmodule AshPostgres.DataLayer do fields_to_upsert = upsert_fields -- - Keyword.keys(Enum.at(changesets, 0).atomics) + Keyword.keys(Enum.at(changesets, 0).atomics) -- keys fields_to_upsert |> Enum.uniq() diff --git a/lib/repo.ex b/lib/repo.ex index b9b2290f..38c33601 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -69,6 +69,9 @@ defmodule AshPostgres.Repo do @doc "The default prefix(postgres schema) to use when building queries" @callback default_prefix() :: String.t() + @doc "Whether or not to explicitly start and close a transaction for each action, even if there are no transaction hooks" + @callback prefer_transaction?() :: boolean + @doc "Allows overriding a given migration type for *all* fields, for example if you wanted to always use :timestamptz for :utc_datetime fields" @callback override_migration_type(atom) :: atom @doc "Should the repo should be created by `mix ash_postgres.create`?" @@ -102,6 +105,9 @@ defmodule AshPostgres.Repo do def create?, do: true def drop?, do: true + # default to false in 4.0 + def prefer_transaction?, do: true + def transaction!(fun) do case fun.() do {:ok, value} -> value @@ -242,6 +248,7 @@ defmodule AshPostgres.Repo do on_transaction_begin: 1, installed_extensions: 0, all_tenants: 0, + prefer_transaction?: 0, tenant_migrations_path: 0, default_prefix: 0, override_migration_type: 1, diff --git a/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs index 5863f499..8b204f25 100644 --- a/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs +++ b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs @@ -16,8 +16,6 @@ defmodule AshPostgres.EmptyAtomicNonBulkActionsPolicyBypassTest do |> Ash.Changeset.for_create(:create, %{}) |> Ash.create!() - Logger.configure(level: :debug) - assert_raise Ash.Error.Forbidden, fn -> post |> Ash.Changeset.for_update(:empty_update, %{}, authorize?: true) diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index c272a2e5..999e928e 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -7,6 +7,8 @@ defmodule AshPostgres.TestRepo do send(self(), data) end + def prefer_transaction?, do: false + def installed_extensions do ["ash-functions", "uuid-ossp", "pg_trgm", "citext", AshPostgres.TestCustomExtension, "ltree"] -- Application.get_env(:ash_postgres, :no_extensions, []) diff --git a/test/test_helper.exs b/test/test_helper.exs index 5b02474b..23858cfd 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,4 @@ -ExUnit.start(capture_log: true) +ExUnit.start(capture_log: false) exclude_tags = case System.get_env("PG_VERSION") do From 60ce92433804a792337e4552dd03613f884a702e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 27 Oct 2024 19:40:45 -0400 Subject: [PATCH 243/690] improvement: add prefer_transaction_for_atomic_updates?/1 --- lib/data_layer.ex | 17 +++++++++--- lib/repo.ex | 14 ++++++++-- test/atomics_test.exs | 54 +++++++++++++++++++-------------------- test/support/test_repo.ex | 4 ++- test/test_helper.exs | 2 +- test/upsert_test.exs | 32 +++++++++++++++++++++++ 6 files changed, 88 insertions(+), 35 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index a16267ea..002f4c0c 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -610,6 +610,11 @@ defmodule AshPostgres.DataLayer do AshPostgres.DataLayer.Info.repo(resource, :mutate).prefer_transaction?() end + @impl true + def prefer_transaction_for_atomic_updates?(resource) do + AshPostgres.DataLayer.Info.repo(resource, :mutate).prefer_transaction_for_atomic_updates?() + end + @impl true def can?(_, :async_engine), do: true def can?(_, :bulk_create), do: true @@ -1515,22 +1520,25 @@ defmodule AshPostgres.DataLayer do query.limit || query.offset -> with {:ok, root_query} <- AshSql.Atomics.select_atomics(resource, root_query, atomics) do - {:ok, from(row in Ecto.Query.subquery(root_query), []), atomics != []} + {:ok, from(row in Ecto.Query.subquery(root_query), []), + root_query.__ash_bindings__.expression_accumulator, atomics != []} end !Enum.empty?(query.joins) || has_exists? -> with root_query <- Ecto.Query.exclude(root_query, :order_by), {:ok, root_query} <- AshSql.Atomics.select_atomics(resource, root_query, atomics) do - {:ok, from(row in Ecto.Query.subquery(root_query), []), atomics != []} + {:ok, from(row in Ecto.Query.subquery(root_query), []), + root_query.__ash_bindings__.expression_accumulator, atomics != []} end true -> - {:ok, Ecto.Query.exclude(root_query, :order_by), false} + {:ok, Ecto.Query.exclude(root_query, :order_by), + root_query.__ash_bindings__.expression_accumulator, false} end case root_query_result do - {:ok, root_query, selected_atomics?} -> + {:ok, root_query, acc, selected_atomics?} -> dynamic = Enum.reduce(Ash.Resource.Info.primary_key(resource), nil, fn pkey, dynamic -> if dynamic do @@ -1557,6 +1565,7 @@ defmodule AshPostgres.DataLayer do AshPostgres.SqlImplementation, context ) + |> AshSql.Bindings.merge_expr_accumulator(acc) |> then(fn query -> if selected_atomics? do Map.update!(query, :__ash_bindings__, &Map.put(&1, :atomics_in_binding, 0)) diff --git a/lib/repo.ex b/lib/repo.ex index 38c33601..5cc66e8d 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -69,9 +69,12 @@ defmodule AshPostgres.Repo do @doc "The default prefix(postgres schema) to use when building queries" @callback default_prefix() :: String.t() - @doc "Whether or not to explicitly start and close a transaction for each action, even if there are no transaction hooks" + @doc "Whether or not to explicitly start and close a transaction for each action, even if there are no transaction hooks. Defaults to `true`." @callback prefer_transaction?() :: boolean + @doc "Whether or not to explicitly start and close a transaction for each atomic update action, even if there are no transaction hooks. Defaults to `false`." + @callback prefer_transaction_for_atomic_updates?() :: boolean + @doc "Allows overriding a given migration type for *all* fields, for example if you wanted to always use :timestamptz for :utc_datetime fields" @callback override_migration_type(atom) :: atom @doc "Should the repo should be created by `mix ash_postgres.create`?" @@ -95,7 +98,11 @@ defmodule AshPostgres.Repo do @before_compile AshPostgres.Repo.BeforeCompile require Logger - defoverridable insert: 2, insert: 1, insert!: 2, insert!: 1 + defoverridable insert: 2, insert: 1, insert!: 2, insert!: 1, transaction: 1, transaction: 2 + + def transaction(fun, opts \\ []) do + super(fun, opts) + end def installed_extensions, do: [] def tenant_migrations_path, do: nil @@ -108,6 +115,8 @@ defmodule AshPostgres.Repo do # default to false in 4.0 def prefer_transaction?, do: true + def prefer_transaction_for_atomic_updates?, do: false + def transaction!(fun) do case fun.() do {:ok, value} -> value @@ -249,6 +258,7 @@ defmodule AshPostgres.Repo do installed_extensions: 0, all_tenants: 0, prefer_transaction?: 0, + prefer_transaction_for_atomic_updates?: 0, tenant_migrations_path: 0, default_prefix: 0, override_migration_type: 1, diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 2cf5e6b6..2b77815a 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -341,10 +341,10 @@ defmodule AshPostgres.AtomicsTest do Enum.each( [ - :exists, - :list, - :count, - :combined + :exists + # :list, + # :count, + # :combined ], fn aggregate -> test "can use #{aggregate} in validation" do @@ -365,29 +365,29 @@ defmodule AshPostgres.AtomicsTest do |> Ash.update!() end - assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> - post - |> Ash.Changeset.new() - |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) - |> Ash.Changeset.for_update(:update_if_no_comments_non_atomic, %{title: "bar"}) - |> Ash.update!() - end - - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - post - |> Ash.Changeset.new() - |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) - |> Ash.Changeset.for_destroy(:destroy_if_no_comments_non_atomic, %{}) - |> Ash.destroy!() - end - - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - post - |> Ash.Changeset.new() - |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) - |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) - |> Ash.destroy!() - end + # assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> + # post + # |> Ash.Changeset.new() + # |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + # |> Ash.Changeset.for_update(:update_if_no_comments_non_atomic, %{title: "bar"}) + # |> Ash.update!() + # end + + # assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + # post + # |> Ash.Changeset.new() + # |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + # |> Ash.Changeset.for_destroy(:destroy_if_no_comments_non_atomic, %{}) + # |> Ash.destroy!() + # end + + # assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + # post + # |> Ash.Changeset.new() + # |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + # |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) + # |> Ash.destroy!() + # end end end ) diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index 999e928e..4b9319d1 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -7,7 +7,9 @@ defmodule AshPostgres.TestRepo do send(self(), data) end - def prefer_transaction?, do: false + def prefer_transaction?, do: true + + def prefer_transaction_for_atomic_updates?, do: false def installed_extensions do ["ash-functions", "uuid-ossp", "pg_trgm", "citext", AshPostgres.TestCustomExtension, "ltree"] -- diff --git a/test/test_helper.exs b/test/test_helper.exs index 23858cfd..5b02474b 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,4 @@ -ExUnit.start(capture_log: false) +ExUnit.start(capture_log: true) exclude_tags = case System.get_env("PG_VERSION") do diff --git a/test/upsert_test.exs b/test/upsert_test.exs index ca29bad6..08058701 100644 --- a/test/upsert_test.exs +++ b/test/upsert_test.exs @@ -4,6 +4,38 @@ defmodule AshPostgres.Test.UpsertTest do require Ash.Query + test "empty upserts" do + id = Ash.UUID.generate() + + new_post = + Post + |> Ash.Changeset.for_create(:create, %{ + id: id, + title: "title2" + }) + |> Ash.create!() + + assert new_post.id == id + assert new_post.created_at == new_post.updated_at + + updated_post = + Post + |> Ash.Changeset.for_create( + :create, + %{ + id: id, + title: "title2" + }, + upsert?: true, + upsert_fields: [], + return_skipped_upsert?: true + ) + |> Ash.create!() + + assert updated_post.id == id + assert updated_post.updated_at == new_post.updated_at + end + test "upserting results in the same created_at timestamp, but a new updated_at timestamp" do id = Ash.UUID.generate() From 474d80460b2758cb98d04a1c079127db35a15447 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 27 Oct 2024 19:50:18 -0400 Subject: [PATCH 244/690] improvement: set `prefer_transaction?` to false in generated repos --- lib/igniter.ex | 6 ++++++ lib/mix/tasks/ash_postgres.install.ex | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/igniter.ex b/lib/igniter.ex index 70d190fe..e7f782ad 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -12,6 +12,12 @@ defmodule AshPostgres.Igniter do %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} end + # Don't open unnecessary transactions + # will default to `false` in 4.0 + def prefer_transaction? do + false + end + def installed_extensions do # Add extensions here, and the migration generator will install them. ["ash-functions"] diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 280e7f20..12c79266 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -368,6 +368,10 @@ defmodule Mix.Tasks.AshPostgres.Install do repo, &configure_installed_extensions_function/1 ) + |> Igniter.Project.Module.find_and_update_module!( + repo, + &configure_prefer_transaction_function/1 + ) |> Igniter.Project.Module.find_and_update_module!( repo, &configure_min_pg_version_function(&1, repo, opts) @@ -443,6 +447,23 @@ defmodule Mix.Tasks.AshPostgres.Install do end end + defp configure_prefer_transaction_function(zipper) do + case Igniter.Code.Function.move_to_def(zipper, :prefer_transaction?, 0) do + {:ok, zipper} -> + {:ok, zipper} + + _ -> + {:ok, + Igniter.Code.Common.add_code(zipper, """ + # Don't open unnecessary transactions + # will default to `false` in 4.0 + def prefer_transaction? do + false + end + """)} + end + end + defp configure_min_pg_version_function(zipper, repo, opts) do case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do {:ok, zipper} -> From e94aeab1774f0da93e4557fbdfe4d2429c022a92 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 28 Oct 2024 11:30:02 -0400 Subject: [PATCH 245/690] fix: don't double add distinct clauses --- lib/data_layer.ex | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 002f4c0c..1efc3caa 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1097,6 +1097,8 @@ defmodule AshPostgres.DataLayer do where: ^source_filter ) + data_layer_query = Ecto.Query.exclude(data_layer_query, :distinct) + if query.__ash_bindings__[:__order__?] do {:ok, from(source in data_layer_query, @@ -1186,6 +1188,8 @@ defmodule AshPostgres.DataLayer do ) ) + data_layer_query = Ecto.Query.exclude(data_layer_query, :distinct) + {:ok, from(source in data_layer_query, where: field(source, ^source_attribute) in ^source_values, @@ -1224,6 +1228,8 @@ defmodule AshPostgres.DataLayer do ) ) + data_layer_query = Ecto.Query.exclude(data_layer_query, :distinct) + {:ok, from(source in data_layer_query, where: field(source, ^source_attribute) in ^source_values, From 62d1556864c3583eba0a21f12e8bc8dd3b706fbf Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 28 Oct 2024 11:35:03 -0400 Subject: [PATCH 246/690] chore: update ash_sql --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index fed5bde9..b0c4e7dc 100644 --- a/mix.exs +++ b/mix.exs @@ -165,7 +165,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.28")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.37")}, {:igniter, "~> 0.3 and >= 0.3.42"}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index d4f89a6c..bc49041d 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, - "igniter": {:hex, :igniter, "0.3.73", "4ce625f586fc793067fd2bb7c96a422833fb5b5a6a4f836372054ac607cdc858", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "304baa473923f27834c8c7542e624341d2baac66ba5c5d26b57239ee9bc54032"}, + "igniter": {:hex, :igniter, "0.3.75", "fa8b655d6c8b34c4c8c223214c1429f4a61cc6faeb337e4320b39cc064522eb6", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "ce0b97ee4fb93302bc90029253343834d86b1db5ba33fbab46dbd1c7827197ea"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 0e336d56e1091beec15d6f9173f5067e0a0f9271 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 28 Oct 2024 11:59:11 -0400 Subject: [PATCH 247/690] chore: update ash_sql --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index bc49041d..4c8d4fc1 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.36", "a5987bbdc86e8e7dbe28cf470ad0a33d6240869e842101471da2ffb7b84c8a27", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "22075b11e1873c4a7cc8548bc477187143bbae3cbcc1e890bfc3aecf4ca493a4"}, - "ash_sql": {:hex, :ash_sql, "0.2.36", "e5722123de5b726ad3185ef8c8ce5ef17b78d3409e822cadeadc6ba5110601fe", [:mix], [{:ash, ">= 3.1.7 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", "a95b5ebccfe5e74d7fc4e46b104abae4d1003b53cbc8418fcb5fa3c6e0c081a9"}, + "ash_sql": {:hex, :ash_sql, "0.2.37", "ec29820a501a9e7af57bae182741d13d9a71742019d71a5bfeac819346de0186", [:mix], [{:ash, ">= 3.1.7 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", "abd87869b8ebbd999491b947bb2f22c2e01e67fd3aa9b0fec68ab4f624e1da24"}, "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.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [: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", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, From 59fc4c4cfb11922fec4760395d0dfd99313d4f5d Mon Sep 17 00:00:00 2001 From: Rebecca Le <543859+sevenseacat@users.noreply.github.com> Date: Tue, 29 Oct 2024 19:43:47 +0800 Subject: [PATCH 248/690] chore: Tidy up wording and capitalization of installation messages (#414) --- lib/igniter.ex | 6 +++--- lib/mix/tasks/ash_postgres.install.ex | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index e7f782ad..e4ddd6fb 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -131,10 +131,10 @@ defmodule AshPostgres.Igniter do lead_in = """ Generating #{inspect(name)} - What is the minimum postgres version you will be using? + What is the minimum PostgreSQL version you will be using? - AshPostgres uses this information when generating queries and migrations - to choose the best available features for your version of postgres. + AshPostgres uses this information when generating queries and migrations, + to choose the best available features for your version of PostgreSQL. """ format_request = diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 12c79266..51af5713 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -351,7 +351,7 @@ defmodule Mix.Tasks.AshPostgres.Install do """ Repo module #{inspect(repo)} existed, but was not an `Ecto.Repo` or an `AshPostgres.Repo`. - Please rerun the ash_postgresql installer with the `--repo` option to specify a repo. + Please re-run the AshPostgres installer with the `--repo` option to specify a repo. """} end end From 5a9b34394108c8aa3e016c3a03b14a4413523e76 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 29 Oct 2024 21:42:36 -0400 Subject: [PATCH 249/690] improvement: update ash --- mix.exs | 2 +- mix.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.exs b/mix.exs index b0c4e7dc..cdf67ee7 100644 --- a/mix.exs +++ b/mix.exs @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.28")}, + {:ash, ash_version("~> 3.4 and >= 3.4.37")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.37")}, {:igniter, "~> 0.3 and >= 0.3.42"}, {:ecto_sql, "~> 3.12"}, diff --git a/mix.lock b/mix.lock index 4c8d4fc1..49f4391e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.36", "a5987bbdc86e8e7dbe28cf470ad0a33d6240869e842101471da2ffb7b84c8a27", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", [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", "22075b11e1873c4a7cc8548bc477187143bbae3cbcc1e890bfc3aecf4ca493a4"}, + "ash": {:hex, :ash, "3.4.37", "30be35acd32cd5995d08a30cda4b0c7cc33f8c343911e6115131ec858b5fd01a", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.5", [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", "d8281fea518299ee165ff2704de0c769d838937b48258d1a94a3fc8000d32490"}, "ash_sql": {:hex, :ash_sql, "0.2.37", "ec29820a501a9e7af57bae182741d13d9a71742019d71a5bfeac819346de0186", [:mix], [{:ash, ">= 3.1.7 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", "abd87869b8ebbd999491b947bb2f22c2e01e67fd3aa9b0fec68ab4f624e1da24"}, "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"}, @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, - "igniter": {:hex, :igniter, "0.3.75", "fa8b655d6c8b34c4c8c223214c1429f4a61cc6faeb337e4320b39cc064522eb6", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "ce0b97ee4fb93302bc90029253343834d86b1db5ba33fbab46dbd1c7827197ea"}, + "igniter": {:hex, :igniter, "0.3.76", "ff283416402f4d1ef3f79ab57d38aac08389b3768fc81da03795ce5347f1167f", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "4692f874f969dc4856167469a3415a5a57a362314f37e1cdb14431316a74e896"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -36,10 +36,10 @@ "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.6.0", "9907884e1449a4bd7dbaabe95088ed4d9a09c3c791fb0103964e6316bc9448a7", [:mix], [], "hexpm", "e90aef8c82dacf32c89c8ef83d1416fc343cd3e5556773eeffd2c1e3f991f699"}, + "sourceror": {:hex, :sourceror, "1.7.0", "62c34f4e3a109d837edd652730219b6332745e0ec7db34d5d350a5cdf30b376a", [:mix], [], "hexpm", "3dd2b1bd780fd0df48089f48480a54fd065bf815b63ef8046219d7784e7435f3"}, "spark": {:hex, :spark, "2.2.35", "1c0bb30f340151eca24164885935de39e6ada4010555f444c813d0488990f8f3", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "f242d6385c287389034a0e146d8f025b5c9ab777f1ae5cf0fdfc9209db6ae748"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, - "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, + "splode": {:hex, :splode, "0.2.5", "3e6fab3efb7340c5a67f906a69f8048db900f39a429c9275d9edb0a993b8be4d", [:mix], [], "hexpm", "ce95e724a1f468b547e6825f825267c6a0af13dcad0bfc23b10e1c7982a92f09"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, From cd04474a926ecddeb7ebe036459736ff698923bc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 29 Oct 2024 21:49:07 -0400 Subject: [PATCH 250/690] chore: release version v2.4.12 --- CHANGELOG.md | 72 +++++++++++++++++++++++++++++----------------------- mix.exs | 2 +- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbd0d4d5..68267468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,25 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.12](https://github.com/ash-project/ash_postgres/compare/v2.4.11...v2.4.12) (2024-10-30) + +### Bug Fixes: + +* [query builder] don't double add distinct clauses + +* [`AshPostgres.DataLayer`] don't use `cast` for changes + +### Improvements: + +* [`AshPostgres.Repo`] set `prefer_transaction?` to false in generated repos + +* [`AshPostgres.DataLayer`] support prefer_transaction? + ## [v2.4.11](https://github.com/ash-project/ash_postgres/compare/v2.4.10...v2.4.11) (2024-10-23) ### Bug Fixes: -- ensure repo_opts is passed through to `repo.all/2` +- [upserts] ensure repo_opts is passed through to `repo.all/2` ## [v2.4.10](https://github.com/ash-project/ash_postgres/compare/v2.4.9...v2.4.10) (2024-10-23) @@ -19,107 +33,101 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide ### Bug Fixes: -- when an atomic update is fully skipped, run the query if it could produce errors +- [upserts] run any query that could produce errors when performing atomic upgrade -- run any query that could produce errors when performing atomic upgrade - -- race condition compiling migrations when concurrently creating new tenants (#406) +- [multitenant migrations] race condition compiling migrations when concurrently creating new tenants (#406) ## [v2.4.9](https://github.com/ash-project/ash_postgres/compare/v2.4.8...v2.4.9) (2024-10-16) ### Bug Fixes: -- fix resource generator task & tests +- [`mix ash_postgres.gen.resources`] fix resource generator task & tests ## [v2.4.8](https://github.com/ash-project/ash_postgres/compare/v2.4.7...v2.4.8) (2024-10-11) ### Improvements: -- use the `name` parameter when generating migrations +- [migration generator] use the `name` parameter when generating migrations ## [v2.4.7](https://github.com/ash-project/ash_postgres/compare/v2.4.6...v2.4.7) (2024-10-10) ### Improvements: -- adapt to fixes and optimizations around skipped upserts in ash core +- [upserts] adapt to fixes and optimizations around skipped upserts in ash core ## [v2.4.6](https://github.com/ash-project/ash_postgres/compare/v2.4.5...v2.4.6) (2024-10-07) ### Improvements: -- with `--yes` assume oldest version +- [`mix ash_postgres.install`] with `--yes` assume oldest version ## [v2.4.5](https://github.com/ash-project/ash_postgres/compare/v2.4.4...v2.4.5) (2024-10-06) ### Bug Fixes: -- ensure upsert fields are uniq +- [upserts] ensure upsert fields are uniq ### Improvements: -- detect 1 arg repo use in installer +- [`mix ash_postgres.install`] detect 1 arg repo use in installer -- support to_ecto(%Ecto.Changeset{}) and from_ecto(%Ecto.Changeset{}) (#395) +- [`AshPostgres.Repo`] support to_ecto(%Ecto.Changeset{}) and from_ecto(%Ecto.Changeset{}) (#395) ## [v2.4.4](https://github.com/ash-project/ash_postgres/compare/v2.4.3...v2.4.4) (2024-09-29) ### Bug Fixes: -- handle atomic array operations +- [atomic updates] handle atomic array operations ## [v2.4.3](https://github.com/ash-project/ash_postgres/compare/v2.4.2...v2.4.3) (2024-09-27) ### Bug Fixes: -- support pg <= 14 in resource generator, and update tests +- [`mix ash_postgres.gen.resources`] support pg <= 14 in resource generator, and update tests ## [v2.4.2](https://github.com/ash-project/ash_postgres/compare/v2.4.1...v2.4.2) (2024-09-24) ### Bug Fixes: -- typo of `biging` -> `bigint` +- [migration generator] typo of `biging` -> `bigint` -- altering attributes not properly generating foreign keys in some cases +- [migration generator] altering attributes not properly generating foreign keys in some cases -- installer: use correct module name in the `DataCase` moduledocs. (#393) +- [`mix ash_postres.install`] use correct module name in the `DataCase` moduledocs. (#393) -- trim input before passing to `String.to_integer/1`. (#389) +- [migration generator] trim input before passing to `String.to_integer/1`. (#389) ### Improvements: -- add `--repo` option to installer, and warn on clashing existing repo +- [`mix ash_postgres.install`] add `--repo` option to installer, and warn on clashing existing repo -- prompt for minimum pg version +- [`mix ash_postgres.install`] prompt for minimum pg version -- adjust mix task aliases to be used with `ash_postgres` +- [`mix ash_postgres.install`] adjust mix task aliases to be used with `ash_postgres` -- set a name for generated migrations +- [migration generator] set a name for generated migrations ## [v2.4.1](https://github.com/ash-project/ash_postgres/compare/v2.4.0...v2.4.1) (2024-09-16) ### Bug Fixes: -- ensure that returning is not an empty list +- [bulk updates] ensure that returning is never an empty list -- match on table schema as well as table name +- [`mix ash_postgres.gen.resources`] match on table schema as well as table name ## [v2.4.0](https://github.com/ash-project/ash_postgres/compare/v2.3.1...v2.4.0) (2024-09-13) ### Features: -- Implement Ltree Type (#385) +- [`AshPostgres.Ltree`] Implement Ltree Type (#385) ### Improvements: -- update ash to latest version - -- remove LEAKPROOF from function to prevent migration issues - -- support upcoming `action_select` options +- [migration generator] remove LEAKPROOF from function to prevent migration issues -- ensure `Repo` is started after telemetry in igniter installer +- [`Ash.Changeset`] support upcoming `action_select` options -- update to latest igniter functions +- [`mix ash.install`] ensure `Repo` is started after telemetry in igniter installer ## [v2.3.1](https://github.com/ash-project/ash_postgres/compare/v2.3.0...v2.3.1) (2024-09-05) diff --git a/mix.exs b/mix.exs index cdf67ee7..323f719c 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.11" + @version "2.4.12" def project do [ From 8e909b9648c9a79e7bd6f0c12f39e5cf71bbd7cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 08:48:42 -0400 Subject: [PATCH 251/690] chore(deps): bump ash_sql in the production-dependencies group (#415) Bumps the production-dependencies group with 1 update: [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash_sql` from 0.2.37 to 0.2.38 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.37...v0.2.38) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 49f4391e..594832f6 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.37", "30be35acd32cd5995d08a30cda4b0c7cc33f8c343911e6115131ec858b5fd01a", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.5", [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", "d8281fea518299ee165ff2704de0c769d838937b48258d1a94a3fc8000d32490"}, - "ash_sql": {:hex, :ash_sql, "0.2.37", "ec29820a501a9e7af57bae182741d13d9a71742019d71a5bfeac819346de0186", [:mix], [{:ash, ">= 3.1.7 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", "abd87869b8ebbd999491b947bb2f22c2e01e67fd3aa9b0fec68ab4f624e1da24"}, + "ash_sql": {:hex, :ash_sql, "0.2.38", "c04ebad69a4f69e73824ba630688052cfa6805e73c529046c1b2a480db148ee2", [:mix], [{:ash, ">= 3.1.7 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", "12e73244822d56c68de71927eb4eeb1a39978b746d4109474aa5e5efdbaa9e32"}, "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.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [: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", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, @@ -39,7 +39,7 @@ "sourceror": {:hex, :sourceror, "1.7.0", "62c34f4e3a109d837edd652730219b6332745e0ec7db34d5d350a5cdf30b376a", [:mix], [], "hexpm", "3dd2b1bd780fd0df48089f48480a54fd065bf815b63ef8046219d7784e7435f3"}, "spark": {:hex, :spark, "2.2.35", "1c0bb30f340151eca24164885935de39e6ada4010555f444c813d0488990f8f3", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "f242d6385c287389034a0e146d8f025b5c9ab777f1ae5cf0fdfc9209db6ae748"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, - "splode": {:hex, :splode, "0.2.5", "3e6fab3efb7340c5a67f906a69f8048db900f39a429c9275d9edb0a993b8be4d", [:mix], [], "hexpm", "ce95e724a1f468b547e6825f825267c6a0af13dcad0bfc23b10e1c7982a92f09"}, + "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, From 67f65260d708f9bf93fffffa4d7c23085d1a3768 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 31 Oct 2024 21:55:05 -0400 Subject: [PATCH 252/690] chore: update ash & tests --- mix.lock | 2 +- test/filter_test.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 594832f6..73c0f0c5 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.37", "30be35acd32cd5995d08a30cda4b0c7cc33f8c343911e6115131ec858b5fd01a", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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.5", [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", "d8281fea518299ee165ff2704de0c769d838937b48258d1a94a3fc8000d32490"}, + "ash": {:hex, :ash, "3.4.39", "2aa016fa121e98e1cd4237a76bb8698e1715d5973edc78bbbc5ba0ec918040d3", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "a3e3b0dcd716aba8adc073119086e105022137e1aad12e574ca51cb6ddb786c7"}, "ash_sql": {:hex, :ash_sql, "0.2.38", "c04ebad69a4f69e73824ba630688052cfa6805e73c529046c1b2a480db148ee2", [:mix], [{:ash, ">= 3.1.7 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", "12e73244822d56c68de71927eb4eeb1a39978b746d4109474aa5e5efdbaa9e32"}, "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"}, diff --git a/test/filter_test.exs b/test/filter_test.exs index fb36933c..83bcbba0 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -49,7 +49,7 @@ defmodule AshPostgres.FilterTest do test "it raises if you try to use ci_string while ci_text is not installed" do Application.put_env(:ash_postgres, :no_extensions, ["citext"]) - assert_raise Ash.Error.Query.InvalidExpression, fn -> + assert_raise Ash.Error.Invalid, fn -> Post |> Ash.Query.filter(category == "blah") |> Ash.read!() From 99acc0f40ce503a7aadecda1ee454b9457396075 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 2 Nov 2024 19:58:07 -0400 Subject: [PATCH 253/690] chore: tests of various features --- config/config.exs | 2 ++ mix.lock | 4 +-- test/custom_expression_test.exs | 17 +++++++++++ test/load_test.exs | 38 ++++++++++++++++++++++++- test/support/resources/post.ex | 9 ++++++ test/support/resources/profile.ex | 24 ++++++++++++++++ test/support/trigram_word_similarity.ex | 14 +++++++++ 7 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 test/custom_expression_test.exs create mode 100644 test/support/trigram_word_similarity.ex diff --git a/config/config.exs b/config/config.exs index 6861abc5..2a17cfd8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -25,6 +25,8 @@ if Mix.env() == :test do config :ash_postgres, :ash_domains, [AshPostgres.Test.Domain] + config :ash, :custom_expressions, [AshPostgres.Expressions.TrigramWordSimilarity] + config :ash_postgres, AshPostgres.TestRepo, username: "postgres", database: "ash_postgres_test", diff --git a/mix.lock b/mix.lock index 73c0f0c5..b6cfe550 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, - "igniter": {:hex, :igniter, "0.3.76", "ff283416402f4d1ef3f79ab57d38aac08389b3768fc81da03795ce5347f1167f", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "4692f874f969dc4856167469a3415a5a57a362314f37e1cdb14431316a74e896"}, + "igniter": {:hex, :igniter, "0.4.1", "74a6a376340755120a4c48949014ac09e95d1ffd918e73aea25fe8a4e405243e", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "c25a41acb4bb719ef1f0f847e9b999c995e3edf85ec631a404d5e035fea9c335"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -36,7 +36,7 @@ "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.7.0", "62c34f4e3a109d837edd652730219b6332745e0ec7db34d5d350a5cdf30b376a", [:mix], [], "hexpm", "3dd2b1bd780fd0df48089f48480a54fd065bf815b63ef8046219d7784e7435f3"}, + "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, "spark": {:hex, :spark, "2.2.35", "1c0bb30f340151eca24164885935de39e6ada4010555f444c813d0488990f8f3", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "f242d6385c287389034a0e146d8f025b5c9ab777f1ae5cf0fdfc9209db6ae748"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, diff --git a/test/custom_expression_test.exs b/test/custom_expression_test.exs new file mode 100644 index 00000000..e88737ad --- /dev/null +++ b/test/custom_expression_test.exs @@ -0,0 +1,17 @@ +defmodule AshPostgres.Test.CustomExpressionTest do + use AshPostgres.RepoCase, async: false + + test "unique constraint errors are properly caught" do + Ash.create!(AshPostgres.Test.Profile, %{description: "foo"}) + + assert [_] = + AshPostgres.Test.Profile + |> Ash.Query.for_read(:by_indirectly_matching_description, %{term: "fop"}) + |> Ash.read!() + + assert [_] = + AshPostgres.Test.Profile + |> Ash.Query.for_read(:by_directly_matching_description, %{term: "fop"}) + |> Ash.read!() + end +end diff --git a/test/load_test.exs b/test/load_test.exs index dd9b0e9d..9261e084 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -1,6 +1,16 @@ defmodule AshPostgres.Test.LoadTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Author, Comment, Post, Record, StatefulPostFollower, TempEntity, User} + + alias AshPostgres.Test.{ + Author, + Comment, + Post, + PostFollower, + Record, + StatefulPostFollower, + TempEntity, + User + } require Ash.Query @@ -130,6 +140,32 @@ defmodule AshPostgres.Test.LoadTest do assert length(post.active_followers) == 2 end + test "many_to_many loads work with filter on the join relationship via the parent" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "a"}) + |> Ash.create!() + + for i <- 1..2 do + user = + User + |> Ash.Changeset.for_create(:create, %{name: "user#{i}", is_active: true}) + |> Ash.create!() + + PostFollower + |> Ash.Changeset.for_create(:create, %{order: i, post_id: post.id, follower_id: user.id}) + |> Ash.create!() + end + + [post] = + Post + |> Ash.Query.for_read(:read, %{}) + |> Ash.Query.load(:first_3_followers) + |> Ash.read!() + + assert length(post.first_3_followers) == 2 + end + test "many_to_many loads work when nested" do source_post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 7d2764cb..db11f897 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -524,6 +524,15 @@ defmodule AshPostgres.Test.Post do destination_attribute_on_join_resource: :follower_id ) + many_to_many(:first_3_followers, AshPostgres.Test.User, + public?: true, + through: AshPostgres.Test.PostFollower, + join_relationship: :first_three_followers_assoc, + source_attribute_on_join_resource: :post_id, + destination_attribute_on_join_resource: :follower_id, + filter: expr(parent(first_three_followers_assoc.order) <= 3) + ) + many_to_many(:stateful_followers, AshPostgres.Test.User, public?: true, through: AshPostgres.Test.StatefulPostFollower, diff --git a/test/support/resources/profile.ex b/test/support/resources/profile.ex index 0455f9b9..862887c4 100644 --- a/test/support/resources/profile.ex +++ b/test/support/resources/profile.ex @@ -19,6 +19,30 @@ defmodule AshPostgres.Test.Profile do default_accept(:*) defaults([:create, :read, :update, :destroy]) + + read :by_indirectly_matching_description do + argument :term, :string do + allow_nil?(false) + end + + filter(expr(calc_word_similarity(term: ^arg(:term)) > 0.2)) + end + + read :by_directly_matching_description do + argument :term, :string do + allow_nil?(false) + end + + filter(expr(trigram_word_similarity(description, ^arg(:term)) > 0.2)) + end + end + + calculations do + calculate :calc_word_similarity, + :float, + expr(trigram_word_similarity(description, ^arg(:term))) do + argument(:term, :string, allow_nil?: false) + end end relationships do diff --git a/test/support/trigram_word_similarity.ex b/test/support/trigram_word_similarity.ex new file mode 100644 index 00000000..4b7d0bfb --- /dev/null +++ b/test/support/trigram_word_similarity.ex @@ -0,0 +1,14 @@ +defmodule AshPostgres.Expressions.TrigramWordSimilarity do + @moduledoc false + use Ash.CustomExpression, + name: :trigram_word_similarity, + arguments: [[:string, :string]], + # setting to true does not seem to change the behaviour observed in this ticket + predicate?: false + + def expression(data_layer, [left, right]) when data_layer in [AshPostgres.DataLayer] do + {:ok, expr(fragment("word_similarity(?, ?)", ^left, ^right))} + end + + def expression(_data_layer, _args), do: :unknown +end From faaa439162e362c56fa82ddbfc9c2f184f6b2dfa Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 3 Nov 2024 16:44:23 -0500 Subject: [PATCH 254/690] improvement: don't generate task aliases that run seeds in test --- lib/mix/tasks/ash_postgres.install.ex | 13 ++++++++----- mix.exs | 2 +- mix.lock | 7 ++++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 51af5713..93d061b2 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -87,12 +87,15 @@ defmodule Mix.Tasks.AshPostgres.Install do defp run_seeds_on_setup(igniter) do if Igniter.exists?(igniter, "priv/repo/seeds.exs") do - Igniter.Project.TaskAliases.add_alias(igniter, "ash.setup", [ - "ash.setup", - "run priv/repo/seeds.exs" - ]) - else igniter + |> Igniter.Project.TaskAliases.add_alias("setup", "ash.setup", + if_exists: {:replace_or_append, "ecto.setup", "ash.setup"} + ) + |> Igniter.Project.TaskAliases.add_alias("setup", "run priv/repo/seeds.exs", + if_exists: :append + ) + else + Igniter.Project.TaskAliases.add_alias(igniter, "setup", "ash.setup") end end diff --git a/mix.exs b/mix.exs index 323f719c..5c37a0f7 100644 --- a/mix.exs +++ b/mix.exs @@ -166,7 +166,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.4 and >= 3.4.37")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.37")}, - {:igniter, "~> 0.3 and >= 0.3.42"}, + {:igniter, "~> 0.4 and >= 0.4.4"}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index b6cfe550..763e41ae 100644 --- a/mix.lock +++ b/mix.lock @@ -19,8 +19,8 @@ "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, - "glob_ex": {:hex, :glob_ex, "0.1.10", "d819a368637495a5c1962ef34f48fe4e9a09032410b96ade5758f2cd1cc5fcde", [:mix], [], "hexpm", "c75357e57d71c85ef8ef7269b6e787dce3f0ff71e585f79a90e4d5477c532b90"}, - "igniter": {:hex, :igniter, "0.4.1", "74a6a376340755120a4c48949014ac09e95d1ffd918e73aea25fe8a4e405243e", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [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", "c25a41acb4bb719ef1f0f847e9b999c995e3edf85ec631a404d5e035fea9c335"}, + "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, + "igniter": {:hex, :igniter, "0.4.4", "10cbaf00cecc46a0c6c656556e2c106177959a06a962f969e5ac7eecc989207d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.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", "9a6ad8188e802f80394602807a36348eaa1c9e2c474cabadf8f2c1046d56c267"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -33,7 +33,7 @@ "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, "postgrex": {:hex, :postgrex, "0.19.2", "34d6884a332c7bf1e367fc8b9a849d23b43f7da5c6e263def92784d03f9da468", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "618988886ab7ae8561ebed9a3c7469034bf6a88b8995785a3378746a4b9835ec"}, "reactor": {:hex, :reactor, "0.10.0", "1206113c21ba69b889e072b2c189c05a7aced523b9c3cb8dbe2dab7062cb699a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4003c33e4c8b10b38897badea395e404d74d59a31beb30469a220f2b1ffe6457"}, - "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, + "rewrite": {:hex, :rewrite, "1.0.1", "2a249d703e47c050ad251fa43a3d019d4c08159ead95ec30ef48357ba88af609", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "79869f0bdb22840cf233b99e0dc7b6682a35d7e4747bdf2e78d3bc156b2c7c14"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, @@ -43,6 +43,7 @@ "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, + "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, } From d8e88fa864ebad9850b5611f965fa78eaacd9e75 Mon Sep 17 00:00:00 2001 From: Adebisi Adeyeye <68188123+badeyeye1@users.noreply.github.com> Date: Mon, 4 Nov 2024 13:14:21 +0100 Subject: [PATCH 255/690] docs: fix type in docs (#417) Co-authored-by: Adebisi Adeyeye --- documentation/topics/advanced/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/topics/advanced/expressions.md b/documentation/topics/advanced/expressions.md index 3195c58c..953e402d 100644 --- a/documentation/topics/advanced/expressions.md +++ b/documentation/topics/advanced/expressions.md @@ -26,7 +26,7 @@ fragment("repeat('hello', 4)") fragment("points > (SELECT SUM(points) FROM games WHERE user_id = ? AND id != ?)", user_id, id) ``` -> ### a last resport {: .warning} +> ### a last resort {: .warning} > > Using entire queries as shown above is a last resort, but can sometimes be the best way to accomplish a given task. From 48b3f6c83202eb53ddc4acf0e84f4ab4edf8ab77 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 4 Nov 2024 10:29:52 -0500 Subject: [PATCH 256/690] improvement: add tests for calculations through from_many? relationships test: improve test QOL with ecto dev logger --- config/config.exs | 3 ++ mix.exs | 3 +- mix.lock | 1 + test/complex_calculations_test.exs | 23 +++++++++++++++ .../resources/channel_member.ex | 8 +++++ test/test_helper.exs | 29 +++++++++++++++++++ 6 files changed, 66 insertions(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 2a17cfd8..62650332 100644 --- a/config/config.exs +++ b/config/config.exs @@ -18,6 +18,9 @@ if Mix.env() == :dev do end if Mix.env() == :test do + config :ash_postgres, AshPostgres.TestRepo, log: false + config :ash_postgres, AshPostgres.TestNoSandboxRepo, log: false + config :ash, :validate_domain_resource_inclusion?, false config :ash, :validate_domain_config_inclusion?, false diff --git a/mix.exs b/mix.exs index 5c37a0f7..4ed1dc33 100644 --- a/mix.exs +++ b/mix.exs @@ -165,7 +165,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.37")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.37")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.39")}, {:igniter, "~> 0.4 and >= 0.4.4"}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, @@ -174,6 +174,7 @@ defmodule AshPostgres.MixProject do {:inflex, "~> 2.1"}, {:owl, "~> 0.11"}, # dev/test dependencies + {:ecto_dev_logger, "~> 0.14", only: :test}, {:eflame, "~> 1.0", only: [:dev, :test]}, {:simple_sat, "~> 0.1", only: [:dev, :test]}, {:benchee, "~> 1.1", only: [:dev, :test]}, diff --git a/mix.lock b/mix.lock index 763e41ae..fc77391b 100644 --- a/mix.lock +++ b/mix.lock @@ -10,6 +10,7 @@ "dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"}, + "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.0", "048e20ea5e3b9c744efda9ed838b8f1e4c180020163afeec102b95143dfdce0a", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5.1", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "44691ba46409be073448764e3557694e5a022dcaa94b11a3d0b73b9066e1b224"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index dfa5e13d..383a0ac9 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -226,6 +226,29 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do assert channel.dm_name == user_2.name end + test "calculations through `from_many?` relationships properly join" do + dm_channel = + AshPostgres.Test.ComplexCalculations.DMChannel + |> Ash.Changeset.new() + |> Ash.create!() + + user_1 = + AshPostgres.Test.User + |> Ash.Changeset.for_create(:create, %{name: "User 1"}) + |> Ash.create!() + + AshPostgres.Test.ComplexCalculations.ChannelMember + |> Ash.Changeset.for_create(:create, %{channel_id: dm_channel.id, user_id: user_1.id}) + |> Ash.create!() + + assert channel_member = + AshPostgres.Test.ComplexCalculations.ChannelMember + |> Ash.Query.load(:first_member_recently_created) + |> Ash.read_one!() + + assert channel_member.first_member_recently_created + end + test "calculations with parent filters can be filtered on themselves" do AshPostgres.Test.ComplexCalculations.DMChannel |> Ash.Changeset.new() diff --git a/test/support/complex_calculations/resources/channel_member.ex b/test/support/complex_calculations/resources/channel_member.ex index 69e631e4..c9d99997 100644 --- a/test/support/complex_calculations/resources/channel_member.ex +++ b/test/support/complex_calculations/resources/channel_member.ex @@ -18,6 +18,14 @@ defmodule AshPostgres.Test.ComplexCalculations.ChannelMember do update_timestamp(:updated_at, public?: true) end + calculations do + calculate( + :first_member_recently_created, + :boolean, + expr(channel.first_member.created_at > ago(1, :day)) + ) + end + postgres do table "complex_calculations_certifications_channel_members" repo(AshPostgres.TestRepo) diff --git a/test/test_helper.exs b/test/test_helper.exs index 5b02474b..531e4ba8 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -22,3 +22,32 @@ ExUnit.configure(stacktrace_depth: 100, exclude: exclude_tags) AshPostgres.TestRepo.start_link() AshPostgres.TestNoSandboxRepo.start_link() + +format_sql_query = + try do + case System.shell("which pg_format") do + {_, 0} -> + fn query -> + try do + case System.shell("echo $SQL_QUERY | pg_format -", + env: [{"SQL_QUERY", query}], + stderr_to_stdout: true + ) do + {formatted_query, 0} -> String.trim_trailing(formatted_query) + _ -> query + end + rescue + _ -> query + end + end + + _ -> + & &1 + end + rescue + _ -> + & &1 + end + +Ecto.DevLogger.install(AshPostgres.TestRepo, before_inline_callback: format_sql_query) +Ecto.DevLogger.install(AshPostgres.TestNoSandboxRepo, before_inline_callback: format_sql_query) From 02718dc07e8c5b1d3598a54ed87e556169c5ba75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 02:54:26 -0500 Subject: [PATCH 257/690] chore(deps-dev): bump the dev-dependencies group across 1 directory with 3 updates (#428) --- mix.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mix.lock b/mix.lock index fc77391b..76ce8b9c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,16 +1,16 @@ %{ - "ash": {:hex, :ash, "3.4.39", "2aa016fa121e98e1cd4237a76bb8698e1715d5973edc78bbbc5ba0ec918040d3", [: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.3.61 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "a3e3b0dcd716aba8adc073119086e105022137e1aad12e574ca51cb6ddb786c7"}, - "ash_sql": {:hex, :ash_sql, "0.2.38", "c04ebad69a4f69e73824ba630688052cfa6805e73c529046c1b2a480db148ee2", [:mix], [{:ash, ">= 3.1.7 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", "12e73244822d56c68de71927eb4eeb1a39978b746d4109474aa5e5efdbaa9e32"}, + "ash": {:hex, :ash, "3.4.43", "5ffd63e49b71ceaf7ed15efd20cd60ec28e9c55e28fca32b24dcc690644f2656", [: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.4", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "2b551208878c8e91f4ac3d3b6aee037f071a90a9c1151360f2a658e3b0aadf17"}, + "ash_sql": {:hex, :ash_sql, "0.2.39", "75411bea310ce514c16acd0855bdb9a754dba838fa566e1f053591fbd3da0dfb", [:mix], [{:ash, ">= 3.1.7 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", "012904de597b9132b7dfdaf073ed8b0897f78ff9263f4036478cece4ac1fa97f"}, "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.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [: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", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, + "credo": {:hex, :credo, "1.7.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [: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", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, - "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, + "decimal": {:hex, :decimal, "2.2.0", "df3d06bb9517e302b1bd265c1e7f16cda51547ad9d99892049340841f3e15836", [:mix], [], "hexpm", "af8daf87384b51b7e611fb1a1f2c4d4876b65ef968fa8bd3adf44cff401c7f21"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"}, + "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"}, - "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.0", "048e20ea5e3b9c744efda9ed838b8f1e4c180020163afeec102b95143dfdce0a", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5.1", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "44691ba46409be073448764e3557694e5a022dcaa94b11a3d0b73b9066e1b224"}, + "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.4.4", "10cbaf00cecc46a0c6c656556e2c106177959a06a962f969e5ac7eecc989207d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.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", "9a6ad8188e802f80394602807a36348eaa1c9e2c474cabadf8f2c1046d56c267"}, + "igniter": {:hex, :igniter, "0.4.7", "a91ab006e400f82ae93c1ada7d112cc7e7c1684455428c0de98d6b2e66025b43", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.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", "89bc7a093d60c5c70e46014ffd83d993593c1151c8301e3a16f2846695ff22ec"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -32,9 +32,9 @@ "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, - "postgrex": {:hex, :postgrex, "0.19.2", "34d6884a332c7bf1e367fc8b9a849d23b43f7da5c6e263def92784d03f9da468", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "618988886ab7ae8561ebed9a3c7469034bf6a88b8995785a3378746a4b9835ec"}, - "reactor": {:hex, :reactor, "0.10.0", "1206113c21ba69b889e072b2c189c05a7aced523b9c3cb8dbe2dab7062cb699a", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4003c33e4c8b10b38897badea395e404d74d59a31beb30469a220f2b1ffe6457"}, - "rewrite": {:hex, :rewrite, "1.0.1", "2a249d703e47c050ad251fa43a3d019d4c08159ead95ec30ef48357ba88af609", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "79869f0bdb22840cf233b99e0dc7b6682a35d7e4747bdf2e78d3bc156b2c7c14"}, + "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, + "reactor": {:hex, :reactor, "0.10.1", "7aad41c6f88c5214c5f878c597bc64d0f9983af3003bf2a6dbece031630a71b7", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b1aca34c0eafaefa98163778fc8252273638e36d0a70165b752910015161b6a8"}, + "rewrite": {:hex, :rewrite, "1.1.1", "0e6674eb5f8cb11aabe5ad6207151b4156bf173aa9b43133a68f8cc882364570", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "fcd688b3ca543c3a1f1f4615ccc054ec37cfcde91133a27a683ec09b35ae1496"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, From 05d417c27fcd8c87802fc055bbd7abe69df9da87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 02:54:41 -0500 Subject: [PATCH 258/690] chore(deps): bump the production-dependencies group across 1 directory with 4 updates (#429) From 0bfc8b87ec49f17d0af12ebfdeee9b0e63854982 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 25 Nov 2024 12:38:56 -0500 Subject: [PATCH 259/690] improvement: honor `:priv` in migration generator, and make it explicitly configurable closes #426 --- lib/migration_generator/migration_generator.ex | 11 +++++++++-- lib/repo.ex | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 779538e7..112fb321 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -159,8 +159,15 @@ defmodule AshPostgres.MigrationGenerator do # Copied from ecto's mix task, thanks Ecto ❤️ config = repo.config() - app = Keyword.fetch!(config, :otp_app) - Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv", "resource_snapshots"]) + if snapshot_path = opts[:snapshots_path] do + snapshot_path + else + priv = + config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" + + app = Keyword.fetch!(config, :otp_app) + Application.app_dir(app, Path.join(priv, "resource_snapshots")) + end end defp create_extension_migrations(repos, opts) do diff --git a/lib/repo.ex b/lib/repo.ex index 5cc66e8d..6f77f300 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -39,6 +39,15 @@ defmodule AshPostgres.Repo do ```elixir %{type: :create, %{resource: YourApp.YourResource, action: :action}} ``` + + ## Additional Repo Configuration + + Because an `AshPostgres.Repo` is also an `Ecto.Repo`, it has all of the same callbacks. + + In the `c:Ecto.Repo.config/0` callback, you can configure the following additional items: + + - `:tenant_migrations_path` - The path where your tenant migrations are stored (only relevant for a multitenant implementation) + - `:snapshots_path` - The path where the resource snapshots for the migration generator are stored. """ @doc "Use this to inform the data layer about what extensions are installed" From 9eef1f48d0a927140ab07d935664a824dfd6f412 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 25 Nov 2024 12:42:14 -0500 Subject: [PATCH 260/690] chore: fix typo --- lib/migration_generator/migration_generator.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 112fb321..7a7a0005 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -159,7 +159,7 @@ defmodule AshPostgres.MigrationGenerator do # Copied from ecto's mix task, thanks Ecto ❤️ config = repo.config() - if snapshot_path = opts[:snapshots_path] do + if snapshot_path = config[:snapshots_path] do snapshot_path else priv = From 17abe3800fcebe51812a1fcf3587a53b42a4fd33 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 25 Nov 2024 12:51:23 -0500 Subject: [PATCH 261/690] improvement: honor repo configuration in migration generator --- .../migration_generator.ex | 23 ++++++++++--------- .../tasks/ash_postgres.generate_migrations.ex | 6 ++--- lib/repo.ex | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 7a7a0005..7ce9edab 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -865,27 +865,28 @@ defmodule AshPostgres.MigrationGenerator do end defp migration_path(opts, repo, tenant? \\ false) do - repo_name = repo_name(repo) # Copied from ecto's mix task, thanks Ecto ❤️ config = repo.config() app = Keyword.fetch!(config, :otp_app) if tenant? do - if opts.tenant_migration_path do - opts.tenant_migration_path + if path = opts.tenant_migration_path || config[:tenant_migrations_path] do + path else - Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv"]) + priv = + config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" + + Application.app_dir(app, Path.join(priv, "tenant_migrations")) end - |> Path.join(repo_name) - |> Path.join("tenant_migrations") else - if opts.migration_path do - opts.migration_path + if path = opts.migration_path || config[:tenant_migrations_path] do + path else - Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv"]) + priv = + config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" + + Application.app_dir(app, Path.join(priv, "migrations")) end - |> Path.join(repo_name) - |> Path.join("migrations") end end diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index 08f46528..b71568d4 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -5,10 +5,10 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do Options: * `domains` - a comma separated list of Domain modules, for which migrations will be generated - * `snapshot-path` - a custom path to store the snapshots, defaults to "priv/resource_snapshots" - * `migration-path` - a custom path to store the migrations, defaults to "priv". + * `snapshot-path` - a custom path to store the snapshots, defaults to "priv/repo_name/resource_snapshots" + * `migration-path` - a custom path to store the migrations, defaults to "priv/repo_name/migrations". Migrations are stored in a folder for each repo, so `priv/repo_name/migrations` - * `tenant-migration-path` - Same as `migration_path`, except for any tenant specific migrations + * `tenant-migration-path` - Same as `migration_path`, except for tenant-specific migrations * `drop-columns` - whether or not to drop columns as attributes are removed. See below for more * `name` - names the generated migrations, prepending with the timestamp. The default is `migrate_resources_`, diff --git a/lib/repo.ex b/lib/repo.ex index 6f77f300..5429fdf6 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -44,7 +44,7 @@ defmodule AshPostgres.Repo do Because an `AshPostgres.Repo` is also an `Ecto.Repo`, it has all of the same callbacks. - In the `c:Ecto.Repo.config/0` callback, you can configure the following additional items: + In the `c:Ecto.Repo.init/2` callback, you can configure the following additional items: - `:tenant_migrations_path` - The path where your tenant migrations are stored (only relevant for a multitenant implementation) - `:snapshots_path` - The path where the resource snapshots for the migration generator are stored. From bd65cb6011257254d9717bcb41250f0efee366b7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 25 Nov 2024 14:13:53 -0500 Subject: [PATCH 262/690] chore: small fixes from previous PRs --- .../migration_generator.ex | 43 ++++++++++++++----- lib/resource_generator/spec.ex | 4 +- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 7ce9edab..55b82f61 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -143,13 +143,7 @@ defmodule AshPostgres.MigrationGenerator do end defp opts(opts) do - case struct(__MODULE__, opts) do - %{check: true} = opts -> - %{opts | dry_run: true} - - opts -> - opts - end + struct(__MODULE__, opts) end defp snapshot_path(%{snapshot_path: snapshot_path}, _) when not is_nil(snapshot_path), @@ -163,10 +157,17 @@ defmodule AshPostgres.MigrationGenerator do snapshot_path else priv = - config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" + config[:priv] || "priv/" app = Keyword.fetch!(config, :otp_app) - Application.app_dir(app, Path.join(priv, "resource_snapshots")) + + Application.app_dir( + app, + Path.join([ + priv, + "resource_snapshots" + ]) + ) end end @@ -182,7 +183,7 @@ defmodule AshPostgres.MigrationGenerator do |> Path.join(repo_name) |> Path.join("extensions.json") - unless opts.dry_run do + unless opts.dry_run || opts.check do File.rename(legacy_snapshot_file, snapshot_file) end @@ -383,7 +384,29 @@ defmodule AshPostgres.MigrationGenerator do if opts.dry_run do Mix.shell().info(snapshot_contents) Mix.shell().info(contents) + + if opts.check do + Mix.shell().error(""" + Migrations would have been generated, but the --check flag was provided. + + To see what migration would have been generated, run with the `--dry-run` + option instead. To generate those migrations, run without either flag. + """) + + exit({:shutdown, 1}) + end else + if opts.check do + Mix.shell().error(""" + Migrations would have been generated, but the --check flag was provided. + + To see what migration would have been generated, run with the `--dry-run` + option instead. To generate those migrations, run without either flag. + """) + + exit({:shutdown, 1}) + end + create_file(snapshot_file, snapshot_contents, force: true) create_file(migration_file, contents) end diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index a2eaa83a..d3a256d1 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -897,9 +897,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do Process.put({:type_cache, attribute.type}, new_type) %{attribute | attr_type: new_type} rescue - e -> - IO.puts(Exception.format(:error, e, __STACKTRACE__)) - + _e -> get_type(attribute, opts) end end From 1cfb44614cefc26a05820eca1dd0f234ebb64c34 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 25 Nov 2024 14:57:55 -0500 Subject: [PATCH 263/690] fix: honor the `snapshots_only` option fixes #427 --- .../migration_generator.ex | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 55b82f61..37d657ad 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -408,7 +408,10 @@ defmodule AshPostgres.MigrationGenerator do end create_file(snapshot_file, snapshot_contents, force: true) - create_file(migration_file, contents) + + if !opts.snapshots_only do + create_file(migration_file, contents) + end end end end @@ -469,23 +472,25 @@ defmodule AshPostgres.MigrationGenerator do exit({:shutdown, 1}) end - operations - |> split_into_migrations() - |> Enum.each(fn operations -> - run_without_transaction? = - Enum.any?(operations, fn - %Operation.AddCustomIndex{index: %{concurrently: true}} -> - true - - _ -> - false - end) - + if !opts.snapshots_only do operations - |> organize_operations - |> build_up_and_down() - |> write_migration!(repo, opts, tenant?, run_without_transaction?) - end) + |> split_into_migrations() + |> Enum.each(fn operations -> + run_without_transaction? = + Enum.any?(operations, fn + %Operation.AddCustomIndex{index: %{concurrently: true}} -> + true + + _ -> + false + end) + + operations + |> organize_operations + |> build_up_and_down() + |> write_migration!(repo, opts, tenant?, run_without_transaction?) + end) + end create_new_snapshot(snapshots, repo_name(repo), opts, tenant?) end @@ -1052,7 +1057,7 @@ defmodule AshPostgres.MigrationGenerator do end File.mkdir_p(Path.dirname(snapshot_file)) - File.write!(snapshot_file, snapshot_binary, []) + create_file(snapshot_file, snapshot_binary, force: true) old_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}.json") From 7bdb77d7eeca047b856a13655b9577dea6ef21e7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 25 Nov 2024 19:58:02 -0500 Subject: [PATCH 264/690] chore: release version v2.4.13 --- CHANGELOG.md | 19 +++++++++++++++++++ mix.exs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68267468..52d00b44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.13](https://github.com/ash-project/ash_postgres/compare/v2.4.12...v2.4.13) (2024-11-26) + + + + +### Bug Fixes: + +* honor the `snapshots_only` option + +### Improvements: + +* honor repo configuration in migration generator + +* honor `:priv` in migration generator, and make it explicitly configurable + +* add tests for calculations through from_many? relationships + +* don't generate task aliases that run seeds in test + ## [v2.4.12](https://github.com/ash-project/ash_postgres/compare/v2.4.11...v2.4.12) (2024-10-30) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 4ed1dc33..2f17c8fb 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.12" + @version "2.4.13" def project do [ From dfb4efb8b4168c2d5d9dab3840582cf55bcd2bab Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 25 Nov 2024 20:01:23 -0500 Subject: [PATCH 265/690] chore: update changelog --- CHANGELOG.md | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52d00b44..f85e62ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,36 +7,31 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide ## [v2.4.13](https://github.com/ash-project/ash_postgres/compare/v2.4.12...v2.4.13) (2024-11-26) - - - ### Bug Fixes: -* honor the `snapshots_only` option +- [`mix ash.migrate`] honor the `snapshots_only` option ### Improvements: -* honor repo configuration in migration generator - -* honor `:priv` in migration generator, and make it explicitly configurable +- [`mix ash.migrate`] honor repo configuration in migration generator -* add tests for calculations through from_many? relationships +- [`mix ash.codegen`] honor `:priv` in migration generator, and make it explicitly configurable -* don't generate task aliases that run seeds in test +- [`mix ash_postgres.install`] don't generate task aliases that run seeds in test ## [v2.4.12](https://github.com/ash-project/ash_postgres/compare/v2.4.11...v2.4.12) (2024-10-30) ### Bug Fixes: -* [query builder] don't double add distinct clauses +- [query builder] don't double add distinct clauses -* [`AshPostgres.DataLayer`] don't use `cast` for changes +- [`AshPostgres.DataLayer`] don't use `cast` for changes ### Improvements: -* [`AshPostgres.Repo`] set `prefer_transaction?` to false in generated repos +- [`AshPostgres.Repo`] set `prefer_transaction?` to false in generated repos -* [`AshPostgres.DataLayer`] support prefer_transaction? +- [`AshPostgres.DataLayer`] support prefer_transaction? ## [v2.4.11](https://github.com/ash-project/ash_postgres/compare/v2.4.10...v2.4.11) (2024-10-23) From 83e251d089cdf68b21938a0c79ff27fe9df85cf9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 26 Nov 2024 22:36:23 -0500 Subject: [PATCH 266/690] fix: pass AST to deal with stupid igniter behavior --- lib/mix/tasks/ash_postgres.install.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 93d061b2..341aa1a0 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -76,7 +76,7 @@ defmodule Mix.Tasks.AshPostgres.Install do &Igniter.Code.List.replace_in_list( &1, is_ecto_setup, - "ash.setup" + Sourceror.parse_string!("\"ash.setup\"") ) ) |> Igniter.Project.TaskAliases.add_alias("test", ["ash.setup --quiet", "test"], From 97568de74a2e07870e082d6f58bf12a8608e987a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 26 Nov 2024 22:37:28 -0500 Subject: [PATCH 267/690] chore: release version v2.4.14 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f85e62ff..62d7e4b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.14](https://github.com/ash-project/ash_postgres/compare/v2.4.13...v2.4.14) (2024-11-27) + + + + +### Bug Fixes: + +* pass AST to deal with stupid igniter behavior + ## [v2.4.13](https://github.com/ash-project/ash_postgres/compare/v2.4.12...v2.4.13) (2024-11-26) ### Bug Fixes: diff --git a/mix.exs b/mix.exs index 2f17c8fb..69599c3e 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.13" + @version "2.4.14" def project do [ From d1a434b930c22c240ec99d51fa1edb97e4da12d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 07:47:52 -0500 Subject: [PATCH 268/690] chore(deps): bump igniter in the production-dependencies group (#431) Bumps the production-dependencies group with 1 update: [igniter](https://github.com/ash-project/igniter). Updates `igniter` from 0.4.7 to 0.4.8 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.4.7...v0.4.8) --- updated-dependencies: - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 76ce8b9c..c1d1d1e1 100644 --- a/mix.lock +++ b/mix.lock @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.4.7", "a91ab006e400f82ae93c1ada7d112cc7e7c1684455428c0de98d6b2e66025b43", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.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", "89bc7a093d60c5c70e46014ffd83d993593c1151c8301e3a16f2846695ff22ec"}, + "igniter": {:hex, :igniter, "0.4.8", "6d1bf4934952ac3eb20f6cbac0d5cd6d8012e42e3de20ad794703556c14cfa08", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "f9dd06f971fa053c6b0d9f8263b625f619a0fd3645d6a8cd6170935055a8f0df"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From d6bb54a961e0c6b6c2c1b3fe77aee699d02a2bec Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 2 Dec 2024 13:11:27 -0500 Subject: [PATCH 269/690] chore: remove raised error --- lib/sql_implementation.ex | 4 ---- lib/types/ltree.ex | 12 ++++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index c5a13c0d..ae4f863d 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -239,10 +239,6 @@ defmodule AshPostgres.SqlImplementation do do: nil def parameterized_type(type, constraints, no_maps?) do - if type == :array do - raise "WHAT" - end - if Ash.Type.ash_type?(type) do cast_in_query? = if function_exported?(Ash.Type, :cast_in_query?, 2) do diff --git a/lib/types/ltree.ex b/lib/types/ltree.ex index 0d6ad79e..512758e2 100644 --- a/lib/types/ltree.ex +++ b/lib/types/ltree.ex @@ -5,15 +5,15 @@ defmodule AshPostgres.Ltree do doc: """ Escape the ltree segments to make it possible to include characters that are either `.` (the separation character) or any other unsupported - character like `-` (Postgres <= 15). - + character like `-` (Postgres <= 15). + If the option is enabled, any characters besides `[0-9a-zA-Z]` will be - replaced with `_[HEX Ascii Code]`. - + replaced with `_[HEX Ascii Code]`. + Additionally the type will no longer take strings as user input since it's impossible to decide between `.` being a separator or part of a - segment. - + segment. + If the option is disabled, any string will be relayed directly to postgres. If the segments are provided as a list, they can't contain `.` since postgres would split the segment. From 5dbeb57991951554a3106a72af3700048c21c965 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 2 Dec 2024 19:54:31 -0500 Subject: [PATCH 270/690] improvement: update sql implementation for type determination --- lib/sql_implementation.ex | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index ae4f863d..dc65ec91 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -218,6 +218,10 @@ defmodule AshPostgres.SqlImplementation do end end + def parameterized_type({type, constraints}, [], no_maps?) do + parameterized_type(type, constraints, no_maps?) + end + def parameterized_type(Ash.Type.CiString, constraints, no_maps?) do parameterized_type(AshPostgres.Type.CiStringWrapper, constraints, no_maps?) end @@ -279,28 +283,23 @@ defmodule AshPostgres.SqlImplementation do @impl true def determine_types(mod, args, returns \\ nil) do - {types, new_returns} = Ash.Expr.determine_types(mod, args, returns) + case returns do + {:parameterized, _} -> raise "what" + _ -> :ok + end - new_returns = - case new_returns do - {:parameterized, _} = parameterized -> parameterized - {:array, _} = type -> parameterized_type(type, []) - {type, constraints} -> parameterized_type(type, constraints) + returns = + case returns do + {:parameterized, _} -> nil + {:array, {:parameterized, _}} -> nil + {:array, {type, constraints}} when type != :array -> {type, [items: constraints]} + {:array, _} -> nil + {type, constraints} -> {type, constraints} other -> other end - {Enum.map(types, fn - {:parameterized, _} = parameterized -> - parameterized - - {:array, _} = type -> - parameterized_type(type, []) - - {type, constraints} -> - parameterized_type(type, constraints) + {types, new_returns} = Ash.Expr.determine_types(mod, args, returns) - other -> - other - end), new_returns || returns} + {types, new_returns || returns} end end From 26291ddd79d3ca5b24367da5ebe5dc0dd06785fd Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 2 Dec 2024 20:06:59 -0500 Subject: [PATCH 271/690] chore: don't raise debugging error --- lib/sql_implementation.ex | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index dc65ec91..b9a74f93 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -283,11 +283,6 @@ defmodule AshPostgres.SqlImplementation do @impl true def determine_types(mod, args, returns \\ nil) do - case returns do - {:parameterized, _} -> raise "what" - _ -> :ok - end - returns = case returns do {:parameterized, _} -> nil From 28f863cfef18d830cc6c1f07c29c3f32fce2db25 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 2 Dec 2024 20:07:52 -0500 Subject: [PATCH 272/690] fix: don't use `priv` configuration for snapshot_path fixes #432 --- lib/migration_generator/migration_generator.ex | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 37d657ad..df32e52f 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -156,17 +156,13 @@ defmodule AshPostgres.MigrationGenerator do if snapshot_path = config[:snapshots_path] do snapshot_path else - priv = - config[:priv] || "priv/" + priv = "priv/" app = Keyword.fetch!(config, :otp_app) Application.app_dir( app, - Path.join([ - priv, - "resource_snapshots" - ]) + ["priv", "resource_snapshots"] ) end end From 8ff7534e56193c2a30ac7be8b6228382b80904cf Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Dec 2024 16:13:24 -0500 Subject: [PATCH 273/690] chore: remove unused variable --- lib/migration_generator/migration_generator.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index df32e52f..110725fc 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -156,8 +156,6 @@ defmodule AshPostgres.MigrationGenerator do if snapshot_path = config[:snapshots_path] do snapshot_path else - priv = "priv/" - app = Keyword.fetch!(config, :otp_app) Application.app_dir( From 813944bc4558bf437f4ab30c70ffbad1d15ca563 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Dec 2024 16:35:23 -0500 Subject: [PATCH 274/690] fix: handle manual/no_attributes? relationships in lateral join logic --- lib/data_layer.ex | 81 +++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 1efc3caa..a0be3ab6 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -983,6 +983,13 @@ defmodule AshPostgres.DataLayer do repo = AshSql.dynamic_repo(source_resource, AshPostgres.SqlImplementation, lateral_join_query) + # patching strange behavior that sets `take` to this empty list even though I'm not telling it to + lateral_join_query = + case lateral_join_query do + %{select: %{take: %{0 => {:map, []}}}} -> put_in(lateral_join_query.select.take, %{}) + _ -> lateral_join_query + end + results = repo.all( lateral_join_query, @@ -1058,46 +1065,52 @@ defmodule AshPostgres.DataLayer do {:ok, data_layer_query} -> source_values = Enum.map(root_data, &Map.get(&1, source_attribute)) - source_filter = - case source_pkey do - [] -> - Ecto.Query.dynamic([source], field(source, ^source_attribute) in ^source_values) - - [field] -> - values = Enum.map(root_data, &Map.get(&1, field)) - Ecto.Query.dynamic([source], field(source, ^field) in ^values) + data_layer_query = + if Map.get(relationship, :manual) || Map.get(relationship, :no_attributes?) do + data_layer_query + else + source_filter = + case source_pkey do + [] -> + Ecto.Query.dynamic([source], field(source, ^source_attribute) in ^source_values) + + [field] -> + values = Enum.map(root_data, &Map.get(&1, field)) + Ecto.Query.dynamic([source], field(source, ^field) in ^values) + + fields -> + Enum.reduce(root_data, nil, fn record, acc -> + row_match = + Enum.reduce(fields, nil, fn field, acc -> + if is_nil(acc) do + Ecto.Query.dynamic( + [source], + field(source, ^field) == ^Map.get(record, field) + ) + else + Ecto.Query.dynamic( + [source], + field(source, ^field) == ^Map.get(record, field) and ^acc + ) + end + end) - fields -> - Enum.reduce(root_data, nil, fn record, acc -> - row_match = - Enum.reduce(fields, nil, fn field, acc -> if is_nil(acc) do - Ecto.Query.dynamic( - [source], - field(source, ^field) == ^Map.get(record, field) - ) + row_match else - Ecto.Query.dynamic( - [source], - field(source, ^field) == ^Map.get(record, field) and ^acc - ) + Ecto.Query.dynamic(^row_match or ^acc) end end) + end - if is_nil(acc) do - row_match - else - Ecto.Query.dynamic(^row_match or ^acc) - end - end) + from(source in data_layer_query, + where: ^source_filter + ) end data_layer_query = - from(source in data_layer_query, - where: ^source_filter - ) - - data_layer_query = Ecto.Query.exclude(data_layer_query, :distinct) + data_layer_query + |> Ecto.Query.exclude(:distinct) if query.__ash_bindings__[:__order__?] do {:ok, @@ -1105,8 +1118,7 @@ defmodule AshPostgres.DataLayer do inner_lateral_join: destination in ^subquery, on: true, order_by: destination.__order__, - select: destination, - select_merge: %{__lateral_join_source__: map(source, ^source_pkey)}, + select: merge(destination, %{__lateral_join_source__: map(source, ^source_pkey)}), distinct: true )} else @@ -1114,8 +1126,7 @@ defmodule AshPostgres.DataLayer do from(source in data_layer_query, inner_lateral_join: destination in ^subquery, on: true, - select: destination, - select_merge: %{__lateral_join_source__: map(source, ^source_pkey)}, + select: merge(destination, %{__lateral_join_source__: map(source, ^source_pkey)}), distinct: true )} end From 715575467a1ba09328c45f4a06cec2b94ad7e54c Mon Sep 17 00:00:00 2001 From: Joshua Hansen Date: Wed, 4 Dec 2024 16:56:50 -0700 Subject: [PATCH 275/690] docs: add configuration example and reference in exceptions (#435) * docs: add configuration example and reference in exceptions * doc: replace module references with hex URLs This makes for better developer experience with terminals smart enough to use hyperlinks. --- .../dsls/DSL-AshPostgres.DataLayer.md | 2 +- lib/data_layer.ex | 10 ++++--- lib/data_layer/info.ex | 30 ++++++++++++++++++- .../migration_generator.ex | 8 +++-- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/documentation/dsls/DSL-AshPostgres.DataLayer.md b/documentation/dsls/DSL-AshPostgres.DataLayer.md index 305a925f..4ad2f0b3 100644 --- a/documentation/dsls/DSL-AshPostgres.DataLayer.md +++ b/documentation/dsls/DSL-AshPostgres.DataLayer.md @@ -44,7 +44,7 @@ end | [`migration_types`](#postgres-migration_types){: #postgres-migration_types } | `keyword` | `[]` | A keyword list of attribute names to the ecto migration type that should be used for that attribute. Only necessary if you need to override the defaults. | | [`migration_defaults`](#postgres-migration_defaults){: #postgres-migration_defaults } | `keyword` | `[]` | A keyword list of attribute names to the ecto migration default that should be used for that attribute. The string you use will be placed verbatim in the migration. Use fragments like `fragment(\\"now()\\")`, or for `nil`, use `\\"nil\\"`. | | [`calculations_to_sql`](#postgres-calculations_to_sql){: #postgres-calculations_to_sql } | `keyword` | | A keyword list of calculations and their SQL representation. Used when creating unique indexes for identities over calculations | -| [`identity_wheres_to_sql`](#postgres-identity_wheres_to_sql){: #postgres-identity_wheres_to_sql } | `keyword` | | A keyword list of identity names and the SQL representation of their `where` clause. Used when creating unique indexes for identities over calculations | +| [`identity_wheres_to_sql`](#postgres-identity_wheres_to_sql){: #postgres-identity_wheres_to_sql } | `keyword` | | A keyword list of identity names and the SQL representation of their `where` clause. See `AshPostgres.DataLayer.Info.identity_wheres_to_sql/1` for more details. | | [`base_filter_sql`](#postgres-base_filter_sql){: #postgres-base_filter_sql } | `String.t` | | A raw sql version of the base_filter, e.g `representative = true`. Required if trying to create a unique constraint on a resource with a base_filter | | [`simple_join_first_aggregates`](#postgres-simple_join_first_aggregates){: #postgres-simple_join_first_aggregates } | `list(atom)` | `[]` | A list of `:first` type aggregate names that can be joined to using a simple join. Use when you have a `:first` aggregate that uses a to-many relationship , but your `filter` statement ensures that there is only one result. Optimizes the generated query. | | [`skip_unique_indexes`](#postgres-skip_unique_indexes){: #postgres-skip_unique_indexes } | `atom \| list(atom)` | `[]` | Skip generating unique indexes when generating migrations | diff --git a/lib/data_layer.ex b/lib/data_layer.ex index a0be3ab6..670567ba 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -315,7 +315,7 @@ defmodule AshPostgres.DataLayer do identity_wheres_to_sql: [ type: :keyword_list, doc: - "A keyword list of identity names and the SQL representation of their `where` clause. Used when creating unique indexes for identities over calculations" + "A keyword list of identity names and the SQL representation of their `where` clause. See `AshPostgres.DataLayer.Info.identity_wheres_to_sql/1` for more details." ], base_filter_sql: [ type: :string, @@ -2668,9 +2668,11 @@ defmodule AshPostgres.DataLayer do case identity do %{name: name, where: where} when not is_nil(where) -> AshPostgres.DataLayer.Info.identity_where_to_sql(resource, name) || - raise( - "Must provide an entry for :#{identity.name} in `postgres.identity_wheres_to_sql` to use it as an upsert_identity" - ) + raise(""" + Must provide an entry for :#{identity.name} in `postgres.identity_wheres_to_sql` to use it as an upsert_identity. + + See https://hexdocs.pm/ash_postgres/AshPostgres.DataLayer.Info.html#identity_wheres_to_sql/1 for an example. + """) _ -> nil diff --git a/lib/data_layer/info.ex b/lib/data_layer/info.ex index 7f66ff2c..696439ae 100644 --- a/lib/data_layer/info.ex +++ b/lib/data_layer/info.ex @@ -23,11 +23,39 @@ defmodule AshPostgres.DataLayer.Info do calculations_to_sql(resource)[calc] end - @doc "A keyword list of identity names to the sql representation of their where clauses" + @doc """ + A keyword list of identity names to the literal SQL string representation of + the `where` clause portion of identity's partial unique index. + + For example, given the following identity for a resource: + + identities do + identity :active, [:status] do + where expr(status == "active") + end + end + + An appropriate `identity_wheres_to_sql` would need to be made to generate the + correct migration for the partial index used by the identity: + + postgres do + ... + + identity_wheres_to_sql active: "status = 'active'" + end + """ + @spec identity_wheres_to_sql(Ash.Resource.t()) :: keyword(String.t()) def identity_wheres_to_sql(resource) do Extension.get_opt(resource, [:postgres], :identity_wheres_to_sql, []) end + @doc """ + Returns the literal SQL for the `where` clause given a resource and an + identity name. + + See `identity_wheres_to_sql/1` for more details. + """ + @spec identity_where_to_sql(Ash.Resource.t(), atom()) :: String.t() | nil def identity_where_to_sql(resource, identity) do identity_wheres_to_sql(resource)[identity] end diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 110725fc..062bf348 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3006,9 +3006,11 @@ defmodule AshPostgres.MigrationGenerator do where: if identity.where do AshPostgres.DataLayer.Info.identity_where_to_sql(resource, identity.name) || - raise( - "Must provide an entry for :#{identity.name} in `postgres.identity_wheres_to_sql`, or skip this identity with `postgres.skip_unique_indexes`" - ) + raise(""" + Must provide an entry for :#{identity.name} in `postgres.identity_wheres_to_sql`, or skip this identity with `postgres.skip_unique_indexes`. + + See https://hexdocs.pm/ash_postgres/AshPostgres.DataLayer.Info.html#identity_wheres_to_sql/1 for an example. + """) end } end) From 25fbdfc9ac3df82d3729a54ca920ef6f1a151a06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:52:49 -0500 Subject: [PATCH 276/690] chore(deps): bump ecto in the production-dependencies group (#436) Bumps the production-dependencies group with 1 update: [ecto](https://github.com/elixir-ecto/ecto). Updates `ecto` from 3.12.4 to 3.12.5 - [Release notes](https://github.com/elixir-ecto/ecto/releases) - [Changelog](https://github.com/elixir-ecto/ecto/blob/master/CHANGELOG.md) - [Commits](https://github.com/elixir-ecto/ecto/compare/v3.12.4...v3.12.5) --- updated-dependencies: - dependency-name: ecto dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index c1d1d1e1..f18f8c17 100644 --- a/mix.lock +++ b/mix.lock @@ -9,7 +9,7 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, - "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"}, + "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, From 48b27031e1dfe8fef8a435f721708a8d8fd39bec Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Dec 2024 11:54:37 -0500 Subject: [PATCH 277/690] fix: don't attempt to use non-existent relationship --- lib/resource_generator/resource_generator.ex | 36 +++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index a4fbdeb4..fb7cdeae 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -362,22 +362,26 @@ defmodule AshPostgres.ResourceGenerator do Enum.find(table_spec.relationships, fn relationship -> relationship.type == :belongs_to and relationship.constraint_name == foreign_key.constraint_name - end).name - - options = - "" - |> add_on(:update, foreign_key.on_update) - |> add_on(:delete, foreign_key.on_delete) - |> add_match_with(foreign_key.match_with) - |> add_match_type(foreign_key.match_type) - - [ - """ - reference :#{relationship} do - #{options} - end - """ - ] + end) + + if relationship do + relationship = relationship.name + + options = + "" + |> add_on(:update, foreign_key.on_update) + |> add_on(:delete, foreign_key.on_delete) + |> add_match_with(foreign_key.match_with) + |> add_match_type(foreign_key.match_type) + + [ + """ + reference :#{relationship} do + #{options} + end + """ + ] + end end |> Enum.join("\n") |> String.trim() From 411a94e923f18feee4f955e7a08db58f19e13930 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Dec 2024 12:34:49 -0500 Subject: [PATCH 278/690] chore: add missing else case --- lib/resource_generator/resource_generator.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index fb7cdeae..9b884778 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -381,6 +381,8 @@ defmodule AshPostgres.ResourceGenerator do end """ ] + else + [] end end |> Enum.join("\n") From 14374adbb48e33c3761b64d61cc90fb4197be31f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Dec 2024 12:45:55 -0500 Subject: [PATCH 279/690] fix: split off varchar options from index --- lib/resource_generator/resource_generator.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 9b884778..34bb5b96 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -452,7 +452,7 @@ defmodule AshPostgres.ResourceGenerator do if String.contains?(thing, "(") do inspect(thing) else - ":#{thing}" + Enum.at(String.split(":#{thing}", " "), 0) end end) From b2151d47d0caae9e42e6fc97c4a49cecf13415c0 Mon Sep 17 00:00:00 2001 From: Steve Brambilla Date: Thu, 5 Dec 2024 14:05:21 -0500 Subject: [PATCH 280/690] improvement: add postgres_reference_expr callback (#438) Custom types can use this to transform bare attribute expressions into boolean expressions for filters. --- lib/sql_implementation.ex | 27 +++++++++++++++++++++++++++ lib/type.ex | 11 ++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index b9a74f93..61cff0cf 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -153,6 +153,33 @@ defmodule AshPostgres.SqlImplementation do {:ok, Ecto.Query.dynamic(fragment("(? <=> ?)", ^arg1, ^arg2)), acc} end + def expr( + query, + %Ash.Query.Ref{ + attribute: %Ash.Resource.Attribute{ + type: attr_type, + constraints: constraints, + }, + bare?: true + } = ref, + bindings, + embedded?, + acc, + type + ) do + if function_exported?(attr_type, :postgres_reference_expr, 3) do + non_bare_ref = %Ash.Query.Ref{ ref | bare?: nil } + {expr, acc} = AshSql.Expr.dynamic_expr(query, non_bare_ref, bindings, embedded?, type, acc) + + case attr_type.postgres_reference_expr(attr_type, constraints, expr) do + {:ok, bare_expr} -> {:ok, bare_expr, acc} + :error -> :error + end + else + :error + end + end + def expr( _query, _expr, diff --git a/lib/type.ex b/lib/type.ex index 4f6343d0..a437057e 100644 --- a/lib/type.ex +++ b/lib/type.ex @@ -8,12 +8,21 @@ defmodule AshPostgres.Type do @callback value_to_postgres_default(Ash.Type.t(), Ash.Type.constraints(), term) :: {:ok, String.t()} | :error + @callback postgres_reference_expr(Ash.Type.t(), Ash.Type.constraints(), term) :: + {:ok, term} | :error + + @optional_callbacks value_to_postgres_default: 3, + postgres_reference_expr: 3 + defmacro __using__(_) do quote do @behaviour AshPostgres.Type + def value_to_postgres_default(_, _, _), do: :error + def postgres_reference_expr(_, _, _), do: :error - defoverridable value_to_postgres_default: 3 + defoverridable value_to_postgres_default: 3, + postgres_reference_expr: 3 end end end From 6da0cf0357b78d1f8da66c07d7514073a00660a5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 6 Dec 2024 14:40:51 -0500 Subject: [PATCH 281/690] chore: release version v2.4.15 --- CHANGELOG.md | 19 +++++++++++++++++++ mix.exs | 6 +++--- mix.lock | 6 +++--- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d7e4b9..71434a9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.15](https://github.com/ash-project/ash_postgres/compare/v2.4.14...v2.4.15) (2024-12-06) + + + + +### Bug Fixes: + +* split off varchar options from index + +* don't attempt to use non-existent relationship + +* handle manual/no_attributes? relationships in lateral join logic + +* don't use `priv` configuration for snapshot_path + +### Improvements: + +* update sql implementation for type determination + ## [v2.4.14](https://github.com/ash-project/ash_postgres/compare/v2.4.13...v2.4.14) (2024-11-27) diff --git a/mix.exs b/mix.exs index 69599c3e..09a6a1b9 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.14" + @version "2.4.15" def project do [ @@ -164,8 +164,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.37")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.39")}, + {:ash, ash_version("~> 3.4 and >= 3.4.44")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.40")}, {:igniter, "~> 0.4 and >= 0.4.4"}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index f18f8c17..ef9171ac 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.43", "5ffd63e49b71ceaf7ed15efd20cd60ec28e9c55e28fca32b24dcc690644f2656", [: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.4", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "2b551208878c8e91f4ac3d3b6aee037f071a90a9c1151360f2a658e3b0aadf17"}, - "ash_sql": {:hex, :ash_sql, "0.2.39", "75411bea310ce514c16acd0855bdb9a754dba838fa566e1f053591fbd3da0dfb", [:mix], [{:ash, ">= 3.1.7 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", "012904de597b9132b7dfdaf073ed8b0897f78ff9263f4036478cece4ac1fa97f"}, + "ash": {:hex, :ash, "3.4.44", "9001c3b7fe6fbacc610ef0ee76d554a4ecca21eab6e7740e546017032f50496b", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "477fcca10f01b9d8dbc6ae0e17afccfb9ce85e63ec08f5f3ec992e836f52c0c7"}, + "ash_sql": {:hex, :ash_sql, "0.2.40", "b44a2b4a90e6bd228e60f673bc325e0c38bb0d94c2f36edfb45fb7d9bb418794", [:mix], [{:ash, ">= 3.1.7 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", "a547a79a4d8ba84c2d8bb40aafbeddb0ad936987452d1612379e9c5f60b62747"}, "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.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [: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", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, @@ -33,7 +33,7 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, - "reactor": {:hex, :reactor, "0.10.1", "7aad41c6f88c5214c5f878c597bc64d0f9983af3003bf2a6dbece031630a71b7", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b1aca34c0eafaefa98163778fc8252273638e36d0a70165b752910015161b6a8"}, + "reactor": {:hex, :reactor, "0.10.2", "a9150cbada58e5331c5250c51c6a8c2d7c4d337919fc71c7dc188a7ae5b6de89", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5c46e71153f540b95e1a240365fc534daead9d19abe0d46eb819b7d715663484"}, "rewrite": {:hex, :rewrite, "1.1.1", "0e6674eb5f8cb11aabe5ad6207151b4156bf173aa9b43133a68f8cc882364570", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "fcd688b3ca543c3a1f1f4615ccc054ec37cfcde91133a27a683ec09b35ae1496"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, From 4392ee1ae8faab0c2eae9a6cf6ed314c73187570 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 8 Dec 2024 23:34:51 -0500 Subject: [PATCH 282/690] docs: fix manual cte relationship example --- documentation/topics/advanced/manual-relationships.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/topics/advanced/manual-relationships.md b/documentation/topics/advanced/manual-relationships.md index 47e90e54..62291adb 100644 --- a/documentation/topics/advanced/manual-relationships.md +++ b/documentation/topics/advanced/manual-relationships.md @@ -236,18 +236,18 @@ defmodule MyApp.Employee.ManagedEmployees do # https://stackoverflow.com/questions/39458572/ecto-declare-schema-for-a-query employee_keys = Employee.__schema__(:fields) - cte_name = + cte_name_ref = from(cte in fragment("?", literal(^cte_name)), select: map(cte, ^employee_keys)) recursion_query = query - |> join(:inner, [l], lt in ^cte_name, on: l.manager_id == lt.id) + |> join(:inner, [l], lt in ^cte_name_ref, on: l.manager_id == lt.id) descendants_query = immediate_parents |> union(^recursion_query) - cte_name + cte_name_ref |> recursive_ctes(true) |> with_cte(^cte_name, as: ^descendants_query) end From f8daf7f6733fb5408c8f0baf8bfdb88c500848a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Bergstr=C3=B6m?= Date: Mon, 9 Dec 2024 18:58:08 +0100 Subject: [PATCH 283/690] test: tests for relationships with `parent(join_resource)` references (#439) --- lib/sql_implementation.ex | 28 +-- .../co_authored_posts/20241208221219.json | 97 ++++++++ .../20241208221219_migrate_resources44.exs | 48 ++++ test/many_to_many_expr_test.exs | 218 ++++++++++++++++++ test/support/domain.ex | 1 + test/support/resources/author.ex | 35 +++ test/support/resources/co_authored_post.ex | 61 +++++ test/support/resources/post.ex | 18 ++ 8 files changed, 492 insertions(+), 14 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json create mode 100644 priv/test_repo/migrations/20241208221219_migrate_resources44.exs create mode 100644 test/many_to_many_expr_test.exs create mode 100644 test/support/resources/co_authored_post.ex diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 61cff0cf..15a50bfd 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -154,21 +154,21 @@ defmodule AshPostgres.SqlImplementation do end def expr( - query, - %Ash.Query.Ref{ - attribute: %Ash.Resource.Attribute{ - type: attr_type, - constraints: constraints, - }, - bare?: true - } = ref, - bindings, - embedded?, - acc, - type - ) do + query, + %Ash.Query.Ref{ + attribute: %Ash.Resource.Attribute{ + type: attr_type, + constraints: constraints + }, + bare?: true + } = ref, + bindings, + embedded?, + acc, + type + ) do if function_exported?(attr_type, :postgres_reference_expr, 3) do - non_bare_ref = %Ash.Query.Ref{ ref | bare?: nil } + non_bare_ref = %Ash.Query.Ref{ref | bare?: nil} {expr, acc} = AshSql.Expr.dynamic_expr(query, non_bare_ref, bindings, embedded?, type, acc) case attr_type.postgres_reference_expr(attr_type, constraints, expr) do diff --git a/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json b/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json new file mode 100644 index 00000000..4503d9d8 --- /dev/null +++ b/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json @@ -0,0 +1,97 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "was_cancelled_at", + "type": "utc_datetime" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "co_authored_posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "co_authored_posts_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "post_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "E1F2AC3AED1987928E3A2446584C268EC54D0BCA616D81A495F4AB26E3999444", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "co_authored_posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20241208221219_migrate_resources44.exs b/priv/test_repo/migrations/20241208221219_migrate_resources44.exs new file mode 100644 index 00000000..3665d579 --- /dev/null +++ b/priv/test_repo/migrations/20241208221219_migrate_resources44.exs @@ -0,0 +1,48 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources44 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:co_authored_posts, primary_key: false) do + add(:role, :text, null: false) + add(:was_cancelled_at, :utc_datetime) + + add( + :author_id, + references(:authors, + column: :id, + name: "co_authored_posts_author_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + + add( + :post_id, + references(:posts, + column: :id, + name: "co_authored_posts_post_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + end + end + + def down do + drop(constraint(:co_authored_posts, "co_authored_posts_author_id_fkey")) + + drop(constraint(:co_authored_posts, "co_authored_posts_post_id_fkey")) + + drop(table(:co_authored_posts)) + end +end diff --git a/test/many_to_many_expr_test.exs b/test/many_to_many_expr_test.exs new file mode 100644 index 00000000..3c112143 --- /dev/null +++ b/test/many_to_many_expr_test.exs @@ -0,0 +1,218 @@ +defmodule AshPostgres.ManyToManyExprTest do + use AshPostgres.RepoCase, async: false + + alias AshPostgres.Test.Author + alias AshPostgres.Test.CoAuthorPost + alias AshPostgres.Test.Post + + require Ash.Query + + setup ctx do + main_author = + if ctx[:main_author?], + do: create_author(), + else: nil + + co_authors = + if ctx[:co_authors], + do: + 1..ctx[:co_authors] + |> Stream.map( + &(Author + |> Ash.Changeset.for_create(:create, %{first_name: "John #{&1}", last_name: "Doe"}) + |> Ash.create!()) + ) + |> Enum.into([]), + else: [] + + %{ + main_author: main_author, + co_authors: co_authors + } + end + + def create_author(params \\ %{first_name: "John", last_name: "Doe"}) do + Author + |> Ash.Changeset.for_create(:create, params) + |> Ash.create!() + end + + def create_post(author) do + Post + |> Ash.Changeset.for_create(:create, %{title: "Post by #{author.first_name}"}) + |> Ash.create!() + end + + def create_co_author_post(author, post, role) do + CoAuthorPost + |> Ash.Changeset.for_create(:create, %{author_id: author.id, post_id: post.id, role: role}) + |> Ash.create!() + end + + def get_author!(author_id) do + Author + |> Ash.Query.new() + |> Ash.Query.filter(id == ^author_id) + |> Ash.Query.load([ + :all_co_authored_posts, + :cancelled_co_authored_posts, + :editor_of, + :writer_of + ]) + |> Ash.read_one!() + end + + def get_co_author_post!(a_id, p_id) do + CoAuthorPost + |> Ash.Query.new() + |> Ash.Query.filter(author_id == ^a_id and post_id == ^p_id) + |> Ash.read_one!() + end + + def get_post!(post_id) do + Post.get_by_id!(post_id, load: [:co_author_posts, :co_authors_unfiltered, :co_authors]) + end + + def cancel(author, post) do + get_co_author_post!(author.id, post.id) + |> CoAuthorPost.cancel() + end + + def uncancel(author, post) do + get_co_author_post!(author.id, post.id) + |> CoAuthorPost.uncancel() + end + + describe "manual join-resource insertion" do + @tag main_author?: true + @tag co_authors: 3 + test "filter on many_to_many relationship using parent works as expected - basic", + %{ + main_author: main_author, + co_authors: co_authors + } do + post = create_post(main_author) + + [first_ca, second_ca, third_ca] = co_authors + + # Add first co-author + create_co_author_post(first_ca, post, :editor) + + first_ca = get_author!(first_ca.id) + post = get_post!(post.id) + + assert Enum.count(post.co_authors) == 1 + assert Enum.count(first_ca.all_co_authored_posts) == 1 + assert Enum.count(first_ca.editor_of) == 1 + assert Enum.empty?(first_ca.writer_of) == true + assert Enum.empty?(first_ca.cancelled_co_authored_posts) == true + + # Add second co-author + create_co_author_post(second_ca, post, :writer) + + second_ca = get_author!(second_ca.id) + post = get_post!(post.id) + + assert Enum.count(post.co_authors) == 2 + assert Enum.count(second_ca.all_co_authored_posts) == 1 + assert Enum.count(second_ca.writer_of) == 1 + assert Enum.empty?(second_ca.editor_of) == true + assert Enum.empty?(second_ca.cancelled_co_authored_posts) == true + + # Add third co-author + create_co_author_post(third_ca, post, :proof_reader) + + third_ca = get_author!(third_ca.id) + post = get_post!(post.id) + + assert Enum.count(post.co_authors) == 3 + assert Enum.count(third_ca.all_co_authored_posts) == 1 + assert Enum.empty?(third_ca.editor_of) == true + assert Enum.empty?(third_ca.writer_of) == true + assert Enum.empty?(third_ca.cancelled_co_authored_posts) == true + end + + @tag main_author?: true + @tag co_authors: 4 + test "filter on many_to_many relationship using parent works as expected - cancelled", + %{ + main_author: main_author, + co_authors: co_authors + } do + first_post = create_post(main_author) + second_post = create_post(main_author) + + [first_ca, second_ca, third_ca, fourth_ca] = co_authors + + # Add first co-author + create_co_author_post(first_ca, first_post, :editor) + create_co_author_post(first_ca, second_post, :writer) + + first_ca = get_author!(first_ca.id) + first_post = get_post!(first_post.id) + + assert Enum.count(first_post.co_authors) == 1 + assert Enum.count(first_post.co_authors_unfiltered) == 1 + + assert Enum.count(first_ca.all_co_authored_posts) == 2 + assert Enum.count(first_ca.editor_of) == 1 + assert Enum.count(first_ca.writer_of) == 1 + assert Enum.empty?(first_ca.cancelled_co_authored_posts) == true + + # Add second co-author + create_co_author_post(second_ca, first_post, :proof_reader) + create_co_author_post(second_ca, second_post, :writer) + + second_ca = get_author!(second_ca.id) + first_post = get_post!(first_post.id) + second_post = get_post!(second_post.id) + + assert Enum.count(second_post.co_authors) == 2 + assert Enum.count(second_post.co_authors_unfiltered) == 2 + + assert Enum.count(second_ca.all_co_authored_posts) == 2 + assert Enum.count(second_ca.writer_of) == 1 + assert Enum.empty?(second_ca.editor_of) == true + assert Enum.empty?(second_ca.cancelled_co_authored_posts) == true + + # Add third co-author + create_co_author_post(third_ca, first_post, :proof_reader) + create_co_author_post(third_ca, second_post, :proof_reader) + cancel(third_ca, second_post) + + third_ca = get_author!(third_ca.id) + first_post = get_post!(first_post.id) + second_post = get_post!(second_post.id) + + assert Enum.count(first_post.co_authors) == 3 + assert Enum.count(first_post.co_authors_unfiltered) == 3 + assert Enum.count(second_post.co_authors) == 2 + assert Enum.count(second_post.co_authors_unfiltered) == 3 + + assert Enum.count(third_ca.all_co_authored_posts) == 2 + assert Enum.count(third_ca.cancelled_co_authored_posts) == 1 + assert Enum.empty?(third_ca.editor_of) == true + assert Enum.empty?(third_ca.writer_of) == true + + # Add fourth co-author + create_co_author_post(fourth_ca, first_post, :proof_reader) + create_co_author_post(fourth_ca, second_post, :editor) + cancel(fourth_ca, first_post) + cancel(fourth_ca, second_post) + + fourth_ca = get_author!(fourth_ca.id) + first_post = get_post!(first_post.id) + second_post = get_post!(second_post.id) + + assert Enum.count(first_post.co_authors) == 3 + assert Enum.count(first_post.co_authors_unfiltered) == 4 + assert Enum.count(second_post.co_authors) == 2 + assert Enum.count(second_post.co_authors_unfiltered) == 4 + + assert Enum.count(fourth_ca.all_co_authored_posts) == 2 + assert Enum.count(fourth_ca.editor_of) == 1 + assert Enum.count(fourth_ca.cancelled_co_authored_posts) == 2 + assert Enum.empty?(fourth_ca.writer_of) == true + end + end +end diff --git a/test/support/domain.ex b/test/support/domain.ex index a571efb9..60d2275a 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -3,6 +3,7 @@ defmodule AshPostgres.Test.Domain do use Ash.Domain resources do + resource(AshPostgres.Test.CoAuthorPost) resource(AshPostgres.Test.Post) resource(AshPostgres.Test.Comment) resource(AshPostgres.Test.IntegerPost) diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index dd358005..d3beca51 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -53,6 +53,41 @@ defmodule AshPostgres.Test.Author do destination_attribute(:first_name) filter(expr(parent(id) != id)) end + + has_many :credited_posts, AshPostgres.Test.CoAuthorPost do + public?(true) + + destination_attribute(:author_id) + end + + many_to_many :all_co_authored_posts, AshPostgres.Test.Post do + public?(true) + join_relationship(:credited_posts) + source_attribute_on_join_resource(:author_id) + destination_attribute_on_join_resource(:post_id) + end + + many_to_many :writer_of, AshPostgres.Test.Post do + public?(true) + join_relationship(:credited_posts) + source_attribute_on_join_resource(:author_id) + destination_attribute_on_join_resource(:post_id) + filter(expr(parent(credited_posts.role) == :writer)) + end + + many_to_many :editor_of, AshPostgres.Test.Post do + public?(true) + join_relationship(:credited_posts) + source_attribute_on_join_resource(:author_id) + destination_attribute_on_join_resource(:post_id) + filter(expr(parent(credited_posts.role) == :editor)) + end + + many_to_many :cancelled_co_authored_posts, AshPostgres.Test.Post do + public?(true) + join_relationship(:credited_posts) + filter(expr(not is_nil(parent(credited_posts.was_cancelled_at)))) + end end aggregates do diff --git a/test/support/resources/co_authored_post.ex b/test/support/resources/co_authored_post.ex new file mode 100644 index 00000000..5519144b --- /dev/null +++ b/test/support/resources/co_authored_post.ex @@ -0,0 +1,61 @@ +defmodule AshPostgres.Test.CoAuthorPost do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "co_authored_posts" + repo AshPostgres.TestRepo + end + + attributes do + attribute :role, :atom do + allow_nil?(false) + public?(true) + + constraints(one_of: [:editor, :writer, :proof_reader]) + end + + attribute :was_cancelled_at, :datetime do + allow_nil?(true) + public?(true) + end + end + + actions do + default_accept(:*) + + defaults([:read, :update, :destroy]) + + create :create do + end + + update :cancel_author do + change(set_attribute(:was_cancelled_at, DateTime.utc_now())) + end + + update :uncancel_author do + change(set_attribute(:was_cancelled_at, nil)) + end + end + + code_interface do + define(:cancel, action: :cancel_author) + define(:uncancel, action: :uncancel_author) + end + + relationships do + belongs_to :author, AshPostgres.Test.Author do + primary_key?(true) + public?(true) + allow_nil?(false) + end + + belongs_to :post, AshPostgres.Test.Post do + primary_key?(true) + public?(true) + allow_nil?(false) + end + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index db11f897..92b6e4ab 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -448,6 +448,24 @@ defmodule AshPostgres.Test.Post do public?(true) end + has_many :co_author_posts, AshPostgres.Test.CoAuthorPost do + public?(true) + + destination_attribute(:post_id) + end + + many_to_many :co_authors, AshPostgres.Test.Author do + public?(true) + join_relationship(:co_author_posts) + + filter(expr(is_nil(parent(co_author_posts.was_cancelled_at)))) + end + + many_to_many :co_authors_unfiltered, AshPostgres.Test.Author do + public?(true) + join_relationship(:co_author_posts) + end + has_many :posts_with_matching_title, __MODULE__ do public?(true) no_attributes?(true) From 5d9f0fc439b0e691b8bd7abb5daf4f8ddd26d1ea Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Dec 2024 10:54:02 -0500 Subject: [PATCH 284/690] fix: only build references for belongs_to relationships --- lib/migration_generator/migration_generator.ex | 7 +++++-- mix.lock | 2 +- test/many_to_many_expr_test.exs | 8 ++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 062bf348..6c58be70 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2852,7 +2852,10 @@ defmodule AshPostgres.MigrationGenerator do end defp find_reference(resource, table, attribute) do - Enum.find_value(Ash.Resource.Info.relationships(resource), fn relationship -> + resource + |> Ash.Resource.Info.relationships() + |> Enum.filter(&(&1.type == :belongs_to)) + |> Enum.find_value(fn relationship -> source_attribute_name = relationship.source |> Ash.Resource.Info.attribute(relationship.source_attribute) @@ -2860,7 +2863,7 @@ defmodule AshPostgres.MigrationGenerator do attribute.source || attribute.name end) - if attribute.source == source_attribute_name && relationship.type == :belongs_to && + if attribute.source == source_attribute_name && foreign_key?(relationship) do configured_reference = configured_reference(resource, table, attribute.source || attribute.name, relationship) diff --git a/mix.lock b/mix.lock index ef9171ac..8d218f70 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.44", "9001c3b7fe6fbacc610ef0ee76d554a4ecca21eab6e7740e546017032f50496b", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "477fcca10f01b9d8dbc6ae0e17afccfb9ce85e63ec08f5f3ec992e836f52c0c7"}, + "ash": {:hex, :ash, "3.4.44", "10f7d0952324e4e618fd79ec6c4a4df88a087342244937c1d7807e424db05242", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "c4d51c03b57b70ab77d782d997ab0b534415789af2fd05190e51eba2e53daee5"}, "ash_sql": {:hex, :ash_sql, "0.2.40", "b44a2b4a90e6bd228e60f673bc325e0c38bb0d94c2f36edfb45fb7d9bb418794", [:mix], [{:ash, ">= 3.1.7 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", "a547a79a4d8ba84c2d8bb40aafbeddb0ad936987452d1612379e9c5f60b62747"}, "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"}, diff --git a/test/many_to_many_expr_test.exs b/test/many_to_many_expr_test.exs index 3c112143..a19fe509 100644 --- a/test/many_to_many_expr_test.exs +++ b/test/many_to_many_expr_test.exs @@ -84,6 +84,14 @@ defmodule AshPostgres.ManyToManyExprTest do end describe "manual join-resource insertion" do + @tag main_author?: true + @tag co_authors: 3 + test "using exists does not raise an error" do + Post + |> Ash.Query.filter(exists(co_authors, true)) + |> Ash.read!() + end + @tag main_author?: true @tag co_authors: 3 test "filter on many_to_many relationship using parent works as expected - basic", From 877ad289a7dae7ddd6ce570fed5ac990a5f98031 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 12 Dec 2024 10:34:55 -0500 Subject: [PATCH 285/690] fix: properly support expr errors in bulk create --- lib/data_layer.ex | 61 +++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 670567ba..c1415814 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1551,7 +1551,7 @@ defmodule AshPostgres.DataLayer do true -> {:ok, Ecto.Query.exclude(root_query, :order_by), - root_query.__ash_bindings__.expression_accumulator, false} + Map.get(root_query, :__ash_bindings__).expression_accumulator, false} end case root_query_result do @@ -1966,7 +1966,7 @@ defmodule AshPostgres.DataLayer do fields_to_upsert = upsert_fields -- - Keyword.keys(Enum.at(changesets, 0).atomics) -- keys + (Keyword.keys(Enum.at(changesets, 0).atomics) -- keys) fields_to_upsert |> Enum.uniq() @@ -2184,33 +2184,6 @@ defmodule AshPostgres.DataLayer do ) end - defp handle_raised_error( - %Postgrex.Error{} = error, - stacktrace, - {:bulk_create, fake_changeset}, - _resource - ) do - case Ecto.Adapters.Postgres.Connection.to_constraints(error, []) do - [] -> - {:error, Ash.Error.to_ash_error(error, stacktrace)} - - constraints -> - {:error, - fake_changeset - |> constraints_to_errors(:insert, constraints) - |> Ash.Error.to_ash_error()} - end - end - - defp handle_raised_error(%Ecto.Query.CastError{} = e, stacktrace, context, resource) do - handle_raised_error( - Ash.Error.Query.InvalidFilterValue.exception(value: e.value, context: context), - stacktrace, - context, - resource - ) - end - defp handle_raised_error( %Postgrex.Error{ postgres: %{ @@ -2254,6 +2227,33 @@ defmodule AshPostgres.DataLayer do {:error, :no_rollback, Ash.Error.from_json(exception, input)} end + defp handle_raised_error( + %Postgrex.Error{} = error, + stacktrace, + {:bulk_create, fake_changeset}, + _resource + ) do + case Ecto.Adapters.Postgres.Connection.to_constraints(error, []) do + [] -> + {:error, Ash.Error.to_ash_error(error, stacktrace)} + + constraints -> + {:error, + fake_changeset + |> constraints_to_errors(:insert, constraints) + |> Ash.Error.to_ash_error()} + end + end + + defp handle_raised_error(%Ecto.Query.CastError{} = e, stacktrace, context, resource) do + handle_raised_error( + Ash.Error.Query.InvalidFilterValue.exception(value: e.value, context: context), + stacktrace, + context, + resource + ) + end + defp handle_raised_error( %Postgrex.Error{} = error, stacktrace, @@ -2657,6 +2657,9 @@ defmodule AshPostgres.DataLayer do {:ok, [result]} -> {:ok, result} + {:error, :no_rollback, error} -> + {:error, :no_rollback, error} + {:error, error} -> {:error, error} end From 2ddcbb549ec0f6c7724f471ef7adb0c7d54ea24b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 12 Dec 2024 10:35:01 -0500 Subject: [PATCH 286/690] chore: release version v2.4.16 --- .tool-versions | 2 +- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.tool-versions b/.tool-versions index ce0360e0..307762be 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ erlang 27.0.1 -elixir 1.17.2-otp-27 +elixir 1.18.0-rc.0-otp-27 diff --git a/CHANGELOG.md b/CHANGELOG.md index 71434a9c..88bc29da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.16](https://github.com/ash-project/ash_postgres/compare/v2.4.15...v2.4.16) (2024-12-12) + + + + +### Bug Fixes: + +* properly support expr errors in bulk create + +* only build references for belongs_to relationships + +### Improvements: + +* add postgres_reference_expr callback (#438) + ## [v2.4.15](https://github.com/ash-project/ash_postgres/compare/v2.4.14...v2.4.15) (2024-12-06) diff --git a/mix.exs b/mix.exs index 09a6a1b9..36f287c6 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.15" + @version "2.4.16" def project do [ From aab226c8e5ef790a640bfca125b7985f7567e7f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:28:37 -0500 Subject: [PATCH 287/690] chore(deps): bump ash in the production-dependencies group (#441) Bumps the production-dependencies group with 1 update: [ash](https://github.com/ash-project/ash). Updates `ash` from 3.4.44 to 3.4.45 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.44...v3.4.45) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 8d218f70..26d3753a 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.44", "10f7d0952324e4e618fd79ec6c4a4df88a087342244937c1d7807e424db05242", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "c4d51c03b57b70ab77d782d997ab0b534415789af2fd05190e51eba2e53daee5"}, + "ash": {:hex, :ash, "3.4.45", "d52f175f213c7d76be40916ed84f26f587c89b396025cc915cda2e9f569dc0f7", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "f9f44536e9dcb852a63abf08c1f334004093d6ad9d6f927e614ffed066bac4fd"}, "ash_sql": {:hex, :ash_sql, "0.2.40", "b44a2b4a90e6bd228e60f673bc325e0c38bb0d94c2f36edfb45fb7d9bb418794", [:mix], [{:ash, ">= 3.1.7 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", "a547a79a4d8ba84c2d8bb40aafbeddb0ad936987452d1612379e9c5f60b62747"}, "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"}, From 122bcf50e10c55b61519f69a5be5397847eae27f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 12 Dec 2024 18:09:22 -0500 Subject: [PATCH 288/690] chore: fix tenant set --- test/multitenancy_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index bacd210a..0c3326b9 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -53,7 +53,7 @@ defmodule AshPostgres.Test.MultitenancyTest do assert [] = Org - |> Ash.Query.set_tenant(org1) + |> Ash.Query.set_tenant("org_" <> org1.id) |> Ash.Query.for_read(:has_policies, %{}, actor: user, authorize?: true) |> Ash.read!() end From 0b11d4379146d8eee9c5e40cab9815c2a2f91468 Mon Sep 17 00:00:00 2001 From: Oliver Severin Mulelid-Tynes Date: Fri, 13 Dec 2024 18:35:41 +0100 Subject: [PATCH 289/690] fix: alter resource generation query to go to the source pg_constraints table instead of to the view to fetch constraint data (#443) --- lib/resource_generator/spec.ex | 75 +++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index d3a256d1..3142573f 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -123,35 +123,52 @@ defmodule AshPostgres.ResourceGenerator.Spec do %Postgrex.Result{rows: fkey_rows} = spec.repo.query!( """ - SELECT - tc.constraint_name, - rc.match_option AS match_type, - rc.update_rule AS on_update, - rc.delete_rule AS on_delete, - array_agg(DISTINCT kcu.column_name) AS referencing_columns, - array_agg(DISTINCT ccu.column_name) AS referenced_columns, - ccu.table_name AS foreign_table_name - FROM - information_schema.table_constraints AS tc - JOIN information_schema.key_column_usage AS kcu - ON tc.constraint_name = kcu.constraint_name - AND tc.table_schema = kcu.table_schema - JOIN information_schema.constraint_column_usage AS ccu - ON ccu.constraint_name = tc.constraint_name - AND ccu.table_schema = tc.table_schema - JOIN information_schema.referential_constraints AS rc - ON tc.constraint_name = rc.constraint_name - AND tc.table_schema = rc.constraint_schema - WHERE - tc.constraint_type = 'FOREIGN KEY' - AND tc.table_name = $1 - AND tc.table_schema = $2 - GROUP BY - tc.constraint_name, - ccu.table_name, - rc.match_option, - rc.update_rule, - rc.delete_rule; + SELECT tc.constraint_name, + -- This has to go via the pg_constraints table directly + -- because the built in constraint view does not surface the table name + -- and constraint names are only unique per table + CASE pgc.confmatchtype + WHEN 'f'::"char" THEN 'FULL'::text + WHEN 'p'::"char" THEN 'PARTIAL'::text + WHEN 's'::"char" THEN 'NONE'::text + ELSE NULL::text + END AS match_option, + CASE pgc.confupdtype + WHEN 'c'::"char" THEN 'CASCADE'::text + WHEN 'n'::"char" THEN 'SET NULL'::text + WHEN 'd'::"char" THEN 'SET DEFAULT'::text + WHEN 'r'::"char" THEN 'RESTRICT'::text + WHEN 'a'::"char" THEN 'NO ACTION'::text + ELSE NULL::text + END AS update_rule, + CASE pgc.confdeltype + WHEN 'c'::"char" THEN 'CASCADE'::text + WHEN 'n'::"char" THEN 'SET NULL'::text + WHEN 'd'::"char" THEN 'SET DEFAULT'::text + WHEN 'r'::"char" THEN 'RESTRICT'::text + WHEN 'a'::"char" THEN 'NO ACTION'::text + ELSE NULL::text + END AS delete_rule, + array_agg(DISTINCT kcu.column_name) AS referencing_columns, + array_agg(DISTINCT ccu.column_name) AS referenced_columns, + ccu.table_name AS foreign_table_name + FROM information_schema.table_constraints AS tc + JOIN information_schema.key_column_usage AS kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_schema = kcu.table_schema + JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name + AND ccu.table_schema = tc.table_schema + JOIN pg_constraint AS pgc ON contype = 'f' AND conrelid = tc.table_name::regclass + WHERE tc.constraint_type = 'FOREIGN KEY' + AND tc.table_name = $1 + AND tc.table_schema = $2 + GROUP BY tc.constraint_name, + ccu.table_name, + pgc.confmatchtype, + pgc.confupdtype, + pgc.confdeltype + """, [spec.table_name, spec.schema], log: false From e0d810eb4508e10e27e96b3558b9e2da847c8173 Mon Sep 17 00:00:00 2001 From: Oliver Severin Mulelid-Tynes Date: Sun, 15 Dec 2024 17:48:47 +0100 Subject: [PATCH 290/690] fix: Fix query for metadata on foreign keys and fix duplicate references being produced (#444) --- lib/resource_generator/resource_generator.ex | 22 ++--- lib/resource_generator/spec.ex | 87 +++++++++++--------- 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 34bb5b96..abc70d5b 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -385,18 +385,18 @@ defmodule AshPostgres.ResourceGenerator do [] end end - |> Enum.join("\n") - |> String.trim() - |> then( - &[ - """ - references do - #{&1} - end - """ - ] - ) end) + |> Enum.join("\n") + |> String.trim() + |> then( + &[ + """ + references do + #{&1} + end + """ + ] + ) end defp add_match_with(str, empty) when empty in [[], nil], do: str diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 3142573f..a813e600 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -123,52 +123,57 @@ defmodule AshPostgres.ResourceGenerator.Spec do %Postgrex.Result{rows: fkey_rows} = spec.repo.query!( """ - SELECT tc.constraint_name, - -- This has to go via the pg_constraints table directly - -- because the built in constraint view does not surface the table name - -- and constraint names are only unique per table - CASE pgc.confmatchtype - WHEN 'f'::"char" THEN 'FULL'::text - WHEN 'p'::"char" THEN 'PARTIAL'::text - WHEN 's'::"char" THEN 'NONE'::text - ELSE NULL::text - END AS match_option, - CASE pgc.confupdtype - WHEN 'c'::"char" THEN 'CASCADE'::text - WHEN 'n'::"char" THEN 'SET NULL'::text - WHEN 'd'::"char" THEN 'SET DEFAULT'::text - WHEN 'r'::"char" THEN 'RESTRICT'::text - WHEN 'a'::"char" THEN 'NO ACTION'::text - ELSE NULL::text - END AS update_rule, - CASE pgc.confdeltype - WHEN 'c'::"char" THEN 'CASCADE'::text - WHEN 'n'::"char" THEN 'SET NULL'::text - WHEN 'd'::"char" THEN 'SET DEFAULT'::text - WHEN 'r'::"char" THEN 'RESTRICT'::text - WHEN 'a'::"char" THEN 'NO ACTION'::text - ELSE NULL::text - END AS delete_rule, + -- This has to go via the pg_constraints table directly + -- because the built in constraint view does not surface the table name + -- and constraint names are only unique per table + WITH constraints AS (SELECT conname as constraint_name, + ns.nspname::information_schema.sql_identifier AS table_schema, + CASE pgc.confmatchtype + WHEN 'f'::"char" THEN 'FULL'::text + WHEN 'p'::"char" THEN 'PARTIAL'::text + WHEN 's'::"char" THEN 'NONE'::text + ELSE NULL::text + END AS match_option, + CASE pgc.confupdtype + WHEN 'c'::"char" THEN 'CASCADE'::text + WHEN 'n'::"char" THEN 'SET NULL'::text + WHEN 'd'::"char" THEN 'SET DEFAULT'::text + WHEN 'r'::"char" THEN 'RESTRICT'::text + WHEN 'a'::"char" THEN 'NO ACTION'::text + ELSE NULL::text + END AS update_rule, + CASE pgc.confdeltype + WHEN 'c'::"char" THEN 'CASCADE'::text + WHEN 'n'::"char" THEN 'SET NULL'::text + WHEN 'd'::"char" THEN 'SET DEFAULT'::text + WHEN 'r'::"char" THEN 'RESTRICT'::text + WHEN 'a'::"char" THEN 'NO ACTION'::text + ELSE NULL::text + END AS delete_rule + FROM pg_constraint AS pgc + INNER JOIN pg_namespace AS ns ON pgc.connamespace = ns.oid + WHERE pgc.contype = 'f' -- Foreign key + AND pgc.conrelid = $1::text::regclass + AND ns.nspname = $2) + SELECT constraints.constraint_name, + constraints.match_option, + constraints.update_rule, + constraints.delete_rule, array_agg(DISTINCT kcu.column_name) AS referencing_columns, array_agg(DISTINCT ccu.column_name) AS referenced_columns, ccu.table_name AS foreign_table_name - FROM information_schema.table_constraints AS tc - JOIN information_schema.key_column_usage AS kcu - ON tc.constraint_name = kcu.constraint_name - AND tc.table_schema = kcu.table_schema + FROM information_schema.key_column_usage AS kcu + JOIN constraints + ON constraints.constraint_name = kcu.constraint_name + AND constraints.table_schema = kcu.table_schema JOIN information_schema.constraint_column_usage AS ccu - ON ccu.constraint_name = tc.constraint_name - AND ccu.table_schema = tc.table_schema - JOIN pg_constraint AS pgc ON contype = 'f' AND conrelid = tc.table_name::regclass - WHERE tc.constraint_type = 'FOREIGN KEY' - AND tc.table_name = $1 - AND tc.table_schema = $2 - GROUP BY tc.constraint_name, + ON ccu.constraint_name = constraints.constraint_name + AND ccu.table_schema = constraints.table_schema + GROUP BY constraints.constraint_name, ccu.table_name, - pgc.confmatchtype, - pgc.confupdtype, - pgc.confdeltype - + constraints.match_option, + constraints.update_rule, + constraints.delete_rule """, [spec.table_name, spec.schema], log: false From d836fa80deb19e748d7f743fbde4435c9820f49e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 15 Dec 2024 11:55:16 -0500 Subject: [PATCH 291/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 26d3753a..bd21dc9a 100644 --- a/mix.lock +++ b/mix.lock @@ -1,11 +1,11 @@ %{ - "ash": {:hex, :ash, "3.4.45", "d52f175f213c7d76be40916ed84f26f587c89b396025cc915cda2e9f569dc0f7", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "f9f44536e9dcb852a63abf08c1f334004093d6ad9d6f927e614ffed066bac4fd"}, - "ash_sql": {:hex, :ash_sql, "0.2.40", "b44a2b4a90e6bd228e60f673bc325e0c38bb0d94c2f36edfb45fb7d9bb418794", [:mix], [{:ash, ">= 3.1.7 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", "a547a79a4d8ba84c2d8bb40aafbeddb0ad936987452d1612379e9c5f60b62747"}, + "ash": {:hex, :ash, "3.4.46", "24286834d87719a8d9e0d1addf4b5be4c2acca30c554dbd5d66229d04748a15d", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "78cd7d1d3ef27516f88a503e181c8e050f80d93222d76696d7491b200bd606db"}, + "ash_sql": {:hex, :ash_sql, "0.2.41", "9e0a1686dc67a7cdc8435ced6c998dcd4de87980dde0a72d77946bbc9d1e65cb", [:mix], [{:ash, ">= 3.1.7 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", "226470dc8eeb3e89f98c0fb4ef11edf1b114e1caf3cd3457af7f9481df8221e8"}, "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.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [: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", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, - "decimal": {:hex, :decimal, "2.2.0", "df3d06bb9517e302b1bd265c1e7f16cda51547ad9d99892049340841f3e15836", [:mix], [], "hexpm", "af8daf87384b51b7e611fb1a1f2c4d4876b65ef968fa8bd3adf44cff401c7f21"}, + "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, From 5b399543648b19c22a301948194a57c2407dd29e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Dec 2024 10:04:24 -0500 Subject: [PATCH 292/690] chore: format & small fix for resource generator --- lib/data_layer.ex | 2 +- lib/resource_generator/resource_generator.ex | 29 ++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index c1415814..19d4452c 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1966,7 +1966,7 @@ defmodule AshPostgres.DataLayer do fields_to_upsert = upsert_fields -- - (Keyword.keys(Enum.at(changesets, 0).atomics) -- keys) + Keyword.keys(Enum.at(changesets, 0).atomics) -- keys fields_to_upsert |> Enum.uniq() diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index abc70d5b..13ced059 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -386,17 +386,24 @@ defmodule AshPostgres.ResourceGenerator do end end end) - |> Enum.join("\n") - |> String.trim() - |> then( - &[ - """ - references do - #{&1} - end - """ - ] - ) + |> case do + [] -> + [] + + refs -> + refs + |> Enum.join("\n") + |> String.trim() + |> then( + &[ + """ + references do + #{&1} + end + """ + ] + ) + end end defp add_match_with(str, empty) when empty in [[], nil], do: str From 6126ef99a07304e00730d48234746e4408f5a5a9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Dec 2024 10:04:48 -0500 Subject: [PATCH 293/690] chore: release version v2.4.17 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88bc29da..af41d627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.17](https://github.com/ash-project/ash_postgres/compare/v2.4.16...v2.4.17) (2024-12-16) + + + + +### Bug Fixes: + +* Fix query for metadata on foreign keys and fix duplicate references being produced (#444) + +* alter resource generation query to go to the source pg_constraints table instead of to the view to fetch constraint data (#443) + ## [v2.4.16](https://github.com/ash-project/ash_postgres/compare/v2.4.15...v2.4.16) (2024-12-12) diff --git a/mix.exs b/mix.exs index 36f287c6..e94bd4b7 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.16" + @version "2.4.17" def project do [ From 25882e936aad8d00c5fa08181baba51d2c23c769 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 16 Dec 2024 11:30:40 -0500 Subject: [PATCH 294/690] test: add test showing no query with `exists` --- test/ash_postgres_test.exs | 27 +++++++++++++++++++++++++++ test/support/resources/post.ex | 9 +++++++++ 2 files changed, 36 insertions(+) diff --git a/test/ash_postgres_test.exs b/test/ash_postgres_test.exs index 346037ad..353d3cdb 100644 --- a/test/ash_postgres_test.exs +++ b/test/ash_postgres_test.exs @@ -1,5 +1,6 @@ defmodule AshPostgresTest do use AshPostgres.RepoCase, async: false + import ExUnit.CaptureLog test "transaction metadata is given to on_transaction_begin" do AshPostgres.Test.Post @@ -40,4 +41,30 @@ defmodule AshPostgresTest do |> Map.get(:title) end end + + test "it does not run queries for exists/2 expressions that can be determined from loaded data" do + author = + AshPostgres.Test.Author + |> Ash.Changeset.for_create(:create, %{}, authorize?: false) + |> Ash.create!() + + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "good", author_id: author.id}) + |> Ash.create!() + |> Ash.load!(:author) + + log = + capture_log(fn -> + post + |> Ash.Changeset.for_update(:update_if_author, %{title: "bad"}, + authorize?: true, + actor: nil, + actor: author + ) + |> then(&AshPostgres.Test.Post.can_update_if_author?(author, &1)) + end) + + assert log == "" + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 92b6e4ab..a3fe41b3 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -80,6 +80,10 @@ defmodule AshPostgres.Test.Post do authorize_if(PassIfOriginalDataPresent) end + bypass action(:update_if_author) do + authorize_if relates_to_actor_via(:author) + end + policy action_type(:update) do authorize_if(action(:requires_initial_data)) authorize_if(relates_to_actor_via([:author, :authors_with_same_first_name])) @@ -231,6 +235,10 @@ defmodule AshPostgres.Test.Post do require_atomic?(false) end + update :update_if_author do + require_atomic?(false) + end + update(:dont_validate) update :change_title_to_foo_unless_its_already_foo do @@ -423,6 +431,7 @@ defmodule AshPostgres.Test.Post do define(:get_by_id, action: :read, get_by: [:id]) define(:increment_score, args: [{:optional, :amount}]) define(:destroy) + define(:update_if_author) define(:update_constrained_int, args: [:amount]) define_calculation(:upper_title, args: [:title]) From ff1e10efe85b25554bd09c6be14beb1f073b3c05 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Tue, 17 Dec 2024 16:55:26 -0600 Subject: [PATCH 295/690] docs: fix mention of `dont-drop-columns` option (#445) --- lib/mix/tasks/ash_postgres.generate_migrations.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index b71568d4..ea2c7383 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -9,7 +9,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do * `migration-path` - a custom path to store the migrations, defaults to "priv/repo_name/migrations". Migrations are stored in a folder for each repo, so `priv/repo_name/migrations` * `tenant-migration-path` - Same as `migration_path`, except for tenant-specific migrations - * `drop-columns` - whether or not to drop columns as attributes are removed. See below for more + * `dont-drop-columns` - whether or not to drop columns as attributes are removed. See below for more * `name` - names the generated migrations, prepending with the timestamp. The default is `migrate_resources_`, where `` is the count of migrations matching `*migrate_resources*` plus one. From db941ccff31f0802753574ff3fda7b6cdce4ee52 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 18 Dec 2024 13:00:22 -0500 Subject: [PATCH 296/690] improvement: make tsvector type selectable --- lib/types/tsvector.ex | 55 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/lib/types/tsvector.ex b/lib/types/tsvector.ex index a00705ec..f753b2b1 100644 --- a/lib/types/tsvector.ex +++ b/lib/types/tsvector.ex @@ -1,12 +1,63 @@ defmodule AshPostgres.Tsvector do @moduledoc """ - A thin wrapper around `:string` for working with tsvector types in calculations. + A type for representing postgres' tsvectors. - A calculation of this type cannot be selected, but may be used in calculations. + Values will be a list of `Postgrex.Lexeme` """ use Ash.Type.NewType, subtype_of: :term @impl true def storage_type(_), do: :tsvector + + @impl true + def cast_input(nil, _) do + {:ok, nil} + end + + def cast_input(values, _) when is_list(values) do + if Enum.all?(values, &is_struct(&1, Postgrex.Lexeme)) do + {:ok, values} + else + :error + end + end + + def cast_input(_, _) do + :error + end + + @impl true + def dump_to_native(nil, _) do + {:ok, nil} + end + + def dump_to_native(values, _) when is_list(values) do + if Enum.all?(values, &is_struct(&1, Postgrex.Lexeme)) do + {:ok, values} + else + :error + end + end + + def dump_to_native(_, _) do + :error + end + + @impl true + def cast_stored(nil, _) do + {:ok, nil} + end + + def cast_stored(values, _) when is_list(values) do + if Enum.all?(values, &is_struct(&1, Postgrex.Lexeme)) do + {:ok, values} + else + :error + end + end + + def cast_stored(_, _) do + :error + end end From a5e3eb7c47f6c9b22fbf730592d3e0375575f248 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 18 Dec 2024 22:58:40 -0500 Subject: [PATCH 297/690] improvement: make igniter optional --- lib/data_layer.ex | 46 +- lib/igniter.ex | 276 ++--- lib/mix/tasks/ash_postgres.gen.resources.ex | 324 +++--- lib/mix/tasks/ash_postgres.install.ex | 814 ++++++------- lib/resource_generator/resource_generator.ex | 1079 +++++++++--------- mix.exs | 2 +- test/ash_postgres_test.exs | 4 +- test/support/resources/post.ex | 2 +- 8 files changed, 1304 insertions(+), 1243 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 19d4452c..480f644f 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -408,8 +408,6 @@ defmodule AshPostgres.DataLayer do A postgres data layer that leverages Ecto's postgres capabilities. """ - require Igniter.Code.Common - use Spark.Dsl.Extension, sections: @sections, verifiers: [ @@ -1966,7 +1964,7 @@ defmodule AshPostgres.DataLayer do fields_to_upsert = upsert_fields -- - Keyword.keys(Enum.at(changesets, 0).atomics) -- keys + (Keyword.keys(Enum.at(changesets, 0).atomics) -- keys) fields_to_upsert |> Enum.uniq() @@ -3067,31 +3065,33 @@ defmodule AshPostgres.DataLayer do end end - def install(igniter, module, Ash.Resource, _path, argv) do - table_name = - module - |> Module.split() - |> List.last() - |> Macro.underscore() - |> Inflex.pluralize() + if Code.ensure_loaded?(Igniter) do + def install(igniter, module, Ash.Resource, _path, argv) do + table_name = + module + |> Module.split() + |> List.last() + |> Macro.underscore() + |> Inflex.pluralize() - {options, _, _} = OptionParser.parse(argv, switches: [repo: :string]) + {options, _, _} = OptionParser.parse(argv, switches: [repo: :string]) - repo = - case options[:repo] do - nil -> - Igniter.Project.Module.module_name(igniter, "Repo") + repo = + case options[:repo] do + nil -> + Igniter.Project.Module.module_name(igniter, "Repo") - repo -> - Igniter.Project.Module.parse(repo) - end + repo -> + Igniter.Project.Module.parse(repo) + end - igniter - |> Spark.Igniter.set_option(module, [:postgres, :table], table_name) - |> Spark.Igniter.set_option(module, [:postgres, :repo], repo) - end + igniter + |> Spark.Igniter.set_option(module, [:postgres, :table], table_name) + |> Spark.Igniter.set_option(module, [:postgres, :repo], repo) + end - def install(igniter, _, _, _), do: igniter + def install(igniter, _, _, _), do: igniter + end @impl true def rollback(resource, term) do diff --git a/lib/igniter.ex b/lib/igniter.ex index e4ddd6fb..75b636e6 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -1,170 +1,172 @@ -defmodule AshPostgres.Igniter do - @moduledoc "Codemods and utilities for working with AshPostgres & Igniter" +if Code.ensure_loaded?(Igniter) do + defmodule AshPostgres.Igniter do + @moduledoc "Codemods and utilities for working with AshPostgres & Igniter" - @doc false - def default_repo_contents(otp_app, name, opts \\ []) do - min_pg_version = get_min_pg_version(name, opts) + @doc false + def default_repo_contents(otp_app, name, opts \\ []) do + min_pg_version = get_min_pg_version(name, opts) - """ - use AshPostgres.Repo, otp_app: #{inspect(otp_app)} + """ + use AshPostgres.Repo, otp_app: #{inspect(otp_app)} - def min_pg_version do - %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} - end + def min_pg_version do + %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} + end - # Don't open unnecessary transactions - # will default to `false` in 4.0 - def prefer_transaction? do - false - end + # Don't open unnecessary transactions + # will default to `false` in 4.0 + def prefer_transaction? do + false + end - def installed_extensions do - # Add extensions here, and the migration generator will install them. - ["ash-functions"] + def installed_extensions do + # Add extensions here, and the migration generator will install them. + ["ash-functions"] + end + """ end - """ - end - def table(igniter, resource) do - igniter - |> Spark.Igniter.get_option(resource, [:postgres, :table]) - |> case do - {igniter, {:ok, value}} when is_binary(value) or is_nil(value) -> - {:ok, igniter, value} + def table(igniter, resource) do + igniter + |> Spark.Igniter.get_option(resource, [:postgres, :table]) + |> case do + {igniter, {:ok, value}} when is_binary(value) or is_nil(value) -> + {:ok, igniter, value} - {igniter, _} -> - {:error, igniter} + {igniter, _} -> + {:error, igniter} + end end - end - def repo(igniter, resource) do - igniter - |> Spark.Igniter.get_option(resource, [:postgres, :repo]) - |> case do - {igniter, {:ok, value}} when is_atom(value) -> - {:ok, igniter, value} + def repo(igniter, resource) do + igniter + |> Spark.Igniter.get_option(resource, [:postgres, :repo]) + |> case do + {igniter, {:ok, value}} when is_atom(value) -> + {:ok, igniter, value} - {igniter, _} -> - {:error, igniter} + {igniter, _} -> + {:error, igniter} + end end - end - def add_postgres_extension(igniter, repo_name, extension) do - Igniter.Project.Module.find_and_update_module!(igniter, repo_name, fn zipper -> - case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do - {:ok, zipper} -> - case Igniter.Code.List.append_new_to_list(zipper, extension) do - {:ok, zipper} -> - {:ok, zipper} - - _ -> - {:warning, - "Could not add installed extension #{inspect(extension)} to #{inspect(repo_name)}.installed_extensions/0"} - end - - _ -> - zipper = Sourceror.Zipper.rightmost(zipper) + def add_postgres_extension(igniter, repo_name, extension) do + Igniter.Project.Module.find_and_update_module!(igniter, repo_name, fn zipper -> + case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do + {:ok, zipper} -> + case Igniter.Code.List.append_new_to_list(zipper, extension) do + {:ok, zipper} -> + {:ok, zipper} + + _ -> + {:warning, + "Could not add installed extension #{inspect(extension)} to #{inspect(repo_name)}.installed_extensions/0"} + end + + _ -> + zipper = Sourceror.Zipper.rightmost(zipper) + + code = """ + def installed_extensions do + [#{inspect(extension)}] + end + """ + + {:ok, Igniter.Code.Common.add_code(zipper, code)} + end + end) + end - code = """ - def installed_extensions do - [#{inspect(extension)}] + def select_repo(igniter, opts \\ []) do + label = Keyword.get(opts, :label, "Which repo should be used?") + generate = Keyword.get(opts, :generate?, false) + + case list_repos(igniter) do + {igniter, []} -> + if generate do + repo = Igniter.Project.Module.module_name(igniter, "Repo") + otp_app = Igniter.Project.Application.app_name(igniter) + + igniter = + Igniter.Project.Module.create_module( + igniter, + repo, + default_repo_contents(otp_app, repo, opts), + opts + ) + + {igniter, repo} + else + {igniter, nil} end - """ - - {:ok, Igniter.Code.Common.add_code(zipper, code)} - end - end) - end - - def select_repo(igniter, opts \\ []) do - label = Keyword.get(opts, :label, "Which repo should be used?") - generate = Keyword.get(opts, :generate?, false) - - case list_repos(igniter) do - {igniter, []} -> - if generate do - repo = Igniter.Project.Module.module_name(igniter, "Repo") - otp_app = Igniter.Project.Application.app_name(igniter) - - igniter = - Igniter.Project.Module.create_module( - igniter, - repo, - default_repo_contents(otp_app, repo, opts), - opts - ) + {igniter, [repo]} -> {igniter, repo} - else - {igniter, nil} - end - {igniter, [repo]} -> - {igniter, repo} + {igniter, repos} -> + {igniter, Owl.IO.select(repos, label: label, render_as: &inspect/1)} + end + end - {igniter, repos} -> - {igniter, Owl.IO.select(repos, label: label, render_as: &inspect/1)} + def list_repos(igniter) do + Igniter.Project.Module.find_all_matching_modules(igniter, fn _mod, zipper -> + move_to_repo_use(zipper) != :error + end) end - end - def list_repos(igniter) do - Igniter.Project.Module.find_all_matching_modules(igniter, fn _mod, zipper -> - move_to_repo_use(zipper) != :error - end) - end + defp move_to_repo_use(zipper) do + Igniter.Code.Function.move_to_function_call(zipper, :use, [1, 2], fn zipper -> + Igniter.Code.Function.argument_equals?( + zipper, + 0, + AshPostgres.Repo + ) + end) + end - defp move_to_repo_use(zipper) do - Igniter.Code.Function.move_to_function_call(zipper, :use, [1, 2], fn zipper -> - Igniter.Code.Function.argument_equals?( - zipper, - 0, - AshPostgres.Repo - ) - end) - end + @doc false + def get_min_pg_version(name, opts) do + if opts[:yes] do + %Version{major: 13, minor: 0, patch: 0} + else + lead_in = """ + Generating #{inspect(name)} - @doc false - def get_min_pg_version(name, opts) do - if opts[:yes] do - %Version{major: 13, minor: 0, patch: 0} - else - lead_in = """ - Generating #{inspect(name)} + What is the minimum PostgreSQL version you will be using? - What is the minimum PostgreSQL version you will be using? + AshPostgres uses this information when generating queries and migrations, + to choose the best available features for your version of PostgreSQL. + """ - AshPostgres uses this information when generating queries and migrations, - to choose the best available features for your version of PostgreSQL. - """ + format_request = + """ + Please enter the version in the format major.minor.patch (e.g. 13.4.0) - format_request = - """ - Please enter the version in the format major.minor.patch (e.g. 13.4.0) + Default: 16.0.0 - Default: 16.0.0 + ❯ + """ - ❯ - """ + prompt = + if opts[:invalid_loop?] do + format_request + else + "#{lead_in}\n\n#{format_request}" + end - prompt = - if opts[:invalid_loop?] do - format_request - else - "#{lead_in}\n\n#{format_request}" + prompt + |> String.trim_trailing() + |> Mix.shell().prompt() + |> String.trim() + |> case do + "" -> "16.0.0" + input -> input + end + |> Version.parse() + |> case do + {:ok, version} -> version + :error -> get_min_pg_version(name, Keyword.put(opts, :invalid_loop?, true)) end - - prompt - |> String.trim_trailing() - |> Mix.shell().prompt() - |> String.trim() - |> case do - "" -> "16.0.0" - input -> input - end - |> Version.parse() - |> case do - {:ok, version} -> version - :error -> get_min_pg_version(name, Keyword.put(opts, :invalid_loop?, true)) end end end diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 6816117a..bd6c4a36 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -1,156 +1,186 @@ -defmodule Mix.Tasks.AshPostgres.Gen.Resources do - use Igniter.Mix.Task - - @example "mix ash_postgres.gen.resource MyApp.MyDomain" - - @shortdoc "Generates or updates resources based on a database schema" - - @moduledoc """ - #{@shortdoc} - - ## Example - - `#{@example}` - - ## Domain - - The domain will be generated if it does not exist. If you aren't sure, - we suggest using something like `MyApp.App`. - - ## Options - - - `repo`, `r` - The repo or repos to generate resources for, comma separated. Can be specified multiple times. Defaults to all repos. - - `tables`, `t` - Defaults to `public.*`. The tables to generate resources for, comma separated. Can be specified multiple times. See the section on tables for more. - - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. - - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. - - `extend`, `e` - Extension or extensions to apply to the generated resources. See `mix ash.patch.extend` for more. - - `yes`, `y` - Answer yes (or skip) to all questions. - - ## Tables - - When specifying tables to include with `--tables`, you can specify the table name, or the schema and table name separated by a period. - For example, `users` will generate resources for the `users` table in the `public` schema, but `accounts.users` will generate resources for the `users` table in the `accounts` schema. - - To include all tables in a given schema, add a period only with no table name, i.e `schema.`, i.e `accounts.`. - - When skipping tables with `--skip-tables`, the same rules apply, except that the `schema.` format is not supported. - """ - - @impl Igniter.Mix.Task - def info(_argv, _parent) do - %Igniter.Mix.Task.Info{ - positional: [:domain], - example: @example, - schema: [ - repo: :keep, - yes: :boolean, - tables: :keep, - skip_tables: :keep, - extend: :keep, - snapshots_only: :boolean, - domain: :keep - ], - aliases: [ - t: :tables, - y: :boolean, - r: :repo, - e: :extend, - d: :domain, - s: :skip_tables - ] - } - end +if Code.ensure_loaded?(Igniter) do + defmodule Mix.Tasks.AshPostgres.Gen.Resources do + use Igniter.Mix.Task + + @example "mix ash_postgres.gen.resource MyApp.MyDomain" + + @shortdoc "Generates resources based on a database schema" + + @moduledoc """ + #{@shortdoc} + + ## Example + + `#{@example}` + + ## Domain + + The domain will be generated if it does not exist. If you aren't sure, + we suggest using something like `MyApp.App`. + + ## Options + + - `repo`, `r` - The repo or repos to generate resources for, comma separated. Can be specified multiple times. Defaults to all repos. + - `tables`, `t` - Defaults to `public.*`. The tables to generate resources for, comma separated. Can be specified multiple times. See the section on tables for more. + - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. + - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. + - `extend`, `e` - Extension or extensions to apply to the generated resources. See `mix ash.patch.extend` for more. + - `yes`, `y` - Answer yes (or skip) to all questions. + + ## Tables + + When specifying tables to include with `--tables`, you can specify the table name, or the schema and table name separated by a period. + For example, `users` will generate resources for the `users` table in the `public` schema, but `accounts.users` will generate resources for the `users` table in the `accounts` schema. + + To include all tables in a given schema, add a period only with no table name, i.e `schema.`, i.e `accounts.`. + + When skipping tables with `--skip-tables`, the same rules apply, except that the `schema.` format is not supported. + """ + + @impl Igniter.Mix.Task + def info(_argv, _parent) do + %Igniter.Mix.Task.Info{ + positional: [:domain], + example: @example, + schema: [ + repo: :keep, + yes: :boolean, + tables: :keep, + skip_tables: :keep, + extend: :keep, + snapshots_only: :boolean, + domain: :keep + ], + aliases: [ + t: :tables, + y: :boolean, + r: :repo, + e: :extend, + d: :domain, + s: :skip_tables + ] + } + end - @impl Igniter.Mix.Task - def igniter(igniter, argv) do - Mix.Task.run("compile") - - {%{domain: domain}, argv} = positional_args!(argv) - - domain = Igniter.Project.Module.parse(domain) - - options = options!(argv) - - repos = - options[:repo] || - Mix.Project.config()[:app] - |> Application.get_env(:ecto_repos, []) - - repos = - repos - |> List.wrap() - |> Enum.map(fn v -> - if is_binary(v) do - Igniter.Project.Module.parse(v) - else - v - end - end) - - case repos do - [] -> - igniter - |> Igniter.add_warning("No ecto repos configured.") - - repos -> - Mix.shell().info("Generating resources from #{inspect(repos)}") - - prompt = - """ - - Would you like to generate migrations for the current structure? (recommended) - - If #{IO.ANSI.green()}yes#{IO.ANSI.reset()}: - We will generate migrations based on the generated resources. - You should then change your database name in your config, and - run `mix ash.setup`. - - If you already have ecto migrations you'd like to use, run - this command with `--snapshots-only`, in which case only resource - snapshots will be generated. - #{IO.ANSI.green()} - Going forward, your resources will be the source of truth.#{IO.ANSI.reset()} - #{IO.ANSI.red()} - *WARNING* - - If you run `mix ash.reset` after this command without updating - your config, you will be *deleting the database you just used to - generate these resources*!#{IO.ANSI.reset()} - - If #{IO.ANSI.red()}no#{IO.ANSI.reset()}: - - We will not generate any migrations. This means you have migrations already that - can get you from zero to the current starting point. - #{IO.ANSI.yellow()} - You will have to hand-write migrations from this point on.#{IO.ANSI.reset()} - """ - - options = - if options[:yes] || Mix.shell().yes?(prompt) do - Keyword.put(options, :no_migrations, false) - else - Keyword.put(options, :no_migrations, true) - end + @impl Igniter.Mix.Task + def igniter(igniter, argv) do + Mix.Task.run("compile") - migration_opts = - if options[:snapshots_only] do - ["--snapshots-only"] - else - [] - end + {%{domain: domain}, argv} = positional_args!(argv) - igniter - |> Igniter.compose_task("ash.gen.domain", [inspect(domain), "--ignore-if-exists"]) - |> AshPostgres.ResourceGenerator.generate(repos, domain, options) - |> then(fn igniter -> - if options[:no_migrations] do - igniter + domain = Igniter.Project.Module.parse(domain) + + options = options!(argv) + + repos = + options[:repo] || + Mix.Project.config()[:app] + |> Application.get_env(:ecto_repos, []) + + repos = + repos + |> List.wrap() + |> Enum.map(fn v -> + if is_binary(v) do + Igniter.Project.Module.parse(v) else - Igniter.add_task(igniter, "ash_postgres.generate_migrations", [ - "import_resources" | migration_opts - ]) + v end end) + + case repos do + [] -> + igniter + |> Igniter.add_warning("No ecto repos configured.") + + repos -> + Mix.shell().info("Generating resources from #{inspect(repos)}") + + prompt = + """ + + Would you like to generate migrations for the current structure? (recommended) + + If #{IO.ANSI.green()}yes#{IO.ANSI.reset()}: + We will generate migrations based on the generated resources. + You should then change your database name in your config, and + run `mix ash.setup`. + + If you already have ecto migrations you'd like to use, run + this command with `--snapshots-only`, in which case only resource + snapshots will be generated. + #{IO.ANSI.green()} + Going forward, your resources will be the source of truth.#{IO.ANSI.reset()} + #{IO.ANSI.red()} + *WARNING* + + If you run `mix ash.reset` after this command without updating + your config, you will be *deleting the database you just used to + generate these resources*!#{IO.ANSI.reset()} + + If #{IO.ANSI.red()}no#{IO.ANSI.reset()}: + + We will not generate any migrations. This means you have migrations already that + can get you from zero to the current starting point. + #{IO.ANSI.yellow()} + You will have to hand-write migrations from this point on.#{IO.ANSI.reset()} + """ + + options = + if options[:yes] || Mix.shell().yes?(prompt) do + Keyword.put(options, :no_migrations, false) + else + Keyword.put(options, :no_migrations, true) + end + + migration_opts = + if options[:snapshots_only] do + ["--snapshots-only"] + else + [] + end + + igniter + |> Igniter.compose_task("ash.gen.domain", [inspect(domain), "--ignore-if-exists"]) + |> AshPostgres.ResourceGenerator.generate(repos, domain, options) + |> then(fn igniter -> + if options[:no_migrations] do + igniter + else + Igniter.add_task(igniter, "ash_postgres.generate_migrations", [ + "import_resources" | migration_opts + ]) + end + end) + end + end + end +else + defmodule Mix.Tasks.AshPostgres.Gen.Resources do + @example "mix ash_postgres.gen.resource MyApp.MyDomain" + + @shortdoc "Generates resources based on a database schema" + + @moduledoc """ + #{@shortdoc} + + ## Example + + `#{@example}` + """ + + use Mix.Task + + def run(_argv) do + Mix.shell().error(""" + The task 'ash_postgres.gen.resources' requires igniter to be run. + + Please install igniter and try again. + + For more information, see: https://hexdocs.pm/igniter + """) + + exit({:shutdown, 1}) end end end diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 341aa1a0..d59e31dd 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -1,286 +1,287 @@ -defmodule Mix.Tasks.AshPostgres.Install do - @moduledoc "Installs AshPostgres. Should be run with `mix igniter.install ash_postgres`" - @shortdoc @moduledoc - require Igniter.Code.Common - require Igniter.Code.Function - use Igniter.Mix.Task - - @impl true - def info(_argv, _source) do - %Igniter.Mix.Task.Info{ - schema: [ - yes: :boolean, - repo: :string - ], - aliases: [ - y: :yes, - r: :repo - ] - } - end +if Code.ensure_loaded?(Igniter) do + defmodule Mix.Tasks.AshPostgres.Install do + @moduledoc "Installs AshPostgres. Should be run with `mix igniter.install ash_postgres`" + @shortdoc @moduledoc + require Igniter.Code.Common + require Igniter.Code.Function + use Igniter.Mix.Task + + @impl true + def info(_argv, _source) do + %Igniter.Mix.Task.Info{ + schema: [ + yes: :boolean, + repo: :string + ], + aliases: [ + y: :yes, + r: :repo + ] + } + end - @impl true - def igniter(igniter, argv) do - opts = options!(argv) + @impl true + def igniter(igniter, argv) do + opts = options!(argv) - repo = - case opts[:repo] do - nil -> - Igniter.Project.Module.module_name(igniter, "Repo") + repo = + case opts[:repo] do + nil -> + Igniter.Project.Module.module_name(igniter, "Repo") - repo -> - Igniter.Project.Module.parse(repo) - end - - otp_app = Igniter.Project.Application.app_name(igniter) - - igniter - |> Igniter.Project.Formatter.import_dep(:ash_postgres) - |> setup_aliases() - |> setup_repo_module(otp_app, repo, opts) - |> configure_config(otp_app, repo) - |> configure_dev(otp_app, repo) - |> configure_runtime(otp_app, repo) - |> configure_test(otp_app, repo) - |> setup_data_case() - |> Igniter.Project.Application.add_new_child(repo, - after: fn mod -> - case Module.split(mod) do - [_, "Telemetry"] -> true - _ -> false + repo -> + Igniter.Project.Module.parse(repo) end - end - ) - |> Spark.Igniter.prepend_to_section_order(:"Ash.Resource", [:postgres]) - |> Ash.Igniter.codegen("initialize") - end - defp setup_aliases(igniter) do - is_ecto_setup = &Igniter.Code.Common.nodes_equal?(&1, "ecto.setup") + otp_app = Igniter.Project.Application.app_name(igniter) - is_ecto_create_or_migrate = - fn zipper -> - Igniter.Code.Common.nodes_equal?(zipper, "ecto.create --quiet") or - Igniter.Code.Common.nodes_equal?(zipper, "ecto.create") or - Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate --quiet") or - Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate") - end - - igniter - |> Igniter.Project.TaskAliases.modify_existing_alias( - "test", - &Igniter.Code.List.remove_from_list(&1, is_ecto_create_or_migrate) - ) - |> Igniter.Project.TaskAliases.modify_existing_alias( - "test", - &Igniter.Code.List.replace_in_list( - &1, - is_ecto_setup, - Sourceror.parse_string!("\"ash.setup\"") + igniter + |> Igniter.Project.Formatter.import_dep(:ash_postgres) + |> setup_aliases() + |> setup_repo_module(otp_app, repo, opts) + |> configure_config(otp_app, repo) + |> configure_dev(otp_app, repo) + |> configure_runtime(otp_app, repo) + |> configure_test(otp_app, repo) + |> setup_data_case() + |> Igniter.Project.Application.add_new_child(repo, + after: fn mod -> + case Module.split(mod) do + [_, "Telemetry"] -> true + _ -> false + end + end ) - ) - |> Igniter.Project.TaskAliases.add_alias("test", ["ash.setup --quiet", "test"], - if_exists: {:prepend, "ash.setup --quiet"} - ) - |> run_seeds_on_setup() - end + |> Spark.Igniter.prepend_to_section_order(:"Ash.Resource", [:postgres]) + |> Ash.Igniter.codegen("initialize") + end + + defp setup_aliases(igniter) do + is_ecto_setup = &Igniter.Code.Common.nodes_equal?(&1, "ecto.setup") + + is_ecto_create_or_migrate = + fn zipper -> + Igniter.Code.Common.nodes_equal?(zipper, "ecto.create --quiet") or + Igniter.Code.Common.nodes_equal?(zipper, "ecto.create") or + Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate --quiet") or + Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate") + end - defp run_seeds_on_setup(igniter) do - if Igniter.exists?(igniter, "priv/repo/seeds.exs") do igniter - |> Igniter.Project.TaskAliases.add_alias("setup", "ash.setup", - if_exists: {:replace_or_append, "ecto.setup", "ash.setup"} + |> Igniter.Project.TaskAliases.modify_existing_alias( + "test", + &Igniter.Code.List.remove_from_list(&1, is_ecto_create_or_migrate) ) - |> Igniter.Project.TaskAliases.add_alias("setup", "run priv/repo/seeds.exs", - if_exists: :append + |> Igniter.Project.TaskAliases.modify_existing_alias( + "test", + &Igniter.Code.List.replace_in_list( + &1, + is_ecto_setup, + Sourceror.parse_string!("\"ash.setup\"") + ) + ) + |> Igniter.Project.TaskAliases.add_alias("test", ["ash.setup --quiet", "test"], + if_exists: {:prepend, "ash.setup --quiet"} ) - else - Igniter.Project.TaskAliases.add_alias(igniter, "setup", "ash.setup") + |> run_seeds_on_setup() end - end - defp configure_config(igniter, otp_app, repo) do - Igniter.Project.Config.configure( - igniter, - "config.exs", - otp_app, - [:ecto_repos], - [repo], - updater: fn zipper -> - Igniter.Code.List.prepend_new_to_list( - zipper, - repo + defp run_seeds_on_setup(igniter) do + if Igniter.exists?(igniter, "priv/repo/seeds.exs") do + igniter + |> Igniter.Project.TaskAliases.add_alias("setup", "ash.setup", + if_exists: {:replace_or_append, "ecto.setup", "ash.setup"} ) + |> Igniter.Project.TaskAliases.add_alias("setup", "run priv/repo/seeds.exs", + if_exists: :append + ) + else + Igniter.Project.TaskAliases.add_alias(igniter, "setup", "ash.setup") end - ) - end - - defp configure_runtime(igniter, otp_app, repo) do - default_runtime = """ - import Config - - if config_env() == :prod do - database_url = - System.get_env("DATABASE_URL") || - raise \"\"\" - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - \"\"\" - - config #{inspect(otp_app)}, #{inspect(repo)}, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") end - """ - igniter - |> Igniter.create_or_update_elixir_file("config/runtime.exs", default_runtime, fn zipper -> - if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo, :url]) do - zipper - else - patterns = [ - """ - if config_env() == :prod do - __cursor__() - end - """, - """ - if :prod == config_env() do - __cursor__() - end - """ - ] - - zipper - |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) - |> case do - {:ok, zipper} -> - case Igniter.Code.Function.move_to_function_call_in_current_scope( - zipper, - :=, - 2, - fn call -> - Igniter.Code.Function.argument_matches_pattern?( - call, - 0, - {:database_url, _, ctx} when is_atom(ctx) - ) - end - ) do - {:ok, _zipper} -> - zipper - |> Igniter.Project.Config.modify_configuration_code( - [repo, :url], - otp_app, - {:database_url, [], nil} - ) - |> Igniter.Project.Config.modify_configuration_code( - [repo, :pool_size], - otp_app, - Sourceror.parse_string!(""" - String.to_integer(System.get_env("POOL_SIZE") || "10") - """) - ) - |> then(&{:ok, &1}) + defp configure_config(igniter, otp_app, repo) do + Igniter.Project.Config.configure( + igniter, + "config.exs", + otp_app, + [:ecto_repos], + [repo], + updater: fn zipper -> + Igniter.Code.List.prepend_new_to_list( + zipper, + repo + ) + end + ) + end - _ -> - Igniter.Code.Common.add_code(zipper, """ - database_url = - System.get_env("DATABASE_URL") || - raise \"\"\" - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - \"\"\" - - config #{inspect(otp_app)}, Helpdesk.Repo, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") - """) - end + defp configure_runtime(igniter, otp_app, repo) do + default_runtime = """ + import Config + + if config_env() == :prod do + database_url = + System.get_env("DATABASE_URL") || + raise \"\"\" + environment variable DATABASE_URL is missing. + For example: ecto://USER:PASS@HOST/DATABASE + \"\"\" + + config #{inspect(otp_app)}, #{inspect(repo)}, + url: database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + end + """ - :error -> - Igniter.Code.Common.add_code(zipper, """ + igniter + |> Igniter.create_or_update_elixir_file("config/runtime.exs", default_runtime, fn zipper -> + if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo, :url]) do + zipper + else + patterns = [ + """ if config_env() == :prod do - database_url = - System.get_env("DATABASE_URL") || - raise \"\"\" - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - \"\"\" - - config #{inspect(otp_app)}, Helpdesk.Repo, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + __cursor__() end - """) + """, + """ + if :prod == config_env() do + __cursor__() + end + """ + ] + + zipper + |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) + |> case do + {:ok, zipper} -> + case Igniter.Code.Function.move_to_function_call_in_current_scope( + zipper, + :=, + 2, + fn call -> + Igniter.Code.Function.argument_matches_pattern?( + call, + 0, + {:database_url, _, ctx} when is_atom(ctx) + ) + end + ) do + {:ok, _zipper} -> + zipper + |> Igniter.Project.Config.modify_configuration_code( + [repo, :url], + otp_app, + {:database_url, [], nil} + ) + |> Igniter.Project.Config.modify_configuration_code( + [repo, :pool_size], + otp_app, + Sourceror.parse_string!(""" + String.to_integer(System.get_env("POOL_SIZE") || "10") + """) + ) + |> then(&{:ok, &1}) + + _ -> + Igniter.Code.Common.add_code(zipper, """ + database_url = + System.get_env("DATABASE_URL") || + raise \"\"\" + environment variable DATABASE_URL is missing. + For example: ecto://USER:PASS@HOST/DATABASE + \"\"\" + + config #{inspect(otp_app)}, Helpdesk.Repo, + url: database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + """) + end + + :error -> + Igniter.Code.Common.add_code(zipper, """ + if config_env() == :prod do + database_url = + System.get_env("DATABASE_URL") || + raise \"\"\" + environment variable DATABASE_URL is missing. + For example: ecto://USER:PASS@HOST/DATABASE + \"\"\" + + config #{inspect(otp_app)}, Helpdesk.Repo, + url: database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + end + """) + end end - end - end) - end + end) + end - defp configure_dev(igniter, otp_app, repo) do - igniter - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :username], "postgres") - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :password], "postgres") - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :hostname], "localhost") - |> Igniter.Project.Config.configure_new( - "dev.exs", - otp_app, - [repo, :database], - "#{otp_app}_dev" - ) - |> Igniter.Project.Config.configure_new( - "dev.exs", - otp_app, - [repo, :show_sensitive_data_on_connection_error], - true - ) - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :pool_size], 10) - end + defp configure_dev(igniter, otp_app, repo) do + igniter + |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :username], "postgres") + |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :password], "postgres") + |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :hostname], "localhost") + |> Igniter.Project.Config.configure_new( + "dev.exs", + otp_app, + [repo, :database], + "#{otp_app}_dev" + ) + |> Igniter.Project.Config.configure_new( + "dev.exs", + otp_app, + [repo, :show_sensitive_data_on_connection_error], + true + ) + |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :pool_size], 10) + end - defp configure_test(igniter, otp_app, repo) do - database = - {:<<>>, [], - [ - "#{otp_app}_test", - {:"::", [], - [ - {{:., [], [Kernel, :to_string]}, [from_interpolation: true], - [ - {{:., [], [{:__aliases__, [alias: false], [:System]}, :get_env]}, [], - ["MIX_TEST_PARTITION"]} - ]}, - {:binary, [], Elixir} - ]} - ]} - |> Sourceror.to_string() - |> Sourceror.parse_string!() - - igniter - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :username], "postgres") - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :password], "postgres") - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :hostname], "localhost") - |> Igniter.Project.Config.configure_new( - "test.exs", - otp_app, - [repo, :database], - {:code, database} - ) - |> Igniter.Project.Config.configure_new( - "test.exs", - otp_app, - [repo, :pool], - Ecto.Adapters.SQL.Sandbox - ) - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :pool_size], 10) - |> Igniter.Project.Config.configure_new("test.exs", :ash, [:disable_async?], true) - |> Igniter.Project.Config.configure_new("test.exs", :logger, [:level], :warning) - end + defp configure_test(igniter, otp_app, repo) do + database = + {:<<>>, [], + [ + "#{otp_app}_test", + {:"::", [], + [ + {{:., [], [Kernel, :to_string]}, [from_interpolation: true], + [ + {{:., [], [{:__aliases__, [alias: false], [:System]}, :get_env]}, [], + ["MIX_TEST_PARTITION"]} + ]}, + {:binary, [], Elixir} + ]} + ]} + |> Sourceror.to_string() + |> Sourceror.parse_string!() + + igniter + |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :username], "postgres") + |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :password], "postgres") + |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :hostname], "localhost") + |> Igniter.Project.Config.configure_new( + "test.exs", + otp_app, + [repo, :database], + {:code, database} + ) + |> Igniter.Project.Config.configure_new( + "test.exs", + otp_app, + [repo, :pool], + Ecto.Adapters.SQL.Sandbox + ) + |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :pool_size], 10) + |> Igniter.Project.Config.configure_new("test.exs", :ash, [:disable_async?], true) + |> Igniter.Project.Config.configure_new("test.exs", :logger, [:level], :warning) + end - defp setup_data_case(igniter) do - module_name = Igniter.Project.Module.module_name(igniter, "DataCase") + defp setup_data_case(igniter) do + module_name = Igniter.Project.Module.module_name(igniter, "DataCase") - default_data_case_contents = ~s| + default_data_case_contents = ~s| @moduledoc """ This module defines the setup for tests requiring access to the application's data layer. @@ -316,171 +317,192 @@ defmodule Mix.Tasks.AshPostgres.Install do end | - igniter - |> Igniter.Project.Module.find_and_update_or_create_module( - module_name, - default_data_case_contents, - # do nothing if already exists - fn zipper -> {:ok, zipper} end, - path: Igniter.Project.Module.proper_location(igniter, module_name, :test_support) - ) - end - - defp setup_repo_module(igniter, otp_app, repo, opts) do - {exists?, igniter} = Igniter.Project.Module.module_exists(igniter, repo) - - if exists? do - Igniter.Project.Module.find_and_update_module!( - igniter, - repo, - fn zipper -> - case Igniter.Code.Module.move_to_use(zipper, Ecto.Repo) do - {:ok, _} -> - {:ok, - zipper - |> set_otp_app(otp_app) - |> Sourceror.Zipper.top() - |> use_ash_postgres_instead_of_ecto() - |> Sourceror.Zipper.top() - |> remove_adapter_option()} - - _ -> - case Igniter.Code.Module.move_to_use(zipper, AshPostgres.Repo) do - {:ok, _} -> - {:ok, zipper} + igniter + |> Igniter.Project.Module.find_and_update_or_create_module( + module_name, + default_data_case_contents, + # do nothing if already exists + fn zipper -> {:ok, zipper} end, + path: Igniter.Project.Module.proper_location(igniter, module_name, :test_support) + ) + end - _ -> - {:error, - """ - Repo module #{inspect(repo)} existed, but was not an `Ecto.Repo` or an `AshPostgres.Repo`. + defp setup_repo_module(igniter, otp_app, repo, opts) do + {exists?, igniter} = Igniter.Project.Module.module_exists(igniter, repo) + + if exists? do + Igniter.Project.Module.find_and_update_module!( + igniter, + repo, + fn zipper -> + case Igniter.Code.Module.move_to_use(zipper, Ecto.Repo) do + {:ok, _} -> + {:ok, + zipper + |> set_otp_app(otp_app) + |> Sourceror.Zipper.top() + |> use_ash_postgres_instead_of_ecto() + |> Sourceror.Zipper.top() + |> remove_adapter_option()} - Please re-run the AshPostgres installer with the `--repo` option to specify a repo. - """} - end + _ -> + case Igniter.Code.Module.move_to_use(zipper, AshPostgres.Repo) do + {:ok, _} -> + {:ok, zipper} + + _ -> + {:error, + """ + Repo module #{inspect(repo)} existed, but was not an `Ecto.Repo` or an `AshPostgres.Repo`. + + Please re-run the AshPostgres installer with the `--repo` option to specify a repo. + """} + end + end end - end + ) + else + Igniter.Project.Module.create_module( + igniter, + repo, + AshPostgres.Igniter.default_repo_contents(otp_app, repo, opts) + ) + end + |> Igniter.Project.Module.find_and_update_module!( + repo, + &configure_installed_extensions_function/1 ) - else - Igniter.Project.Module.create_module( - igniter, + |> Igniter.Project.Module.find_and_update_module!( + repo, + &configure_prefer_transaction_function/1 + ) + |> Igniter.Project.Module.find_and_update_module!( repo, - AshPostgres.Igniter.default_repo_contents(otp_app, repo, opts) + &configure_min_pg_version_function(&1, repo, opts) ) end - |> Igniter.Project.Module.find_and_update_module!( - repo, - &configure_installed_extensions_function/1 - ) - |> Igniter.Project.Module.find_and_update_module!( - repo, - &configure_prefer_transaction_function/1 - ) - |> Igniter.Project.Module.find_and_update_module!( - repo, - &configure_min_pg_version_function(&1, repo, opts) - ) - end - defp use_ash_postgres_instead_of_ecto(zipper) do - with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Ecto.Repo), - {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, Ecto.Repo), - {:ok, zipper} <- - Igniter.Code.Function.update_nth_argument(zipper, 0, fn zipper -> - {:ok, Igniter.Code.Common.replace_code(zipper, AshPostgres.Repo)} - end) do - zipper - else - _ -> + defp use_ash_postgres_instead_of_ecto(zipper) do + with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Ecto.Repo), + {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, Ecto.Repo), + {:ok, zipper} <- + Igniter.Code.Function.update_nth_argument(zipper, 0, fn zipper -> + {:ok, Igniter.Code.Common.replace_code(zipper, AshPostgres.Repo)} + end) do zipper + else + _ -> + zipper + end end - end - defp remove_adapter_option(zipper) do - with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo), - {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, AshPostgres.Repo), - {:ok, zipper} <- - Igniter.Code.Function.update_nth_argument(zipper, 1, fn values_zipper -> - Igniter.Code.Keyword.remove_keyword_key(values_zipper, :adapter) - end) do - zipper - else - _ -> + defp remove_adapter_option(zipper) do + with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo), + {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, AshPostgres.Repo), + {:ok, zipper} <- + Igniter.Code.Function.update_nth_argument(zipper, 1, fn values_zipper -> + Igniter.Code.Keyword.remove_keyword_key(values_zipper, :adapter) + end) do zipper + else + _ -> + zipper + end end - end - defp set_otp_app(zipper, otp_app) do - with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo), - {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, AshPostgres.Repo), - {:ok, zipper} <- - Igniter.Code.Function.update_nth_argument(zipper, 0, fn zipper -> - {:ok, Igniter.Code.Common.replace_code(zipper, AshPostgres.Repo)} - end), - {:ok, zipper} <- - Igniter.Code.Function.update_nth_argument(zipper, 1, fn values_zipper -> - values_zipper - |> Igniter.Code.Keyword.set_keyword_key(:otp_app, otp_app, fn x -> {:ok, x} end) - end) do - zipper - else - _ -> + defp set_otp_app(zipper, otp_app) do + with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, AshPostgres.Repo), + {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, AshPostgres.Repo), + {:ok, zipper} <- + Igniter.Code.Function.update_nth_argument(zipper, 0, fn zipper -> + {:ok, Igniter.Code.Common.replace_code(zipper, AshPostgres.Repo)} + end), + {:ok, zipper} <- + Igniter.Code.Function.update_nth_argument(zipper, 1, fn values_zipper -> + values_zipper + |> Igniter.Code.Keyword.set_keyword_key(:otp_app, otp_app, fn x -> {:ok, x} end) + end) do zipper + else + _ -> + zipper + end end - end - defp configure_installed_extensions_function(zipper) do - case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do - {:ok, zipper} -> - case Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do - {:ok, zipper} -> - Igniter.Code.List.append_new_to_list(zipper, "ash-functions") + defp configure_installed_extensions_function(zipper) do + case Igniter.Code.Function.move_to_def(zipper, :installed_extensions, 0) do + {:ok, zipper} -> + case Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do + {:ok, zipper} -> + Igniter.Code.List.append_new_to_list(zipper, "ash-functions") - :error -> - {:error, "installed_extensions/0 doesn't return a list"} - end + :error -> + {:error, "installed_extensions/0 doesn't return a list"} + end - _ -> - {:ok, - Igniter.Code.Common.add_code(zipper, """ - def installed_extensions do - # Add extensions here, and the migration generator will install them. - ["ash-functions"] - end - """)} + _ -> + {:ok, + Igniter.Code.Common.add_code(zipper, """ + def installed_extensions do + # Add extensions here, and the migration generator will install them. + ["ash-functions"] + end + """)} + end end - end - defp configure_prefer_transaction_function(zipper) do - case Igniter.Code.Function.move_to_def(zipper, :prefer_transaction?, 0) do - {:ok, zipper} -> - {:ok, zipper} - - _ -> - {:ok, - Igniter.Code.Common.add_code(zipper, """ - # Don't open unnecessary transactions - # will default to `false` in 4.0 - def prefer_transaction? do - false - end - """)} + defp configure_prefer_transaction_function(zipper) do + case Igniter.Code.Function.move_to_def(zipper, :prefer_transaction?, 0) do + {:ok, zipper} -> + {:ok, zipper} + + _ -> + {:ok, + Igniter.Code.Common.add_code(zipper, """ + # Don't open unnecessary transactions + # will default to `false` in 4.0 + def prefer_transaction? do + false + end + """)} + end + end + + defp configure_min_pg_version_function(zipper, repo, opts) do + case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do + {:ok, zipper} -> + {:ok, zipper} + + _ -> + min_pg_version = AshPostgres.Igniter.get_min_pg_version(repo, opts) + + {:ok, + Igniter.Code.Common.add_code(zipper, """ + def min_pg_version do + %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} + end + """)} + end end end +else + defmodule Mix.Tasks.AshPostgres.Install do + @moduledoc "Installs AshPostgres into a project. Should be called with `mix igniter.install ash_postgres`" + + @shortdoc @moduledoc + + use Mix.Task + + def run(_argv) do + Mix.shell().error(""" + The task 'ash_postgres.install' requires igniter to be run. - defp configure_min_pg_version_function(zipper, repo, opts) do - case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do - {:ok, zipper} -> - {:ok, zipper} + Please install igniter and try again. - _ -> - min_pg_version = AshPostgres.Igniter.get_min_pg_version(repo, opts) + For more information, see: https://hexdocs.pm/igniter + """) - {:ok, - Igniter.Code.Common.add_code(zipper, """ - def min_pg_version do - %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} - end - """)} + exit({:shutdown, 1}) end end end diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 13ced059..f67e79c3 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -1,649 +1,656 @@ -defmodule AshPostgres.ResourceGenerator do - @moduledoc false - alias AshPostgres.ResourceGenerator.Spec +if Code.ensure_loaded?(Igniter) do + defmodule AshPostgres.ResourceGenerator do + @moduledoc false + alias AshPostgres.ResourceGenerator.Spec - require Logger + require Logger - def generate(igniter, repos, domain, opts \\ []) do - {igniter, resources} = Ash.Resource.Igniter.list_resources(igniter) + def generate(igniter, repos, domain, opts \\ []) do + {igniter, resources} = Ash.Resource.Igniter.list_resources(igniter) - # This is a hack. We should be looking at compiled resources - # unlikely to ever matter given how this task will be used though. - resources = Enum.filter(resources, &Code.ensure_loaded?/1) + # This is a hack. We should be looking at compiled resources + # unlikely to ever matter given how this task will be used though. + resources = Enum.filter(resources, &Code.ensure_loaded?/1) - igniter = Igniter.include_all_elixir_files(igniter) + igniter = Igniter.include_all_elixir_files(igniter) - opts = handle_csv_opts(opts, [:tables, :skip_tables, :extend]) + opts = handle_csv_opts(opts, [:tables, :skip_tables, :extend]) - specs = - repos - |> Enum.flat_map(&Spec.tables(&1, skip_tables: opts[:skip_tables], tables: opts[:tables])) - |> Enum.map(fn %{table_name: table} = spec -> - resource = - table - |> Inflex.singularize() - |> Macro.camelize() - |> then(&Module.concat([domain, &1])) + specs = + repos + |> Enum.flat_map(&Spec.tables(&1, skip_tables: opts[:skip_tables], tables: opts[:tables])) + |> Enum.map(fn %{table_name: table} = spec -> + resource = + table + |> Inflex.singularize() + |> Macro.camelize() + |> then(&Module.concat([domain, &1])) - %{spec | resource: resource} - end) - |> Enum.group_by(& &1.resource) - |> Enum.map(fn - {_resource, [single]} -> - single - - {resource, specs} -> - raise """ - Duplicate resource names detected across multiple repos: #{inspect(resource)} - - #{inspect(Enum.map(specs, & &1.repo))} - - To address this, run this command separately for each repo and specify the - `--domain` option to put the resources into a separate domain, or omit the table - with `--tables` or `--skip-tables` - """ - end) - |> Spec.add_relationships(resources, opts) - - Enum.reduce(specs, igniter, fn table_spec, igniter -> - table_to_resource(igniter, table_spec, domain, opts) - end) - end - - defp handle_csv_opts(opts, keys) do - Enum.reduce(keys, opts, fn key, opts -> - opts - |> Keyword.get_values(key) - |> case do - [] -> - opts + %{spec | resource: resource} + end) + |> Enum.group_by(& &1.resource) + |> Enum.map(fn + {_resource, [single]} -> + single - values -> - values - |> Enum.join(",") - |> String.split(",", trim: true) - |> then(&Keyword.put(opts, key, &1)) - end - end) - end + {resource, specs} -> + raise """ + Duplicate resource names detected across multiple repos: #{inspect(resource)} - defp table_to_resource( - igniter, - %AshPostgres.ResourceGenerator.Spec{} = table_spec, - domain, - opts - ) do - no_migrate_flag = - if opts[:no_migrations] do - "migrate? false" - end + #{inspect(Enum.map(specs, & &1.repo))} - resource = - """ - use Ash.Resource, - domain: #{inspect(domain)}, - data_layer: AshPostgres.DataLayer - - postgres do - table #{inspect(table_spec.table_name)} - repo #{inspect(table_spec.repo)} - #{no_migrate_flag} - #{references(table_spec, opts[:no_migrations])} - #{custom_indexes(table_spec, opts[:no_migrations])} - #{check_constraints(table_spec, opts[:no_migrations])} - #{skip_unique_indexes(table_spec)} - #{identity_index_names(table_spec)} - end + To address this, run this command separately for each repo and specify the + `--domain` option to put the resources into a separate domain, or omit the table + with `--tables` or `--skip-tables` + """ + end) + |> Spec.add_relationships(resources, opts) - attributes do - #{attributes(table_spec)} - end - """ - |> add_identities(table_spec) - |> add_relationships(table_spec) - - igniter - |> Ash.Domain.Igniter.add_resource_reference(domain, table_spec.resource) - |> Igniter.Project.Module.create_module(table_spec.resource, resource) - |> then(fn igniter -> - if opts[:extend] && opts[:extend] != [] do - Igniter.compose_task(igniter, "ash.patch.extend", [ - table_spec.resource | opts[:extend] || [] - ]) - else - igniter - end - end) - end + Enum.reduce(specs, igniter, fn table_spec, igniter -> + table_to_resource(igniter, table_spec, domain, opts) + end) + end - defp check_constraints(%{check_constraints: _check_constraints}, true) do - "" - end + defp handle_csv_opts(opts, keys) do + Enum.reduce(keys, opts, fn key, opts -> + opts + |> Keyword.get_values(key) + |> case do + [] -> + opts + + values -> + values + |> Enum.join(",") + |> String.split(",", trim: true) + |> then(&Keyword.put(opts, key, &1)) + end + end) + end - defp check_constraints(%{check_constraints: []}, _) do - "" - end + defp table_to_resource( + igniter, + %AshPostgres.ResourceGenerator.Spec{} = table_spec, + domain, + opts + ) do + no_migrate_flag = + if opts[:no_migrations] do + "migrate? false" + end - defp check_constraints(%{check_constraints: check_constraints}, _) do - check_constraints = - Enum.map_join(check_constraints, "\n", fn check_constraint -> + resource = """ - check_constraint :#{check_constraint.column}, "#{check_constraint.name}", check: "#{check_constraint.expression}", message: "is invalid" + use Ash.Resource, + domain: #{inspect(domain)}, + data_layer: AshPostgres.DataLayer + + postgres do + table #{inspect(table_spec.table_name)} + repo #{inspect(table_spec.repo)} + #{no_migrate_flag} + #{references(table_spec, opts[:no_migrations])} + #{custom_indexes(table_spec, opts[:no_migrations])} + #{check_constraints(table_spec, opts[:no_migrations])} + #{skip_unique_indexes(table_spec)} + #{identity_index_names(table_spec)} + end + + attributes do + #{attributes(table_spec)} + end """ + |> add_identities(table_spec) + |> add_relationships(table_spec) + + igniter + |> Ash.Domain.Igniter.add_resource_reference(domain, table_spec.resource) + |> Igniter.Project.Module.create_module(table_spec.resource, resource) + |> then(fn igniter -> + if opts[:extend] && opts[:extend] != [] do + Igniter.compose_task(igniter, "ash.patch.extend", [ + table_spec.resource | opts[:extend] || [] + ]) + else + igniter + end end) - - """ - check_constraints do - #{check_constraints} end - """ - end - defp skip_unique_indexes(%{indexes: indexes}) do - indexes - |> Enum.filter(fn %{unique?: unique?, columns: columns} -> - unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) - end) - |> Enum.reject(&index_as_identity?/1) - |> case do - [] -> - "" - - indexes -> - """ - skip_unique_indexes [#{Enum.map_join(indexes, ",", &":#{&1.identity_name}")}] - """ + defp check_constraints(%{check_constraints: _check_constraints}, true) do + "" end - end - defp identity_index_names(%{indexes: indexes}) do - indexes - |> Enum.filter(fn %{unique?: unique?, columns: columns} -> - unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) - end) - |> case do - [] -> - [] - - indexes -> - indexes - |> Enum.map_join(", ", fn index -> - "#{index.identity_name}: \"#{index.name}\"" - end) - |> then(&"identity_index_names [#{&1}]") + defp check_constraints(%{check_constraints: []}, _) do + "" end - end - defp add_identities(str, %{indexes: indexes}) do - indexes - |> Enum.filter(fn %{unique?: unique?, columns: columns} -> - unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) - end) - |> Enum.map(fn index -> - name = index.identity_name + defp check_constraints(%{check_constraints: check_constraints}, _) do + check_constraints = + Enum.map_join(check_constraints, "\n", fn check_constraint -> + """ + check_constraint :#{check_constraint.column}, "#{check_constraint.name}", check: "#{check_constraint.expression}", message: "is invalid" + """ + end) - fields = "[" <> Enum.map_join(index.columns, ", ", &":#{&1}") <> "]" + """ + check_constraints do + #{check_constraints} + end + """ + end - case identity_options(index) do - "" -> - "identity :#{name}, #{fields}" + defp skip_unique_indexes(%{indexes: indexes}) do + indexes + |> Enum.filter(fn %{unique?: unique?, columns: columns} -> + unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end) + |> Enum.reject(&index_as_identity?/1) + |> case do + [] -> + "" - options -> + indexes -> """ - identity :#{name}, #{fields} do - #{options} - end + skip_unique_indexes [#{Enum.map_join(indexes, ",", &":#{&1.identity_name}")}] """ end - end) - |> case do - [] -> - str - - identities -> - """ - #{str} - - identities do - #{Enum.join(identities, "\n")} - end - """ end - end - - defp identity_options(index) do - "" - |> add_identity_where(index) - |> add_nils_distinct?(index) - end - defp add_identity_where(str, %{where_clause: nil}), do: str + defp identity_index_names(%{indexes: indexes}) do + indexes + |> Enum.filter(fn %{unique?: unique?, columns: columns} -> + unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end) + |> case do + [] -> + [] - defp add_identity_where(str, %{name: name, where_clause: where_clause}) do - Logger.warning(""" - Index #{name} has been left commented out in its resource - Manual conversion of `#{where_clause}` to an Ash expression is required. - """) + indexes -> + indexes + |> Enum.map_join(", ", fn index -> + "#{index.identity_name}: \"#{index.name}\"" + end) + |> then(&"identity_index_names [#{&1}]") + end + end - """ - #{str} - # Express `#{where_clause}` as an Ash expression - # where expr(...) - """ - end + defp add_identities(str, %{indexes: indexes}) do + indexes + |> Enum.filter(fn %{unique?: unique?, columns: columns} -> + unique? && Enum.all?(columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end) + |> Enum.map(fn index -> + name = index.identity_name - defp add_nils_distinct?(str, %{nils_distinct?: false}) do - "#{str}\n nils_distinct? false" - end + fields = "[" <> Enum.map_join(index.columns, ", ", &":#{&1}") <> "]" - defp add_nils_distinct?(str, _), do: str + case identity_options(index) do + "" -> + "identity :#{name}, #{fields}" - defp add_relationships(str, %{relationships: []}) do - str - end - - defp add_relationships(str, %{relationships: relationships} = spec) do - relationships - |> Enum.map_join("\n", fn relationship -> - case relationship_options(spec, relationship) do - "" -> - "#{relationship.type} :#{relationship.name}, #{inspect(relationship.destination)}" + options -> + """ + identity :#{name}, #{fields} do + #{options} + end + """ + end + end) + |> case do + [] -> + str - options -> + identities -> """ - #{relationship.type} :#{relationship.name}, #{inspect(relationship.destination)} do - #{options} + #{str} + + identities do + #{Enum.join(identities, "\n")} end """ end - end) - |> then(fn rels -> - """ - #{str} - - relationships do - #{rels} - end - """ - end) - end - - defp relationship_options(spec, %{type: :belongs_to} = rel) do - case Enum.find(spec.attributes, fn attribute -> - attribute.name == rel.source_attribute - end) do - %{ - default: default, - generated?: generated?, - source: source, - name: name - } - when not is_nil(default) or generated? or source != name -> - "define_attribute? false" - |> add_destination_attribute(rel, "id") - |> add_source_attribute(rel, "#{rel.name}_id") - |> add_allow_nil(rel) - |> add_filter(rel) - - attribute -> - "" - |> add_destination_attribute(rel, "id") - |> add_source_attribute(rel, "#{rel.name}_id") - |> add_allow_nil(rel) - |> add_primary_key(attribute.primary_key?) - |> add_attribute_type(attribute) - |> add_filter(rel) end - end - - defp relationship_options(_spec, rel) do - default_destination_attribute = - rel.source - |> Module.split() - |> List.last() - |> Macro.underscore() - |> Kernel.<>("_id") - - "" - |> add_destination_attribute(rel, default_destination_attribute) - |> add_source_attribute(rel, "id") - |> add_filter(rel) - end - - defp add_filter(str, %{match_with: []}), do: str - defp add_filter(str, %{match_with: match_with}) do - filter = - Enum.map_join(match_with, " and ", fn {source, dest} -> - "parent(#{source}) == #{dest}" - end) - - "#{str}\n filter expr(#{filter})" - end + defp identity_options(index) do + "" + |> add_identity_where(index) + |> add_nils_distinct?(index) + end - defp add_attribute_type(str, %{attr_type: :uuid}), do: str + defp add_identity_where(str, %{where_clause: nil}), do: str - defp add_attribute_type(str, %{attr_type: attr_type}) do - "#{str}\n attribute_type :#{attr_type}" - end + defp add_identity_where(str, %{name: name, where_clause: where_clause}) do + Logger.warning(""" + Index #{name} has been left commented out in its resource + Manual conversion of `#{where_clause}` to an Ash expression is required. + """) - defp add_destination_attribute(str, rel, default) do - if rel.destination_attribute == default do - str - else - "#{str}\n destination_attribute :#{rel.destination_attribute}" + """ + #{str} + # Express `#{where_clause}` as an Ash expression + # where expr(...) + """ end - end - defp add_source_attribute(str, rel, default) do - if rel.source_attribute == default do - str - else - "#{str}\n source_attribute :#{rel.source_attribute}" + defp add_nils_distinct?(str, %{nils_distinct?: false}) do + "#{str}\n nils_distinct? false" end - end - defp references(_table_spec, true) do - "" - end - - defp references(table_spec, _) do - table_spec.foreign_keys - |> Enum.flat_map(fn %Spec.ForeignKey{} = foreign_key -> - default_name = "#{table_spec.table_name}_#{foreign_key.column}_fkey" + defp add_nils_distinct?(str, _), do: str - if default_name == foreign_key.constraint_name and - foreign_key.on_update == "NO ACTION" and - foreign_key.on_delete == "NO ACTION" and - foreign_key.match_type in ["SIMPLE", "NONE"] do - [] - else - relationship = - Enum.find(table_spec.relationships, fn relationship -> - relationship.type == :belongs_to and - relationship.constraint_name == foreign_key.constraint_name - end) - - if relationship do - relationship = relationship.name + defp add_relationships(str, %{relationships: []}) do + str + end - options = - "" - |> add_on(:update, foreign_key.on_update) - |> add_on(:delete, foreign_key.on_delete) - |> add_match_with(foreign_key.match_with) - |> add_match_type(foreign_key.match_type) + defp add_relationships(str, %{relationships: relationships} = spec) do + relationships + |> Enum.map_join("\n", fn relationship -> + case relationship_options(spec, relationship) do + "" -> + "#{relationship.type} :#{relationship.name}, #{inspect(relationship.destination)}" - [ + options -> """ - reference :#{relationship} do - #{options} + #{relationship.type} :#{relationship.name}, #{inspect(relationship.destination)} do + #{options} end """ - ] - else - [] end + end) + |> then(fn rels -> + """ + #{str} + + relationships do + #{rels} + end + """ + end) + end + + defp relationship_options(spec, %{type: :belongs_to} = rel) do + case Enum.find(spec.attributes, fn attribute -> + attribute.name == rel.source_attribute + end) do + %{ + default: default, + generated?: generated?, + source: source, + name: name + } + when not is_nil(default) or generated? or source != name -> + "define_attribute? false" + |> add_destination_attribute(rel, "id") + |> add_source_attribute(rel, "#{rel.name}_id") + |> add_allow_nil(rel) + |> add_filter(rel) + + attribute -> + "" + |> add_destination_attribute(rel, "id") + |> add_source_attribute(rel, "#{rel.name}_id") + |> add_allow_nil(rel) + |> add_primary_key(attribute.primary_key?) + |> add_attribute_type(attribute) + |> add_filter(rel) end - end) - |> case do - [] -> - [] - - refs -> - refs - |> Enum.join("\n") - |> String.trim() - |> then( - &[ - """ - references do - #{&1} - end - """ - ] - ) end - end - defp add_match_with(str, empty) when empty in [[], nil], do: str + defp relationship_options(_spec, rel) do + default_destination_attribute = + rel.source + |> Module.split() + |> List.last() + |> Macro.underscore() + |> Kernel.<>("_id") + + "" + |> add_destination_attribute(rel, default_destination_attribute) + |> add_source_attribute(rel, "id") + |> add_filter(rel) + end - defp add_match_with(str, keyval), - do: str <> "\nmatch_with [#{Enum.map_join(keyval, fn {key, val} -> "#{key}: :#{val}" end)}]" + defp add_filter(str, %{match_with: []}), do: str - defp add_match_type(str, type) when type in ["SIMPLE", "NONE"], do: str + defp add_filter(str, %{match_with: match_with}) do + filter = + Enum.map_join(match_with, " and ", fn {source, dest} -> + "parent(#{source}) == #{dest}" + end) - defp add_match_type(str, "FULL"), do: str <> "\nmatch_type :full" - defp add_match_type(str, "PARTIAL"), do: str <> "\nmatch_type :partial" + "#{str}\n filter expr(#{filter})" + end - defp add_on(str, type, "RESTRICT"), do: str <> "\non_#{type} :restrict" - defp add_on(str, type, "CASCADE"), do: str <> "\non_#{type} :#{type}" - defp add_on(str, type, "SET NULL"), do: str <> "\non_#{type} :nilify" - defp add_on(str, _type, _), do: str + defp add_attribute_type(str, %{attr_type: :uuid}), do: str - defp custom_indexes(table_spec, true) do - table_spec.indexes - |> Enum.reject(fn index -> - !index.unique? || (&index_as_identity?/1) || - Enum.any?(index.columns, &String.contains?(&1, "(")) - end) - |> case do - [] -> - "" + defp add_attribute_type(str, %{attr_type: attr_type}) do + "#{str}\n attribute_type :#{attr_type}" + end - indexes -> - indexes - |> Enum.map_join(", ", fn %{index: name, columns: columns} -> - columns = Enum.map_join(columns, ", ", &":#{&1}") - "{[#{columns}], #{inspect(name)}}" - end) - |> then(fn index_names -> - "unique_index_names [#{index_names}]" - end) + defp add_destination_attribute(str, rel, default) do + if rel.destination_attribute == default do + str + else + "#{str}\n destination_attribute :#{rel.destination_attribute}" + end end - end - defp custom_indexes(table_spec, _) do - table_spec.indexes - |> Enum.reject(&index_as_identity?/1) - |> case do - [] -> - "" - - indexes -> - indexes - |> Enum.map_join("\n", fn index -> - columns = - index.columns - |> Enum.map_join(", ", fn thing -> - if String.contains?(thing, "(") do - inspect(thing) - else - Enum.at(String.split(":#{thing}", " "), 0) - end + defp add_source_attribute(str, rel, default) do + if rel.source_attribute == default do + str + else + "#{str}\n source_attribute :#{rel.source_attribute}" + end + end + + defp references(_table_spec, true) do + "" + end + + defp references(table_spec, _) do + table_spec.foreign_keys + |> Enum.flat_map(fn %Spec.ForeignKey{} = foreign_key -> + default_name = "#{table_spec.table_name}_#{foreign_key.column}_fkey" + + if default_name == foreign_key.constraint_name and + foreign_key.on_update == "NO ACTION" and + foreign_key.on_delete == "NO ACTION" and + foreign_key.match_type in ["SIMPLE", "NONE"] do + [] + else + relationship = + Enum.find(table_spec.relationships, fn relationship -> + relationship.type == :belongs_to and + relationship.constraint_name == foreign_key.constraint_name end) - case index_options(table_spec, index) do - "" -> - "index [#{columns}]" + if relationship do + relationship = relationship.name - options -> + options = + "" + |> add_on(:update, foreign_key.on_update) + |> add_on(:delete, foreign_key.on_delete) + |> add_match_with(foreign_key.match_with) + |> add_match_type(foreign_key.match_type) + + [ """ - index [#{columns}] do + reference :#{relationship} do #{options} end """ + ] + else + [] end - end) - |> then(fn indexes -> - """ - custom_indexes do - #{indexes} - end - """ - end) + end + end) + |> case do + [] -> + [] + + refs -> + refs + |> Enum.join("\n") + |> String.trim() + |> then( + &[ + """ + references do + #{&1} + end + """ + ] + ) + end end - end - defp index_as_identity?(index) do - is_nil(index.where_clause) and index.using == "btree" and index.include in [nil, []] and - Enum.all?(index.columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) - end + defp add_match_with(str, empty) when empty in [[], nil], do: str + + defp add_match_with(str, keyval), + do: str <> "\nmatch_with [#{Enum.map_join(keyval, fn {key, val} -> "#{key}: :#{val}" end)}]" + + defp add_match_type(str, type) when type in ["SIMPLE", "NONE"], do: str + + defp add_match_type(str, "FULL"), do: str <> "\nmatch_type :full" + defp add_match_type(str, "PARTIAL"), do: str <> "\nmatch_type :partial" + + defp add_on(str, type, "RESTRICT"), do: str <> "\non_#{type} :restrict" + defp add_on(str, type, "CASCADE"), do: str <> "\non_#{type} :#{type}" + defp add_on(str, type, "SET NULL"), do: str <> "\non_#{type} :nilify" + defp add_on(str, _type, _), do: str - defp index_options(spec, index) do - default_name = - if Enum.all?(index.columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) do - AshPostgres.CustomIndex.name(spec.table_name, %{fields: index.columns}) + defp custom_indexes(table_spec, true) do + table_spec.indexes + |> Enum.reject(fn index -> + !index.unique? || (&index_as_identity?/1) || + Enum.any?(index.columns, &String.contains?(&1, "(")) + end) + |> case do + [] -> + "" + + indexes -> + indexes + |> Enum.map_join(", ", fn %{index: name, columns: columns} -> + columns = Enum.map_join(columns, ", ", &":#{&1}") + "{[#{columns}], #{inspect(name)}}" + end) + |> then(fn index_names -> + "unique_index_names [#{index_names}]" + end) end + end - "" - |> add_index_name(index.name, default_name) - |> add_unique(index.unique?) - |> add_using(index.using) - |> add_where(index.where_clause) - |> add_include(index.include) - |> add_nulls_distinct(index.nulls_distinct) - end + defp custom_indexes(table_spec, _) do + table_spec.indexes + |> Enum.reject(&index_as_identity?/1) + |> case do + [] -> + "" + + indexes -> + indexes + |> Enum.map_join("\n", fn index -> + columns = + index.columns + |> Enum.map_join(", ", fn thing -> + if String.contains?(thing, "(") do + inspect(thing) + else + Enum.at(String.split(":#{thing}", " "), 0) + end + end) + + case index_options(table_spec, index) do + "" -> + "index [#{columns}]" + + options -> + """ + index [#{columns}] do + #{options} + end + """ + end + end) + |> then(fn indexes -> + """ + custom_indexes do + #{indexes} + end + """ + end) + end + end - defp add_index_name(str, default, default), do: str - defp add_index_name(str, name, _), do: str <> "\nname #{inspect(name)}" + defp index_as_identity?(index) do + is_nil(index.where_clause) and index.using == "btree" and index.include in [nil, []] and + Enum.all?(index.columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) + end - defp add_unique(str, false), do: str - defp add_unique(str, true), do: str <> "\nunique true" + defp index_options(spec, index) do + default_name = + if Enum.all?(index.columns, &Regex.match?(~r/^[0-9a-zA-Z_]+$/, &1)) do + AshPostgres.CustomIndex.name(spec.table_name, %{fields: index.columns}) + end - defp add_nulls_distinct(str, true), do: str - defp add_nulls_distinct(str, false), do: str <> "\nnulls_distinct false" + "" + |> add_index_name(index.name, default_name) + |> add_unique(index.unique?) + |> add_using(index.using) + |> add_where(index.where_clause) + |> add_include(index.include) + |> add_nulls_distinct(index.nulls_distinct) + end - defp add_using(str, "btree"), do: str - defp add_using(str, using), do: str <> "\nusing #{inspect(using)}" + defp add_index_name(str, default, default), do: str + defp add_index_name(str, name, _), do: str <> "\nname #{inspect(name)}" - defp add_where(str, empty) when empty in [nil, ""], do: str - defp add_where(str, where), do: str <> "\nwhere #{inspect(where)}" + defp add_unique(str, false), do: str + defp add_unique(str, true), do: str <> "\nunique true" - defp add_include(str, empty) when empty in [nil, []], do: str + defp add_nulls_distinct(str, true), do: str + defp add_nulls_distinct(str, false), do: str <> "\nnulls_distinct false" - defp add_include(str, include), - do: str <> "\ninclude [#{Enum.map_join(include, ", ", &inspect/1)}]" + defp add_using(str, "btree"), do: str + defp add_using(str, using), do: str <> "\nusing #{inspect(using)}" - defp attributes(table_spec) do - table_spec.attributes - |> Enum.split_with(& &1.default) - |> then(fn {l, r} -> r ++ l end) - |> Enum.split_with(& &1.primary_key?) - |> then(fn {l, r} -> l ++ r end) - |> Enum.filter(fn attribute -> - if not is_nil(attribute.default) or !!attribute.generated? or - attribute.source != attribute.name do - true - else - not Enum.any?(table_spec.relationships, fn relationship -> - relationship.type == :belongs_to and relationship.source_attribute == attribute.name - end) - end - end) - |> Enum.map_join("\n", &attribute(&1)) - end + defp add_where(str, empty) when empty in [nil, ""], do: str + defp add_where(str, where), do: str <> "\nwhere #{inspect(where)}" - defp attribute(attribute) do - now_default = &DateTime.utc_now/0 - uuid_default = &Ash.UUID.generate/0 - - {constructor, attribute, type?, type_option?} = - case attribute do - %{name: "updated_at", attr_type: attr_type} -> - {"update_timestamp", %{attribute | default: nil, generated?: false}, false, - attr_type != :utc_datetime_usec} - - %{default: default, attr_type: attr_type} - when default == now_default -> - {"create_timestamp", %{attribute | default: nil, generated?: false}, false, - attr_type != :utc_datetime_usec} - - %{default: default, attr_type: attr_type, primary_key?: true} - when default == uuid_default -> - {"uuid_primary_key", - %{attribute | default: nil, primary_key?: false, generated?: false, allow_nil?: true}, - false, attr_type != :uuid} - - _ -> - {"attribute", attribute, true, false} - end + defp add_include(str, empty) when empty in [nil, []], do: str + + defp add_include(str, include), + do: str <> "\ninclude [#{Enum.map_join(include, ", ", &inspect/1)}]" - case String.trim(options(attribute, type_option?)) do - "" -> - if type? do - "#{constructor} :#{attribute.name}, #{inspect(attribute.attr_type)}" + defp attributes(table_spec) do + table_spec.attributes + |> Enum.split_with(& &1.default) + |> then(fn {l, r} -> r ++ l end) + |> Enum.split_with(& &1.primary_key?) + |> then(fn {l, r} -> l ++ r end) + |> Enum.filter(fn attribute -> + if not is_nil(attribute.default) or !!attribute.generated? or + attribute.source != attribute.name do + true else - "#{constructor} :#{attribute.name}" + not Enum.any?(table_spec.relationships, fn relationship -> + relationship.type == :belongs_to and relationship.source_attribute == attribute.name + end) end + end) + |> Enum.map_join("\n", &attribute(&1)) + end - options -> - if type? do - """ - #{constructor} :#{attribute.name}, #{inspect(attribute.attr_type)} do - #{options} + defp attribute(attribute) do + now_default = &DateTime.utc_now/0 + uuid_default = &Ash.UUID.generate/0 + + {constructor, attribute, type?, type_option?} = + case attribute do + %{name: "updated_at", attr_type: attr_type} -> + {"update_timestamp", %{attribute | default: nil, generated?: false}, false, + attr_type != :utc_datetime_usec} + + %{default: default, attr_type: attr_type} + when default == now_default -> + {"create_timestamp", %{attribute | default: nil, generated?: false}, false, + attr_type != :utc_datetime_usec} + + %{default: default, attr_type: attr_type, primary_key?: true} + when default == uuid_default -> + {"uuid_primary_key", + %{ + attribute + | default: nil, + primary_key?: false, + generated?: false, + allow_nil?: true + }, false, attr_type != :uuid} + + _ -> + {"attribute", attribute, true, false} + end + + case String.trim(options(attribute, type_option?)) do + "" -> + if type? do + "#{constructor} :#{attribute.name}, #{inspect(attribute.attr_type)}" + else + "#{constructor} :#{attribute.name}" end - """ - else - """ - #{constructor} :#{attribute.name} do - #{options} + + options -> + if type? do + """ + #{constructor} :#{attribute.name}, #{inspect(attribute.attr_type)} do + #{options} + end + """ + else + """ + #{constructor} :#{attribute.name} do + #{options} + end + """ end - """ - end + end end - end - defp options(attribute, type_option?) do - "" - |> add_primary_key(attribute) - |> add_allow_nil(attribute) - |> add_sensitive(attribute) - |> add_default(attribute) - |> add_type(attribute, type_option?) - |> add_generated(attribute) - |> add_source(attribute) - end + defp options(attribute, type_option?) do + "" + |> add_primary_key(attribute) + |> add_allow_nil(attribute) + |> add_sensitive(attribute) + |> add_default(attribute) + |> add_type(attribute, type_option?) + |> add_generated(attribute) + |> add_source(attribute) + end - defp add_type(str, %{attr_type: attr_type}, true) do - str <> "\n type #{inspect(attr_type)}" - end + defp add_type(str, %{attr_type: attr_type}, true) do + str <> "\n type #{inspect(attr_type)}" + end - defp add_type(str, _, _), do: str + defp add_type(str, _, _), do: str - defp add_generated(str, %{generated?: true}) do - str <> "\n generated? true" - end + defp add_generated(str, %{generated?: true}) do + str <> "\n generated? true" + end - defp add_generated(str, _), do: str + defp add_generated(str, _), do: str - defp add_source(str, %{name: name, source: source}) when name != source do - str <> "\n source :#{source}" - end + defp add_source(str, %{name: name, source: source}) when name != source do + str <> "\n source :#{source}" + end - defp add_source(str, _), do: str + defp add_source(str, _), do: str - defp add_primary_key(str, %{primary_key?: true}) do - str <> "\n primary_key? true" - end + defp add_primary_key(str, %{primary_key?: true}) do + str <> "\n primary_key? true" + end - defp add_primary_key(str, _), do: str + defp add_primary_key(str, _), do: str - defp add_allow_nil(str, %{allow_nil?: false}) do - str <> "\n allow_nil? false" - end + defp add_allow_nil(str, %{allow_nil?: false}) do + str <> "\n allow_nil? false" + end - defp add_allow_nil(str, _), do: str + defp add_allow_nil(str, _), do: str - defp add_sensitive(str, %{sensitive?: true}) do - str <> "\n sensitive? true" - end + defp add_sensitive(str, %{sensitive?: true}) do + str <> "\n sensitive? true" + end - defp add_sensitive(str, _), do: str + defp add_sensitive(str, _), do: str - defp add_default(str, %{default: default}) when not is_nil(default) do - str <> "\n default #{inspect(default)}" - end + defp add_default(str, %{default: default}) when not is_nil(default) do + str <> "\n default #{inspect(default)}" + end - defp add_default(str, _), do: str + defp add_default(str, _), do: str + end end diff --git a/mix.exs b/mix.exs index e94bd4b7..be1f9f54 100644 --- a/mix.exs +++ b/mix.exs @@ -166,7 +166,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.4 and >= 3.4.44")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.40")}, - {:igniter, "~> 0.4 and >= 0.4.4"}, + {:igniter, "~> 0.4 and >= 0.4.4", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, diff --git a/test/ash_postgres_test.exs b/test/ash_postgres_test.exs index 353d3cdb..7141b79b 100644 --- a/test/ash_postgres_test.exs +++ b/test/ash_postgres_test.exs @@ -43,7 +43,7 @@ defmodule AshPostgresTest do end test "it does not run queries for exists/2 expressions that can be determined from loaded data" do - author = + author = AshPostgres.Test.Author |> Ash.Changeset.for_create(:create, %{}, authorize?: false) |> Ash.create!() @@ -55,7 +55,7 @@ defmodule AshPostgresTest do |> Ash.load!(:author) log = - capture_log(fn -> + capture_log(fn -> post |> Ash.Changeset.for_update(:update_if_author, %{title: "bad"}, authorize?: true, diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index a3fe41b3..d9dfcdf9 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -81,7 +81,7 @@ defmodule AshPostgres.Test.Post do end bypass action(:update_if_author) do - authorize_if relates_to_actor_via(:author) + authorize_if(relates_to_actor_via(:author)) end policy action_type(:update) do From 056979ce9439734f647b98cb4ababcff60ebfa96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:28:00 -0500 Subject: [PATCH 298/690] chore(deps): bump ash in the production-dependencies group (#447) --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index bd21dc9a..bbea3320 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.46", "24286834d87719a8d9e0d1addf4b5be4c2acca30c554dbd5d66229d04748a15d", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "78cd7d1d3ef27516f88a503e181c8e050f80d93222d76696d7491b200bd606db"}, + "ash": {:hex, :ash, "3.4.47", "3d5326b45fc264419347a387b0c9ccf9e032b4d1466aa7b62c737a94585fd232", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "c1e40a04efa8df5e1cbfc71b685ec846c8090a4b19a23be50450659ed259988e"}, "ash_sql": {:hex, :ash_sql, "0.2.41", "9e0a1686dc67a7cdc8435ced6c998dcd4de87980dde0a72d77946bbc9d1e65cb", [:mix], [{:ash, ">= 3.1.7 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", "226470dc8eeb3e89f98c0fb4ef11edf1b114e1caf3cd3457af7f9481df8221e8"}, "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"}, @@ -33,12 +33,12 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, - "reactor": {:hex, :reactor, "0.10.2", "a9150cbada58e5331c5250c51c6a8c2d7c4d337919fc71c7dc188a7ae5b6de89", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5c46e71153f540b95e1a240365fc534daead9d19abe0d46eb819b7d715663484"}, + "reactor": {:hex, :reactor, "0.10.3", "41a8c34251148e36dd7c75aa8433f2c2f283f29c097f9eb84a630ab28dd75651", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b34380e22b69a35943a7bcceffd5a8b766870f1fc9052162a7ff74ef9cdb3b2"}, "rewrite": {:hex, :rewrite, "1.1.1", "0e6674eb5f8cb11aabe5ad6207151b4156bf173aa9b43133a68f8cc882364570", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "fcd688b3ca543c3a1f1f4615ccc054ec37cfcde91133a27a683ec09b35ae1496"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.35", "1c0bb30f340151eca24164885935de39e6ada4010555f444c813d0488990f8f3", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "f242d6385c287389034a0e146d8f025b5c9ab777f1ae5cf0fdfc9209db6ae748"}, + "spark": {:hex, :spark, "2.2.36", "07c921e5efb27f184267c3431d2f82099e24cac90748a47383dd75cbfb558268", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "e5ac56b75e5ad43da6d8302b6713277488f8e9a3abdba9aae8f0d0f9cff04538"}, "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From d2657c1ffb720abf3d610e8d27f3c1d715cab043 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 19 Dec 2024 16:07:13 -0500 Subject: [PATCH 299/690] fix: handle double select issue chore: update for 1.18 --- .tool-versions | 2 +- lib/data_layer.ex | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.tool-versions b/.tool-versions index 307762be..cab727e0 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ erlang 27.0.1 -elixir 1.18.0-rc.0-otp-27 +elixir 1.18.0-otp-27 diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 480f644f..2e7cc0ea 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1109,6 +1109,7 @@ defmodule AshPostgres.DataLayer do data_layer_query = data_layer_query |> Ecto.Query.exclude(:distinct) + |> Ecto.Query.exclude(:select) if query.__ash_bindings__[:__order__?] do {:ok, @@ -1149,10 +1150,12 @@ defmodule AshPostgres.DataLayer do case lateral_join_source_query(query, source_query) do {:ok, data_layer_query} -> + data_layer_query = Ecto.Query.exclude(data_layer_query, :select) + through_resource |> Ash.Query.new() |> Ash.Query.put_context(:data_layer, %{ - start_bindings_at: data_layer_query.__ash_bindings__.current + start_bindings_at: Map.get(data_layer_query, :__ash_bindings__)[:current] }) |> Ash.Query.set_context(through_relationship.context) |> Ash.Query.do_filter(through_relationship.filter) @@ -1168,6 +1171,7 @@ defmodule AshPostgres.DataLayer do end |> case do {:ok, through_query} -> + through_query = Ecto.Query.exclude(through_query, :select) if query.__ash_bindings__[:__order__?] do subquery = subquery( @@ -1180,7 +1184,7 @@ defmodule AshPostgres.DataLayer do source_query, relationship.through ), - as: ^data_layer_query.__ash_bindings__.current, + as: ^Map.get(data_layer_query, :__ash_bindings__)[:current], on: field(through, ^destination_attribute_on_join_resource) == field(destination, ^destination_attribute), @@ -1197,7 +1201,6 @@ defmodule AshPostgres.DataLayer do ) ) - data_layer_query = Ecto.Query.exclude(data_layer_query, :distinct) {:ok, from(source in data_layer_query, @@ -1220,7 +1223,7 @@ defmodule AshPostgres.DataLayer do source_query, relationship.through ), - as: ^data_layer_query.__ash_bindings__.current, + as: ^Map.get(data_layer_query, :__ash_bindings__)[:current], on: field(through, ^destination_attribute_on_join_resource) == field(destination, ^destination_attribute), From 16fe1f15b421046fcec6d6d11c9903d8799b941f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 19 Dec 2024 16:26:41 -0500 Subject: [PATCH 300/690] chore: upgrade igniter --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index bbea3320..5de55445 100644 --- a/mix.lock +++ b/mix.lock @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.4.8", "6d1bf4934952ac3eb20f6cbac0d5cd6d8012e42e3de20ad794703556c14cfa08", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "f9dd06f971fa053c6b0d9f8263b625f619a0fd3645d6a8cd6170935055a8f0df"}, + "igniter": {:hex, :igniter, "0.5.0", "00984e515c4bcd0aa0cffec83612e19041295f834392c4426e9cb0a67de16eb1", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "4cbb8acc908343bf79d90697d593b9d1bbce49ae72a0d755664d4cfe897dba53"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 410da84a669632256de4780b569437932c278036 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 19 Dec 2024 16:27:52 -0500 Subject: [PATCH 301/690] chore: format --- lib/data_layer.ex | 4 ++-- lib/migration_generator/migration_generator.ex | 6 +++--- lib/multitenancy.ex | 2 +- lib/repo/before_compile.ex | 2 +- lib/verifiers/validate_references.ex | 2 +- mix.exs | 1 + test/support/repo_case.ex | 2 +- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 2e7cc0ea..4614dd44 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1171,7 +1171,8 @@ defmodule AshPostgres.DataLayer do end |> case do {:ok, through_query} -> - through_query = Ecto.Query.exclude(through_query, :select) + through_query = Ecto.Query.exclude(through_query, :select) + if query.__ash_bindings__[:__order__?] do subquery = subquery( @@ -1201,7 +1202,6 @@ defmodule AshPostgres.DataLayer do ) ) - {:ok, from(source in data_layer_query, where: field(source, ^source_attribute) in ^source_values, diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 6c58be70..3f3dd5bf 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -177,7 +177,7 @@ defmodule AshPostgres.MigrationGenerator do |> Path.join(repo_name) |> Path.join("extensions.json") - unless opts.dry_run || opts.check do + if !(opts.dry_run || opts.check) do File.rename(legacy_snapshot_file, snapshot_file) end @@ -1027,7 +1027,7 @@ defmodule AshPostgres.MigrationGenerator do end defp create_new_snapshot(snapshots, repo_name, opts, tenant?) do - unless opts.dry_run do + if !opts.dry_run do Enum.each(snapshots, fn snapshot -> snapshot_binary = snapshot_to_binary(snapshot) @@ -2868,7 +2868,7 @@ defmodule AshPostgres.MigrationGenerator do configured_reference = configured_reference(resource, table, attribute.source || attribute.name, relationship) - unless Map.get(configured_reference, :ignore?) do + if !Map.get(configured_reference, :ignore?) do destination_attribute = Ash.Resource.Info.attribute( relationship.destination, diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index fbae77fe..505c9cb0 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -90,7 +90,7 @@ defmodule AshPostgres.MultiTenancy do end defp validate_tenant_name!(tenant_name) do - unless Regex.match?(@tenant_name_regex, tenant_name) do + if !Regex.match?(@tenant_name_regex, tenant_name) do raise "Tenant name must match #{inspect(@tenant_name_regex)}, got: #{tenant_name}" end end diff --git a/lib/repo/before_compile.ex b/lib/repo/before_compile.ex index a53f96d0..c2e9a310 100644 --- a/lib/repo/before_compile.ex +++ b/lib/repo/before_compile.ex @@ -3,7 +3,7 @@ defmodule AshPostgres.Repo.BeforeCompile do defmacro __before_compile__(_env) do quote do - unless Module.defines?(__MODULE__, {:min_pg_version, 0}, :def) do + if !Module.defines?(__MODULE__, {:min_pg_version, 0}, :def) do IO.warn(""" Please define `min_pg_version/0` in repo module: #{inspect(__MODULE__)} diff --git a/lib/verifiers/validate_references.ex b/lib/verifiers/validate_references.ex index 0bb6955c..3f2c90aa 100644 --- a/lib/verifiers/validate_references.ex +++ b/lib/verifiers/validate_references.ex @@ -7,7 +7,7 @@ defmodule AshPostgres.Verifiers.ValidateReferences do dsl |> AshPostgres.DataLayer.Info.references() |> Enum.each(fn reference -> - unless Ash.Resource.Info.relationship(dsl, reference.relationship) do + if !Ash.Resource.Info.relationship(dsl, reference.relationship) do raise Spark.Error.DslError, path: [:postgres, :references, reference.relationship], module: Verifier.get_persisted(dsl, :module), diff --git a/mix.exs b/mix.exs index be1f9f54..ec2ef870 100644 --- a/mix.exs +++ b/mix.exs @@ -237,6 +237,7 @@ defmodule AshPostgres.MixProject do "spark.replace_doc_links", "spark.cheat_sheets_in_search" ], + format: "format --migrate", "spark.formatter": "spark.formatter --extensions AshPostgres.DataLayer", "spark.cheat_sheets": "spark.cheat_sheets --extensions AshPostgres.DataLayer", "spark.cheat_sheets_in_search": diff --git a/test/support/repo_case.ex b/test/support/repo_case.ex index f4b535c9..28d9f3d2 100644 --- a/test/support/repo_case.ex +++ b/test/support/repo_case.ex @@ -19,7 +19,7 @@ defmodule AshPostgres.RepoCase do setup tags do :ok = Sandbox.checkout(AshPostgres.TestRepo) - unless tags[:async] do + if !tags[:async] do Sandbox.mode(AshPostgres.TestRepo, {:shared, self()}) end From e47cf93a00d93bcb2b3cad0ebec9ceceee8fa979 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 20 Dec 2024 11:30:53 -0500 Subject: [PATCH 302/690] chore: release version v2.4.18 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 4 ++-- mix.lock | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af41d627..32279517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.18](https://github.com/ash-project/ash_postgres/compare/v2.4.17...v2.4.18) (2024-12-20) + + + + +### Bug Fixes: + +* handle double select issue + +### Improvements: + +* make igniter optional + +* make tsvector type selectable + ## [v2.4.17](https://github.com/ash-project/ash_postgres/compare/v2.4.16...v2.4.17) (2024-12-16) diff --git a/mix.exs b/mix.exs index ec2ef870..cfddc3bd 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.17" + @version "2.4.18" def project do [ @@ -164,7 +164,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.44")}, + {:ash, ash_version("~> 3.4 and >= 3.4.48")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.40")}, {:igniter, "~> 0.4 and >= 0.4.4", optional: true}, {:ecto_sql, "~> 3.12"}, diff --git a/mix.lock b/mix.lock index 5de55445..87c21283 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.47", "3d5326b45fc264419347a387b0c9ccf9e032b4d1466aa7b62c737a94585fd232", [: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.4.8 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {: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.9", [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", "c1e40a04efa8df5e1cbfc71b685ec846c8090a4b19a23be50450659ed259988e"}, + "ash": {:hex, :ash, "3.4.48", "e2948ca59a97305f49155dda9ebe647465bdc6524cffcf2afb1d7a62904d7eb1", [: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.4.8 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.9", [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", "0086400da603a70ef5ceaee6a3cb817cb345e077bf94c0308255f2094617c5b2"}, "ash_sql": {:hex, :ash_sql, "0.2.41", "9e0a1686dc67a7cdc8435ced6c998dcd4de87980dde0a72d77946bbc9d1e65cb", [:mix], [{:ash, ">= 3.1.7 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", "226470dc8eeb3e89f98c0fb4ef11edf1b114e1caf3cd3457af7f9481df8221e8"}, "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"}, From 7e0c2053a1dc7f0732c78d5f3e41ce4e3ef58504 Mon Sep 17 00:00:00 2001 From: Alex Slade Date: Wed, 25 Dec 2024 01:13:09 +0000 Subject: [PATCH 303/690] bug: add search path to postgres functions (#449) --- lib/migration_generator/ash_functions.ex | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index 369173cb..53b29ac9 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -10,6 +10,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do CREATE OR REPLACE FUNCTION ash_elixir_or(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ SELECT COALESCE(NULLIF($1, FALSE), $2) $$ LANGUAGE SQL + SET search_path = '' IMMUTABLE; \"\"\") @@ -17,6 +18,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do CREATE OR REPLACE FUNCTION ash_elixir_or(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ SELECT COALESCE($1, $2) $$ LANGUAGE SQL + SET search_path = '' IMMUTABLE; \"\"\") @@ -27,6 +29,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do ELSE $1 END $$ LANGUAGE SQL + SET search_path = '' IMMUTABLE; \"\"\") @@ -37,6 +40,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do ELSE $1 END $$ LANGUAGE SQL + SET search_path = '' IMMUTABLE; \"\"\") @@ -62,6 +66,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do END IF; END; $$ LANGUAGE plpgsql + SET search_path = '' IMMUTABLE; \"\"\") @@ -115,6 +120,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do END IF; END; $$ LANGUAGE plpgsql + SET search_path = '' IMMUTABLE; \"\"\") """ @@ -177,7 +183,8 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do RAISE EXCEPTION '#{prefix}%', json_data::text; RETURN NULL; END; - $$ LANGUAGE plpgsql; + $$ LANGUAGE plpgsql + SET search_path = ''; \"\"\") execute(\"\"\" @@ -189,7 +196,8 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do RAISE EXCEPTION '#{prefix}%', json_data::text; RETURN NULL; END; - $$ LANGUAGE plpgsql; + $$ LANGUAGE plpgsql + SET search_path = ''; \"\"\") """ end @@ -220,6 +228,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do END $$ LANGUAGE PLPGSQL + SET search_path = '' VOLATILE; \"\"\") @@ -230,6 +239,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); $$ LANGUAGE SQL + SET search_path = '' IMMUTABLE PARALLEL SAFE STRICT; \"\"\") """ From 3da10a19b311d02cb1e120c8c6f83046eddae4ae Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 25 Dec 2024 01:25:36 -0500 Subject: [PATCH 304/690] improvement: automatically set `min_pg_version` where possible improvement: use a notice to suggest configuring `min_pg_version` doing this instead of showing a prompt, to reduce initial sign-up friction fixes #430 --- lib/igniter.ex | 29 +++++++++++---- lib/mix/tasks/ash_postgres.install.ex | 53 ++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index 75b636e6..2e00bb7b 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -3,8 +3,8 @@ if Code.ensure_loaded?(Igniter) do @moduledoc "Codemods and utilities for working with AshPostgres & Igniter" @doc false - def default_repo_contents(otp_app, name, opts \\ []) do - min_pg_version = get_min_pg_version(name, opts) + def default_repo_contents(otp_app, opts \\ []) do + min_pg_version = opts[:min_pg_version] || Version.parse!("16.0.0") """ use AshPostgres.Repo, otp_app: #{inspect(otp_app)} @@ -88,12 +88,25 @@ if Code.ensure_loaded?(Igniter) do otp_app = Igniter.Project.Application.app_name(igniter) igniter = - Igniter.Project.Module.create_module( - igniter, - repo, - default_repo_contents(otp_app, repo, opts), - opts - ) + if opts[:min_pg_version] do + igniter + else + Igniter.add_notice(igniter, """ + A `min_pg_version/0` function has been defined + in `#{inspect(repo)}` as `16.0.0`. + + You may wish to update this configuration. It should + be set to the lowest version that your application + expects to be run against. + """) + end + + Igniter.Project.Module.create_module( + igniter, + repo, + default_repo_contents(otp_app, opts), + opts + ) {igniter, repo} else diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index d59e31dd..d8942193 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -362,11 +362,40 @@ if Code.ensure_loaded?(Igniter) do end ) else + min_pg_version = get_min_pg_version() + + notice = + if min_pg_version do + """ + A `min_pg_version/0` function has been defined + in `#{inspect(repo)}` as `#{min_pg_version}`. + + This was based on running `postgres -V`. + + You may wish to update this configuration. It should + be set to the lowest version that your application + expects to be run against. + """ + else + """ + A `min_pg_version/0` function has been defined in + `#{inspect(repo)}` automatically. + + You may wish to update this configuration. It should + be set to the lowest version that your application + expects to be run against. + """ + end + Igniter.Project.Module.create_module( igniter, repo, - AshPostgres.Igniter.default_repo_contents(otp_app, repo, opts) + AshPostgres.Igniter.default_repo_contents( + otp_app, + Keyword.put(opts, :min_pg_version, min_pg_version) + ) ) + |> Igniter.add_notice(notice) end |> Igniter.Project.Module.find_and_update_module!( repo, @@ -382,6 +411,28 @@ if Code.ensure_loaded?(Igniter) do ) end + def get_min_pg_version do + case System.cmd("postgres", ["-V"]) do + {"postgres (PostgreSQL) " <> version_and_text, 0} -> + version_and_text + |> String.split(~r/\s+/, parts: 2, trim: true) + |> Enum.at(0) + |> String.split(".", trim: true) + |> case do + [major, minor, patch | _] -> Version.parse!("#{major}.#{minor}.#{patch}") + [major, minor] -> Version.parse!("#{major}.#{minor}.0") + [major] -> Version.parse!("#{major}.0.0") + _ -> nil + end + + _ -> + nil + end + rescue + _ -> + nil + end + defp use_ash_postgres_instead_of_ecto(zipper) do with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Ecto.Repo), {:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, Ecto.Repo), From a630f4b854c72247dc576790514c07d1f239d6bc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 25 Dec 2024 02:25:57 -0500 Subject: [PATCH 305/690] improvement: better min_pg_version when modifying a repo --- lib/mix/tasks/ash_postgres.install.ex | 79 ++++++++++++++++----------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index d8942193..460637bb 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -362,30 +362,7 @@ if Code.ensure_loaded?(Igniter) do end ) else - min_pg_version = get_min_pg_version() - - notice = - if min_pg_version do - """ - A `min_pg_version/0` function has been defined - in `#{inspect(repo)}` as `#{min_pg_version}`. - - This was based on running `postgres -V`. - - You may wish to update this configuration. It should - be set to the lowest version that your application - expects to be run against. - """ - else - """ - A `min_pg_version/0` function has been defined in - `#{inspect(repo)}` automatically. - - You may wish to update this configuration. It should - be set to the lowest version that your application - expects to be run against. - """ - end + {min_pg_version, notice} = min_pg_version_and_notice(repo) Igniter.Project.Module.create_module( igniter, @@ -405,13 +382,53 @@ if Code.ensure_loaded?(Igniter) do repo, &configure_prefer_transaction_function/1 ) - |> Igniter.Project.Module.find_and_update_module!( - repo, - &configure_min_pg_version_function(&1, repo, opts) - ) + |> then(fn igniter -> + {min_pg_version, notice} = min_pg_version_and_notice(repo) + + igniter + |> Igniter.Project.Module.find_and_update_module!( + repo, + &configure_min_pg_version_function( + &1, + repo, + min_pg_version || Version.parse!("16.0.0"), + opts + ) + ) + |> Igniter.add_notice(notice) + end) + end + + defp min_pg_version_and_notice(repo) do + min_pg_version = get_min_pg_version() + + notice = + if min_pg_version do + """ + A `min_pg_version/0` function has been defined + in `#{inspect(repo)}` as `#{min_pg_version}`. + + This was based on running `postgres -V`. + + You may wish to update this configuration. It should + be set to the lowest version that your application + expects to be run against. + """ + else + """ + A `min_pg_version/0` function has been defined in + `#{inspect(repo)}` automatically. + + You may wish to update this configuration. It should + be set to the lowest version that your application + expects to be run against. + """ + end + + {min_pg_version, notice} end - def get_min_pg_version do + defp get_min_pg_version do case System.cmd("postgres", ["-V"]) do {"postgres (PostgreSQL) " <> version_and_text, 0} -> version_and_text @@ -519,13 +536,13 @@ if Code.ensure_loaded?(Igniter) do end end - defp configure_min_pg_version_function(zipper, repo, opts) do + defp configure_min_pg_version_function(zipper, repo, version, opts) do case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do {:ok, zipper} -> {:ok, zipper} _ -> - min_pg_version = AshPostgres.Igniter.get_min_pg_version(repo, opts) + min_pg_version = get_min_pg_version() {:ok, Igniter.Code.Common.add_code(zipper, """ From 39033fb5a2bac87a63ff73474845a076e5f646f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2024 10:42:27 -0500 Subject: [PATCH 306/690] chore(deps): bump the production-dependencies group with 3 updates (#450) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.4.48 to 3.4.49 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.48...v3.4.49) Updates `ash_sql` from 0.2.41 to 0.2.42 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.41...v0.2.42) Updates `igniter` from 0.5.0 to 0.5.2 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.0...v0.5.2) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 87c21283..a0589999 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.48", "e2948ca59a97305f49155dda9ebe647465bdc6524cffcf2afb1d7a62904d7eb1", [: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.4.8 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.9", [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", "0086400da603a70ef5ceaee6a3cb817cb345e077bf94c0308255f2094617c5b2"}, - "ash_sql": {:hex, :ash_sql, "0.2.41", "9e0a1686dc67a7cdc8435ced6c998dcd4de87980dde0a72d77946bbc9d1e65cb", [:mix], [{:ash, ">= 3.1.7 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", "226470dc8eeb3e89f98c0fb4ef11edf1b114e1caf3cd3457af7f9481df8221e8"}, + "ash": {:hex, :ash, "3.4.49", "85d1e115058ce6dbd9111b66ed55e2425dc0cfda874b60ed3f49299996326a72", [: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.4.8 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.9", [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", "ef2573a43b035e2c3bdee614522a33845f9904d07c519cac801972102f5ca057"}, + "ash_sql": {:hex, :ash_sql, "0.2.42", "01c160f1cbcce2bad534fd8372a3ce04b1b88bb9348c59aab6755f76963f444e", [:mix], [{:ash, ">= 3.1.7 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", "75ca2d3265b529b2441d0dc300a0b18c20a18f766a1d7cc97cf5904ce3bd9813"}, "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.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [: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", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.5.0", "00984e515c4bcd0aa0cffec83612e19041295f834392c4426e9cb0a67de16eb1", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "4cbb8acc908343bf79d90697d593b9d1bbce49ae72a0d755664d4cfe897dba53"}, + "igniter": {:hex, :igniter, "0.5.2", "0fd8aacbb5b80c27a0cf2e9b66fe2b633f181f759ba6bbcdc3ae758cef146f1d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "3a5c5085d4dfa1c23c53b25b891b9b56e9b2ba6a7ef281c0baee12bff17bf4d0"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 452a8208dd81057e9bcae19dfcbaccc34113a52a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Dec 2024 12:22:04 -0500 Subject: [PATCH 307/690] fix: ensure there is always at least one upsert field so filter is run --- lib/data_layer.ex | 18 ++++++++++-------- lib/mix/tasks/ash_postgres.install.ex | 2 +- mix.exs | 2 +- mix.lock | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 4614dd44..7fb3dd0a 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1383,7 +1383,7 @@ defmodule AshPostgres.DataLayer do ecto_changeset.changes, [] ) do - :empty -> + {:empty, query} -> if options[:return_records?] do if changeset.context[:data_layer][:use_atomic_update_data?] do case query.__ash_bindings__ do @@ -1821,12 +1821,8 @@ defmodule AshPostgres.DataLayer do %{}, upsert_set ) do - :empty -> - if options[:return_records?] do - {:replace, options[:upsert_keys] || Ash.Resource.Info.primary_key(resource)} - else - :nothing - end + {:empty, _query} -> + raise "Cannot upsert with no fields to specify in the upsert statement. This can only happen on resources without a primary key." {:ok, query} -> query @@ -1967,7 +1963,13 @@ defmodule AshPostgres.DataLayer do fields_to_upsert = upsert_fields -- - (Keyword.keys(Enum.at(changesets, 0).atomics) -- keys) + Keyword.keys(Enum.at(changesets, 0).atomics) -- keys + + fields_to_upsert = + case fields_to_upsert do + [] -> keys + fields_to_upsert -> fields_to_upsert + end fields_to_upsert |> Enum.uniq() diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 460637bb..60a3b6a7 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -536,7 +536,7 @@ if Code.ensure_loaded?(Igniter) do end end - defp configure_min_pg_version_function(zipper, repo, version, opts) do + defp configure_min_pg_version_function(zipper, _repo, _version, _opts) do case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do {:ok, zipper} -> {:ok, zipper} diff --git a/mix.exs b/mix.exs index cfddc3bd..e4e95809 100644 --- a/mix.exs +++ b/mix.exs @@ -165,7 +165,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.48")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.40")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.43")}, {:igniter, "~> 0.4 and >= 0.4.4", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index a0589999..1d165cab 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.49", "85d1e115058ce6dbd9111b66ed55e2425dc0cfda874b60ed3f49299996326a72", [: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.4.8 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.9", [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", "ef2573a43b035e2c3bdee614522a33845f9904d07c519cac801972102f5ca057"}, - "ash_sql": {:hex, :ash_sql, "0.2.42", "01c160f1cbcce2bad534fd8372a3ce04b1b88bb9348c59aab6755f76963f444e", [:mix], [{:ash, ">= 3.1.7 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", "75ca2d3265b529b2441d0dc300a0b18c20a18f766a1d7cc97cf5904ce3bd9813"}, + "ash_sql": {:hex, :ash_sql, "0.2.43", "80579d708630d3d31e9bb74b74d16ff8ef70de8c1d5043d87a682b5b17cb3154", [:mix], [{:ash, ">= 3.1.7 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", "c3fc710129178c017002bd108fc9411b10ca1d276fa5e99bd01b99addf28ff42"}, "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.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [: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", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, From a3edddde8b564056772d00d3e821136576f5e609 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Dec 2024 12:23:00 -0500 Subject: [PATCH 308/690] chore: release version v2.4.19 --- CHANGELOG.md | 17 +++++++++++++++++ mix.exs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32279517..be5782a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.19](https://github.com/ash-project/ash_postgres/compare/v2.4.18...v2.4.19) (2024-12-26) + + + + +### Bug Fixes: + +* ensure there is always at least one upsert field so filter is run + +### Improvements: + +* better min_pg_version when modifying a repo + +* automatically set `min_pg_version` where possible + +* use a notice to suggest configuring `min_pg_version` + ## [v2.4.18](https://github.com/ash-project/ash_postgres/compare/v2.4.17...v2.4.18) (2024-12-20) diff --git a/mix.exs b/mix.exs index e4e95809..e9ea8826 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.18" + @version "2.4.19" def project do [ From 80ccc19a919419f71498891817a0a86ef9d7e67b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Dec 2024 15:23:09 -0500 Subject: [PATCH 309/690] fix: use passed in version of postgres when modifying existing repo --- lib/mix/tasks/ash_postgres.install.ex | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 60a3b6a7..636fe999 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -536,18 +536,16 @@ if Code.ensure_loaded?(Igniter) do end end - defp configure_min_pg_version_function(zipper, _repo, _version, _opts) do + defp configure_min_pg_version_function(zipper, _repo, version, _opts) do case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do {:ok, zipper} -> {:ok, zipper} _ -> - min_pg_version = get_min_pg_version() - {:ok, Igniter.Code.Common.add_code(zipper, """ def min_pg_version do - %Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor}, patch: #{min_pg_version.patch}} + %Version{major: #{version.major}, minor: #{version.minor}, patch: #{version.patch}} end """)} end From 2dadf5be25fa9f50ad84ac9751120f05e0b5ff15 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Dec 2024 15:23:30 -0500 Subject: [PATCH 310/690] chore: release version v2.4.20 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be5782a1..b8a557fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.20](https://github.com/ash-project/ash_postgres/compare/v2.4.19...v2.4.20) (2024-12-26) + + + + +### Bug Fixes: + +* use passed in version of postgres when modifying existing repo + ## [v2.4.19](https://github.com/ash-project/ash_postgres/compare/v2.4.18...v2.4.19) (2024-12-26) diff --git a/mix.exs b/mix.exs index e9ea8826..17fb306e 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.19" + @version "2.4.20" def project do [ From ab7f9b054c69bf1b1cc0a9734ec3235d4ea7df79 Mon Sep 17 00:00:00 2001 From: Rebecca Le <543859+sevenseacat@users.noreply.github.com> Date: Sun, 29 Dec 2024 19:44:24 +0800 Subject: [PATCH 311/690] docs: Fix old code in Getting Started guide (#451) --- documentation/tutorials/get-started-with-ash-postgres.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/tutorials/get-started-with-ash-postgres.md b/documentation/tutorials/get-started-with-ash-postgres.md index 12d88328..8e02c72a 100644 --- a/documentation/tutorials/get-started-with-ash-postgres.md +++ b/documentation/tutorials/get-started-with-ash-postgres.md @@ -241,7 +241,7 @@ for i <- 0..5 do ticket = Helpdesk.Support.Ticket |> Ash.Changeset.for_create(:open, %{subject: "Issue #{i}"}) - |> Helpdesk.Support.create!() + |> Ash.create!() |> Ash.Changeset.for_update(:assign, %{representative_id: representative.id}) |> Ash.update!() From 9701d83c03bf49cb254a4c75aac6f40f55384200 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 07:52:43 -0500 Subject: [PATCH 312/690] chore(deps): bump the production-dependencies group with 2 updates (#453) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.4.49 to 3.4.50 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.49...v3.4.50) Updates `igniter` from 0.5.2 to 0.5.3 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.2...v0.5.3) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 1d165cab..e50ef9c6 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.49", "85d1e115058ce6dbd9111b66ed55e2425dc0cfda874b60ed3f49299996326a72", [: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.4.8 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.9", [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", "ef2573a43b035e2c3bdee614522a33845f9904d07c519cac801972102f5ca057"}, + "ash": {:hex, :ash, "3.4.50", "1dadf1ac9302893c16276c613891e01e6ab205782c4dc2b3b82609f5032073d9", [: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.4.8 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.9", [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", "055cc3260b73c1c9dc584a0cdb94820fdd228faeb9551020750d9af18f4bb75d"}, "ash_sql": {:hex, :ash_sql, "0.2.43", "80579d708630d3d31e9bb74b74d16ff8ef70de8c1d5043d87a682b5b17cb3154", [:mix], [{:ash, ">= 3.1.7 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", "c3fc710129178c017002bd108fc9411b10ca1d276fa5e99bd01b99addf28ff42"}, "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"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.5.2", "0fd8aacbb5b80c27a0cf2e9b66fe2b633f181f759ba6bbcdc3ae758cef146f1d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "3a5c5085d4dfa1c23c53b25b891b9b56e9b2ba6a7ef281c0baee12bff17bf4d0"}, + "igniter": {:hex, :igniter, "0.5.3", "7cd26c707df380d7f1e3d1969b911d1485f582d3fc5f76a6d39d5ca94e039a71", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "3a22a74e8cc4af02fd89b0a6ea0184f22764ddb254ec31c194e89839ad22baf4"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -34,7 +34,7 @@ "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, "reactor": {:hex, :reactor, "0.10.3", "41a8c34251148e36dd7c75aa8433f2c2f283f29c097f9eb84a630ab28dd75651", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b34380e22b69a35943a7bcceffd5a8b766870f1fc9052162a7ff74ef9cdb3b2"}, - "rewrite": {:hex, :rewrite, "1.1.1", "0e6674eb5f8cb11aabe5ad6207151b4156bf173aa9b43133a68f8cc882364570", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "fcd688b3ca543c3a1f1f4615ccc054ec37cfcde91133a27a683ec09b35ae1496"}, + "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, From 304a896ec82deca43fe720b455fdddccdd30dcfe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 07:52:59 -0500 Subject: [PATCH 313/690] chore(deps-dev): bump credo in the dev-dependencies group (#454) Bumps the dev-dependencies group with 1 update: [credo](https://github.com/rrrene/credo). Updates `credo` from 1.7.10 to 1.7.11 - [Release notes](https://github.com/rrrene/credo/releases) - [Changelog](https://github.com/rrrene/credo/blob/master/CHANGELOG.md) - [Commits](https://github.com/rrrene/credo/compare/v1.7.10...v1.7.11) --- updated-dependencies: - dependency-name: credo dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index e50ef9c6..442cf03b 100644 --- a/mix.lock +++ b/mix.lock @@ -3,7 +3,7 @@ "ash_sql": {:hex, :ash_sql, "0.2.43", "80579d708630d3d31e9bb74b74d16ff8ef70de8c1d5043d87a682b5b17cb3154", [:mix], [{:ash, ">= 3.1.7 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", "c3fc710129178c017002bd108fc9411b10ca1d276fa5e99bd01b99addf28ff42"}, "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.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [: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", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, + "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"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, From a5f6de785df0cb41fc523a1018672c6fabb64a63 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 2 Jan 2025 15:01:11 -0500 Subject: [PATCH 314/690] fix: don't use symlinked app dir for migration's path fixes #452 --- lib/data_layer.ex | 2 +- lib/migration_generator/migration_generator.ex | 15 +++++---------- lib/mix/helpers.ex | 13 ++++++++----- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 7fb3dd0a..07deed32 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1963,7 +1963,7 @@ defmodule AshPostgres.DataLayer do fields_to_upsert = upsert_fields -- - Keyword.keys(Enum.at(changesets, 0).atomics) -- keys + (Keyword.keys(Enum.at(changesets, 0).atomics) -- keys) fields_to_upsert = case fields_to_upsert do diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 3f3dd5bf..004df533 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -157,11 +157,7 @@ defmodule AshPostgres.MigrationGenerator do snapshot_path else app = Keyword.fetch!(config, :otp_app) - - Application.app_dir( - app, - ["priv", "resource_snapshots"] - ) + Path.join(Mix.Project.deps_paths()[app] || File.cwd!(), "priv/resource_snapshots") end end @@ -889,25 +885,24 @@ defmodule AshPostgres.MigrationGenerator do defp migration_path(opts, repo, tenant? \\ false) do # Copied from ecto's mix task, thanks Ecto ❤️ config = repo.config() - app = Keyword.fetch!(config, :otp_app) if tenant? do if path = opts.tenant_migration_path || config[:tenant_migrations_path] do path else priv = - config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" + AshPostgres.Mix.Helpers.source_repo_priv(repo) - Application.app_dir(app, Path.join(priv, "tenant_migrations")) + Path.join(priv, "tenant_migrations") end else if path = opts.migration_path || config[:tenant_migrations_path] do path else priv = - config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" + AshPostgres.Mix.Helpers.source_repo_priv(repo) - Application.app_dir(app, Path.join(priv, "migrations")) + Path.join(priv, "migrations") end end end diff --git a/lib/mix/helpers.ex b/lib/mix/helpers.ex index 6858ec47..26abfabd 100644 --- a/lib/mix/helpers.ex +++ b/lib/mix/helpers.ex @@ -170,16 +170,19 @@ defmodule AshPostgres.Mix.Helpers do end def derive_migrations_path(repo) do - config = repo.config() - priv = config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" - app = Keyword.fetch!(config, :otp_app) - Application.app_dir(app, Path.join(priv, "migrations")) + priv = source_repo_priv(repo) + Path.join(priv, "migrations") end def derive_tenant_migrations_path(repo) do + priv = source_repo_priv(repo) + Path.join(priv, "tenant_migrations") + end + + def source_repo_priv(repo) do config = repo.config() priv = config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}" app = Keyword.fetch!(config, :otp_app) - Application.app_dir(app, Path.join(priv, "tenant_migrations")) + Path.join(Mix.Project.deps_paths()[app] || File.cwd!(), priv) end end From 1c4ae7bed69d0e1318167ed5c90cd8b1eeb77e77 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 3 Jan 2025 10:19:59 -0500 Subject: [PATCH 315/690] fix: filter query by source record ids when lateral joining --- lib/data_layer.ex | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 07deed32..1f7d0c49 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1059,7 +1059,7 @@ defmodule AshPostgres.DataLayer do source_pkey = Ash.Resource.Info.primary_key(source_query.resource) - case lateral_join_source_query(query, source_query) do + case lateral_join_source_query(query, source_query, root_data) do {:ok, data_layer_query} -> source_values = Enum.map(root_data, &Map.get(&1, source_attribute)) @@ -1148,7 +1148,7 @@ defmodule AshPostgres.DataLayer do source_values = Enum.map(root_data, &Map.get(&1, source_attribute)) source_pkey = Ash.Resource.Info.primary_key(source_query.resource) - case lateral_join_source_query(query, source_query) do + case lateral_join_source_query(query, source_query, root_data) do {:ok, data_layer_query} -> data_layer_query = Ecto.Query.exclude(data_layer_query, :select) @@ -1268,7 +1268,8 @@ defmodule AshPostgres.DataLayer do lateral_join_source_query: lateral_join_source_query } }, - source_query + source_query, + _root_data ) when not is_nil(lateral_join_source_query) do {:ok, @@ -1276,10 +1277,11 @@ defmodule AshPostgres.DataLayer do |> set_subquery_prefix(source_query, lateral_join_source_query.__ash_bindings__.resource)} end - defp lateral_join_source_query(query, source_query) do + defp lateral_join_source_query(query, source_query, root_data) do source_query.resource |> Ash.Query.set_context(%{:data_layer => source_query.context[:data_layer]}) |> Ash.Query.set_tenant(source_query.tenant) + |> filter_for_records(root_data) |> set_lateral_join_prefix(query) |> case do %{valid?: true} = query -> @@ -1290,6 +1292,38 @@ defmodule AshPostgres.DataLayer do end end + defp filter_for_records(query, records) do + keys = + case Ash.Resource.Info.primary_key(query.resource) do + [] -> + case Ash.Resource.Info.identities(query.resource) do + %{keys: keys} -> keys + _ -> [] + end + + pkey -> + pkey + end + + expr = + case keys do + [] -> + raise "Cannot use lateral joins with a resource that has no primary key and no identities" + + keys -> + Enum.reduce(records, Ash.Expr.expr(false), fn record, filter_expr -> + all_keys_match_expr = + Enum.reduce(keys, Ash.Expr.expr(true), fn key, key_expr -> + Ash.Expr.expr(^key_expr and ^Ash.Expr.ref(key) == ^Map.get(record, key)) + end) + + Ash.Expr.expr(^filter_expr or ^all_keys_match_expr) + end) + end + + Ash.Query.do_filter(query, expr) + end + @doc false def set_subquery_prefix(data_layer_query, source_query, resource) do repo = AshPostgres.DataLayer.Info.repo(resource, :mutate) From 96dc292fa80cce00fade890e2bd7ab9f1082fab8 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Sat, 4 Jan 2025 05:26:27 -0600 Subject: [PATCH 316/690] chore: add changelog to package links (#455) --- mix.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/mix.exs b/mix.exs index 17fb306e..b6f10848 100644 --- a/mix.exs +++ b/mix.exs @@ -59,6 +59,7 @@ defmodule AshPostgres.MixProject do files: ~w(lib .formatter.exs mix.exs README* LICENSE* CHANGELOG* documentation), links: %{ + Changelog: "https://hexdocs.pm/ash_postgres/changelog.html", GitHub: "https://github.com/ash-project/ash_postgres" } ] From 5f26d6900915e2a8f988fe469beaa631606a84e3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 6 Jan 2025 17:07:01 -0500 Subject: [PATCH 317/690] chore: release version v2.4.21 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8a557fe..4c49243f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.21](https://github.com/ash-project/ash_postgres/compare/v2.4.20...v2.4.21) (2025-01-06) + + + + +### Bug Fixes: + +* filter query by source record ids when lateral joining + +* don't use symlinked app dir for migration's path + ## [v2.4.20](https://github.com/ash-project/ash_postgres/compare/v2.4.19...v2.4.20) (2024-12-26) diff --git a/mix.exs b/mix.exs index b6f10848..bd364740 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.20" + @version "2.4.21" def project do [ From fbc434689223180ed3cc7077732913c587811802 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Wed, 8 Jan 2025 08:05:52 -0600 Subject: [PATCH 318/690] test: Failing test for module calculation inside expression one (#456) --- .../test_repo/comedians/20241217232254.json | 59 +++++++++++ .../test_repo/jokes/20241217232254.json | 98 +++++++++++++++++++ .../20241217232254_migrate_resources45.exs | 77 +++++++++++++++ test/calculation_test.exs | 8 +- test/support/domain.ex | 2 + test/support/resources/comedian.ex | 57 +++++++++++ test/support/resources/joke.ex | 28 ++++++ 7 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/comedians/20241217232254.json create mode 100644 priv/resource_snapshots/test_repo/jokes/20241217232254.json create mode 100644 priv/test_repo/migrations/20241217232254_migrate_resources45.exs create mode 100644 test/support/resources/comedian.ex create mode 100644 test/support/resources/joke.ex diff --git a/priv/resource_snapshots/test_repo/comedians/20241217232254.json b/priv/resource_snapshots/test_repo/comedians/20241217232254.json new file mode 100644 index 00000000..ed9e2fd8 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comedians/20241217232254.json @@ -0,0 +1,59 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "A376A922D4610DEAD0294DD863E8E2FF72FEC6316AC6B809C3DFC17B29094EBA", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "comedians" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/jokes/20241217232254.json b/priv/resource_snapshots/test_repo/jokes/20241217232254.json new file mode 100644 index 00000000..2393183f --- /dev/null +++ b/priv/resource_snapshots/test_repo/jokes/20241217232254.json @@ -0,0 +1,98 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "text", + "type": "text" + }, + { + "allow_nil?": true, + "default": "false", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "is_good", + "type": "boolean" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "jokes_comedian_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "comedians" + }, + "size": null, + "source": "comedian_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "CFDCBDBAC925B20A1EA8EB4B3C37ACF1FD915FA21F6B07DE4D066AA167B9EEF5", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "jokes" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20241217232254_migrate_resources45.exs b/priv/test_repo/migrations/20241217232254_migrate_resources45.exs new file mode 100644 index 00000000..acfc2b39 --- /dev/null +++ b/priv/test_repo/migrations/20241217232254_migrate_resources45.exs @@ -0,0 +1,77 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources45 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:jokes, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:text, :text) + add(:is_good, :boolean, default: false) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:comedian_id, :uuid) + end + + create table(:comedians, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + end + + alter table(:jokes) do + modify( + :comedian_id, + references(:comedians, + column: :id, + name: "jokes_comedian_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + + alter table(:comedians) do + add(:name, :text) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + end + end + + def down do + alter table(:comedians) do + remove(:updated_at) + remove(:inserted_at) + remove(:name) + end + + drop(constraint(:jokes, "jokes_comedian_id_fkey")) + + alter table(:jokes) do + modify(:comedian_id, :uuid) + end + + drop(table(:comedians)) + + drop(table(:jokes)) + end +end diff --git a/test/calculation_test.exs b/test/calculation_test.exs index fd0ab43f..f1a091a2 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1,6 +1,6 @@ defmodule AshPostgres.CalculationTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Account, Author, Comment, Post, User} + alias AshPostgres.Test.{Account, Author, Comedian, Comment, Post, User} require Ash.Query import Ash.Expr @@ -937,6 +937,12 @@ defmodule AshPostgres.CalculationTest do |> Ash.read!() end + test "module calculation inside expr calculation works" do + commedian = Comedian.create!(%{name: "John"}) + commedian = Ash.get!(Comedian, commedian.id, load: [:has_jokes_expr], authorize?: false) + assert %{has_jokes_expr: false} = commedian + end + def fred do "fred" end diff --git a/test/support/domain.ex b/test/support/domain.ex index 60d2275a..f690211a 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -5,6 +5,7 @@ defmodule AshPostgres.Test.Domain do resources do resource(AshPostgres.Test.CoAuthorPost) resource(AshPostgres.Test.Post) + resource(AshPostgres.Test.Comedian) resource(AshPostgres.Test.Comment) resource(AshPostgres.Test.IntegerPost) resource(AshPostgres.Test.Rating) @@ -14,6 +15,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Profile) resource(AshPostgres.Test.User) resource(AshPostgres.Test.Invite) + resource(AshPostgres.Test.Joke) resource(AshPostgres.Test.Account) resource(AshPostgres.Test.Organization) resource(AshPostgres.Test.Manager) diff --git a/test/support/resources/comedian.ex b/test/support/resources/comedian.ex new file mode 100644 index 00000000..1fa08c54 --- /dev/null +++ b/test/support/resources/comedian.ex @@ -0,0 +1,57 @@ +defmodule AshPostgres.Test.Comedian do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + create_timestamp(:inserted_at, public?: true) + update_timestamp(:updated_at, public?: true) + end + + relationships do + has_many(:jokes, AshPostgres.Test.Joke, public?: true) + end + + calculations do + calculate(:has_jokes_mod, :boolean, AshPostgres.Test.Comedian.HasJokes) + calculate(:has_jokes_expr, :boolean, expr(has_jokes_mod == true)) + end + + actions do + defaults([:read]) + + create :create do + primary?(true) + accept([:name]) + end + end + + code_interface do + define(:create) + end + + postgres do + table("comedians") + repo(AshPostgres.TestRepo) + end +end + +defmodule AshPostgres.Test.Comedian.HasJokes do + use Ash.Resource.Calculation + + @impl true + def load(_, _, _) do + [:jokes] + end + + @impl true + def calculate(comedians, _, _) do + Enum.map(comedians, fn %{jokes: jokes} -> + Enum.any?(jokes) + end) + end +end diff --git a/test/support/resources/joke.ex b/test/support/resources/joke.ex new file mode 100644 index 00000000..a97b1e3f --- /dev/null +++ b/test/support/resources/joke.ex @@ -0,0 +1,28 @@ +defmodule AshPostgres.Test.Joke do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + attributes do + uuid_primary_key(:id) + attribute(:text, :string, public?: true) + attribute(:is_good, :boolean, default: false, public?: true) + create_timestamp(:inserted_at, public?: true) + update_timestamp(:updated_at, public?: true) + end + + relationships do + belongs_to(:comedian, AshPostgres.Test.Comedian, public?: true) + end + + actions do + defaults([:read]) + end + + postgres do + table("jokes") + repo(AshPostgres.TestRepo) + end +end From 2b5b3bd505d0ecace94a7aba149ff22dc21a99fd Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 11 Jan 2025 19:42:12 -0500 Subject: [PATCH 319/690] fix: fully specificy synthesized indices from multi-resource tables --- lib/migration_generator/migration_generator.ex | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 004df533..2810ceb8 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -814,7 +814,11 @@ defmodule AshPostgres.MigrationGenerator do %{ keys: pkey_names, - name: name + name: name, + base_filter: nil, + all_tenants?: false, + nils_distinct?: false, + where: nil } end) @@ -849,7 +853,11 @@ defmodule AshPostgres.MigrationGenerator do %{ keys: pkey_names, - name: name + name: name, + base_filter: nil, + all_tenants?: false, + nils_distinct?: false, + where: nil } end) From 696bbe73a69c882caccd257c60e547b4b64e7330 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 13 Jan 2025 08:31:21 -0500 Subject: [PATCH 320/690] fix: inner join bulk operations if distinct? is present --- lib/data_layer.ex | 4 +++- mix.lock | 6 +++--- test/bulk_destroy_test.exs | 10 ++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 1f7d0c49..6a524453 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1560,7 +1560,7 @@ defmodule AshPostgres.DataLayer do end) needs_to_join? = - requires_adding_inner_join? || + requires_adding_inner_join? || query.distinct || query.limit || query.offset || has_exists? query = @@ -1730,6 +1730,8 @@ defmodule AshPostgres.DataLayer do Ecto.Query.exclude(query, :select) end + # query = Ecto.Query.exclude(query, :distinct) + {_, results} = with_savepoint(repo, query, fn -> repo.delete_all( diff --git a/mix.lock b/mix.lock index 442cf03b..2a858f30 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.50", "1dadf1ac9302893c16276c613891e01e6ab205782c4dc2b3b82609f5032073d9", [: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.4.8 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.9", [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", "055cc3260b73c1c9dc584a0cdb94820fdd228faeb9551020750d9af18f4bb75d"}, + "ash": {:hex, :ash, "3.4.55", "81132171412dc92bd1630500e1403a48f5ea7948552c528189d13d4c4c181878", [: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.4.8 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.9", [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", "6fb89c9bb6e158b2dab08184f3b6ebfd88785348c21b2a9fd5bd71b1f96e2c5e"}, "ash_sql": {:hex, :ash_sql, "0.2.43", "80579d708630d3d31e9bb74b74d16ff8ef70de8c1d5043d87a682b5b17cb3154", [:mix], [{:ash, ">= 3.1.7 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", "c3fc710129178c017002bd108fc9411b10ca1d276fa5e99bd01b99addf28ff42"}, "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"}, @@ -21,7 +21,7 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.5.3", "7cd26c707df380d7f1e3d1969b911d1485f582d3fc5f76a6d39d5ca94e039a71", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "3a22a74e8cc4af02fd89b0a6ea0184f22764ddb254ec31c194e89839ad22baf4"}, + "igniter": {:hex, :igniter, "0.5.8", "d91e90fecb99beadfa9d0d8434fbd4f0fe06ea1a1d29cae4dfd0cb058cb3a5c7", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "fef198324925405ea5c3b16166002be03b2d7497c038cfc9708aa557d27ba5a2"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,7 +39,7 @@ "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, "spark": {:hex, :spark, "2.2.36", "07c921e5efb27f184267c3431d2f82099e24cac90748a47383dd75cbfb558268", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "e5ac56b75e5ad43da6d8302b6713277488f8e9a3abdba9aae8f0d0f9cff04538"}, - "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, + "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, diff --git a/test/bulk_destroy_test.exs b/test/bulk_destroy_test.exs index ddc9b65a..ff159a8f 100644 --- a/test/bulk_destroy_test.exs +++ b/test/bulk_destroy_test.exs @@ -60,6 +60,16 @@ defmodule AshPostgres.BulkDestroyTest do assert [%{title: "george"}] = Ash.read!(Post) end + test "the query can join to to-many related tables when necessary" do + Ash.bulk_create!([%{title: "fred"}, %{title: "fred"}], Post, :create) + + Post + |> Ash.Query.filter(posts_with_matching_title.title == title) + |> Ash.bulk_destroy!(:destroy, %{}, return_records?: true) + + assert [] = Ash.read!(Post) + end + test "bulk destroys can be done even on stream inputs" do Ash.bulk_create!([%{title: "fred"}, %{title: "george"}], Post, :create) From 8e59757864ce65c6581f6fdb779332291d5c06b4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 13 Jan 2025 08:32:16 -0500 Subject: [PATCH 321/690] chore: release version v2.4.22 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c49243f..93357fd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.4.22](https://github.com/ash-project/ash_postgres/compare/v2.4.21...v2.4.22) (2025-01-13) + + + + +### Bug Fixes: + +* inner join bulk operations if distinct? is present + +* fully specificy synthesized indices from multi-resource tables + ## [v2.4.21](https://github.com/ash-project/ash_postgres/compare/v2.4.20...v2.4.21) (2025-01-06) diff --git a/mix.exs b/mix.exs index bd364740..06279f90 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.21" + @version "2.4.22" def project do [ From 1d0437a675b883ae10298d72b758a8b5b67356cc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 13 Jan 2025 16:12:19 -0500 Subject: [PATCH 322/690] improvement: mark ash_raise_error as STABLE --- lib/migration_generator/ash_functions.ex | 25 +++++++- .../test_no_sandbox_repo/extensions.json | 2 +- .../test_repo/extensions.json | 2 +- ...3205301_migrate_resources_extensions_1.exs | 60 +++++++++++++++++++ ...3205259_migrate_resources_extensions_1.exs | 60 +++++++++++++++++++ 5 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs create mode 100644 priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index 53b29ac9..a9c4659c 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -1,5 +1,5 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do - @latest_version 4 + @latest_version 5 def latest_version, do: @latest_version @@ -143,7 +143,26 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do end def install(3) do - uuid_generate_v7() + """ + execute("ALTER FUNCTION ash_raise_error(jsonb) STABLE;") + execute("ALTER FUNCTION ash_raise_error(jsonb, ANYCOMPATIBLE) STABLE") + #{uuid_generate_v7()} + """ + end + + def install(4) do + """ + execute("ALTER FUNCTION ash_raise_error(jsonb) STABLE;") + execute("ALTER FUNCTION ash_raise_error(jsonb, ANYCOMPATIBLE) STABLE") + #{uuid_generate_v7()} + """ + end + + def drop(4) do + """ + execute("ALTER FUNCTION ash_raise_error(jsonb) VOLATILE;") + execute("ALTER FUNCTION ash_raise_error(jsonb, ANYCOMPATIBLE) VOLATILE") + """ end def drop(3) do @@ -184,6 +203,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do RETURN NULL; END; $$ LANGUAGE plpgsql + STABLE SET search_path = ''; \"\"\") @@ -197,6 +217,7 @@ defmodule AshPostgres.MigrationGenerator.AshFunctions do RETURN NULL; END; $$ LANGUAGE plpgsql + STABLE SET search_path = ''; \"\"\") """ diff --git a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json index 40d20b77..4430c306 100644 --- a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json +++ b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json @@ -1,5 +1,5 @@ { - "ash_functions_version": 4, + "ash_functions_version": 5, "installed": [ "ash-functions", "uuid-ossp", diff --git a/priv/resource_snapshots/test_repo/extensions.json b/priv/resource_snapshots/test_repo/extensions.json index 557d0ea8..d1c5a122 100644 --- a/priv/resource_snapshots/test_repo/extensions.json +++ b/priv/resource_snapshots/test_repo/extensions.json @@ -1,5 +1,5 @@ { - "ash_functions_version": 4, + "ash_functions_version": 5, "installed": [ "ash-functions", "uuid-ossp", diff --git a/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs b/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs new file mode 100644 index 00000000..9794c3be --- /dev/null +++ b/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs @@ -0,0 +1,60 @@ +defmodule AshPostgres.TestNoSandboxRepo.Migrations.MigrateResourcesExtensions1 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute("ALTER FUNCTION ash_raise_error(jsonb) STABLE;") + execute("ALTER FUNCTION ash_raise_error(jsonb, ANYCOMPATIBLE) STABLE") + + execute(""" + CREATE OR REPLACE FUNCTION uuid_generate_v7() + RETURNS UUID + AS $$ + DECLARE + timestamp TIMESTAMPTZ; + microseconds INT; + BEGIN + timestamp = clock_timestamp(); + microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT; + + RETURN encode( + set_byte( + set_byte( + overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6 + ), + 6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int + ), + 7, microseconds::bit(8)::int + ), + 'hex')::UUID; + END + $$ + LANGUAGE PLPGSQL + SET search_path = '' + VOLATILE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid) + RETURNS TIMESTAMP WITHOUT TIME ZONE + AS $$ + SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); + $$ + LANGUAGE SQL + SET search_path = '' + IMMUTABLE PARALLEL SAFE STRICT; + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute("ALTER FUNCTION ash_raise_error(jsonb) VOLATILE;") + execute("ALTER FUNCTION ash_raise_error(jsonb, ANYCOMPATIBLE) VOLATILE") + end +end diff --git a/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs b/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs new file mode 100644 index 00000000..e6efdcb9 --- /dev/null +++ b/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs @@ -0,0 +1,60 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResourcesExtensions1 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute("ALTER FUNCTION ash_raise_error(jsonb) STABLE;") + execute("ALTER FUNCTION ash_raise_error(jsonb, ANYCOMPATIBLE) STABLE") + + execute(""" + CREATE OR REPLACE FUNCTION uuid_generate_v7() + RETURNS UUID + AS $$ + DECLARE + timestamp TIMESTAMPTZ; + microseconds INT; + BEGIN + timestamp = clock_timestamp(); + microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT; + + RETURN encode( + set_byte( + set_byte( + overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6 + ), + 6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int + ), + 7, microseconds::bit(8)::int + ), + 'hex')::UUID; + END + $$ + LANGUAGE PLPGSQL + SET search_path = '' + VOLATILE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid) + RETURNS TIMESTAMP WITHOUT TIME ZONE + AS $$ + SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); + $$ + LANGUAGE SQL + SET search_path = '' + IMMUTABLE PARALLEL SAFE STRICT; + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute("ALTER FUNCTION ash_raise_error(jsonb) VOLATILE;") + execute("ALTER FUNCTION ash_raise_error(jsonb, ANYCOMPATIBLE) VOLATILE") + end +end From 1ff16563800ae5e9a36aae33807d40356971248d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 13 Jan 2025 17:03:41 -0500 Subject: [PATCH 323/690] improvement: add `c:AshPostgres.Repo.default_constraint_match_type` --- lib/data_layer.ex | 114 ++++++++++++++++++++++++++++++---------------- lib/repo.ex | 16 +++++++ 2 files changed, 92 insertions(+), 38 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 6a524453..a69851cc 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1375,6 +1375,8 @@ defmodule AshPostgres.DataLayer do @impl true def update_query(query, changeset, resource, options) do + repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) + ecto_changeset = case changeset.data do %Ash.Changeset.OriginalDataNotAvailable{} -> @@ -1384,7 +1386,7 @@ defmodule AshPostgres.DataLayer do data end |> Map.update!(:__meta__, &Map.put(&1, :source, table(resource, changeset))) - |> ecto_changeset(changeset, :update, true) + |> ecto_changeset(changeset, :update, repo, true) case bulk_updatable_query( query, @@ -1398,8 +1400,6 @@ defmodule AshPostgres.DataLayer do {:ok, query} -> try do - repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) - repo_opts = AshSql.repo_opts( repo, @@ -1673,6 +1673,8 @@ defmodule AshPostgres.DataLayer do @impl true def destroy_query(query, changeset, resource, options) do + repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) + ecto_changeset = case changeset.data do %Ash.Changeset.OriginalDataNotAvailable{} -> @@ -1682,7 +1684,7 @@ defmodule AshPostgres.DataLayer do data end |> Map.update!(:__meta__, &Map.put(&1, :source, table(resource, changeset))) - |> ecto_changeset(changeset, :delete, true) + |> ecto_changeset(changeset, :delete, repo, true) case bulk_updatable_query( query, @@ -1697,8 +1699,6 @@ defmodule AshPostgres.DataLayer do {:ok, query} -> try do - repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) - repo_opts = AshSql.repo_opts( repo, @@ -1926,7 +1926,7 @@ defmodule AshPostgres.DataLayer do handle_raised_error( e, __STACKTRACE__, - {:bulk_create, ecto_changeset(changeset.data, changeset, :create, false)}, + {:bulk_create, ecto_changeset(changeset.data, changeset, :create, repo, false)}, resource ) end @@ -2142,7 +2142,7 @@ defmodule AshPostgres.DataLayer do ) end - defp ecto_changeset(record, changeset, type, table_error?) do + defp ecto_changeset(record, changeset, type, repo, table_error?) do attributes = changeset.resource |> Ash.Resource.Info.attributes() @@ -2159,24 +2159,24 @@ defmodule AshPostgres.DataLayer do |> set_table(changeset, type, table_error?) |> Ecto.Changeset.cast(%{}, []) |> force_changes(Map.take(changeset.attributes, attributes_to_change)) - |> add_configured_foreign_key_constraints(record.__struct__) - |> add_unique_indexes(record.__struct__, changeset) - |> add_check_constraints(record.__struct__) - |> add_exclusion_constraints(record.__struct__) + |> add_configured_foreign_key_constraints(record.__struct__, repo) + |> add_unique_indexes(record.__struct__, changeset, repo) + |> add_check_constraints(record.__struct__, repo) + |> add_exclusion_constraints(record.__struct__, repo) case type do :create -> ecto_changeset - |> add_my_foreign_key_constraints(record.__struct__) + |> add_my_foreign_key_constraints(record.__struct__, repo) type when type in [:upsert, :update] -> ecto_changeset - |> add_my_foreign_key_constraints(record.__struct__) - |> add_related_foreign_key_constraints(record.__struct__) + |> add_my_foreign_key_constraints(record.__struct__, repo) + |> add_related_foreign_key_constraints(record.__struct__, repo) :delete -> ecto_changeset - |> add_related_foreign_key_constraints(record.__struct__) + |> add_related_foreign_key_constraints(record.__struct__, repo) end end @@ -2461,7 +2461,7 @@ defmodule AshPostgres.DataLayer do def to_ecto(other), do: other - defp add_check_constraints(changeset, resource) do + defp add_check_constraints(changeset, resource, repo) do resource |> AshPostgres.DataLayer.Info.check_constraints() |> Enum.reduce(changeset, fn constraint, changeset -> @@ -2470,27 +2470,35 @@ defmodule AshPostgres.DataLayer do |> Enum.reduce(changeset, fn attribute, changeset -> Ecto.Changeset.check_constraint(changeset, attribute, name: constraint.name, - message: constraint.message || "is invalid" + message: constraint.message || "is invalid", + match: repo.default_constraint_match_type(:check, constraint.name) ) end) end) end - defp add_exclusion_constraints(changeset, resource) do + defp add_exclusion_constraints(changeset, resource, repo) do resource |> AshPostgres.DataLayer.Info.exclusion_constraint_names() |> Enum.reduce(changeset, fn constraint, changeset -> case constraint do {key, name} -> - Ecto.Changeset.exclusion_constraint(changeset, key, name: name) + Ecto.Changeset.exclusion_constraint(changeset, key, + name: name, + match: repo.default_constraint_match_type(:exclusion, constraint.name) + ) {key, name, message} -> - Ecto.Changeset.exclusion_constraint(changeset, key, name: name, message: message) + Ecto.Changeset.exclusion_constraint(changeset, key, + name: name, + message: message, + match: repo.default_constraint_match_type(:exclusion, constraint.name) + ) end end) end - defp add_related_foreign_key_constraints(changeset, resource) do + defp add_related_foreign_key_constraints(changeset, resource, repo) do # TODO: this doesn't guarantee us to get all of them, because if something is related to this # schema and there is no back-relation, then this won't catch it's foreign key constraints resource @@ -2514,25 +2522,37 @@ defmodule AshPostgres.DataLayer do %{name: name} when not is_nil(name) -> Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, name: name, + match: repo.default_constraint_match_type(:foreign, name), message: "would leave records behind" ) _ -> + name = "#{AshPostgres.DataLayer.Info.table(source)}_#{source_attribute}_fkey" + Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, - name: "#{AshPostgres.DataLayer.Info.table(source)}_#{source_attribute}_fkey", + name: name, + match: repo.default_constraint_match_type(:foreign, name), message: "would leave records behind" ) end end) end - defp add_my_foreign_key_constraints(changeset, resource) do + defp add_my_foreign_key_constraints(changeset, resource, repo) do resource |> Ash.Resource.Info.relationships() - |> Enum.reduce(changeset, &Ecto.Changeset.foreign_key_constraint(&2, &1.source_attribute)) + |> Enum.reduce(changeset, fn relationship, changeset -> + name = + "#{AshPostgres.DataLayer.Info.table(resource)}_#{relationship.source_attribute}_fkey" + + Ecto.Changeset.foreign_key_constraint(changeset, relationship.source_attribute, + name: name, + match: repo.default_constraint_match_type(:foreign, name) + ) + end) end - defp add_configured_foreign_key_constraints(changeset, resource) do + defp add_configured_foreign_key_constraints(changeset, resource, repo) do resource |> AshPostgres.DataLayer.Info.foreign_key_names() |> case do @@ -2541,14 +2561,21 @@ defmodule AshPostgres.DataLayer do end |> Enum.reduce(changeset, fn {key, name}, changeset -> - Ecto.Changeset.foreign_key_constraint(changeset, key, name: name) + Ecto.Changeset.foreign_key_constraint(changeset, key, + name: name, + match: repo.default_constraint_match_type(:foreign, name) + ) {key, name, message}, changeset -> - Ecto.Changeset.foreign_key_constraint(changeset, key, name: name, message: message) + Ecto.Changeset.foreign_key_constraint(changeset, key, + name: name, + message: message, + match: repo.default_constraint_match_type(:foreign, name) + ) end) end - defp add_unique_indexes(changeset, resource, ash_changeset) do + defp add_unique_indexes(changeset, resource, ash_changeset, repo) do table = table(resource, ash_changeset) pkey = Ash.Resource.Info.primary_key(resource) @@ -2560,11 +2587,13 @@ defmodule AshPostgres.DataLayer do AshPostgres.DataLayer.Info.identity_index_names(resource)[identity.name] || "#{table}_#{identity.name}_index" + index_match_type = repo.default_constraint_match_type(:unique, name) + opts = if Map.get(identity, :message) do - [name: name, message: identity.message] + [name: name, message: identity.message, match: index_match_type] else - [name: name] + [name: name, match: index_match_type] end fields = @@ -2585,11 +2614,13 @@ defmodule AshPostgres.DataLayer do |> Enum.reduce(changeset, fn index, changeset -> name = index.name || AshPostgres.CustomIndex.name(table, index) + index_match_type = repo.default_constraint_match_type(:custom, name) + opts = if index.message do - [name: name, message: index.message] + [name: name, message: index.message, match: index_match_type] else - [name: name] + [name: name, match: index_match_type] end fields = @@ -2631,10 +2662,17 @@ defmodule AshPostgres.DataLayer do Enum.reduce(names, changeset, fn {keys, name}, changeset -> - Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), name: name) + Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), + name: name, + match: repo.default_constraint_match_type(:unique, name) + ) {keys, name, message}, changeset -> - Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), name: name, message: message) + Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), + name: name, + message: message, + match: repo.default_constraint_match_type(:unique, name) + ) end) end @@ -2917,6 +2955,8 @@ defmodule AshPostgres.DataLayer do ) |> pkey_filter(record) + repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) + with {:ok, query} <- filter(query, changeset.filter, resource) do ecto_changeset = case changeset.data do @@ -2927,7 +2967,7 @@ defmodule AshPostgres.DataLayer do data end |> Map.update!(:__meta__, &Map.put(&1, :source, table(resource, changeset))) - |> ecto_changeset(changeset, :delete, true) + |> ecto_changeset(changeset, :delete, repo, true) case bulk_updatable_query( query, @@ -2942,8 +2982,6 @@ defmodule AshPostgres.DataLayer do {:ok, query} -> try do - repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) - repo_opts = AshSql.repo_opts( repo, diff --git a/lib/repo.ex b/lib/repo.ex index 5429fdf6..a40cfd16 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -84,6 +84,19 @@ defmodule AshPostgres.Repo do @doc "Whether or not to explicitly start and close a transaction for each atomic update action, even if there are no transaction hooks. Defaults to `false`." @callback prefer_transaction_for_atomic_updates?() :: boolean + @doc """ + Determine how constraint names are matched when generating errors. + + This is useful if you are using something like citus that creates generated constraint + names for each node. In that case, for example, you might return a regex that + matches the name plus digits. + """ + @callback default_constraint_match_type( + type :: :custom | :exclusion | :unique | :foreign | :check, + name :: String.t() + ) :: + :exact | :prefix | :suffix | {:regex, Regex.t()} + @doc "Allows overriding a given migration type for *all* fields, for example if you wanted to always use :timestamptz for :utc_datetime fields" @callback override_migration_type(atom) :: atom @doc "Should the repo should be created by `mix ash_postgres.create`?" @@ -126,6 +139,8 @@ defmodule AshPostgres.Repo do def prefer_transaction_for_atomic_updates?, do: false + def default_constraint_match_type(_type, _name), do: :exact + def transaction!(fun) do case fun.() do {:ok, value} -> value @@ -266,6 +281,7 @@ defmodule AshPostgres.Repo do on_transaction_begin: 1, installed_extensions: 0, all_tenants: 0, + default_constraint_match_type: 2, prefer_transaction?: 0, prefer_transaction_for_atomic_updates?: 0, tenant_migrations_path: 0, From 12f914dc9913b07f31fc1c566e48b144c678deab Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Tue, 14 Jan 2025 13:18:08 +0100 Subject: [PATCH 324/690] fix: handle regex match correctly (#460) --- lib/data_layer.ex | 228 +++++++++++++++++++++-------- test/support/resources/comedian.ex | 1 + 2 files changed, 171 insertions(+), 58 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index a69851cc..40723180 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2468,11 +2468,21 @@ defmodule AshPostgres.DataLayer do constraint.attribute |> List.wrap() |> Enum.reduce(changeset, fn attribute, changeset -> - Ecto.Changeset.check_constraint(changeset, attribute, - name: constraint.name, - message: constraint.message || "is invalid", - match: repo.default_constraint_match_type(:check, constraint.name) - ) + case repo.default_constraint_match_type(:check, constraint.name) do + {:regex, regex} -> + Ecto.Changeset.check_constraint(changeset, attribute, + name: regex, + message: constraint.message || "is invalid", + match: :exact + ) + + match -> + Ecto.Changeset.check_constraint(changeset, attribute, + name: constraint.name, + message: constraint.message || "is invalid", + match: match + ) + end end) end) end @@ -2483,17 +2493,36 @@ defmodule AshPostgres.DataLayer do |> Enum.reduce(changeset, fn constraint, changeset -> case constraint do {key, name} -> - Ecto.Changeset.exclusion_constraint(changeset, key, - name: name, - match: repo.default_constraint_match_type(:exclusion, constraint.name) - ) + case repo.default_constraint_match_type(:check, name) do + {:regex, regex} -> + Ecto.Changeset.check_constraint(changeset, key, + name: regex, + match: :exact + ) + + match -> + Ecto.Changeset.check_constraint(changeset, key, + name: name, + match: match + ) + end {key, name, message} -> - Ecto.Changeset.exclusion_constraint(changeset, key, - name: name, - message: message, - match: repo.default_constraint_match_type(:exclusion, constraint.name) - ) + case repo.default_constraint_match_type(:check, name) do + {:regex, regex} -> + Ecto.Changeset.check_constraint(changeset, key, + name: regex, + message: message, + match: :exact + ) + + match -> + Ecto.Changeset.check_constraint(changeset, key, + name: name, + message: message, + match: match + ) + end end end) end @@ -2520,20 +2549,40 @@ defmodule AshPostgres.DataLayer do changeset -> case AshPostgres.DataLayer.Info.reference(resource, relationship_name) do %{name: name} when not is_nil(name) -> - Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, - name: name, - match: repo.default_constraint_match_type(:foreign, name), - message: "would leave records behind" - ) + case repo.default_constraint_match_type(:foreign, name) do + {:regex, regex} -> + Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, + name: regex, + message: "would leave records behind", + match: :exact + ) + + match -> + Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, + name: name, + message: "would leave records behind", + match: match + ) + end _ -> name = "#{AshPostgres.DataLayer.Info.table(source)}_#{source_attribute}_fkey" - Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, - name: name, - match: repo.default_constraint_match_type(:foreign, name), - message: "would leave records behind" - ) + case repo.default_constraint_match_type(:foreign, name) do + {:regex, regex} -> + Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, + name: regex, + message: "would leave records behind", + match: :exact + ) + + match -> + Ecto.Changeset.foreign_key_constraint(changeset, destination_attribute, + name: name, + message: "would leave records behind", + match: match + ) + end end end) end @@ -2545,10 +2594,19 @@ defmodule AshPostgres.DataLayer do name = "#{AshPostgres.DataLayer.Info.table(resource)}_#{relationship.source_attribute}_fkey" - Ecto.Changeset.foreign_key_constraint(changeset, relationship.source_attribute, - name: name, - match: repo.default_constraint_match_type(:foreign, name) - ) + case repo.default_constraint_match_type(:foreign, name) do + {:regex, regex} -> + Ecto.Changeset.foreign_key_constraint(changeset, relationship.source_attribute, + name: regex, + match: :exact + ) + + match -> + Ecto.Changeset.foreign_key_constraint(changeset, relationship.source_attribute, + name: name, + match: match + ) + end end) end @@ -2561,17 +2619,36 @@ defmodule AshPostgres.DataLayer do end |> Enum.reduce(changeset, fn {key, name}, changeset -> - Ecto.Changeset.foreign_key_constraint(changeset, key, - name: name, - match: repo.default_constraint_match_type(:foreign, name) - ) + case repo.default_constraint_match_type(:foreign, name) do + {:regex, regex} -> + Ecto.Changeset.foreign_key_constraint(changeset, key, + name: regex, + match: :exact + ) + + match -> + Ecto.Changeset.foreign_key_constraint(changeset, key, + name: name, + match: match + ) + end {key, name, message}, changeset -> - Ecto.Changeset.foreign_key_constraint(changeset, key, - name: name, - message: message, - match: repo.default_constraint_match_type(:foreign, name) - ) + case repo.default_constraint_match_type(:foreign, name) do + {:regex, regex} -> + Ecto.Changeset.foreign_key_constraint(changeset, key, + name: regex, + message: message, + match: :exact + ) + + match -> + Ecto.Changeset.foreign_key_constraint(changeset, key, + name: name, + message: message, + match: match + ) + end end) end @@ -2587,13 +2664,21 @@ defmodule AshPostgres.DataLayer do AshPostgres.DataLayer.Info.identity_index_names(resource)[identity.name] || "#{table}_#{identity.name}_index" - index_match_type = repo.default_constraint_match_type(:unique, name) - opts = - if Map.get(identity, :message) do - [name: name, message: identity.message, match: index_match_type] - else - [name: name, match: index_match_type] + case repo.default_constraint_match_type(:unique, name) do + {:regex, regex} -> + if Map.get(identity, :message) do + [name: regex, message: identity.message, match: :exact] + else + [name: regex, match: :exact] + end + + index_match_type -> + if Map.get(identity, :message) do + [name: name, message: identity.message, match: index_match_type] + else + [name: name, match: index_match_type] + end end fields = @@ -2614,13 +2699,21 @@ defmodule AshPostgres.DataLayer do |> Enum.reduce(changeset, fn index, changeset -> name = index.name || AshPostgres.CustomIndex.name(table, index) - index_match_type = repo.default_constraint_match_type(:custom, name) - opts = - if index.message do - [name: name, message: index.message, match: index_match_type] - else - [name: name, match: index_match_type] + case repo.default_constraint_match_type(:custom, name) do + {:regex, regex} -> + if Map.get(index, :message) do + [name: regex, message: index.message, match: :exact] + else + [name: regex, match: :exact] + end + + index_match_type -> + if Map.get(index, :message) do + [name: name, message: index.message, match: index_match_type] + else + [name: name, match: index_match_type] + end end fields = @@ -2662,17 +2755,36 @@ defmodule AshPostgres.DataLayer do Enum.reduce(names, changeset, fn {keys, name}, changeset -> - Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), - name: name, - match: repo.default_constraint_match_type(:unique, name) - ) + case repo.default_constraint_match_type(:unique, name) do + {:regex, regex} -> + Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), + name: regex, + match: :exact + ) + + match -> + Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), + name: name, + match: match + ) + end {keys, name, message}, changeset -> - Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), - name: name, - message: message, - match: repo.default_constraint_match_type(:unique, name) - ) + case repo.default_constraint_match_type(:unique, name) do + {:regex, regex} -> + Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), + name: regex, + message: message, + match: :exact + ) + + match -> + Ecto.Changeset.unique_constraint(changeset, List.wrap(keys), + name: name, + message: message, + match: match + ) + end end) end diff --git a/test/support/resources/comedian.ex b/test/support/resources/comedian.ex index 1fa08c54..a210270c 100644 --- a/test/support/resources/comedian.ex +++ b/test/support/resources/comedian.ex @@ -41,6 +41,7 @@ defmodule AshPostgres.Test.Comedian do end defmodule AshPostgres.Test.Comedian.HasJokes do + @moduledoc false use Ash.Resource.Calculation @impl true From 6cf1b661390689a1c4aa90ae4b9bb4c964d61ad4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 15 Jan 2025 13:16:22 -0500 Subject: [PATCH 325/690] improvement: use prettier SQL in `Ash.calculate` --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 40723180..68a4cf00 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1787,7 +1787,7 @@ defmodule AshPostgres.DataLayer do |> Map.new(fn {dynamic, index} -> {index, dynamic} end) query = - Ecto.Query.from(row in fragment("UNNEST(ARRAY[1])"), select: ^dynamics) + Ecto.Query.from(row in fragment("(VALUES(1))"), select: ^dynamics) |> Map.put(:__ash_bindings__, query.__ash_bindings__) repo = From bb9bd5b7325f71eaadeb3d426867c70f8c329ec2 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 15 Jan 2025 13:28:52 -0500 Subject: [PATCH 326/690] chore: fix dialyzer --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 68a4cf00..3ef52d78 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1297,7 +1297,7 @@ defmodule AshPostgres.DataLayer do case Ash.Resource.Info.primary_key(query.resource) do [] -> case Ash.Resource.Info.identities(query.resource) do - %{keys: keys} -> keys + [%{keys: keys} | _] -> keys _ -> [] end From 0f38bf2c331a2598300daa410efd0a626397713c Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Thu, 16 Jan 2025 17:16:19 +0100 Subject: [PATCH 327/690] feat: add repo callback to disable atomic actions and error expressions (#464) --- lib/data_layer.ex | 14 ++++++++++---- lib/repo.ex | 12 +++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 3ef52d78..274fd495 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -644,8 +644,11 @@ defmodule AshPostgres.DataLayer do def can?(_, :transact), do: true def can?(_, :composite_primary_key), do: true - def can?(_resource, {:atomic, :update}), do: true - def can?(_resource, {:atomic, :upsert}), do: true + def can?(resource, {:atomic, :update}), + do: not AshPostgres.DataLayer.Info.repo(resource, :mutate).disable_atomic_actions?() + + def can?(resource, {:atomic, :upsert}), + do: not AshPostgres.DataLayer.Info.repo(resource, :mutate).disable_atomic_actions?() def can?(_, :upsert), do: true def can?(_, :changeset_filter), do: true @@ -709,10 +712,13 @@ defmodule AshPostgres.DataLayer do def can?(_, {:aggregate_relationship, _}), do: true def can?(_, :timeout), do: true - def can?(_, :expr_error), do: true + + def can?(resource, :expr_error), + do: not AshPostgres.DataLayer.Info.repo(resource, :mutate).disable_expr_error?() def can?(resource, {:filter_expr, %Ash.Query.Function.Error{}}) do - "ash-functions" in AshPostgres.DataLayer.Info.repo(resource, :read).installed_extensions() && + not AshPostgres.DataLayer.Info.repo(resource, :mutate).disable_expr_error?() && + "ash-functions" in AshPostgres.DataLayer.Info.repo(resource, :read).installed_extensions() && "ash-functions" in AshPostgres.DataLayer.Info.repo(resource, :mutate).installed_extensions() end diff --git a/lib/repo.ex b/lib/repo.ex index a40cfd16..a0bb292d 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -104,6 +104,12 @@ defmodule AshPostgres.Repo do @doc "Should the repo should be dropped by `mix ash_postgres.drop`?" @callback drop?() :: boolean + @doc "Disable atomic actions for this repo" + @callback disable_atomic_actions?() :: boolean + + @doc "Disable expression errors for this repo" + @callback disable_expr_error?() :: boolean + defmacro __using__(opts) do quote bind_quoted: [opts: opts] do if Keyword.get(opts, :define_ecto_repo?, true) do @@ -133,6 +139,8 @@ defmodule AshPostgres.Repo do def override_migration_type(type), do: type def create?, do: true def drop?, do: true + def disable_atomic_actions?, do: false + def disable_expr_error?, do: false # default to false in 4.0 def prefer_transaction?, do: true @@ -288,7 +296,9 @@ defmodule AshPostgres.Repo do default_prefix: 0, override_migration_type: 1, create?: 0, - drop?: 0 + drop?: 0, + disable_atomic_actions?: 0, + disable_expr_error?: 0 # We do this switch because `!@warn_on_missing_ash_functions` in the function body triggers # a dialyzer error From 785fc608a8251fdbc3f6ba4f972fe44e734346c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:50:39 -0500 Subject: [PATCH 328/690] chore(deps): bump ash_sql in the production-dependencies group (#463) Bumps the production-dependencies group with 1 update: [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash_sql` from 0.2.43 to 0.2.45 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.43...v0.2.45) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 2a858f30..4caaedd6 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.55", "81132171412dc92bd1630500e1403a48f5ea7948552c528189d13d4c4c181878", [: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.4.8 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.9", [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", "6fb89c9bb6e158b2dab08184f3b6ebfd88785348c21b2a9fd5bd71b1f96e2c5e"}, - "ash_sql": {:hex, :ash_sql, "0.2.43", "80579d708630d3d31e9bb74b74d16ff8ef70de8c1d5043d87a682b5b17cb3154", [:mix], [{:ash, ">= 3.1.7 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", "c3fc710129178c017002bd108fc9411b10ca1d276fa5e99bd01b99addf28ff42"}, + "ash_sql": {:hex, :ash_sql, "0.2.45", "9c73522c13db7c7a82c1d1599e3eeaa63a4272ad2c9f7649abb34de6404763ea", [:mix], [{:ash, ">= 3.1.7 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", "4a55465e49c2f0ba28f19a4b0dafeb2b031df8ab9fecf9607611d20918b34ca9"}, "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"}, From 22915b666581ad623ac8f6086378610c0198b521 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 20 Jan 2025 11:51:42 -0500 Subject: [PATCH 329/690] fix: generate a repo when selecting one --- lib/igniter.ex | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/igniter.ex b/lib/igniter.ex index 2e00bb7b..02ef4476 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -101,12 +101,13 @@ if Code.ensure_loaded?(Igniter) do """) end - Igniter.Project.Module.create_module( - igniter, - repo, - default_repo_contents(otp_app, opts), - opts - ) + igniter = + Igniter.Project.Module.create_module( + igniter, + repo, + default_repo_contents(otp_app, opts), + opts + ) {igniter, repo} else From e2df7b600abeac95546fdcc1357712294684d74c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 20 Jan 2025 12:00:54 -0500 Subject: [PATCH 330/690] chore: release version v2.5.0 --- CHANGELOG.md | 23 +++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93357fd0..a60eea78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,29 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.0](https://github.com/ash-project/ash_postgres/compare/v2.4.22...v2.5.0) (2025-01-20) + + + + +### Features: + +* add repo callback to disable atomic actions and error expressions (#464) + +### Bug Fixes: + +* generate a repo when selecting one + +* handle regex match correctly (#460) + +### Improvements: + +* use prettier SQL in `Ash.calculate` + +* add `c:AshPostgres.Repo.default_constraint_match_type` + +* mark ash_raise_error as STABLE + ## [v2.4.22](https://github.com/ash-project/ash_postgres/compare/v2.4.21...v2.4.22) (2025-01-13) diff --git a/mix.exs b/mix.exs index 06279f90..d6810d80 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.4.22" + @version "2.5.0" def project do [ From c9a911e582a4a6ac6ef712522372f8cb25b2f0dc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 22 Jan 2025 15:41:24 -0500 Subject: [PATCH 331/690] fix: handle cross global to tenant references in migration generator test: add test for ash_sql fix chore: remove unnecessary prod deps --- .../migration_generator.ex | 1 + lib/migration_generator/operation.ex | 25 +++++ mix.exs | 4 +- mix.lock | 13 ++- .../20250122190558.json | 106 ++++++++++++++++++ .../20250122203454.json | 77 +++++++++++++ .../20250122190558_migrate_resources46.exs | 48 ++++++++ .../20250122203454_migrate_resources4.exs | 45 ++++++++ test/multitenancy_test.exs | 16 +++ test/support/multitenancy/domain.ex | 2 + .../resources/cross_tenant_post_link.ex | 31 +++++ .../resources/non_multitenant_post_link.ex | 43 +++++++ test/support/multitenancy/resources/post.ex | 9 ++ test/support/resources/post.ex | 7 ++ 14 files changed, 421 insertions(+), 6 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json create mode 100644 priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json create mode 100644 priv/test_repo/migrations/20250122190558_migrate_resources46.exs create mode 100644 priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs create mode 100644 test/support/multitenancy/resources/cross_tenant_post_link.ex create mode 100644 test/support/multitenancy/resources/non_multitenant_post_link.ex diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 2810ceb8..ca733282 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -815,6 +815,7 @@ defmodule AshPostgres.MigrationGenerator do %{ keys: pkey_names, name: name, + index_name: name, base_filter: nil, all_tenants?: false, nils_distinct?: false, diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 930a375b..a2a4a1af 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -247,6 +247,31 @@ defmodule AshPostgres.MigrationGenerator.Operation do |> join() end + def up(%{ + multitenancy: %{strategy: nil}, + attribute: + %{ + references: %{ + multitenancy: %{strategy: :context} + } + } = attribute + }) do + size = + if attribute.size do + "size: #{attribute.size}" + end + + [ + "add #{inspect(attribute.source)}", + inspect(attribute.type), + maybe_add_default(attribute.default), + maybe_add_primary_key(attribute.primary_key?), + size, + maybe_add_null(attribute.allow_nil?) + ] + |> join() + end + def up(%{ multitenancy: %{strategy: :context}, attribute: diff --git a/mix.exs b/mix.exs index d6810d80..1589d2b6 100644 --- a/mix.exs +++ b/mix.exs @@ -167,13 +167,11 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.4 and >= 3.4.48")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.43")}, - {:igniter, "~> 0.4 and >= 0.4.4", optional: true}, + {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, - {:inflex, "~> 2.1"}, - {:owl, "~> 0.11"}, # dev/test dependencies {:ecto_dev_logger, "~> 0.14", only: :test}, {:eflame, "~> 1.0", only: [:dev, :test]}, diff --git a/mix.lock b/mix.lock index 4caaedd6..19b23f25 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.55", "81132171412dc92bd1630500e1403a48f5ea7948552c528189d13d4c4c181878", [: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.4.8 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.9", [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", "6fb89c9bb6e158b2dab08184f3b6ebfd88785348c21b2a9fd5bd71b1f96e2c5e"}, + "ash": {:hex, :ash, "3.4.56", "2591ef830200b9840b1915b6e2889518964d6852a44e58f06a0752f7b9e114a3", [: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.4.8 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.9", [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", "c7d8091db87aa72b7a9e1082edea5b17308942b58c4f24c2d01499db6de05486"}, "ash_sql": {:hex, :ash_sql, "0.2.45", "9c73522c13db7c7a82c1d1599e3eeaa63a4272ad2c9f7649abb34de6404763ea", [:mix], [{:ash, ">= 3.1.7 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", "4a55465e49c2f0ba28f19a4b0dafeb2b031df8ab9fecf9607611d20918b34ca9"}, "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"}, @@ -18,10 +18,12 @@ "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "d571628fd829a510d219bcb7162400baff50977f", []}, "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.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "igniter": {:hex, :igniter, "0.5.8", "d91e90fecb99beadfa9d0d8434fbd4f0fe06ea1a1d29cae4dfd0cb058cb3a5c7", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, 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", "fef198324925405ea5c3b16166002be03b2d7497c038cfc9708aa557d27ba5a2"}, + "hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"}, + "igniter": {:hex, :igniter, "0.5.16", "3a6cc46f2ac93c8772038d513df5da6ab37aa06538ab96feb9d84b631fbbc073", [: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", "b6b5c74ac01541e0cdb296a93f7cc76a783d2020c152c9bc1f314ba0e83e1421"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -29,16 +31,21 @@ "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, + "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, "reactor": {:hex, :reactor, "0.10.3", "41a8c34251148e36dd7c75aa8433f2c2f283f29c097f9eb84a630ab28dd75651", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b34380e22b69a35943a7bcceffd5a8b766870f1fc9052162a7ff74ef9cdb3b2"}, + "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.36", "07c921e5efb27f184267c3431d2f82099e24cac90748a47383dd75cbfb558268", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "e5ac56b75e5ad43da6d8302b6713277488f8e9a3abdba9aae8f0d0f9cff04538"}, + "spark": {:hex, :spark, "2.2.38", "cb84e7229122e1f1e0f8584ec65268ef6cd9a14dcc85a37eaaf70470267044ef", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "cca1322243506dee820fe72e6d323e76ffb9eb1fe44f0591355c9be5eccb0431"}, "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json b/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json new file mode 100644 index 00000000..e0577141 --- /dev/null +++ b/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json @@ -0,0 +1,106 @@ +{ + "attributes": [ + { + "allow_nil?": true, + "default": "\"active\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "state", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": false, + "strategy": "context" + }, + "name": "non_multitenant_post_links_source_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_posts" + }, + "size": null, + "source": "source_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "non_multitenant_post_links_dest_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "dest_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "5B5A0B9459B9D31BE1BEA278DC64440D848D117EA9D43AB92C23C85ADB65102D", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "non_multitenant_post_links_unique_link_index", + "keys": [ + { + "type": "atom", + "value": "source_id" + }, + { + "type": "atom", + "value": "dest_id" + } + ], + "name": "unique_link", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "non_multitenant_post_links" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json b/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json new file mode 100644 index 00000000..b1f8c6bd --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json @@ -0,0 +1,77 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "cross_tenant_post_links_source_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "source_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": false, + "strategy": "context" + }, + "name": "cross_tenant_post_links_dest_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_posts" + }, + "size": null, + "source": "dest_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "A58B6473A5BEDECB3AFCC907EB96BD983DD78019B54016D7DE818C46B36303A0", + "identities": [], + "multitenancy": { + "attribute": null, + "global": false, + "strategy": "context" + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "cross_tenant_post_links" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250122190558_migrate_resources46.exs b/priv/test_repo/migrations/20250122190558_migrate_resources46.exs new file mode 100644 index 00000000..9f7eec04 --- /dev/null +++ b/priv/test_repo/migrations/20250122190558_migrate_resources46.exs @@ -0,0 +1,48 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources46 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:non_multitenant_post_links, primary_key: false) do + add(:state, :text, default: "active") + add(:source_id, :uuid, primary_key: true, null: false) + + add( + :dest_id, + references(:posts, + column: :id, + name: "non_multitenant_post_links_dest_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + end + + create( + unique_index(:non_multitenant_post_links, [:source_id, :dest_id], + name: "non_multitenant_post_links_unique_link_index" + ) + ) + end + + def down do + drop_if_exists( + unique_index(:non_multitenant_post_links, [:source_id, :dest_id], + name: "non_multitenant_post_links_unique_link_index" + ) + ) + + drop(constraint(:non_multitenant_post_links, "non_multitenant_post_links_source_id_fkey")) + + drop(constraint(:non_multitenant_post_links, "non_multitenant_post_links_dest_id_fkey")) + + drop(table(:non_multitenant_post_links)) + end +end diff --git a/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs b/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs new file mode 100644 index 00000000..36cbc1d1 --- /dev/null +++ b/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs @@ -0,0 +1,45 @@ +defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources4 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:cross_tenant_post_links, primary_key: false, prefix: prefix()) do + add( + :source_id, + references(:posts, + column: :id, + name: "cross_tenant_post_links_source_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + + add( + :dest_id, + references(:multitenant_posts, + column: :id, + name: "cross_tenant_post_links_dest_id_fkey", + type: :uuid, + prefix: prefix() + ), + primary_key: true, + null: false + ) + end + end + + def down do + drop(constraint(:cross_tenant_post_links, "cross_tenant_post_links_source_id_fkey")) + + drop(constraint(:cross_tenant_post_links, "cross_tenant_post_links_dest_id_fkey")) + + drop(table(:cross_tenant_post_links, prefix: prefix())) + end +end diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 0c3326b9..afd5cbe5 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -1,7 +1,9 @@ defmodule AshPostgres.Test.MultitenancyTest do use AshPostgres.RepoCase, async: false + require Ash.Query alias AshPostgres.MultitenancyTest.{Org, Post, User} + alias AshPostgres.Test.Post, as: GlobalPost setup do org1 = @@ -44,6 +46,20 @@ defmodule AshPostgres.Test.MultitenancyTest do |> Ash.read!() end + test "joining to non multitenant through relationship works", %{org1: org1} do + Post + |> Ash.Query.filter(linked_non_multitenant_posts.title == "fred") + |> Ash.Query.set_tenant("org_" <> org1.id) + |> Ash.read!() + end + + test "joining from non multitenant through relationship works", %{org1: org1} do + GlobalPost + |> Ash.Query.filter(linked_multitenant_posts.name == "fred") + |> Ash.Query.set_tenant("org_" <> org1.id) + |> Ash.read!() + end + test "attribute multitenancy works with authorization", %{org1: org1} do user = User diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 68a5d9de..2394c234 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -7,6 +7,8 @@ defmodule AshPostgres.MultitenancyTest.Domain do resource(AshPostgres.MultitenancyTest.User) resource(AshPostgres.MultitenancyTest.Post) resource(AshPostgres.MultitenancyTest.PostLink) + resource(AshPostgres.MultitenancyTest.NonMultitenantPostLink) + resource(AshPostgres.MultitenancyTest.CrossTenantPostLink) end authorization do diff --git a/test/support/multitenancy/resources/cross_tenant_post_link.ex b/test/support/multitenancy/resources/cross_tenant_post_link.ex new file mode 100644 index 00000000..0bcc7111 --- /dev/null +++ b/test/support/multitenancy/resources/cross_tenant_post_link.ex @@ -0,0 +1,31 @@ +defmodule AshPostgres.MultitenancyTest.CrossTenantPostLink do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.MultitenancyTest.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "cross_tenant_post_links" + repo AshPostgres.TestRepo + end + + multitenancy do + strategy(:context) + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + relationships do + belongs_to(:source, AshPostgres.Test.Post, + primary_key?: true, + allow_nil?: false + ) + + belongs_to(:dest, AshPostgres.MultitenancyTest.Post, + primary_key?: true, + allow_nil?: false + ) + end +end diff --git a/test/support/multitenancy/resources/non_multitenant_post_link.ex b/test/support/multitenancy/resources/non_multitenant_post_link.ex new file mode 100644 index 00000000..9d986bdb --- /dev/null +++ b/test/support/multitenancy/resources/non_multitenant_post_link.ex @@ -0,0 +1,43 @@ +defmodule AshPostgres.MultitenancyTest.NonMultitenantPostLink do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.MultitenancyTest.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "non_multitenant_post_links" + repo AshPostgres.TestRepo + end + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + end + + identities do + identity(:unique_link, [:source_id, :dest_id]) + end + + attributes do + attribute :state, :atom do + public?(true) + constraints(one_of: [:active, :archived]) + default(:active) + end + end + + relationships do + belongs_to :source, AshPostgres.MultitenancyTest.Post do + public?(true) + allow_nil?(false) + primary_key?(true) + end + + belongs_to :dest, AshPostgres.Test.Post do + public?(true) + allow_nil?(false) + primary_key?(true) + end + end +end diff --git a/test/support/multitenancy/resources/post.ex b/test/support/multitenancy/resources/post.ex index d7999771..e097fffb 100644 --- a/test/support/multitenancy/resources/post.ex +++ b/test/support/multitenancy/resources/post.ex @@ -56,6 +56,15 @@ defmodule AshPostgres.MultitenancyTest.Post do source_attribute_on_join_resource(:source_id) destination_attribute_on_join_resource(:dest_id) end + + # has_many(:non_multitenant_post_links, AshPostgres.MultitenancyTest.NonMultitenantPostLink) + + many_to_many :linked_non_multitenant_posts, AshPostgres.Test.Post do + through(AshPostgres.MultitenancyTest.NonMultitenantPostLink) + join_relationship(:non_multitenant_post_links) + source_attribute_on_join_resource(:source_id) + destination_attribute_on_join_resource(:dest_id) + end end calculations do diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index d9dfcdf9..6a3a1904 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -530,6 +530,13 @@ defmodule AshPostgres.Test.Post do destination_attribute_on_join_resource: :destination_post_id ) + many_to_many(:linked_multitenant_posts, AshPostgres.MultitenancyTest.Post, + public?: true, + through: AshPostgres.MultitenancyTest.CrossTenantPostLink, + source_attribute_on_join_resource: :source_id, + destination_attribute_on_join_resource: :dest_id + ) + many_to_many(:followers, AshPostgres.Test.User, public?: true, through: AshPostgres.Test.PostFollower, From 8cc8d632154559605a03a6c6a61652983cec750d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 22 Jan 2025 15:44:02 -0500 Subject: [PATCH 332/690] WIP --- .../dsls/DSL-AshPostgres.DataLayer.md | 20 +++++++++---------- mix.lock | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/documentation/dsls/DSL-AshPostgres.DataLayer.md b/documentation/dsls/DSL-AshPostgres.DataLayer.md index 4ad2f0b3..a3938dcf 100644 --- a/documentation/dsls/DSL-AshPostgres.DataLayer.md +++ b/documentation/dsls/DSL-AshPostgres.DataLayer.md @@ -1,7 +1,7 @@ -# DSL: AshPostgres.DataLayer +# AshPostgres.DataLayer A postgres data layer that leverages Ecto's postgres capabilities. @@ -58,7 +58,7 @@ end | [`polymorphic?`](#postgres-polymorphic?){: #postgres-polymorphic? } | `boolean` | `false` | Declares this resource as polymorphic. See the [polymorphic resources guide](/documentation/topics/resources/polymorphic-resources.md) for more. | -## postgres.custom_indexes +### postgres.custom_indexes A section for configuring indexes to be created by the migration generator. In general, prefer to use `identities` for simple unique constraints. This is a tool to allow @@ -80,7 +80,7 @@ end -## postgres.custom_indexes.index +### postgres.custom_indexes.index ```elixir index fields ``` @@ -128,7 +128,7 @@ index ["column", "column2"], unique: true, where: "thing = TRUE" Target: `AshPostgres.CustomIndex` -## postgres.custom_statements +### postgres.custom_statements A section for configuring custom statements to be added to migrations. Changing custom statements may require manual intervention, because Ash can't determine what order they should run @@ -161,7 +161,7 @@ end -## postgres.custom_statements.statement +### postgres.custom_statements.statement ```elixir statement name ``` @@ -205,7 +205,7 @@ end Target: `AshPostgres.Statement` -## postgres.manage_tenant +### postgres.manage_tenant Configuration for the behavior of a resource that manages a tenant @@ -235,7 +235,7 @@ end -## postgres.references +### postgres.references A section for configuring the references (foreign keys) in resource migrations. This section is only relevant if you are using the migration generator with this resource. @@ -266,7 +266,7 @@ end -## postgres.references.reference +### postgres.references.reference ```elixir reference relationship ``` @@ -317,7 +317,7 @@ reference :post, on_delete: :delete, on_update: :update, name: "comments_to_post Target: `AshPostgres.Reference` -## postgres.check_constraints +### postgres.check_constraints A section for configuring the check constraints for a given table. This can be used to automatically create those check constraints, or just to provide message when they are raised @@ -338,7 +338,7 @@ end -## postgres.check_constraints.check_constraint +### postgres.check_constraints.check_constraint ```elixir check_constraint attribute, name ``` diff --git a/mix.lock b/mix.lock index 19b23f25..bd880a5e 100644 --- a/mix.lock +++ b/mix.lock @@ -45,7 +45,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.38", "cb84e7229122e1f1e0f8584ec65268ef6cd9a14dcc85a37eaaf70470267044ef", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "cca1322243506dee820fe72e6d323e76ffb9eb1fe44f0591355c9be5eccb0431"}, + "spark": {:hex, :spark, "2.2.39", "6c9e5d89146df8f7729236d9700518f53e1d6a7d6aaf9cc5ae3c7e4ab11f65ee", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "115f35d263895ebd810faf197ba3e42d5a0912c51e5350af899142d33aaa11dd"}, "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From abc9ad1d494959a60b4187e50537db437139353f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 22 Jan 2025 22:44:56 -0500 Subject: [PATCH 333/690] chore: only update lock file compatible deps --- .github/dependabot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2f0ee6ff..a3168e45 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,6 +2,7 @@ version: 2 updates: - package-ecosystem: mix directory: "/" + versioning-strategy: lockfile-only schedule: interval: weekly day: thursday From d6afc183f2487dbd35950886104f208d9c98a2a6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 23 Jan 2025 00:38:01 -0500 Subject: [PATCH 334/690] chore: update deps --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index bd880a5e..968886aa 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.56", "2591ef830200b9840b1915b6e2889518964d6852a44e58f06a0752f7b9e114a3", [: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.4.8 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.9", [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", "c7d8091db87aa72b7a9e1082edea5b17308942b58c4f24c2d01499db6de05486"}, - "ash_sql": {:hex, :ash_sql, "0.2.45", "9c73522c13db7c7a82c1d1599e3eeaa63a4272ad2c9f7649abb34de6404763ea", [:mix], [{:ash, ">= 3.1.7 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", "4a55465e49c2f0ba28f19a4b0dafeb2b031df8ab9fecf9607611d20918b34ca9"}, + "ash_sql": {:hex, :ash_sql, "0.2.47", "812194f28ffe88cb6ff30c32615e08fe49c4157dbc2cc80bf11f4844192c1f24", [:mix], [{:ash, ">= 3.1.7 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", "1c3563c10d29b7e36498ee58fe652882ce4931d6a736025c6ccf7e862ddda191"}, "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"}, @@ -45,7 +45,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.39", "6c9e5d89146df8f7729236d9700518f53e1d6a7d6aaf9cc5ae3c7e4ab11f65ee", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "115f35d263895ebd810faf197ba3e42d5a0912c51e5350af899142d33aaa11dd"}, + "spark": {:hex, :spark, "2.2.40", "4fef851c346d891ce2aaf13d72e8af9b4371bf3059530b58c4a1149923faaf37", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d3cd4487932f4c63261c67568cec77d535dc6f9546c334d28f3b9d17c7f23fc0"}, "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 846a98ac9052d07666f922516dd25acec4d52ad4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 00:42:38 -0500 Subject: [PATCH 335/690] chore(deps): bump ash_sql in the production-dependencies group (#465) Bumps the production-dependencies group with 1 update: [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash_sql` from 0.2.45 to 0.2.47 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.45...v0.2.47) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 10f4354df2319b876887e4db2712c6eafc99d01a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 23 Jan 2025 11:52:41 -0500 Subject: [PATCH 336/690] chore: add tests for nested many to many issue --- .../comment_links/20250123161002.json | 96 +++++++++++ .../test_repo/content/20250123164209.json | 78 +++++++++ .../20250123164209.json | 77 +++++++++ .../test_repo/note/20250123164209.json | 59 +++++++ .../test_repo/staff_group/20250123164209.json | 49 ++++++ .../staff_group_member/20250123164209.json | 87 ++++++++++ .../20250123161002_migrate_resources47.exs | 57 +++++++ .../20250123164209_migrate_resources48.exs | 160 ++++++++++++++++++ test/complex_calculations_test.exs | 6 + test/support/domain.ex | 6 + test/support/resources/comment.ex | 11 ++ test/support/resources/comment_link.ex | 35 ++++ test/support/resources/content.ex | 36 ++++ .../resources/content_visibility_group.ex | 21 +++ test/support/resources/note.ex | 36 ++++ test/support/resources/post.ex | 5 + test/support/resources/staff_group.ex | 32 ++++ test/support/resources/staff_group_member.ex | 25 +++ test/test_helper.exs | 2 +- 19 files changed, 877 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/comment_links/20250123161002.json create mode 100644 priv/resource_snapshots/test_repo/content/20250123164209.json create mode 100644 priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json create mode 100644 priv/resource_snapshots/test_repo/note/20250123164209.json create mode 100644 priv/resource_snapshots/test_repo/staff_group/20250123164209.json create mode 100644 priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json create mode 100644 priv/test_repo/migrations/20250123161002_migrate_resources47.exs create mode 100644 priv/test_repo/migrations/20250123164209_migrate_resources48.exs create mode 100644 test/support/resources/comment_link.ex create mode 100644 test/support/resources/content.ex create mode 100644 test/support/resources/content_visibility_group.ex create mode 100644 test/support/resources/note.ex create mode 100644 test/support/resources/staff_group.ex create mode 100644 test/support/resources/staff_group_member.ex diff --git a/priv/resource_snapshots/test_repo/comment_links/20250123161002.json b/priv/resource_snapshots/test_repo/comment_links/20250123161002.json new file mode 100644 index 00000000..7f029e7d --- /dev/null +++ b/priv/resource_snapshots/test_repo/comment_links/20250123161002.json @@ -0,0 +1,96 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "comment_links_source_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "comments" + }, + "size": null, + "source": "source_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "comment_links_dest_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "comments" + }, + "size": null, + "source": "dest_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "C6B8BE5033D412C2E597F975082E6D985EC260BED163E504500FFB684FAD0BD2", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "comment_links_unique_link_index", + "keys": [ + { + "type": "atom", + "value": "source_id" + }, + { + "type": "atom", + "value": "dest_id" + } + ], + "name": "unique_link", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "comment_links" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/content/20250123164209.json b/priv/resource_snapshots/test_repo/content/20250123164209.json new file mode 100644 index 00000000..58a9de23 --- /dev/null +++ b/priv/resource_snapshots/test_repo/content/20250123164209.json @@ -0,0 +1,78 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "content_note_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "note" + }, + "size": null, + "source": "note_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "F045A8746F9BEC0CA9C585954072792A9DEB0FE0702789163E2F6BF9CC1A41A1", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "content" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json b/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json new file mode 100644 index 00000000..f49c0ae5 --- /dev/null +++ b/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json @@ -0,0 +1,77 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "content_visibility_group_content_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "content" + }, + "size": null, + "source": "content_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "content_visibility_group_staff_group_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "staff_group" + }, + "size": null, + "source": "staff_group_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "36C3B7305D83A64EAB2A7B934D2961D7ACA0557254D2DF059EF500BADFF4A177", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "content_visibility_group" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/note/20250123164209.json b/priv/resource_snapshots/test_repo/note/20250123164209.json new file mode 100644 index 00000000..469e89f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/note/20250123164209.json @@ -0,0 +1,59 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "body", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "3AEFA76A190732E6BDB6EA0686B4D6872F1E6395CFD58975853FDA3C3CADD98C", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "note" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/staff_group/20250123164209.json b/priv/resource_snapshots/test_repo/staff_group/20250123164209.json new file mode 100644 index 00000000..530dee1b --- /dev/null +++ b/priv/resource_snapshots/test_repo/staff_group/20250123164209.json @@ -0,0 +1,49 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "4353CC893BCF75218813E38289037CD3F213C4CFC4200426351DDCD5BA48F778", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "staff_group" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json b/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json new file mode 100644 index 00000000..9ef0e0aa --- /dev/null +++ b/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json @@ -0,0 +1,87 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "staff_group_member_staff_group_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "staff_group" + }, + "size": null, + "source": "staff_group_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "staff_group_member_user_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "users" + }, + "size": null, + "source": "user_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "6B740A55EA43FF7876BDA82F624D11ADB1539EF574541A508399280D0B0DA083", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "staff_group_member" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250123161002_migrate_resources47.exs b/priv/test_repo/migrations/20250123161002_migrate_resources47.exs new file mode 100644 index 00000000..59036b61 --- /dev/null +++ b/priv/test_repo/migrations/20250123161002_migrate_resources47.exs @@ -0,0 +1,57 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources47 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:comment_links, primary_key: false) do + add( + :source_id, + references(:comments, + column: :id, + name: "comment_links_source_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + + add( + :dest_id, + references(:comments, + column: :id, + name: "comment_links_dest_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + end + + create( + unique_index(:comment_links, [:source_id, :dest_id], + name: "comment_links_unique_link_index" + ) + ) + end + + def down do + drop_if_exists( + unique_index(:comment_links, [:source_id, :dest_id], + name: "comment_links_unique_link_index" + ) + ) + + drop(constraint(:comment_links, "comment_links_source_id_fkey")) + + drop(constraint(:comment_links, "comment_links_dest_id_fkey")) + + drop(table(:comment_links)) + end +end diff --git a/priv/test_repo/migrations/20250123164209_migrate_resources48.exs b/priv/test_repo/migrations/20250123164209_migrate_resources48.exs new file mode 100644 index 00000000..99bc4982 --- /dev/null +++ b/priv/test_repo/migrations/20250123164209_migrate_resources48.exs @@ -0,0 +1,160 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources48 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:staff_group, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + end + + create table(:content, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:note_id, :uuid) + end + + create table(:note, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + end + + alter table(:content) do + modify( + :note_id, + references(:note, + column: :id, + name: "content_note_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + + alter table(:note) do + add(:body, :text, null: false) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + end + + create table(:staff_group_member, primary_key: false) do + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add( + :staff_group_id, + references(:staff_group, + column: :id, + name: "staff_group_member_staff_group_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + + add( + :user_id, + references(:users, + column: :id, + name: "staff_group_member_user_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + end + + create table(:content_visibility_group, primary_key: false) do + add( + :content_id, + references(:content, + column: :id, + name: "content_visibility_group_content_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + + add( + :staff_group_id, + references(:staff_group, + column: :id, + name: "content_visibility_group_staff_group_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + end + end + + def down do + drop(constraint(:content_visibility_group, "content_visibility_group_content_id_fkey")) + + drop(constraint(:content_visibility_group, "content_visibility_group_staff_group_id_fkey")) + + drop(table(:content_visibility_group)) + + drop(constraint(:staff_group_member, "staff_group_member_staff_group_id_fkey")) + + drop(constraint(:staff_group_member, "staff_group_member_user_id_fkey")) + + drop(table(:staff_group_member)) + + alter table(:note) do + remove(:updated_at) + remove(:inserted_at) + remove(:body) + end + + drop(constraint(:content, "content_note_id_fkey")) + + alter table(:content) do + modify(:note_id, :uuid) + end + + drop(table(:note)) + + drop(table(:content)) + + drop(table(:staff_group)) + end +end diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index 383a0ac9..73fd689d 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -340,4 +340,10 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do |> Ash.Query.filter(sum_of_author_count_of_posts == 1) |> Ash.read!() end + + test "filters with nested related list aggregate references don't raise errors" do + AshPostgres.Test.Note + |> Ash.Query.for_read(:failing_many_reference) + |> Ash.read!(page: [count: true]) + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index f690211a..c2d867a7 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -7,6 +7,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Post) resource(AshPostgres.Test.Comedian) resource(AshPostgres.Test.Comment) + resource(AshPostgres.Test.CommentLink) resource(AshPostgres.Test.IntegerPost) resource(AshPostgres.Test.Rating) resource(AshPostgres.Test.PostLink) @@ -16,10 +17,15 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.User) resource(AshPostgres.Test.Invite) resource(AshPostgres.Test.Joke) + resource(AshPostgres.Test.Note) + resource(AshPostgres.Test.StaffGroup) + resource(AshPostgres.Test.StaffGroupMember) + resource(AshPostgres.Test.Content) resource(AshPostgres.Test.Account) resource(AshPostgres.Test.Organization) resource(AshPostgres.Test.Manager) resource(AshPostgres.Test.Entity) + resource(AshPostgres.Test.ContentVisibilityGroup) resource(AshPostgres.Test.TempEntity) resource(AshPostgres.Test.Permalink) resource(AshPostgres.Test.Record) diff --git a/test/support/resources/comment.ex b/test/support/resources/comment.ex index 82bccc9a..fe4a818e 100644 --- a/test/support/resources/comment.ex +++ b/test/support/resources/comment.ex @@ -48,6 +48,10 @@ defmodule AshPostgres.Test.Comment do count(:co_popular_comments, [:post, :popular_comments]) count(:count_of_comments_containing_title, [:post, :comments_containing_title]) list(:posts_for_comments_containing_title, [:post, :comments_containing_title, :post], :title) + + list :linked_comment_post_ids, [:linked_comments, :post], :id do + uniq?(true) + end end calculations do @@ -72,6 +76,13 @@ defmodule AshPostgres.Test.Comment do public?(true) end + many_to_many(:linked_comments, AshPostgres.Test.Comment) do + public?(true) + through(AshPostgres.Test.CommentLink) + source_attribute_on_join_resource(:source_id) + destination_attribute_on_join_resource(:dest_id) + end + has_many(:ratings, AshPostgres.Test.Rating, public?: true, destination_attribute: :resource_id, diff --git a/test/support/resources/comment_link.ex b/test/support/resources/comment_link.ex new file mode 100644 index 00000000..2654ff0f --- /dev/null +++ b/test/support/resources/comment_link.ex @@ -0,0 +1,35 @@ +defmodule AshPostgres.Test.CommentLink do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "comment_links" + repo AshPostgres.TestRepo + end + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + end + + identities do + identity(:unique_link, [:source_id, :dest_id]) + end + + relationships do + belongs_to :source, AshPostgres.Test.Comment do + public?(true) + allow_nil?(false) + primary_key?(true) + end + + belongs_to :dest, AshPostgres.Test.Comment do + public?(true) + allow_nil?(false) + primary_key?(true) + end + end +end diff --git a/test/support/resources/content.ex b/test/support/resources/content.ex new file mode 100644 index 00000000..370d7016 --- /dev/null +++ b/test/support/resources/content.ex @@ -0,0 +1,36 @@ +defmodule AshPostgres.Test.Content do + @moduledoc false + use Ash.Resource, + otp_app: :ash_postgres, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "content" + repo AshPostgres.TestRepo + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + + timestamps() + end + + relationships do + belongs_to(:note, AshPostgres.Test.Note) + + many_to_many :visibility_groups, AshPostgres.Test.StaffGroup do + through(AshPostgres.Test.ContentVisibilityGroup) + end + end + + aggregates do + list :visibility_group_staff_ids, [:visibility_groups, :members], :id do + uniq?(true) + end + end +end diff --git a/test/support/resources/content_visibility_group.ex b/test/support/resources/content_visibility_group.ex new file mode 100644 index 00000000..d618fcb4 --- /dev/null +++ b/test/support/resources/content_visibility_group.ex @@ -0,0 +1,21 @@ +defmodule AshPostgres.Test.ContentVisibilityGroup do + @moduledoc false + use Ash.Resource, + otp_app: :ash_postgres, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "content_visibility_group" + repo AshPostgres.TestRepo + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + relationships do + belongs_to(:content, AshPostgres.Test.Content, primary_key?: true, allow_nil?: false) + belongs_to(:staff_group, AshPostgres.Test.StaffGroup, primary_key?: true, allow_nil?: false) + end +end diff --git a/test/support/resources/note.ex b/test/support/resources/note.ex new file mode 100644 index 00000000..b5880dfd --- /dev/null +++ b/test/support/resources/note.ex @@ -0,0 +1,36 @@ +defmodule AshPostgres.Test.Note do + @moduledoc false + use Ash.Resource, + otp_app: :ash_postgres, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "note" + repo AshPostgres.TestRepo + end + + actions do + defaults([:read]) + + read :failing_many_reference do + pagination(keyset?: true, default_limit: 25) + filter(expr(count_nils(content.visibility_group_staff_ids) == 0)) + end + end + + attributes do + uuid_primary_key(:id) + + attribute :body, :string do + allow_nil?(false) + public?(true) + end + + timestamps() + end + + relationships do + has_one(:content, AshPostgres.Test.Content) + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 6a3a1904..d41f4198 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -345,6 +345,11 @@ defmodule AshPostgres.Test.Post do accept([:title]) 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)) + end end identities do diff --git a/test/support/resources/staff_group.ex b/test/support/resources/staff_group.ex new file mode 100644 index 00000000..3902ca07 --- /dev/null +++ b/test/support/resources/staff_group.ex @@ -0,0 +1,32 @@ +defmodule AshPostgres.Test.StaffGroup do + @moduledoc false + use Ash.Resource, + otp_app: :ash_postgres, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "staff_group" + repo AshPostgres.TestRepo + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + attributes do + uuid_primary_key(:id) + + timestamps() + end + + relationships do + many_to_many :members, AshPostgres.Test.User do + through(AshPostgres.Test.StaffGroupMember) + end + end + + aggregates do + count(:members_count, :members) + end +end diff --git a/test/support/resources/staff_group_member.ex b/test/support/resources/staff_group_member.ex new file mode 100644 index 00000000..7624a9ce --- /dev/null +++ b/test/support/resources/staff_group_member.ex @@ -0,0 +1,25 @@ +defmodule AshPostgres.Test.StaffGroupMember do + @moduledoc false + use Ash.Resource, + otp_app: :ash_postgres, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "staff_group_member" + repo AshPostgres.TestRepo + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + attributes do + create_timestamp(:inserted_at) + end + + relationships do + belongs_to(:staff_group, AshPostgres.Test.StaffGroup, primary_key?: true, allow_nil?: false) + belongs_to(:user, AshPostgres.Test.User, primary_key?: true, allow_nil?: false) + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs index 531e4ba8..97a70f24 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,4 @@ -ExUnit.start(capture_log: true) +ExUnit.start() exclude_tags = case System.get_env("PG_VERSION") do From cef9d02b48a510185e959215a0d2e28af81ad635 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 23 Jan 2025 13:28:05 -0500 Subject: [PATCH 337/690] chore: only build docs once --- .github/workflows/elixir.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index 4590fca9..73c0e340 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -16,5 +16,6 @@ jobs: with: postgres: true postgres-version: ${{ matrix.postgres-version }} + publish-docs: ${{ matrix.postgres-version == "16" }} secrets: hex_api_key: ${{ secrets.HEX_API_KEY }} From 260823deabc14f246b14a8fccb260764d86d8dc8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 23 Jan 2025 13:29:59 -0500 Subject: [PATCH 338/690] ci: single quotes --- .github/workflows/elixir.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index 73c0e340..3b2c94fd 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -16,6 +16,6 @@ jobs: with: postgres: true postgres-version: ${{ matrix.postgres-version }} - publish-docs: ${{ matrix.postgres-version == "16" }} + publish-docs: ${{ matrix.postgres-version == '16' }} secrets: hex_api_key: ${{ secrets.HEX_API_KEY }} From f628d37bc7b26c2471e53fd112e1964dc5d9b908 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 26 Jan 2025 00:15:05 -0500 Subject: [PATCH 339/690] ci: only run release on postgres 16 CI --- .github/workflows/elixir.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index 3b2c94fd..084df209 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -17,5 +17,8 @@ jobs: postgres: true postgres-version: ${{ matrix.postgres-version }} publish-docs: ${{ matrix.postgres-version == '16' }} + release: ${{ matrix.postgres-version == '16' }} + igniter-upgrade: ${{matrix.postgres-version == '16'}} + secrets: hex_api_key: ${{ secrets.HEX_API_KEY }} From 837ea8f9ecf4ca1ad1c4a5d78bf9a86d5a054fed Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 27 Jan 2025 13:44:32 -0500 Subject: [PATCH 340/690] chore: release version v2.5.1 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a60eea78..5cc0c85a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.1](https://github.com/ash-project/ash_postgres/compare/v2.5.0...v2.5.1) (2025-01-27) + + + + +### Bug Fixes: + +* handle cross global to tenant references in migration generator + ## [v2.5.0](https://github.com/ash-project/ash_postgres/compare/v2.4.22...v2.5.0) (2025-01-20) diff --git a/mix.exs b/mix.exs index 1589d2b6..becd385c 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.0" + @version "2.5.1" def project do [ From dbadef83764dd6b7f3f02c03423ed3bce1b894ad Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 27 Jan 2025 20:53:49 -0500 Subject: [PATCH 341/690] docs: update ex_doc & spark for better search --- mix.exs | 15 ++++++--------- mix.lock | 10 +++++----- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/mix.exs b/mix.exs index becd385c..29a95129 100644 --- a/mix.exs +++ b/mix.exs @@ -32,7 +32,7 @@ defmodule AshPostgres.MixProject do dialyzer: [ plt_add_apps: [:ecto, :ash, :mix] ], - docs: docs(), + docs: &docs/0, aliases: aliases(), package: package(), source_url: "https://github.com/ash-project/ash_postgres/", @@ -98,7 +98,8 @@ defmodule AshPostgres.MixProject do "documentation/topics/advanced/expressions.md", "documentation/topics/advanced/schema-based-multitenancy.md", "documentation/topics/advanced/manual-relationships.md", - "documentation/dsls/DSL-AshPostgres.DataLayer.md", + {"documentation/dsls/DSL-AshPostgres.DataLayer.md", + search_data: Spark.Docs.search_data_for(AshPostgres.DataLayer)}, "CHANGELOG.md" ], groups_for_extras: [ @@ -107,8 +108,7 @@ defmodule AshPostgres.MixProject do Development: ~r"documentation/topics/development", "About AshPostgres": ["CHANGELOG.md"], Advanced: ~r"documentation/topics/advanced", - Reference: ~r"documentation/topics/dsls", - DSLs: ~r"documentation/dsls" + Reference: ~r"documentation/topics/dsls" ], skip_undefined_reference_warnings_on: [ "CHANGELOG.md", @@ -178,7 +178,7 @@ defmodule AshPostgres.MixProject do {:simple_sat, "~> 0.1", only: [:dev, :test]}, {:benchee, "~> 1.1", only: [:dev, :test]}, {:git_ops, "~> 2.5", only: [:dev, :test]}, - {:ex_doc, github: "elixir-lang/ex_doc", only: [:dev, :test], runtime: false}, + {:ex_doc, "~> 0.37-rc", only: [:dev, :test], runtime: false}, {:ex_check, "~> 0.14", only: [:dev, :test]}, {:credo, ">= 0.0.0", only: [:dev, :test], runtime: false}, {:mix_audit, ">= 0.0.0", only: [:dev, :test], runtime: false}, @@ -233,14 +233,11 @@ defmodule AshPostgres.MixProject do docs: [ "spark.cheat_sheets", "docs", - "spark.replace_doc_links", - "spark.cheat_sheets_in_search" + "spark.replace_doc_links" ], format: "format --migrate", "spark.formatter": "spark.formatter --extensions AshPostgres.DataLayer", "spark.cheat_sheets": "spark.cheat_sheets --extensions AshPostgres.DataLayer", - "spark.cheat_sheets_in_search": - "spark.cheat_sheets_in_search --extensions AshPostgres.DataLayer", "test.generate_migrations": "ash_postgres.generate_migrations", "test.check_migrations": "ash_postgres.generate_migrations --check", "test.migrate_tenants": "ash_postgres.migrate --tenants", diff --git a/mix.lock b/mix.lock index 968886aa..0b1b8d83 100644 --- a/mix.lock +++ b/mix.lock @@ -8,7 +8,7 @@ "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"}, "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, @@ -16,14 +16,14 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:git, "https://github.com/elixir-lang/ex_doc.git", "d571628fd829a510d219bcb7162400baff50977f", []}, + "ex_doc": {:hex, :ex_doc, "0.37.0-rc.0", "cf3b582b8410052a2ce92e181b4f92e6fe1e4d77e0c966715a112de189667cd6", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "32aa9e539f23aafd6bec490ec84d0bfc10ab9086561239aaf4aa8559f3ba559c"}, "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.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "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.16", "3a6cc46f2ac93c8772038d513df5da6ab37aa06538ab96feb9d84b631fbbc073", [: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", "b6b5c74ac01541e0cdb296a93f7cc76a783d2020c152c9bc1f314ba0e83e1421"}, + "igniter": {:hex, :igniter, "0.5.20", "f95227c1cc1e9ee21151d670a3f1bce2151fb2cd7a81fec85a3b832f6ba0d866", [: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", "fbc48dfb15ce7cf35e2e688d969ebbaad7ca3291a21a297879169370cc8efef4"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -37,7 +37,7 @@ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, - "owl": {:hex, :owl, "0.12.0", "0c4b48f90797a7f5f09ebd67ba7ebdc20761c3ec9c7928dfcafcb6d3c2d25c99", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "241d85ae62824dd72f9b2e4a5ba4e69ebb9960089a3c68ce6c1ddf2073db3c15"}, + "owl": {:hex, :owl, "0.12.1", "d3146087315c4528ee32411495ba10ec88102597b638d4d1455cf9d245dfb57a", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "d7eb9746aa89c40c46b479d6c2a70b82b94993520e40f21d0b09654f23eebf35"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, "reactor": {:hex, :reactor, "0.10.3", "41a8c34251148e36dd7c75aa8433f2c2f283f29c097f9eb84a630ab28dd75651", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b34380e22b69a35943a7bcceffd5a8b766870f1fc9052162a7ff74ef9cdb3b2"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, @@ -45,7 +45,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.40", "4fef851c346d891ce2aaf13d72e8af9b4371bf3059530b58c4a1149923faaf37", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d3cd4487932f4c63261c67568cec77d535dc6f9546c334d28f3b9d17c7f23fc0"}, + "spark": {:hex, :spark, "2.2.42", "2e01e237329aa766bf367d0a4e17774ca0f5bdd147452889fee00b7b1d799330", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "0b993234c7a145709e4ff97ee5afa0354ebc623c391d551f5555a4476d6336c1"}, "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 0af8a48a76a88501e15d1727a9e9e6a26e9c718f Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Thu, 30 Jan 2025 01:01:17 +0100 Subject: [PATCH 342/690] test: add test for cascade destroy change (#466) --- test/cascade_destroy_test.exs | 25 +++++++++++++++++++++++++ test/support/resources/post.ex | 11 +++++++++++ 2 files changed, 36 insertions(+) create mode 100644 test/cascade_destroy_test.exs diff --git a/test/cascade_destroy_test.exs b/test/cascade_destroy_test.exs new file mode 100644 index 00000000..a407ea35 --- /dev/null +++ b/test/cascade_destroy_test.exs @@ -0,0 +1,25 @@ +defmodule AshPostgresTest.CascadeDestroyTest do + use AshPostgres.RepoCase, async: true + + alias AshPostgres.Test.{Post, Rating} + + test "can cascade destroy a has_many with parent filter" do + post = + Post.create!("post", %{score: 1}) + + Rating + |> Ash.Changeset.for_create(:create, %{score: 2, resource_id: post.id}) + |> Ash.Changeset.set_context(%{data_layer: %{table: "post_ratings"}}) + |> Ash.create!() + + post + |> Ash.Changeset.for_destroy(:cascade_destroy) + |> Ash.destroy!() + + assert [] = + Rating + |> Ash.Query.for_read(:read) + |> Ash.Query.set_context(%{data_layer: %{table: "post_ratings"}}) + |> Ash.read!() + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index d41f4198..d221bdd6 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -230,6 +230,10 @@ defmodule AshPostgres.Test.Post do ) end + destroy :cascade_destroy do + change(cascade_destroy(:high_ratings, after_action?: false)) + end + update :update do primary?(true) require_atomic?(false) @@ -521,6 +525,13 @@ defmodule AshPostgres.Test.Post do relationship_context: %{data_layer: %{table: "post_ratings"}} ) + has_many :high_ratings, AshPostgres.Test.Rating do + public?(true) + destination_attribute(:resource_id) + relationship_context(%{data_layer: %{table: "post_ratings"}}) + filter(expr(score > parent(score))) + end + has_many(:post_links, AshPostgres.Test.PostLink, public?: true, destination_attribute: :source_post_id, From 96c8859283a07567946d0a7a09d618bf5e0dccba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 07:40:04 -0500 Subject: [PATCH 343/690] chore(deps): bump the production-dependencies group with 2 updates (#468) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash` from 3.4.56 to 3.4.60 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/3.4.56...v3.4.60) Updates `ash_sql` from 0.2.47 to 0.2.48 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.47...v0.2.48) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 0b1b8d83..0eb76542 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.56", "2591ef830200b9840b1915b6e2889518964d6852a44e58f06a0752f7b9e114a3", [: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.4.8 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.9", [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", "c7d8091db87aa72b7a9e1082edea5b17308942b58c4f24c2d01499db6de05486"}, - "ash_sql": {:hex, :ash_sql, "0.2.47", "812194f28ffe88cb6ff30c32615e08fe49c4157dbc2cc80bf11f4844192c1f24", [:mix], [{:ash, ">= 3.1.7 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", "1c3563c10d29b7e36498ee58fe652882ce4931d6a736025c6ccf7e862ddda191"}, + "ash": {:hex, :ash, "3.4.60", "c5002ffde3ef108ca24faa44702573c6e64afe3dfe5a670a5253d252c93aecae", [: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.4.8 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.9", [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", "1b8e983f9cb973ed3300cd8fa261b136c0c389f8f51bee728cccc57edbe91a94"}, + "ash_sql": {:hex, :ash_sql, "0.2.48", "aea787441e97f9aaffe954e6f0f3b2d6206241d92bb104daf12b178befd65a1f", [:mix], [{:ash, ">= 3.1.7 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", "b19c5d3bc89cc6575f87ebfa57db33d697831df54a812589b9f4638b8b94864b"}, "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"}, @@ -39,15 +39,15 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.1", "d3146087315c4528ee32411495ba10ec88102597b638d4d1455cf9d245dfb57a", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "d7eb9746aa89c40c46b479d6c2a70b82b94993520e40f21d0b09654f23eebf35"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, - "reactor": {:hex, :reactor, "0.10.3", "41a8c34251148e36dd7c75aa8433f2c2f283f29c097f9eb84a630ab28dd75651", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b34380e22b69a35943a7bcceffd5a8b766870f1fc9052162a7ff74ef9cdb3b2"}, + "reactor": {:hex, :reactor, "0.11.0", "a985b1b6d60562459a1e820c1cdf74f5408e62089be995ce805d1b30f6762f09", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "19b362159f15871715f6632b4bad6ef0c666b49968e53af73673edabadd0b88b"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.42", "2e01e237329aa766bf367d0a4e17774ca0f5bdd147452889fee00b7b1d799330", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "0b993234c7a145709e4ff97ee5afa0354ebc623c391d551f5555a4476d6336c1"}, + "spark": {:hex, :spark, "2.2.43", "4ce84fcc9626f7759e9b9d698c95bdfcbbe9732184e1bc8f6ab9f9963bce2a6a", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "bbd83de69f4436e6f075d632d41110f840ce3a12c34d5499c15e60cf7b45a67b"}, "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, - "splode": {:hex, :splode, "0.2.7", "ed042fa9bd8fe7b66dd0a0faabdb97352058420d90cd1c7c1537f609deb7ef6d", [:mix], [], "hexpm", "267f1f51d5a5ac988cda0649498294844988c5086916fed5a8aff297d69a2059"}, + "splode": {:hex, :splode, "0.2.8", "289d4eec13e7a83061bc44827877eb4c575e1fdf198bd1a9c6449f9b64805059", [:mix], [], "hexpm", "dbe92fa526589416435e12203b56db1f74c834d207bc474016cedf930d987284"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, From f48fc0cad965e31f5d88b59e7b1b8ef5cbf7f7f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 07:40:21 -0500 Subject: [PATCH 344/690] chore(deps-dev): bump ex_doc in the dev-dependencies group (#469) Bumps the dev-dependencies group with 1 update: [ex_doc](https://github.com/elixir-lang/ex_doc). Updates `ex_doc` from 0.37.0-rc.0 to 0.37.0-rc.2 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.37.0-rc.0...v0.37.0-rc.2) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 0eb76542..5fbae7b6 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.37.0-rc.0", "cf3b582b8410052a2ce92e181b4f92e6fe1e4d77e0c966715a112de189667cd6", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "32aa9e539f23aafd6bec490ec84d0bfc10ab9086561239aaf4aa8559f3ba559c"}, + "ex_doc": {:hex, :ex_doc, "0.37.0-rc.2", "6e55e065aea63c2dfb3c0e18786a22d5107923ff7fb6a91f6e575f607735d09b", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "91e09b4ca47b2a83ce4c7035de7f0bb6e531c5d43cab19bb0c7820f73470df49"}, "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"}, @@ -28,14 +28,14 @@ "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, - "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, - "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, + "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.1", "d3146087315c4528ee32411495ba10ec88102597b638d4d1455cf9d245dfb57a", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "d7eb9746aa89c40c46b479d6c2a70b82b94993520e40f21d0b09654f23eebf35"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, From 36dab3a180a5b57a0d6f4bddbc341bfe6605e1f5 Mon Sep 17 00:00:00 2001 From: Yusuke Higuchi <17329720+hy2k@users.noreply.github.com> Date: Thu, 30 Jan 2025 23:12:45 +0900 Subject: [PATCH 345/690] fix: update sql log switches for migration and rollback tasks (#470) --- lib/mix/tasks/ash_postgres.migrate.ex | 8 ++++++-- lib/mix/tasks/ash_postgres.rollback.ex | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index fd74ff65..1db3965d 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -18,7 +18,8 @@ defmodule Mix.Tasks.AshPostgres.Migrate do quiet: :boolean, prefix: :string, pool_size: :integer, - log_sql: :boolean, + log_migrations_sql: :boolean, + log_migrator_sql: :boolean, strict_version_order: :boolean, domains: :string, no_compile: :boolean, @@ -81,7 +82,10 @@ defmodule Mix.Tasks.AshPostgres.Migrate do * `--pool-size` - the pool size if the repository is started only for the task (defaults to 2) - * `--log-sql` - log the raw sql migrations are running + * `--log-migrations-sql` - log SQL generated by migration commands + + * `--log-migrator-sql` - log SQL generated by the migrator, such as + transactions, table locks, etc * `--strict-version-order` - abort when applying a migration with old timestamp diff --git a/lib/mix/tasks/ash_postgres.rollback.ex b/lib/mix/tasks/ash_postgres.rollback.ex index ac5da2fa..afdb3c8d 100644 --- a/lib/mix/tasks/ash_postgres.rollback.ex +++ b/lib/mix/tasks/ash_postgres.rollback.ex @@ -37,7 +37,8 @@ defmodule Mix.Tasks.AshPostgres.Rollback do * `--quiet` - do not log migration commands * `--prefix` - the prefix to run migrations on * `--pool-size` - the pool size if the repository is started only for the task (defaults to 1) - * `--log-sql` - log the raw sql migrations are running + * `--log-migrations-sql` - log SQL generated by migration commands + * `--log-migrator-sql` - log SQL generated by the migrator, such as transactions, table locks, etc * `--tenants` - roll back tenant migrations * `--only-tenants` - in combo with `--tenants`, only rolls back the provided tenants, e.g `tenant1,tenant2,tenant3` * `--except-tenants` - in combo with `--tenants`, does not rollback the provided tenants, e.g `tenant1,tenant2,tenant3` @@ -55,7 +56,8 @@ defmodule Mix.Tasks.AshPostgres.Rollback do quiet: :boolean, prefix: :string, pool_size: :integer, - log_sql: :boolean, + log_migrations_sql: :boolean, + log_migrator_sql: :boolean, only_tenants: :string, except_tenants: :string ], From ac3d0fa3e8dd8cce138684f0f219bd1e08d1b6cc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 30 Jan 2025 13:13:44 -0500 Subject: [PATCH 346/690] chore: make version parsing more consistent --- test/support/test_no_sandbox_repo.ex | 10 ++++++++-- test/test_helper.exs | 3 --- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/support/test_no_sandbox_repo.ex b/test/support/test_no_sandbox_repo.ex index 201d3667..fca4bf13 100644 --- a/test/support/test_no_sandbox_repo.ex +++ b/test/support/test_no_sandbox_repo.ex @@ -9,8 +9,14 @@ defmodule AshPostgres.TestNoSandboxRepo do def min_pg_version do case System.get_env("PG_VERSION") do - nil -> %Version{major: 16, minor: 0, patch: 0} - version -> Version.parse!(version) + nil -> + %Version{major: 16, minor: 0, patch: 0} + + version -> + case Integer.parse(version) do + {major, ""} -> %Version{major: major, minor: 0, patch: 0} + _ -> Version.parse!(version) + end end end diff --git a/test/test_helper.exs b/test/test_helper.exs index 97a70f24..8438eaf9 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -11,9 +11,6 @@ exclude_tags = "15" -> [:postgres_16] - "16" -> - [] - _ -> [] end From 6e29a4df55e05f88f04436a3320e789f3b510693 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 30 Jan 2025 15:12:03 -0500 Subject: [PATCH 347/690] test: test new start_of_day logic from ash core this test won't pass until ash is updated --- config/config.exs | 1 + mix.exs | 1 + mix.lock | 3 ++- test/calculation_test.exs | 5 +++++ test/support/resources/post.ex | 2 ++ 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 62650332..ee88e028 100644 --- a/config/config.exs +++ b/config/config.exs @@ -18,6 +18,7 @@ if Mix.env() == :dev do end if Mix.env() == :test do + config :elixir, :time_zone_database, Tz.TimeZoneDatabase config :ash_postgres, AshPostgres.TestRepo, log: false config :ash_postgres, AshPostgres.TestNoSandboxRepo, log: false diff --git a/mix.exs b/mix.exs index 29a95129..4ad5f2be 100644 --- a/mix.exs +++ b/mix.exs @@ -173,6 +173,7 @@ defmodule AshPostgres.MixProject do {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, # dev/test dependencies + {:tz, "~> 0.28.1"}, {:ecto_dev_logger, "~> 0.14", only: :test}, {:eflame, "~> 1.0", only: [:dev, :test]}, {:simple_sat, "~> 0.1", only: [:dev, :test]}, diff --git a/mix.lock b/mix.lock index 5fbae7b6..6f2343ee 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.60", "c5002ffde3ef108ca24faa44702573c6e64afe3dfe5a670a5253d252c93aecae", [: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.4.8 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.9", [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", "1b8e983f9cb973ed3300cd8fa261b136c0c389f8f51bee728cccc57edbe91a94"}, - "ash_sql": {:hex, :ash_sql, "0.2.48", "aea787441e97f9aaffe954e6f0f3b2d6206241d92bb104daf12b178befd65a1f", [:mix], [{:ash, ">= 3.1.7 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", "b19c5d3bc89cc6575f87ebfa57db33d697831df54a812589b9f4638b8b94864b"}, + "ash_sql": {:hex, :ash_sql, "0.2.49", "9c8a063d0ff9ee5b87716d4719751cee9224aae96ff59258621d3524c2aecdc6", [: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", "681e8c98ea8f23cd406e9ed0ed09822fa7f08eaf9196d8acb092b9815ae0921d"}, "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"}, @@ -52,6 +52,7 @@ "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, + "tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, } diff --git a/test/calculation_test.exs b/test/calculation_test.exs index f1a091a2..3703ced7 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -44,6 +44,11 @@ defmodule AshPostgres.CalculationTest do |> Ash.read!() end + test "start_of_day functions the same as Elixir's start of ay" do + assert Ash.calculate!(Post, :start_of_day) == + Ash.Expr.eval!(Ash.Expr.expr(start_of_day(^DateTime.utc_now(), "EST"))) + end + @tag :regression test "an expression calculation that requires a left join & distinct doesn't raise errors on out of order params" do post = diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index d221bdd6..d1082c54 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -750,6 +750,8 @@ defmodule AshPostgres.Test.Post do ) ) + calculate(:start_of_day, :datetime, expr(start_of_day(fragment("now()::timestamp"), "EST"))) + calculate(:author_count_of_posts, :integer, expr(author.count_of_posts_with_calc)) calculate( From ad51da73c26927dca3f27361be786f4c48a25b82 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 31 Jan 2025 07:37:04 -0500 Subject: [PATCH 348/690] chore: fix build --- mix.lock | 2 +- test/support/resources/subquery/access.ex | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 6f2343ee..e3e41139 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.60", "c5002ffde3ef108ca24faa44702573c6e64afe3dfe5a670a5253d252c93aecae", [: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.4.8 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.9", [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", "1b8e983f9cb973ed3300cd8fa261b136c0c389f8f51bee728cccc57edbe91a94"}, + "ash": {:hex, :ash, "3.4.61", "8c34174597ff8d5c0ff8da9a77ad207fb9bce8dfe680fcf1cbf23964d01be739", [: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.4.8 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", "5e311aab8bf5a1a1bf63ac630a61d218a07de3da16d60f7972e7e85c0eb53d36"}, "ash_sql": {:hex, :ash_sql, "0.2.49", "9c8a063d0ff9ee5b87716d4719751cee9224aae96ff59258621d3524c2aecdc6", [: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", "681e8c98ea8f23cd406e9ed0ed09822fa7f08eaf9196d8acb092b9815ae0921d"}, "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"}, diff --git a/test/support/resources/subquery/access.ex b/test/support/resources/subquery/access.ex index a3df6531..90a356ff 100644 --- a/test/support/resources/subquery/access.ex +++ b/test/support/resources/subquery/access.ex @@ -5,6 +5,7 @@ defmodule AshPostgres.Test.Subquery.Access do use Ash.Resource, domain: AshPostgres.Test.Subquery.ParentDomain, data_layer: AshPostgres.DataLayer, + primary_read_warning?: false, authorizers: [ Ash.Policy.Authorizer ] From ce539a6dec74cedfe18855d1a80308540ccf0ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Fri, 31 Jan 2025 14:56:54 +0100 Subject: [PATCH 349/690] Improvement: generate migrations task support concurrent indexes flag (#471) --- .../migration_generator.ex | 10 ++++- lib/migration_generator/operation.ex | 10 ++++- .../tasks/ash_postgres.generate_migrations.ex | 4 +- test/migration_generator_test.exs | 39 +++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index ca733282..98a18c65 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -12,6 +12,7 @@ defmodule AshPostgres.MigrationGenerator do name: nil, tenant_migration_path: nil, quiet: false, + concurrent_indexes: false, current_snapshots: nil, answers: [], no_shell?: false, @@ -471,6 +472,9 @@ defmodule AshPostgres.MigrationGenerator do %Operation.AddCustomIndex{index: %{concurrently: true}} -> true + %Operation.AddUniqueIndex{concurrently: true} -> + true + _ -> false end) @@ -493,6 +497,9 @@ defmodule AshPostgres.MigrationGenerator do %Operation.AddCustomIndex{index: %{concurrently: true}} -> true + %Operation.AddUniqueIndex{concurrently: true} -> + true + _ -> false end) @@ -2000,7 +2007,8 @@ defmodule AshPostgres.MigrationGenerator do %Operation.AddUniqueIndex{ identity: identity, schema: snapshot.schema, - table: snapshot.table + table: snapshot.table, + concurrently: opts.concurrent_indexes } end) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index a2a4a1af..cc4f1975 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -807,7 +807,15 @@ defmodule AshPostgres.MigrationGenerator.Operation do defmodule AddUniqueIndex do @moduledoc false - defstruct [:identity, :table, :schema, :multitenancy, :old_multitenancy, no_phase: true] + defstruct [ + :identity, + :table, + :schema, + :multitenancy, + :old_multitenancy, + no_phase: true, + concurrently: false + ] import Helper diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index ea2c7383..4a126d24 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -22,6 +22,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do * `dry-run` - no files are created, instead the new migration is printed * `check` - no files are created, returns an exit(1) code if the current snapshots and resources don't fit * `snapshots-only` - no migrations are generated, only snapshots are stored + * `concurrent-indexes` - new identities will be run in a separate migration (like concurrent custom indexes) #### Snapshots @@ -96,7 +97,8 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do no_format: :boolean, dry_run: :boolean, check: :boolean, - dont_drop_columns: :boolean + dont_drop_columns: :boolean, + concurrent_indexes: :boolean ] ) diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index fd0e9045..131f8c4a 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -819,6 +819,45 @@ defmodule AshPostgres.MigrationGeneratorTest do "create unique_index(:posts, [:title], name: \"posts_unique_title_index\")" end + test "when concurrent-indexes flag set to true, identities are added in separate migration" do + defposts do + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true) + attribute(:name, :string, public?: true) + end + + identities do + identity(:unique_title, [:title]) + identity(:unique_name, [:name]) + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + concurrent_indexes: true, + format: false + ) + + assert [_file1, _file2, file3] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + file3_content = File.read!(file3) + + assert file3_content =~ ~S[@disable_ddl_transaction true] + + assert file3_content =~ + "create unique_index(:posts, [:title], name: \"posts_unique_title_index\")" + + assert file3_content =~ + "create unique_index(:posts, [:name], name: \"posts_unique_name_index\")" + end + test "when an attribute exists only on some of the resources that use the same table, it isn't marked as null: false" do defposts do attributes do From 586c10b87b7776fdbafef955a4bc3733a8385887 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 31 Jan 2025 08:57:37 -0500 Subject: [PATCH 350/690] chore: update docs --- lib/mix/tasks/ash_postgres.generate_migrations.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index 4a126d24..065942c8 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -22,7 +22,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do * `dry-run` - no files are created, instead the new migration is printed * `check` - no files are created, returns an exit(1) code if the current snapshots and resources don't fit * `snapshots-only` - no migrations are generated, only snapshots are stored - * `concurrent-indexes` - new identities will be run in a separate migration (like concurrent custom indexes) + * `concurrent-indexes` - new identities will be run concurrently and in a separate migration (like concurrent custom indexes) #### Snapshots From 49013012791b5684a1faefd98904a1e3af0f5240 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 31 Jan 2025 10:21:57 -0500 Subject: [PATCH 351/690] chore: update test --- test/support/resources/post.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index d1082c54..8d1eb3a4 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -750,7 +750,7 @@ defmodule AshPostgres.Test.Post do ) ) - calculate(:start_of_day, :datetime, expr(start_of_day(fragment("now()::timestamp"), "EST"))) + calculate(:start_of_day, :datetime, expr(start_of_day(fragment("now()"), "EST"))) calculate(:author_count_of_posts, :integer, expr(author.count_of_posts_with_calc)) From 0022110afb97d4f01ff3c678b780fa6a8bceee48 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 31 Jan 2025 10:23:58 -0500 Subject: [PATCH 352/690] chore: update ash_sql --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index e3e41139..976f4819 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.61", "8c34174597ff8d5c0ff8da9a77ad207fb9bce8dfe680fcf1cbf23964d01be739", [: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.4.8 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", "5e311aab8bf5a1a1bf63ac630a61d218a07de3da16d60f7972e7e85c0eb53d36"}, - "ash_sql": {:hex, :ash_sql, "0.2.49", "9c8a063d0ff9ee5b87716d4719751cee9224aae96ff59258621d3524c2aecdc6", [: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", "681e8c98ea8f23cd406e9ed0ed09822fa7f08eaf9196d8acb092b9815ae0921d"}, + "ash_sql": {:hex, :ash_sql, "0.2.50", "b647825905b6e5195cf26ac90f5980b4dedee040ed3caf6078c0f4e3a80f2b14", [: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", "d6a70ffc5d1343aa41ef4804fb3164b4b6a2a135b83075fe89532be9a3b5c370"}, "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"}, From 8fbc109ff2cac4158b801cab97eae7f919b33de8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 3 Feb 2025 09:53:27 -0500 Subject: [PATCH 353/690] test: add test for reuse values calculations --- test/calculation_test.exs | 32 ++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 1 + 2 files changed, 33 insertions(+) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 3703ced7..59c2539e 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -4,6 +4,13 @@ defmodule AshPostgres.CalculationTest do require Ash.Query import Ash.Expr + import ExUnit.CaptureLog + + setup do + on_exit(fn -> + Logger.configure(level: :debug) + end) + end test "a calculation that references a first optimizable aggregate can be sorted on" do author1 = @@ -87,6 +94,31 @@ defmodule AshPostgres.CalculationTest do |> Ash.read!() end + test "expression calculations don't load when `reuse_values?` is true" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + Logger.configure(level: :debug) + + log1 = + capture_log(fn -> + post + |> Ash.load!(:title_twice) + end) + + refute log1 == "" + + log2 = + capture_log(fn -> + post + |> Ash.load!(:title_twice, reuse_values?: true, lazy?: true) + end) + + assert log2 == "" + end + test "an expression calculation can be filtered on" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 8d1eb3a4..efdfbaf7 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -619,6 +619,7 @@ defmodule AshPostgres.Test.Post do calculate(:upper_thing, :string, expr(fragment("UPPER(?)", uniq_on_upper))) calculate(:upper_title, :string, expr(fragment("UPPER(?)", title))) + calculate(:title_twice, :string, expr(title <> title)) calculate( :author_has_post_with_follower_named_fred, From 3a25da75949188ba82de6c2fe11af5b597bf1a5b Mon Sep 17 00:00:00 2001 From: kernel-io Date: Tue, 4 Feb 2025 08:33:48 +1300 Subject: [PATCH 354/690] add failing test (#472) Signed-off-by: kernel-io --- test/aggregate_test.exs | 4 ++++ test/support/resources/organization.ex | 6 ++++++ test/support/types/status_enum_no_cast.ex | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index bc2ac0b3..14ff389b 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -12,6 +12,10 @@ defmodule AshSql.AggregateTest do |> Ash.read!() == [] end + test "count aggregate on no cast enum field" do + Organization |> Ash.read!(load: [:no_cast_open_posts_count]) + end + test "relates to actor via has_many and with an aggregate" do org = Organization diff --git a/test/support/resources/organization.ex b/test/support/resources/organization.ex index 6c7346a2..d5a22d65 100644 --- a/test/support/resources/organization.ex +++ b/test/support/resources/organization.ex @@ -24,6 +24,12 @@ defmodule AshPostgres.Test.Organization do end end + aggregates do + count :no_cast_open_posts_count, :posts do + filter(expr(status_enum_no_cast != :closed)) + end + end + actions do default_accept(:*) diff --git a/test/support/types/status_enum_no_cast.ex b/test/support/types/status_enum_no_cast.ex index 267c2481..d5e0c1e1 100644 --- a/test/support/types/status_enum_no_cast.ex +++ b/test/support/types/status_enum_no_cast.ex @@ -4,5 +4,5 @@ defmodule AshPostgres.Test.Types.StatusEnumNoCast do def storage_type, do: :status - def cast_in_query?, do: false + def cast_in_query?(_), do: false end From 439166ae319b0feff9b60e6dc9d255233a96dada Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 3 Feb 2025 15:36:00 -0500 Subject: [PATCH 355/690] chore: add missing @impl --- test/calculation_test.exs | 2 +- test/support/types/status_enum_no_cast.ex | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 59c2539e..93ca0e81 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -8,7 +8,7 @@ defmodule AshPostgres.CalculationTest do setup do on_exit(fn -> - Logger.configure(level: :debug) + Logger.configure(level: :error) end) end diff --git a/test/support/types/status_enum_no_cast.ex b/test/support/types/status_enum_no_cast.ex index d5e0c1e1..ec4a5e6b 100644 --- a/test/support/types/status_enum_no_cast.ex +++ b/test/support/types/status_enum_no_cast.ex @@ -2,7 +2,9 @@ defmodule AshPostgres.Test.Types.StatusEnumNoCast do @moduledoc false use Ash.Type.Enum, values: [:open, :closed] + @impl true def storage_type, do: :status + @impl true def cast_in_query?(_), do: false end From 13ac95e602d6e34ec193ad3c96ee36777ef03afc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 4 Feb 2025 09:44:31 -0500 Subject: [PATCH 356/690] chore: update ash_sql --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 976f4819..45bce1db 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.61", "8c34174597ff8d5c0ff8da9a77ad207fb9bce8dfe680fcf1cbf23964d01be739", [: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.4.8 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", "5e311aab8bf5a1a1bf63ac630a61d218a07de3da16d60f7972e7e85c0eb53d36"}, + "ash": {:hex, :ash, "3.4.62", "ef41463b12095fe9566962793f4e4d94c2753e1c3bfc79acc09471cc1efc7f51", [: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.4.8 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", "1780ec2029353213d5a35b1950a53da7225bce756f0be05e35708330f51d9cf0"}, "ash_sql": {:hex, :ash_sql, "0.2.50", "b647825905b6e5195cf26ac90f5980b4dedee040ed3caf6078c0f4e3a80f2b14", [: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", "d6a70ffc5d1343aa41ef4804fb3164b4b6a2a135b83075fe89532be9a3b5c370"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "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.20", "f95227c1cc1e9ee21151d670a3f1bce2151fb2cd7a81fec85a3b832f6ba0d866", [: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", "fbc48dfb15ce7cf35e2e688d969ebbaad7ca3291a21a297879169370cc8efef4"}, + "igniter": {:hex, :igniter, "0.5.21", "b80e16a47cb1fe724a2113c1f2661507d9e458978c2d610aeb87b15d9c2d43e5", [: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", "19e516b5e06d90447c74fc4fdfc14b71318c41ef966999ac6b34d038e1aa2b9c"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,13 +39,13 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.1", "d3146087315c4528ee32411495ba10ec88102597b638d4d1455cf9d245dfb57a", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "d7eb9746aa89c40c46b479d6c2a70b82b94993520e40f21d0b09654f23eebf35"}, "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, - "reactor": {:hex, :reactor, "0.11.0", "a985b1b6d60562459a1e820c1cdf74f5408e62089be995ce805d1b30f6762f09", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "19b362159f15871715f6632b4bad6ef0c666b49968e53af73673edabadd0b88b"}, + "reactor": {:hex, :reactor, "0.12.0", "6191b691219c710f7910c275a0ad8853c93f4df99cb1d867321649206231f2e5", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f86335570bb360ef2a403679aa4e94b0f97b97410165d5ae35fb2c5cbf68ddcc"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.43", "4ce84fcc9626f7759e9b9d698c95bdfcbbe9732184e1bc8f6ab9f9963bce2a6a", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "bbd83de69f4436e6f075d632d41110f840ce3a12c34d5499c15e60cf7b45a67b"}, + "spark": {:hex, :spark, "2.2.44", "4333b62fa2c3e9ef1da39792911375063597ca8a960cd677d8e0c2db0064d5b7", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "8a238079c2460a9cbae8e78c43ab2de10bb51a61d7f06e20ae3d3b1291d72ddb"}, "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, "splode": {:hex, :splode, "0.2.8", "289d4eec13e7a83061bc44827877eb4c575e1fdf198bd1a9c6449f9b64805059", [:mix], [], "hexpm", "dbe92fa526589416435e12203b56db1f74c834d207bc474016cedf930d987284"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 0004386e0d8179046fd98da6519c5e3379e46b88 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 4 Feb 2025 11:52:57 -0500 Subject: [PATCH 357/690] chore: update ash_sql --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 45bce1db..402b9c27 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.62", "ef41463b12095fe9566962793f4e4d94c2753e1c3bfc79acc09471cc1efc7f51", [: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.4.8 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", "1780ec2029353213d5a35b1950a53da7225bce756f0be05e35708330f51d9cf0"}, - "ash_sql": {:hex, :ash_sql, "0.2.50", "b647825905b6e5195cf26ac90f5980b4dedee040ed3caf6078c0f4e3a80f2b14", [: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", "d6a70ffc5d1343aa41ef4804fb3164b4b6a2a135b83075fe89532be9a3b5c370"}, + "ash_sql": {:hex, :ash_sql, "0.2.52", "8ca8858f85a4d9a4dcc05deb9f2116b92f939e006e5907e8f97998dfb8d5ff04", [: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", "c17207c7169c8ba1d8b5e705be944160b2ad74a780fdb9442202bd1afd6e4549"}, "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"}, From 713b615128dc0a3b978182ed7ef7e1145403dbad Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 5 Feb 2025 14:55:50 -0500 Subject: [PATCH 358/690] improvement: consider identity.where in identity deduplicator test: add some calculation related tests --- .../migration_generator.ex | 2 +- mix.lock | 8 +++---- test/calculation_test.exs | 23 ++++++++++++++++++- test/support/resources/post.ex | 21 +++++++++++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 98a18c65..baf26c7f 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -645,7 +645,7 @@ defmodule AshPostgres.MigrationGenerator do |> Kernel.!() end) |> Enum.uniq_by(fn identity -> - {identity.keys, identity.base_filter} + {identity.keys, identity.base_filter, identity.where} end) new_snapshot = %{new_snapshot | identities: all_identities} diff --git a/mix.lock b/mix.lock index 402b9c27..d62e7283 100644 --- a/mix.lock +++ b/mix.lock @@ -32,20 +32,20 @@ "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, - "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, + "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.1", "d3146087315c4528ee32411495ba10ec88102597b638d4d1455cf9d245dfb57a", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "d7eb9746aa89c40c46b479d6c2a70b82b94993520e40f21d0b09654f23eebf35"}, - "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, - "reactor": {:hex, :reactor, "0.12.0", "6191b691219c710f7910c275a0ad8853c93f4df99cb1d867321649206231f2e5", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f86335570bb360ef2a403679aa4e94b0f97b97410165d5ae35fb2c5cbf68ddcc"}, + "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, + "reactor": {:hex, :reactor, "0.12.1", "8bc7b0547c5ada64c9c16ef55f598cea9037d19810c59709d5cede33c5e5b562", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1f26550b4079d46a1b84a153d7427990c2e4adf3dfdbf6ca04c2ea0a9bf1d24d"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.44", "4333b62fa2c3e9ef1da39792911375063597ca8a960cd677d8e0c2db0064d5b7", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "8a238079c2460a9cbae8e78c43ab2de10bb51a61d7f06e20ae3d3b1291d72ddb"}, + "spark": {:hex, :spark, "2.2.45", "19e3a879e80d02853ded85ed7b4c0a84a5d2e395f9d0c884e1a13afbe026929d", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "70b272d0ee16e3c10a4f8cf0ef6152840828152e68f2f8e3046e89567f2b49ad"}, "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, "splode": {:hex, :splode, "0.2.8", "289d4eec13e7a83061bc44827877eb4c575e1fdf198bd1a9c6449f9b64805059", [:mix], [], "hexpm", "dbe92fa526589416435e12203b56db1f74c834d207bc474016cedf930d987284"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 93ca0e81..7f10d0af 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -113,12 +113,33 @@ defmodule AshPostgres.CalculationTest do log2 = capture_log(fn -> post - |> Ash.load!(:title_twice, reuse_values?: true, lazy?: true) + |> Ash.load!(:title_twice, reuse_values?: true) + + assert "in calc:" <> _ = + post + |> Ash.load!(:title_twice_with_calc, reuse_values?: true) + |> Map.get(:title_twice_with_calc) end) assert log2 == "" end + test "calculations use `calculate/3` when possible" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + Logger.configure(level: :debug) + + log = + capture_log(fn -> + assert "in calc:" <> _ = Ash.calculate!(post, :title_twice_with_calc, reuse_values?: true) + end) + + assert log == "" + end + test "an expression calculation can be filtered on" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index efdfbaf7..df5c96cf 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -66,6 +66,26 @@ defmodule AshPostgres.Test.Post do require Ash.Sort + defmodule TitleTwice do + @moduledoc false + use Ash.Resource.Calculation + + def load(_, _, _), do: [:title] + + # it would always be a bug for these + # to produce different values + # but we do it here for testing + def calculate(records, _, _) do + Enum.map(records, fn record -> + "in calc:" <> record.title <> record.title + end) + end + + def expression(_, _) do + expr("in expr:" <> title <> title) + end + end + policies do bypass action_type(:read) do # Check that the post is in the same org as actor @@ -620,6 +640,7 @@ defmodule AshPostgres.Test.Post do calculate(:upper_title, :string, expr(fragment("UPPER(?)", title))) calculate(:title_twice, :string, expr(title <> title)) + calculate(:title_twice_with_calc, :string, TitleTwice) calculate( :author_has_post_with_follower_named_fred, From 33b1291c594d936bdf4e561d1af1ecb0d16d9fa8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 5 Feb 2025 15:34:47 -0500 Subject: [PATCH 359/690] test: fix tests to account for ash bulk action fix --- test/bulk_create_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index f4e7ceb6..01769ccb 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -295,7 +295,7 @@ defmodule AshPostgres.BulkCreateTest do describe "validation errors" do test "skips invalid by default" do assert %{records: [_], errors: [_]} = - Ash.bulk_create!([%{title: "fred"}, %{title: "not allowed"}], Post, :create, + Ash.bulk_create([%{title: "fred"}, %{title: "not allowed"}], Post, :create, return_records?: true, return_errors?: true ) From 05b1fd3dba454570f74001cdd3b87d8482fdb591 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 5 Feb 2025 15:40:11 -0500 Subject: [PATCH 360/690] test: fix test log level issue --- test/calculation_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 7f10d0af..97d5a3c4 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -8,7 +8,7 @@ defmodule AshPostgres.CalculationTest do setup do on_exit(fn -> - Logger.configure(level: :error) + Logger.configure(level: :warning) end) end From b93c3b54feb7b615e3878a61b867418f8ecb9a30 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 5 Feb 2025 15:58:12 -0500 Subject: [PATCH 361/690] chore: only dev/test for tz --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 4ad5f2be..7eda5369 100644 --- a/mix.exs +++ b/mix.exs @@ -173,7 +173,7 @@ defmodule AshPostgres.MixProject do {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, # dev/test dependencies - {:tz, "~> 0.28.1"}, + {:tz, "~> 0.28.1", only: [:dev, :test]}, {:ecto_dev_logger, "~> 0.14", only: :test}, {:eflame, "~> 1.0", only: [:dev, :test]}, {:simple_sat, "~> 0.1", only: [:dev, :test]}, From 7bd5a41f2cd8321c86b70434f290356e7a9c43a9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 5 Feb 2025 16:20:14 -0500 Subject: [PATCH 362/690] fix: simplify lateral join source filter --- lib/data_layer.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 274fd495..30a502ea 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1316,6 +1316,9 @@ defmodule AshPostgres.DataLayer do [] -> raise "Cannot use lateral joins with a resource that has no primary key and no identities" + [key] -> + Ash.Expr.expr(^Ash.Expr.ref(key) in ^Enum.map(records, &Map.get(&1, key))) + keys -> Enum.reduce(records, Ash.Expr.expr(false), fn record, filter_expr -> all_keys_match_expr = From e4bd2272d60077847a7f26fcc27f5dc4096b0cba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 08:08:50 -0500 Subject: [PATCH 363/690] chore(deps): bump ash_sql in the production-dependencies group (#476) Bumps the production-dependencies group with 1 update: [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash_sql` from 0.2.52 to 0.2.53 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.52...v0.2.53) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index d62e7283..b43360ac 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.62", "ef41463b12095fe9566962793f4e4d94c2753e1c3bfc79acc09471cc1efc7f51", [: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.4.8 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", "1780ec2029353213d5a35b1950a53da7225bce756f0be05e35708330f51d9cf0"}, - "ash_sql": {:hex, :ash_sql, "0.2.52", "8ca8858f85a4d9a4dcc05deb9f2116b92f939e006e5907e8f97998dfb8d5ff04", [: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", "c17207c7169c8ba1d8b5e705be944160b2ad74a780fdb9442202bd1afd6e4549"}, + "ash_sql": {:hex, :ash_sql, "0.2.53", "522a0829410ef5a35f172d7da089549b9f071b32d228283daebef921dba9c89b", [: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", "a384206185192421f40f517125ea9429c76db6bf177d7b268870f21dbcf32f8b"}, "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"}, From 9f6f7ba9bf5ea9107df009c7ece1ef3d812bde5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 08:09:09 -0500 Subject: [PATCH 364/690] chore(deps-dev): bump ex_doc in the dev-dependencies group (#477) Bumps the dev-dependencies group with 1 update: [ex_doc](https://github.com/elixir-lang/ex_doc). Updates `ex_doc` from 0.37.0-rc.2 to 0.37.0 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.37.0-rc.2...v0.37.0) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index b43360ac..a6d0a6d9 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.37.0-rc.2", "6e55e065aea63c2dfb3c0e18786a22d5107923ff7fb6a91f6e575f607735d09b", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "91e09b4ca47b2a83ce4c7035de7f0bb6e531c5d43cab19bb0c7820f73470df49"}, + "ex_doc": {:hex, :ex_doc, "0.37.0", "970f92b39e62c460aa8a367508e938f5e4da6e2ff3eaed3f8530b25870f45471", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "b0ee7f17373948e0cf471e59c3a0ee42f3bd1171c67d91eb3626456ef9c6202c"}, "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"}, From c3d0326a52732de6de05c57bd0cb9fd0a018e6e0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Feb 2025 20:59:38 -0500 Subject: [PATCH 365/690] fix: update lateral join logic to match ash_sql's test: update tests for tz calculation --- lib/data_layer.ex | 44 ++++++++++++++++++++++++++++------ test/calculation_test.exs | 8 ++++--- test/support/resources/post.ex | 2 +- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 30a502ea..bd1992d3 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1015,7 +1015,7 @@ defmodule AshPostgres.DataLayer do defp lateral_join_query( query, root_data, - [{source_query, source_attribute, destination_attribute, relationship}] + [{source_query, source_attribute, destination_attribute, relationship}] = path ) do source_query = Ash.Query.new(source_query) @@ -1065,7 +1065,7 @@ defmodule AshPostgres.DataLayer do source_pkey = Ash.Resource.Info.primary_key(source_query.resource) - case lateral_join_source_query(query, source_query, root_data) do + case lateral_join_source_query(query, source_query, root_data, path) do {:ok, data_layer_query} -> source_values = Enum.map(root_data, &Map.get(&1, source_attribute)) @@ -1148,13 +1148,13 @@ defmodule AshPostgres.DataLayer do {source_query, source_attribute, source_attribute_on_join_resource, relationship}, {through_resource, destination_attribute_on_join_resource, destination_attribute, through_relationship} - ] + ] = path ) do source_query = Ash.Query.new(source_query) source_values = Enum.map(root_data, &Map.get(&1, source_attribute)) source_pkey = Ash.Resource.Info.primary_key(source_query.resource) - case lateral_join_source_query(query, source_query, root_data) do + case lateral_join_source_query(query, source_query, root_data, path) do {:ok, data_layer_query} -> data_layer_query = Ecto.Query.exclude(data_layer_query, :select) @@ -1275,7 +1275,8 @@ defmodule AshPostgres.DataLayer do } }, source_query, - _root_data + _root_data, + _path ) when not is_nil(lateral_join_source_query) do {:ok, @@ -1283,15 +1284,44 @@ defmodule AshPostgres.DataLayer do |> set_subquery_prefix(source_query, lateral_join_source_query.__ash_bindings__.resource)} end - defp lateral_join_source_query(query, source_query, root_data) do + defp lateral_join_source_query(query, source_query, root_data, path) do source_query.resource |> Ash.Query.set_context(%{:data_layer => source_query.context[:data_layer]}) + |> Ash.Query.set_context(%{ + :data_layer => + Map.put( + source_query.context[:data_layer] || %{}, + :no_inner_join?, + true + ) + }) |> Ash.Query.set_tenant(source_query.tenant) |> filter_for_records(root_data) |> set_lateral_join_prefix(query) |> case do %{valid?: true} = query -> - Ash.Query.data_layer_query(query) + relationship = path |> List.first() |> elem(3) + + {:ok, expr} = + Ash.Filter.hydrate_refs(relationship.filter, %{ + resource: relationship.destination, + parent_stack: [relationship.source] + }) + + parent_expr = AshSql.Join.parent_expr(expr) + + used_aggregates = + Ash.Filter.used_aggregates(parent_expr, []) + + with {:ok, query} <- Ash.Query.data_layer_query(query) do + AshSql.Aggregate.add_aggregates( + query, + used_aggregates, + relationship.source, + false, + query.__ash_bindings__.root_binding + ) + end query -> {:error, query} diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 97d5a3c4..b84e9732 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -51,9 +51,11 @@ defmodule AshPostgres.CalculationTest do |> Ash.read!() end - test "start_of_day functions the same as Elixir's start of ay" do - assert Ash.calculate!(Post, :start_of_day) == - Ash.Expr.eval!(Ash.Expr.expr(start_of_day(^DateTime.utc_now(), "EST"))) + test "start_of_day functions the same as Elixir's start of day" do + Logger.configure(level: :debug) + + assert Ash.calculate!(Post, :start_of_day, data_layer?: true) == + Ash.Expr.eval!(Ash.Expr.expr(start_of_day(now(), "EST"))) end @tag :regression diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index df5c96cf..f87e6dc2 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -772,7 +772,7 @@ defmodule AshPostgres.Test.Post do ) ) - calculate(:start_of_day, :datetime, expr(start_of_day(fragment("now()"), "EST"))) + calculate(:start_of_day, :datetime, expr(start_of_day(now(), "EST"))) calculate(:author_count_of_posts, :integer, expr(author.count_of_posts_with_calc)) From 95c674b7c417e35015c9359d00690245393e5a50 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 10 Feb 2025 17:00:56 -0500 Subject: [PATCH 366/690] improvement: add vector l2 distance function improvement: use dimenstions constraint on vector for size --- lib/data_layer.ex | 3 ++- lib/functions/vector_cosine_distance.ex | 2 ++ lib/functions/vector_l2_distance.ex | 11 ++++++++++ .../migration_generator.ex | 8 ++++++++ lib/sql_implementation.ex | 20 +++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 lib/functions/vector_l2_distance.ex diff --git a/lib/data_layer.ex b/lib/data_layer.ex index bd1992d3..274919e3 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -820,7 +820,8 @@ defmodule AshPostgres.DataLayer do if "vector" in (config[:installed_extensions] || []) do functions ++ [ - AshPostgres.Functions.VectorCosineDistance + AshPostgres.Functions.VectorCosineDistance, + AshPostgres.Functions.VectorL2Distance ] else functions diff --git a/lib/functions/vector_cosine_distance.ex b/lib/functions/vector_cosine_distance.ex index f2e20d3a..349c1977 100644 --- a/lib/functions/vector_cosine_distance.ex +++ b/lib/functions/vector_cosine_distance.ex @@ -6,4 +6,6 @@ defmodule AshPostgres.Functions.VectorCosineDistance do use Ash.Query.Function, name: :vector_cosine_distance def args, do: [[:vector, :vector]] + + def returns, do: [:float] end diff --git a/lib/functions/vector_l2_distance.ex b/lib/functions/vector_l2_distance.ex new file mode 100644 index 00000000..c3f13ca0 --- /dev/null +++ b/lib/functions/vector_l2_distance.ex @@ -0,0 +1,11 @@ +defmodule AshPostgres.Functions.VectorL2Distance do + @moduledoc """ + Maps to the vector l2 distance operator. Requires `vector` extension to be installed. + """ + + use Ash.Query.Function, name: :vector_l2_distance + + def args, do: [[:vector, :vector]] + + def returns, do: [:float] +end diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index baf26c7f..584bc5c0 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2959,6 +2959,14 @@ defmodule AshPostgres.MigrationGenerator do defp migration_type(Ash.Type.UUIDv7, _), do: :uuid defp migration_type(Ash.Type.Integer, _), do: :bigint + defp migration_type(Ash.Type.Vector, constraints) do + if constraints[:dimensions] do + {:vector, constraints[:dimensions]} + else + :vector + end + end + defp migration_type(other, constraints) do type = Ash.Type.get_type(other) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 15a50bfd..8f530861 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -153,6 +153,26 @@ defmodule AshPostgres.SqlImplementation do {:ok, Ecto.Query.dynamic(fragment("(? <=> ?)", ^arg1, ^arg2)), acc} end + def expr( + query, + %AshPostgres.Functions.VectorL2Distance{ + arguments: [arg1, arg2], + embedded?: pred_embedded? + }, + bindings, + embedded?, + acc, + _type + ) do + {arg1, acc} = + AshSql.Expr.dynamic_expr(query, arg1, bindings, pred_embedded? || embedded?, :string, acc) + + {arg2, acc} = + AshSql.Expr.dynamic_expr(query, arg2, bindings, pred_embedded? || embedded?, :string, acc) + + {:ok, Ecto.Query.dynamic(fragment("(? <-> ?)", ^arg1, ^arg2)), acc} + end + def expr( query, %Ash.Query.Ref{ From d70c5c2fa43392257c4eec8522fd73a168717007 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 11 Feb 2025 09:59:04 -0500 Subject: [PATCH 367/690] chore: update deps --- mix.lock | 14 +++++++------- test/calculation_test.exs | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mix.lock b/mix.lock index a6d0a6d9..c49a0fd9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.62", "ef41463b12095fe9566962793f4e4d94c2753e1c3bfc79acc09471cc1efc7f51", [: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.4.8 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", "1780ec2029353213d5a35b1950a53da7225bce756f0be05e35708330f51d9cf0"}, - "ash_sql": {:hex, :ash_sql, "0.2.53", "522a0829410ef5a35f172d7da089549b9f071b32d228283daebef921dba9c89b", [: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", "a384206185192421f40f517125ea9429c76db6bf177d7b268870f21dbcf32f8b"}, + "ash": {:hex, :ash, "3.4.63", "7bf24d7e40039bf82652975460dca55e3d23fdb77738ebf665c16b7a4519b86e", [: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.4.8 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", "10175209ca1f01237959ce1ba0638b04c8d5a231dc0c128b2eea431ee32699e8"}, + "ash_sql": {:hex, :ash_sql, "0.2.54", "25f8c0aab413d31f7c795c158c52fb79487b6252c897e15d94ff7faabd8c7246", [: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", "5cd87c166260e661854efa3eb03dd91f3358d2e1b93e50ab07cbce21e33105e6"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "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.21", "b80e16a47cb1fe724a2113c1f2661507d9e458978c2d610aeb87b15d9c2d43e5", [: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", "19e516b5e06d90447c74fc4fdfc14b71318c41ef966999ac6b34d038e1aa2b9c"}, + "igniter": {:hex, :igniter, "0.5.22", "af4deba45c9c0ffdff257f9730fcfb6322e785b030b4982550affe0aaabfa3fd", [: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", "601b639bbf3a4740335a91b038999c3381ff9371f07122d0640b820cd2d5cfe3"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -37,19 +37,19 @@ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, - "owl": {:hex, :owl, "0.12.1", "d3146087315c4528ee32411495ba10ec88102597b638d4d1455cf9d245dfb57a", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "d7eb9746aa89c40c46b479d6c2a70b82b94993520e40f21d0b09654f23eebf35"}, + "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.12.1", "8bc7b0547c5ada64c9c16ef55f598cea9037d19810c59709d5cede33c5e5b562", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1f26550b4079d46a1b84a153d7427990c2e4adf3dfdbf6ca04c2ea0a9bf1d24d"}, + "reactor": {:hex, :reactor, "0.13.0", "072570a78e4cafcb81b81f143fc37f534ab7b206b2c5b445480638468bf59637", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "72aadf43584bab94b1907bff9371ac324acebd28f095f4320dd14dee2b499319"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, "spark": {:hex, :spark, "2.2.45", "19e3a879e80d02853ded85ed7b4c0a84a5d2e395f9d0c884e1a13afbe026929d", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "70b272d0ee16e3c10a4f8cf0ef6152840828152e68f2f8e3046e89567f2b49ad"}, - "spitfire": {:hex, :spitfire, "0.1.4", "8fe0df66e735323e4f2a56e719603391b160dd68efd922cadfbb85a2cf6c68af", [:mix], [], "hexpm", "d40d850f4ede5235084876246756b90c7bcd12994111d57c55e2e1e23ac3fe61"}, + "spitfire": {:hex, :spitfire, "0.1.5", "10b041e781bff9544d2fdf00893e1a325758408c5366a9bfa4333072568659b1", [:mix], [], "hexpm", "866a55d21fe827934ff38200111335c9dd311df13cbf2580ed71d84b0a783150"}, "splode": {:hex, :splode, "0.2.8", "289d4eec13e7a83061bc44827877eb4c575e1fdf198bd1a9c6449f9b64805059", [:mix], [], "hexpm", "dbe92fa526589416435e12203b56db1f74c834d207bc474016cedf930d987284"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, - "stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"}, + "stream_data": {:hex, :stream_data, "1.1.3", "15fdb14c64e84437901258bb56fc7d80aaf6ceaf85b9324f359e219241353bfb", [:mix], [], "hexpm", "859eb2be72d74be26c1c4f272905667672a52e44f743839c57c7ee73a1a66420"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, "tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"}, diff --git a/test/calculation_test.exs b/test/calculation_test.exs index b84e9732..70f9b11d 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -52,8 +52,6 @@ defmodule AshPostgres.CalculationTest do end test "start_of_day functions the same as Elixir's start of day" do - Logger.configure(level: :debug) - assert Ash.calculate!(Post, :start_of_day, data_layer?: true) == Ash.Expr.eval!(Ash.Expr.expr(start_of_day(now(), "EST"))) end From c293359353aa0d8865511dc56c40e54c72bea0bb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 11 Feb 2025 09:59:21 -0500 Subject: [PATCH 368/690] chore: release version v2.5.2 --- CHANGELOG.md | 23 +++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cc0c85a..658758ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,29 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.2](https://github.com/ash-project/ash_postgres/compare/v2.5.1...v2.5.2) (2025-02-11) + + + + +### Bug Fixes: + +* update lateral join logic to match ash_sql's + +* simplify lateral join source filter + +* update sql log switches for migration and rollback tasks (#470) + +### Improvements: + +* add vector l2 distance function + +* use dimenstions constraint on vector for size + +* consider identity.where in identity deduplicator + +* generate migrations task support concurrent indexes flag (#471) + ## [v2.5.1](https://github.com/ash-project/ash_postgres/compare/v2.5.0...v2.5.1) (2025-01-27) diff --git a/mix.exs b/mix.exs index 7eda5369..bb70edca 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.1" + @version "2.5.2" def project do [ From cfdbe79c8f044098bf7ae4c185bceecbad2c9ddb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 11 Feb 2025 11:07:01 -0500 Subject: [PATCH 369/690] chore: update start_of_day calc --- test/support/resources/post.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index f87e6dc2..3fb6e103 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -772,7 +772,11 @@ defmodule AshPostgres.Test.Post do ) ) - calculate(:start_of_day, :datetime, expr(start_of_day(now(), "EST"))) + calculate( + :start_of_day, + :datetime, + expr(start_of_day(fragment("now() AT TIME ZONE 'UTC'"), "EST")) + ) calculate(:author_count_of_posts, :integer, expr(author.count_of_posts_with_calc)) From a84358ce0c9c525e285640300d455257602b6c5b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 11 Feb 2025 11:10:11 -0500 Subject: [PATCH 370/690] chore: update ash_sql --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index c49a0fd9..1fcbc77a 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.4.63", "7bf24d7e40039bf82652975460dca55e3d23fdb77738ebf665c16b7a4519b86e", [: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.4.8 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", "10175209ca1f01237959ce1ba0638b04c8d5a231dc0c128b2eea431ee32699e8"}, - "ash_sql": {:hex, :ash_sql, "0.2.54", "25f8c0aab413d31f7c795c158c52fb79487b6252c897e15d94ff7faabd8c7246", [: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", "5cd87c166260e661854efa3eb03dd91f3358d2e1b93e50ab07cbce21e33105e6"}, + "ash_sql": {:hex, :ash_sql, "0.2.56", "3d438a18af5d7c39e0b2b2ba6b6adc8b2abe40d9caa18af720433fc3126efac1", [: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", "22296a2afe1f69ec1c2de7490f6821a8551c16c914e746663458068a7808a9d4"}, "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"}, From d21f06ca19b22dfd6231ceb4f9af990b16c44478 Mon Sep 17 00:00:00 2001 From: Maciej Malecki Date: Wed, 12 Feb 2025 21:51:13 +0100 Subject: [PATCH 371/690] fix: Ignore module conflict when compiling migration file (#482) This fixes the problem of logging "redefining module" entries when using context-driven multitenancy (where each tenant tries to compile the migration module). Fixes #480 --- lib/migration_compile_cache.ex | 3 +++ lib/multitenancy.ex | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/migration_compile_cache.ex b/lib/migration_compile_cache.ex index c8f9108a..802c21ad 100644 --- a/lib/migration_compile_cache.ex +++ b/lib/migration_compile_cache.ex @@ -28,11 +28,14 @@ defmodule AshPostgres.MigrationCompileCache do defp ensure_compiled(state, file) do case Map.get(state, file) do nil -> + Code.put_compiler_option(:ignore_module_conflict, true) compiled = Code.compile_file(file) Map.put(state, file, compiled) _ -> state end + after + Code.put_compiler_option(:ignore_module_conflict, false) end end diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 505c9cb0..20e67c0c 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -15,8 +15,6 @@ defmodule AshPostgres.MultiTenancy do migrations_path || repo.config()[:tenant_migrations_path] || default_tenant_migration_path(repo) - Code.compiler_options(ignore_module_conflict: true) - Ecto.Migration.SchemaMigration.ensure_schema_migrations_table!( repo, repo.config(), @@ -44,8 +42,6 @@ defmodule AshPostgres.MultiTenancy do Ecto.Migration.SchemaMigration.up(repo, repo.config(), version, prefix: tenant_name) end) - after - Code.compiler_options(ignore_module_conflict: false) end # sobelow_skip ["SQL"] From d3788e35ca54c2cc53f23dd5dabe9ffbab7a2af1 Mon Sep 17 00:00:00 2001 From: quartz Date: Wed, 12 Feb 2025 21:55:17 +0100 Subject: [PATCH 372/690] test: custom types in expr (#481) --- test/type_test.exs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/type_test.exs b/test/type_test.exs index 53c073e4..beebbe82 100644 --- a/test/type_test.exs +++ b/test/type_test.exs @@ -35,4 +35,20 @@ defmodule AshPostgres.Test.TypeTest do |> Ash.Query.filter(fragment("? = ?", id, type(^uuid, :uuid))) |> Ash.read!() end + + test "complex custom types can be used in filters" do + Post + |> Ash.Changeset.for_create(:create, %{point: {1.0, 2.0, 3.0}, composite_point: %{x: 1, y: 2}}) + |> Ash.create!() + + assert [_] = + Post + |> Ash.Query.filter(composite_point == %{x: 1, y: 2}) + |> Ash.read!() + + assert [_] = + Post + |> Ash.Query.filter(point == {1.0, 2.0, 3.0}) + |> Ash.read!() + end end From 68fddacd3bacd1a1b5f8edc805a757c90d30ff2c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 12 Feb 2025 16:44:58 -0500 Subject: [PATCH 373/690] chore: update test --- test/type_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/type_test.exs b/test/type_test.exs index beebbe82..856a2da3 100644 --- a/test/type_test.exs +++ b/test/type_test.exs @@ -48,7 +48,7 @@ defmodule AshPostgres.Test.TypeTest do assert [_] = Post - |> Ash.Query.filter(point == {1.0, 2.0, 3.0}) + |> Ash.Query.filter(point == ^{1.0, 2.0, 3.0}) |> Ash.read!() end end From 5313f466bb46a894b663bd9ac89b147deeb9aae6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Feb 2025 08:46:47 -0500 Subject: [PATCH 374/690] chore(deps-dev): bump ex_doc in the dev-dependencies group (#484) Bumps the dev-dependencies group with 1 update: [ex_doc](https://github.com/elixir-lang/ex_doc). Updates `ex_doc` from 0.37.0 to 0.37.1 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.37.0...v0.37.1) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 1fcbc77a..f483186e 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.37.0", "970f92b39e62c460aa8a367508e938f5e4da6e2ff3eaed3f8530b25870f45471", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "b0ee7f17373948e0cf471e59c3a0ee42f3bd1171c67d91eb3626456ef9c6202c"}, + "ex_doc": {:hex, :ex_doc, "0.37.1", "65ca30d242082b95aa852b3b73c9d9914279fff56db5dc7b3859be5504417980", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "6774f75477733ea88ce861476db031f9399c110640752ca2b400dbbb50491224"}, "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"}, From 8936bc1f2a85f89e3bb4ffc4ca9d0451e71ebbb7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 13 Feb 2025 23:34:40 -0500 Subject: [PATCH 375/690] fix: handle dropping primary key columns properly --- .../migration_generator.ex | 138 ++++++++++++++++-- lib/migration_generator/operation.ex | 62 ++++++++ 2 files changed, 187 insertions(+), 13 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 584bc5c0..bd9dd1f7 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -1298,6 +1298,12 @@ defmodule AshPostgres.MigrationGenerator do defp after?(%Operation.RemovePrimaryKeyDown{}, _), do: true defp after?(_, %Operation.RemovePrimaryKeyDown{}), do: false + defp after?(%Operation.AddPrimaryKeyDown{}, _), do: false + defp after?(_, %Operation.AddPrimaryKeyDown{}), do: true + + defp after?(%Operation.AddPrimaryKey{}, _), do: true + defp after?(_, %Operation.AddPrimaryKey{}), do: false + defp after?( %Operation.AddCustomStatement{}, _ @@ -1803,7 +1809,9 @@ defmodule AshPostgres.MigrationGenerator do defp do_fetch_operations(snapshot, old_snapshot, opts, acc) do attribute_operations = attribute_operations(snapshot, old_snapshot, opts) - pkey_operations = pkey_operations(snapshot, old_snapshot, attribute_operations, opts) + + {pkey_operations, attribute_operations} = + pkey_operations(snapshot, old_snapshot, attribute_operations, opts) rewrite_all_identities? = changing_multitenancy_affects_identities?(snapshot, old_snapshot) @@ -2097,7 +2105,7 @@ defmodule AshPostgres.MigrationGenerator do defp pkey_operations(snapshot, old_snapshot, attribute_operations, opts) do if old_snapshot[:empty?] do - [] + {[], attribute_operations} else must_drop_pkey? = Enum.any?( @@ -2115,11 +2123,38 @@ defmodule AshPostgres.MigrationGenerator do } -> true + %Operation.RemoveAttribute{ + attribute: %{primary_key?: true} + } -> + true + _ -> false end ) + must_add_primary_key? = + must_drop_pkey? && + Enum.any?(snapshot.attributes, fn attribute -> + attribute.primary_key? + end) + + must_add_primary_key_in_down? = + must_drop_pkey? && + Enum.any?(snapshot.attributes, fn attribute -> + attribute.primary_key? && + !Enum.any?(attribute_operations, fn + %Operation.AlterAttribute{} = operation -> + operation.new_attribute.source == attribute.source + + %Operation.AddAttribute{} = operation -> + operation.attribute.source == attribute.source + + _ -> + false + end) + end) + drop_in_down? = Enum.any?(attribute_operations, fn %Operation.AlterAttribute{ @@ -2148,17 +2183,94 @@ defmodule AshPostgres.MigrationGenerator do false end) - [ - must_drop_pkey? && - %Operation.RemovePrimaryKey{schema: snapshot.schema, table: snapshot.table}, - must_drop_pkey? && drop_in_down? && - %Operation.RemovePrimaryKeyDown{ - commented?: opts.dont_drop_columns && drop_in_down_commented?, - schema: snapshot.schema, - table: snapshot.table - } - ] - |> Enum.filter(& &1) + attribute_operations = + if must_add_primary_key? do + Enum.map( + attribute_operations, + fn + %Operation.AlterAttribute{} = operation -> + %{ + operation + | new_attribute: %{ + operation.new_attribute + | primary_key?: operation.old_attribute.primary_key? + } + } + + %Operation.AddAttribute{} = operation -> + %{operation | attribute: %{operation.attribute | primary_key?: false}} + + other -> + other + end + ) + else + attribute_operations + end + + attribute_operations = + if must_add_primary_key_in_down? do + Enum.map( + attribute_operations, + fn + %Operation.AlterAttribute{} = operation -> + %{ + operation + | old_attribute: %{ + operation.old_attribute + | primary_key?: operation.new_attribute.primary_key? + } + } + + %Operation.RemoveAttribute{} = operation -> + %{operation | attribute: %{operation.attribute | primary_key?: false}} + + other -> + other + end + ) + else + attribute_operations + end + + {[ + must_drop_pkey? && + %Operation.RemovePrimaryKey{schema: snapshot.schema, table: snapshot.table}, + must_drop_pkey? && drop_in_down? && + %Operation.RemovePrimaryKeyDown{ + commented?: opts.dont_drop_columns && drop_in_down_commented?, + schema: snapshot.schema, + table: snapshot.table + }, + must_add_primary_key? && + %Operation.AddPrimaryKey{ + schema: snapshot.schema, + table: snapshot.table, + keys: + Enum.flat_map(snapshot.attributes, fn attribute -> + if attribute.primary_key? do + [attribute.source] + else + [] + end + end) + }, + must_add_primary_key_in_down? && + %Operation.AddPrimaryKeyDown{ + schema: old_snapshot.schema, + table: old_snapshot.table, + remove_old?: must_add_primary_key? && !(must_drop_pkey? && drop_in_down?), + keys: + Enum.flat_map(old_snapshot.attributes, fn attribute -> + if attribute.primary_key? do + [attribute.source] + else + [] + end + end) + } + ] + |> Enum.filter(& &1), attribute_operations} end end diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index cc4f1975..4b8c4eae 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1051,6 +1051,68 @@ defmodule AshPostgres.MigrationGenerator.Operation do end end + defmodule AddPrimaryKey do + @moduledoc false + defstruct [:schema, :table, :keys, no_phase: true] + + def up(%{schema: schema, table: table, keys: keys}) do + keys = Enum.join(keys, ", ") + + if schema do + """ + execute("ALTER TABLE \\\"#{schema}.#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + else + """ + execute("ALTER TABLE \\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + end + end + + def down(_) do + "" + end + end + + defmodule AddPrimaryKeyDown do + @moduledoc false + defstruct [:schema, :table, :keys, :remove_old?, no_phase: true] + + def up(_) do + "" + end + + def down(%{schema: schema, table: table, remove_old?: remove_old?, keys: keys}) do + keys = Enum.join(keys, ", ") + + if schema do + remove_old = + if remove_old? do + """ + execute("ALTER TABLE \\\"#{schema}.#{table}\\\" DROP constraint #{table}_pkey") + """ + end + + """ + #{remove_old} + execute("ALTER TABLE \\\"#{schema}.#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + else + remove_old = + if remove_old? do + """ + execute("ALTER TABLE \\\"#{table}\\\" DROP constraint #{table}_pkey") + """ + end + + """ + #{remove_old} + execute("ALTER TABLE \\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + end + end + end + defmodule RemovePrimaryKey do @moduledoc false defstruct [:schema, :table, no_phase: true] From e19c93a62c1377b93bddea00931175a8b1fc7f3d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 14 Feb 2025 00:14:06 -0500 Subject: [PATCH 376/690] chore: fix tests --- .../migration_generator.ex | 12 ++- test/migration_generator_test.exs | 99 +++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index bd9dd1f7..e0301956 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2136,7 +2136,17 @@ defmodule AshPostgres.MigrationGenerator do must_add_primary_key? = must_drop_pkey? && Enum.any?(snapshot.attributes, fn attribute -> - attribute.primary_key? + attribute.primary_key? && + !Enum.any?(attribute_operations, fn + %Operation.AlterAttribute{} = operation -> + operation.new_attribute.source == attribute.source + + %Operation.AddAttribute{} = operation -> + operation.attribute.source == attribute.source + + _ -> + false + end) end) must_add_primary_key_in_down? = diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 131f8c4a..b7f10688 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -393,6 +393,105 @@ defmodule AshPostgres.MigrationGeneratorTest do end end + describe "creating follow up migrations with a composite primary key" do + setup do + on_exit(fn -> + File.rm_rf!("test_snapshots_path") + File.rm_rf!("test_migration_path") + end) + + defposts do + postgres do + schema("example") + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true, primary_key?: true, allow_nil?: false) + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + :ok + end + + test "when removing an element, it recreates the primary key" do + defposts do + postgres do + schema("example") + end + + attributes do + uuid_primary_key(:id) + end + end + + defdomain([Post]) + + send(self(), {:mix_shell_input, :yes?, true}) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [_file1, file2] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + contents = File.read!(file2) + + [up_side, down_side] = String.split(contents, "def down", parts: 2) + + assert up_side =~ ~S[execute("ALTER TABLE \"example.posts\" ADD PRIMARY KEY (id)")] + assert down_side =~ ~S[execute("ALTER TABLE \"example.posts\" DROP constraint posts_pkey")] + assert down_side =~ ~S[execute("ALTER TABLE \"example.posts\" ADD PRIMARY KEY (id, title)")] + + defposts do + postgres do + schema("example") + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true, primary_key?: true, allow_nil?: false) + end + end + + defdomain([Post]) + + send(self(), {:mix_shell_input, :yes?, true}) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [_file1, _file2, file3] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + contents = File.read!(file3) + + [up_side, down_side] = String.split(contents, "def down", parts: 2) + + assert up_side =~ ~S[execute("ALTER TABLE \"example.posts\" ADD PRIMARY KEY (id, title)")] + assert down_side =~ ~S[execute("ALTER TABLE \"example.posts\" ADD PRIMARY KEY (id)")] + end + end + describe "creating follow up migrations with a schema" do setup do on_exit(fn -> From d82af2374339e38df8f5f8afcbab53fa40deb147 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 14 Feb 2025 00:21:20 -0500 Subject: [PATCH 377/690] chore: release version v2.5.3 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 658758ce..62f756d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.3](https://github.com/ash-project/ash_postgres/compare/v2.5.2...v2.5.3) (2025-02-14) + + + + +### Bug Fixes: + +* handle dropping primary key columns properly + +* Ignore module conflict when compiling migration file (#482) + ## [v2.5.2](https://github.com/ash-project/ash_postgres/compare/v2.5.1...v2.5.2) (2025-02-11) diff --git a/mix.exs b/mix.exs index bb70edca..27170ce8 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.2" + @version "2.5.3" def project do [ From c2b2a7d43ca369e80fe05c15ea69d4cff185bf85 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 01:11:20 -0500 Subject: [PATCH 378/690] chore: add test for map atomic updates --- .../test_repo/posts/20250217054207.json | 509 ++++++++++++++++++ .../20250217054207_migrate_resources49.exs | 21 + test/bulk_update_test.exs | 8 + test/support/resources/post.ex | 5 + 4 files changed, 543 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/posts/20250217054207.json create mode 100644 priv/test_repo/migrations/20250217054207_migrate_resources49.exs diff --git a/priv/resource_snapshots/test_repo/posts/20250217054207.json b/priv/resource_snapshots/test_repo/posts/20250217054207.json new file mode 100644 index 00000000..47298089 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250217054207.json @@ -0,0 +1,509 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "limited_score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "metadata", + "type": "map" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "65F28CF9B30958792FAE16BED984833E82C5461CCC9AD8814C18B871BAAE4E1B", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250217054207_migrate_resources49.exs b/priv/test_repo/migrations/20250217054207_migrate_resources49.exs new file mode 100644 index 00000000..19f6424f --- /dev/null +++ b/priv/test_repo/migrations/20250217054207_migrate_resources49.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources49 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:metadata, :map) + end + end + + def down do + alter table(:posts) do + remove(:metadata) + end + end +end diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index 6ed482df..201595a7 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -20,6 +20,14 @@ defmodule AshPostgres.BulkUpdateTest do assert Enum.all?(posts, &String.ends_with?(&1.title, "_stuff")) end + @tag :regression + test "bulk updates can update maps with the join strategy" do + Post + |> Ash.Query.limit(1) + |> Ash.Query.filter(exists(comments, title == parent(title))) + |> Ash.bulk_update!(:update_metadata, %{metadata: %{1 => 2}}) + end + test "bulk updates can set datetimes" do Post |> Ash.Changeset.for_create(:create, %{title: "fred"}) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 3fb6e103..26fae521 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -250,6 +250,10 @@ defmodule AshPostgres.Test.Post do ) end + update :update_metadata do + accept([:metadata]) + end + destroy :cascade_destroy do change(cascade_destroy(:high_ratings, after_action?: false)) end @@ -410,6 +414,7 @@ defmodule AshPostgres.Test.Post do attribute(:decimal, :decimal, default: Decimal.new(0), public?: true) attribute(:status, AshPostgres.Test.Types.Status, public?: true) attribute(:status_enum, AshPostgres.Test.Types.StatusEnum, public?: true) + attribute(:metadata, :map) attribute(:status_enum_no_cast, AshPostgres.Test.Types.StatusEnumNoCast, source: :status_enum, From 64d768c79ce3f96054a1b6920d9f854390e2f9d8 Mon Sep 17 00:00:00 2001 From: Lucas Mendelowski Date: Mon, 17 Feb 2025 19:11:15 +0100 Subject: [PATCH 379/690] improvement: Add support for field names in idenitity constraints (#478) --- lib/data_layer.ex | 33 ++++++---- mix.exs | 4 +- .../test_repo/orgs/20250210191116.json | 64 +++++++++++++++++++ .../20250210191116_migrate_resources49.exs | 25 ++++++++ test/support/resources/organization.ex | 11 ++++ test/unique_identity_test.exs | 14 ++++ 6 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/orgs/20250210191116.json create mode 100644 priv/test_repo/migrations/20250210191116_migrate_resources49.exs diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 274919e3..a073e5ea 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2310,7 +2310,7 @@ defmodule AshPostgres.DataLayer do %Postgrex.Error{} = error, stacktrace, {:bulk_create, fake_changeset}, - _resource + resource ) do case Ecto.Adapters.Postgres.Connection.to_constraints(error, []) do [] -> @@ -2319,7 +2319,7 @@ defmodule AshPostgres.DataLayer do constraints -> {:error, fake_changeset - |> constraints_to_errors(:insert, constraints) + |> constraints_to_errors(:insert, constraints, resource) |> Ash.Error.to_ash_error()} end end @@ -2372,7 +2372,7 @@ defmodule AshPostgres.DataLayer do {:error, Ash.Error.to_ash_error(error, stacktrace)} end - defp constraints_to_errors(%{constraints: user_constraints} = changeset, action, constraints) do + defp constraints_to_errors(%{constraints: user_constraints} = changeset, action, constraints, resource) do Enum.map(constraints, fn {type, constraint} -> user_constraint = Enum.find(user_constraints, fn c -> @@ -2387,14 +2387,25 @@ defmodule AshPostgres.DataLayer do case user_constraint do %{field: field, error_message: error_message, type: type, constraint: constraint} -> - Ash.Error.Changes.InvalidAttribute.exception( - field: field, - message: error_message, - private_vars: [ - constraint: constraint, - constraint_type: type - ] - ) + identities = Ash.Resource.Info.identities(resource) + table = AshPostgres.DataLayer.Info.table(resource) + + identity = Enum.find(identities, fn identity -> + "#{table}_#{identity.name}_index" == constraint + end) + + field_names = if identity, do: identity.field_names, else: [field] + + Enum.map(field_names, fn field_name -> + Ash.Error.Changes.InvalidAttribute.exception( + field: field_name, + message: error_message, + private_vars: [ + constraint: constraint, + constraint_type: type + ] + ) + end) nil -> Ecto.ConstraintError.exception( diff --git a/mix.exs b/mix.exs index 27170ce8..fe528021 100644 --- a/mix.exs +++ b/mix.exs @@ -165,7 +165,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.48")}, + {:ash, ash_version("~> 3.4 and >= 3.4.64")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.43")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, @@ -197,7 +197,7 @@ defmodule AshPostgres.MixProject do [path: "../ash", override: true] "main" -> - [git: "https://github.com/ash-project/ash.git"] + [git: "https://github.com/ash-project/ash.git", override: true] version when is_binary(version) -> "~> #{version}" diff --git a/priv/resource_snapshots/test_repo/orgs/20250210191116.json b/priv/resource_snapshots/test_repo/orgs/20250210191116.json new file mode 100644 index 00000000..61cc82a1 --- /dev/null +++ b/priv/resource_snapshots/test_repo/orgs/20250210191116.json @@ -0,0 +1,64 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "department", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "1D1BA9E1E272238D80C9861CAA67C4A85F675E3B052A15F4D5AC272551B820A7", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "orgs_department_index", + "keys": [ + { + "type": "string", + "value": "(LOWER(department))" + } + ], + "name": "department", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "orgs" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250210191116_migrate_resources49.exs b/priv/test_repo/migrations/20250210191116_migrate_resources49.exs new file mode 100644 index 00000000..622dddc6 --- /dev/null +++ b/priv/test_repo/migrations/20250210191116_migrate_resources49.exs @@ -0,0 +1,25 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources49 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:orgs) do + add(:department, :text) + end + + create(unique_index(:orgs, ["(LOWER(department))"], name: "orgs_department_index")) + end + + def down do + drop_if_exists(unique_index(:orgs, ["(LOWER(department))"], name: "orgs_department_index")) + + alter table(:orgs) do + remove(:department) + end + end +end diff --git a/test/support/resources/organization.ex b/test/support/resources/organization.ex index d5a22d65..0013f909 100644 --- a/test/support/resources/organization.ex +++ b/test/support/resources/organization.ex @@ -10,6 +10,8 @@ defmodule AshPostgres.Test.Organization do postgres do table("orgs") repo(AshPostgres.TestRepo) + + calculations_to_sql(lower_department: "LOWER(department)") end policies do @@ -39,6 +41,15 @@ defmodule AshPostgres.Test.Organization do attributes do uuid_primary_key(:id, writable?: true) attribute(:name, :string, public?: true) + attribute(:department, :string, public?: true) + end + + calculations do + calculate(:lower_department, :string, expr(fragment("LOWER(?)", department))) + end + + identities do + identity(:department, [:lower_department], field_names: [:department_slug]) end relationships do diff --git a/test/unique_identity_test.exs b/test/unique_identity_test.exs index e210ac77..8fae1b98 100644 --- a/test/unique_identity_test.exs +++ b/test/unique_identity_test.exs @@ -1,6 +1,7 @@ defmodule AshPostgres.Test.UniqueIdentityTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post + alias AshPostgres.Test.Organization require Ash.Query @@ -19,6 +20,19 @@ defmodule AshPostgres.Test.UniqueIdentityTest do end end + test "unique constraint field names are property set" do + Organization + |> Ash.Changeset.for_create(:create, %{name: "Acme", department: "Sales"}) + |> Ash.create!() + + assert {:error, %Ash.Error.Invalid{errors: [invalid_attribute]}} = + Organization + |> Ash.Changeset.for_create(:create, %{name: "Acme", department: "SALES"}) + |> Ash.create() + + assert %Ash.Error.Changes.InvalidAttribute{field: :department_slug} = invalid_attribute + end + test "a unique constraint can be used to upsert when the resource has a base filter" do post = Post From 5377c15447d3fe16b57512717e74bc3df4a52eeb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 14:39:27 -0500 Subject: [PATCH 380/690] chore: format/test --- lib/data_layer.ex | 14 ++++++++++---- test/calculation_test.exs | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index a073e5ea..dfa561c0 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2372,7 +2372,12 @@ defmodule AshPostgres.DataLayer do {:error, Ash.Error.to_ash_error(error, stacktrace)} end - defp constraints_to_errors(%{constraints: user_constraints} = changeset, action, constraints, resource) do + defp constraints_to_errors( + %{constraints: user_constraints} = changeset, + action, + constraints, + resource + ) do Enum.map(constraints, fn {type, constraint} -> user_constraint = Enum.find(user_constraints, fn c -> @@ -2390,9 +2395,10 @@ defmodule AshPostgres.DataLayer do identities = Ash.Resource.Info.identities(resource) table = AshPostgres.DataLayer.Info.table(resource) - identity = Enum.find(identities, fn identity -> - "#{table}_#{identity.name}_index" == constraint - end) + identity = + Enum.find(identities, fn identity -> + "#{table}_#{identity.name}_index" == constraint + end) field_names = if identity, do: identity.field_names, else: [field] diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 70f9b11d..94d5e5ec 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -563,7 +563,7 @@ defmodule AshPostgres.CalculationTest do assert [%{first_name: "abc"}, %{first_name: "tom"}] = Author - |> Ash.Query.sort(param_full_name: [separator: "~"]) + |> Ash.Query.sort(param_full_name: %{separator: "~"}) |> Ash.read!() end From 3eaa959619ea047ca4bfc58a1a308d93bb3aaa42 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 15:00:27 -0500 Subject: [PATCH 381/690] chore: update deps & tests --- mix.lock | 8 ++++---- test/unique_identity_test.exs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index f483186e..f96a76a5 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.63", "7bf24d7e40039bf82652975460dca55e3d23fdb77738ebf665c16b7a4519b86e", [: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.4.8 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", "10175209ca1f01237959ce1ba0638b04c8d5a231dc0c128b2eea431ee32699e8"}, - "ash_sql": {:hex, :ash_sql, "0.2.56", "3d438a18af5d7c39e0b2b2ba6b6adc8b2abe40d9caa18af720433fc3126efac1", [: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", "22296a2afe1f69ec1c2de7490f6821a8551c16c914e746663458068a7808a9d4"}, + "ash": {:hex, :ash, "3.4.64", "cbc337173fada2c094aa7f852fbb82d16f7090c06272aa34feb7479d1ff91162", [: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", "f29472b64cec1c340a3f2f32ef3542b4d719a041a86678d0793442922f365709"}, + "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"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, "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.22", "af4deba45c9c0ffdff257f9730fcfb6322e785b030b4982550affe0aaabfa3fd", [: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", "601b639bbf3a4740335a91b038999c3381ff9371f07122d0640b820cd2d5cfe3"}, + "igniter": {:hex, :igniter, "0.5.25", "a9e26794efe4b5619edd112b2ce8ffa3931f1e4d558dfebcd344553024e359b5", [: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", "d944d3ed8439bb2d98391f39b86305d109f4123c947061db54c1c0f9ecad890e"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,7 +39,7 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.13.0", "072570a78e4cafcb81b81f143fc37f534ab7b206b2c5b445480638468bf59637", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "72aadf43584bab94b1907bff9371ac324acebd28f095f4320dd14dee2b499319"}, + "reactor": {:hex, :reactor, "0.13.2", "8260c8c7159748891298b05527b754d31c8d305a00497d03e638ba84654b8797", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2ec44588d61763da544382942c0218d7f7eab454b709756c1b1b9d70ed8821a"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, diff --git a/test/unique_identity_test.exs b/test/unique_identity_test.exs index 8fae1b98..47638025 100644 --- a/test/unique_identity_test.exs +++ b/test/unique_identity_test.exs @@ -1,7 +1,7 @@ defmodule AshPostgres.Test.UniqueIdentityTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.Post alias AshPostgres.Test.Organization + alias AshPostgres.Test.Post require Ash.Query From f66c743a988a1f091f3028d135c534a21cc65083 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 15:00:43 -0500 Subject: [PATCH 382/690] chore: release version v2.5.4 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f756d9..af71c364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.4](https://github.com/ash-project/ash_postgres/compare/v2.5.3...v2.5.4) (2025-02-17) + + + + +### Improvements: + +* Add support for field names in idenitity constraints (#478) + ## [v2.5.3](https://github.com/ash-project/ash_postgres/compare/v2.5.2...v2.5.3) (2025-02-14) diff --git a/mix.exs b/mix.exs index fe528021..c5f4943d 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.3" + @version "2.5.4" def project do [ From 72170bda79881a07ec5a5dda97e994ad5e7add7c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 17:26:51 -0500 Subject: [PATCH 383/690] fix: ensure field names defaults to the field of the constraint --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index dfa561c0..5fbcaa71 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2400,7 +2400,7 @@ defmodule AshPostgres.DataLayer do "#{table}_#{identity.name}_index" == constraint end) - field_names = if identity, do: identity.field_names, else: [field] + field_names = if identity, do: identity.field_names || [field], else: [field] Enum.map(field_names, fn field_name -> Ash.Error.Changes.InvalidAttribute.exception( From aafb473588e6f09bb04df4cb8ed636c23df6f866 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 18:08:31 -0500 Subject: [PATCH 384/690] chore: release version v2.5.5 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af71c364..f1da8e75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.5](https://github.com/ash-project/ash_postgres/compare/v2.5.4...v2.5.5) (2025-02-17) + + + + +### Bug Fixes: + +* ensure field names defaults to the field of the constraint + ## [v2.5.4](https://github.com/ash-project/ash_postgres/compare/v2.5.3...v2.5.4) (2025-02-17) diff --git a/mix.exs b/mix.exs index c5f4943d..c7463e23 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.4" + @version "2.5.5" def project do [ From a0a1c35451c06cce79cbf8d25d48cee63d2eafd3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 21:05:23 -0500 Subject: [PATCH 385/690] fix: don't rewrite identities when only global? is changed fix: don't modify an attribute when it only needs to be renamed --- .../migration_generator.ex | 27 +++-- test/migration_generator_test.exs | 102 ++++++++++++++++++ 2 files changed, 123 insertions(+), 6 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index e0301956..0ad2bc7f 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2305,21 +2305,22 @@ defmodule AshPostgres.MigrationGenerator do Enum.find( old_snapshot.attributes, fn old_attribute -> - source_match = - Enum.find_value(attributes_to_rename, old_attribute.source, fn {new, old} -> + renaming_to_source = + Enum.find_value(attributes_to_rename, fn {new, old} -> if old.source == old_attribute.source do new.source end end) - source_match == + (renaming_to_source || old_attribute.source) == attribute.source && attributes_unequal?( old_attribute, attribute, snapshot.repo, old_snapshot, - snapshot + snapshot, + not is_nil(renaming_to_source) ) end )} @@ -2522,11 +2523,25 @@ defmodule AshPostgres.MigrationGenerator do # This exists to handle the fact that the remapping of the key name -> source caused attributes # to be considered unequal. We ignore things that only differ in that way using this function. - defp attributes_unequal?(left, right, repo, _old_snapshot, _new_snapshot) do + defp attributes_unequal?(left, right, repo, _old_snapshot, _new_snapshot, ignore_names?) do left = clean_for_equality(left, repo) right = clean_for_equality(right, repo) + left = + if ignore_names? do + Map.drop(left, [:source, :name]) + else + left + end + + right = + if ignore_names? do + Map.drop(left, [:source, :name]) + else + right + end + left != right end @@ -2583,7 +2598,7 @@ defmodule AshPostgres.MigrationGenerator do end def changing_multitenancy_affects_identities?(snapshot, old_snapshot) do - snapshot.multitenancy != old_snapshot.multitenancy || + Map.delete(snapshot.multitenancy, :global) != Map.delete(old_snapshot.multitenancy, :global) || snapshot.base_filter != old_snapshot.base_filter end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index b7f10688..c39a1578 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -584,6 +584,77 @@ defmodule AshPostgres.MigrationGeneratorTest do end end + describe "changing global multitenancy" do + setup do + on_exit(fn -> + File.rm_rf!("test_snapshots_path") + File.rm_rf!("test_migration_path") + end) + + defposts do + identities do + identity(:title, [:title]) + end + + multitenancy do + strategy(:attribute) + attribute(:organization_id) + global?(false) + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true) + attribute(:organization_id, :string) + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + :ok + end + + test "when changing multitenancy to global, identities aren't rewritten" do + defposts do + identities do + identity(:title, [:title]) + end + + multitenancy do + strategy(:attribute) + attribute(:organization_id) + global?(true) + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true) + attribute(:organization_id, :string) + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [_file1] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + end + end + describe "creating follow up migrations" do setup do on_exit(fn -> @@ -614,6 +685,37 @@ defmodule AshPostgres.MigrationGeneratorTest do :ok end + test "when renaming an attribute of an index, it is properly renamed without modifying the attribute" do + defposts do + identities do + identity(:title, [:foobar]) + end + + attributes do + uuid_primary_key(:id) + attribute(:foobar, :string, public?: true) + end + end + + defdomain([Post]) + + send(self(), {:mix_shell_input, :yes?, true}) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [_file1, file2] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + contents = File.read!(file2) + refute contents =~ "modify" + end + test "when renaming an index, it is properly renamed" do defposts do postgres do From 120d2049b954caed768526008ce8ddbf3b6b56b8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Feb 2025 21:22:53 -0500 Subject: [PATCH 386/690] chore: fix migraiton numbers --- ...e_resources49.exs => 20250217054207_migrate_resources50.exs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename priv/test_repo/migrations/{20250217054207_migrate_resources49.exs => 20250217054207_migrate_resources50.exs} (84%) diff --git a/priv/test_repo/migrations/20250217054207_migrate_resources49.exs b/priv/test_repo/migrations/20250217054207_migrate_resources50.exs similarity index 84% rename from priv/test_repo/migrations/20250217054207_migrate_resources49.exs rename to priv/test_repo/migrations/20250217054207_migrate_resources50.exs index 19f6424f..58a69c80 100644 --- a/priv/test_repo/migrations/20250217054207_migrate_resources49.exs +++ b/priv/test_repo/migrations/20250217054207_migrate_resources50.exs @@ -1,4 +1,4 @@ -defmodule AshPostgres.TestRepo.Migrations.MigrateResources49 do +defmodule AshPostgres.TestRepo.Migrations.MigrateResources50 do @moduledoc """ Updates resources based on their most recent snapshots. From 2c74df3716862b2df8c9b543856e2b9c833fd6c1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 18 Feb 2025 22:03:00 -0500 Subject: [PATCH 387/690] test: capture logs in tests, test various atomic behaviors --- test/ash_postgres_test.exs | 5 +- test/support/resources/post.ex | 22 ++++++++ test/support/test_repo.ex | 2 +- test/test_helper.exs | 4 +- test/update_test.exs | 95 ++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 3 deletions(-) diff --git a/test/ash_postgres_test.exs b/test/ash_postgres_test.exs index 7141b79b..a3318b57 100644 --- a/test/ash_postgres_test.exs +++ b/test/ash_postgres_test.exs @@ -5,6 +5,9 @@ defmodule AshPostgresTest do test "transaction metadata is given to on_transaction_begin" do AshPostgres.Test.Post |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.Changeset.after_action(fn _, result -> + {:ok, result} + end) |> Ash.create!() assert_receive %{ @@ -62,7 +65,7 @@ defmodule AshPostgresTest do actor: nil, actor: author ) - |> then(&AshPostgres.Test.Post.can_update_if_author?(author, &1)) + |> then(&AshPostgres.Test.Post.can_update_if_author?(author, &1, reuse_values?: true)) end) assert log == "" diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 26fae521..926e3caa 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -159,6 +159,28 @@ defmodule AshPostgres.Test.Post do change(atomic_update(:limited_score, expr((limited_score || 0) + ^arg(:amount)))) end + update :change_nothing do + accept([]) + require_atomic?(false) + change(fn changeset, _ -> changeset end) + end + + update :change_nothing_atomic do + accept([]) + require_atomic?(true) + end + + update :change_title do + accept([:title]) + require_atomic?(false) + change(fn changeset, _ -> changeset end) + end + + update :change_title_atomic do + accept([:title]) + require_atomic?(true) + end + destroy :destroy_only_freds do change(filter(expr(title == "fred"))) end diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index 4b9319d1..351c94ac 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -7,7 +7,7 @@ defmodule AshPostgres.TestRepo do send(self(), data) end - def prefer_transaction?, do: true + def prefer_transaction?, do: false def prefer_transaction_for_atomic_updates?, do: false diff --git a/test/test_helper.exs b/test/test_helper.exs index 8438eaf9..056ebefd 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,6 @@ -ExUnit.start() +ExUnit.start(capture_log: true) + +Logger.configure(level: :debug) exclude_tags = case System.get_env("PG_VERSION") do diff --git a/test/update_test.exs b/test/update_test.exs index 953a55d9..ef6f1384 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -2,6 +2,8 @@ defmodule AshPostgres.UpdateTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post require Ash.Query + import ExUnit.CaptureLog + import Ash.Expr test "can update with nested maps" do Post @@ -60,6 +62,99 @@ defmodule AshPostgres.UpdateTest do |> Ash.update!() end + test "timestamps arent updated if there are no changes non-atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + post2 = + post + |> Ash.update!(action: :change_nothing) + + assert post.updated_at == post2.updated_at + end + + test "no queries are run if there are no changes non-atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + assert "" = + capture_log(fn -> + post + |> Ash.update!(action: :change_nothing) + end) + end + + test "queries are run if there are no changes but there are filters non-atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + assert_raise Ash.Error.Invalid, ~r/stale/, fn -> + post + |> Ash.Changeset.for_update(:change_nothing, %{}) + |> Ash.Changeset.filter(expr(title != "match")) + |> Ash.update!(action: :change_nothing) + end + end + + test "timestamps arent updated if there are no changes atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + post2 = + post + |> Ash.update!(action: :change_nothing_atomic) + + assert post.updated_at == post2.updated_at + end + + test "timestamps arent updated if nothing changes non-atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + post2 = + post + |> Ash.update!(%{title: "match"}, action: :change_title) + + assert post.updated_at == post2.updated_at + end + + test "timestamps arent updated if nothing changes atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + post2 = + post + |> Ash.update!(%{title: "match"}, action: :change_title_atomic) + + assert post.updated_at == post2.updated_at + end + + test "queries are run if there are no changes atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + assert_raise Ash.Error.Invalid, ~r/stale/, fn -> + post + |> Ash.Changeset.for_update(:change_nothing_atomic, %{}) + |> Ash.Changeset.filter(expr(title != "match")) + |> Ash.update!(action: :change_nothing) + end + end + test "can unrelate belongs_to" do author = AshPostgres.Test.Author From 866e5a282d7902aa58621a5b50140e9a4989991a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 19 Feb 2025 09:45:52 -0500 Subject: [PATCH 388/690] chore: fix for recently added source renaming handling --- lib/migration_generator/migration_generator.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 0ad2bc7f..1c35b6b0 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2312,8 +2312,7 @@ defmodule AshPostgres.MigrationGenerator do end end) - (renaming_to_source || old_attribute.source) == - attribute.source && + if (renaming_to_source || old_attribute.source) == attribute.source do attributes_unequal?( old_attribute, attribute, @@ -2322,6 +2321,7 @@ defmodule AshPostgres.MigrationGenerator do snapshot, not is_nil(renaming_to_source) ) + end end )} end) @@ -2537,7 +2537,7 @@ defmodule AshPostgres.MigrationGenerator do right = if ignore_names? do - Map.drop(left, [:source, :name]) + Map.drop(right, [:source, :name]) else right end From 9b2a0192896bea6be5fc695119363c36b71fec6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Feb 2025 09:10:48 -0500 Subject: [PATCH 389/690] chore(deps-dev): bump the dev-dependencies group with 2 updates (#489) Bumps the dev-dependencies group with 2 updates: [ex_doc](https://github.com/elixir-lang/ex_doc) and [git_ops](https://github.com/zachdaniel/git_ops). Updates `ex_doc` from 0.37.1 to 0.37.2 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.37.1...v0.37.2) Updates `git_ops` from 2.6.3 to 2.7.0 - [Changelog](https://github.com/zachdaniel/git_ops/blob/master/CHANGELOG.md) - [Commits](https://github.com/zachdaniel/git_ops/compare/v2.6.3...v2.7.0) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: git_ops dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index f96a76a5..86d790a2 100644 --- a/mix.lock +++ b/mix.lock @@ -16,11 +16,11 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.37.1", "65ca30d242082b95aa852b3b73c9d9914279fff56db5dc7b3859be5504417980", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "6774f75477733ea88ce861476db031f9399c110640752ca2b400dbbb50491224"}, + "ex_doc": {:hex, :ex_doc, "0.37.2", "2a3aa7014094f0e4e286a82aa5194a34dd17057160988b8509b15aa6c292720c", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "4dfa56075ce4887e4e8b1dcc121cd5fcb0f02b00391fd367ff5336d98fa49049"}, "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.6.3", "38c6e381b8281b86e2911fa39bea4eab2d171c86d7428786566891efb73b68c3", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a81cb6c6a2a026a4d48cb9a2e1dfca203f9283a3a70aa0c7bc171970c44f23f8"}, + "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"}, "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.25", "a9e26794efe4b5619edd112b2ce8ffa3931f1e4d558dfebcd344553024e359b5", [: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", "d944d3ed8439bb2d98391f39b86305d109f4123c947061db54c1c0f9ecad890e"}, From 5e3f12dc8d269cdd083db315b50a974bd2512b43 Mon Sep 17 00:00:00 2001 From: m0rt3nlund Date: Fri, 21 Feb 2025 15:05:37 +0100 Subject: [PATCH 390/690] fix: Ensure primary key migrations use prefix for multitenancy (#488) --- .gitignore | 1 + lib/migration_generator/operation.ex | 122 ++++++++++++------ .../tenants/composite_key/20250220073135.json | 68 ++++++++++ .../tenants/composite_key/20250220073141.json | 68 ++++++++++ .../20250220073135_migrate_resources5.exs | 32 +++++ .../20250220073141_migrate_resources6.exs | 29 +++++ test/migration_generator_test.exs | 85 +++++++++++- test/multitenancy_test.exs | 12 +- test/support/multitenancy/domain.ex | 1 + .../resources/composite_key_post.ex | 32 +++++ test_snapshot_path/test_repo/extensions.json | 10 -- 11 files changed, 406 insertions(+), 54 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json create mode 100644 priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json create mode 100644 priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs create mode 100644 priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs create mode 100644 test/support/multitenancy/resources/composite_key_post.ex delete mode 100644 test_snapshot_path/test_repo/extensions.json diff --git a/.gitignore b/.gitignore index 4fe6d351..7d849d6b 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ ash_postgres-*.tar test_migration_path test_snapshots_path +test_tenant_migration_path diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 4b8c4eae..1dc72ad7 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1055,17 +1055,24 @@ defmodule AshPostgres.MigrationGenerator.Operation do @moduledoc false defstruct [:schema, :table, :keys, no_phase: true] - def up(%{schema: schema, table: table, keys: keys}) do + def up(%{schema: schema, table: table, keys: keys, multitenancy: multitenancy}) do keys = Enum.join(keys, ", ") - if schema do - """ - execute("ALTER TABLE \\\"#{schema}.#{table}\\\" ADD PRIMARY KEY (#{keys})") - """ - else - """ - execute("ALTER TABLE \\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") - """ + cond do + multitenancy.strategy == :context -> + """ + execute("ALTER TABLE \\\"\#{prefix()}\\\".\\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + + schema -> + """ + execute("ALTER TABLE \\\"#{schema}.#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + + true -> + """ + execute("ALTER TABLE \\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ end end @@ -1082,33 +1089,54 @@ defmodule AshPostgres.MigrationGenerator.Operation do "" end - def down(%{schema: schema, table: table, remove_old?: remove_old?, keys: keys}) do + def down(%{ + schema: schema, + table: table, + remove_old?: remove_old?, + keys: keys, + multitenancy: multitenancy + }) do keys = Enum.join(keys, ", ") - if schema do - remove_old = - if remove_old? do - """ - execute("ALTER TABLE \\\"#{schema}.#{table}\\\" DROP constraint #{table}_pkey") - """ - end + cond do + multitenancy.strategy == :context -> + remove_old = + if remove_old? do + """ + execute("ALTER TABLE \\\"\#{prefix()}\\\".\\\"#{table}\\\" DROP constraint #{table}_pkey") + """ + end - """ - #{remove_old} - execute("ALTER TABLE \\\"#{schema}.#{table}\\\" ADD PRIMARY KEY (#{keys})") - """ - else - remove_old = - if remove_old? do - """ - execute("ALTER TABLE \\\"#{table}\\\" DROP constraint #{table}_pkey") - """ - end + """ + #{remove_old} + execute("ALTER TABLE \\\"\#{prefix()}\\\".\\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + + not is_nil(schema) -> + remove_old = + if remove_old? do + """ + execute("ALTER TABLE \\\"#{schema}.#{table}\\\" DROP constraint #{table}_pkey") + """ + end + + """ + #{remove_old} + execute("ALTER TABLE \\\"#{schema}.#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ + + true -> + remove_old = + if remove_old? do + """ + execute("ALTER TABLE \\\"#{table}\\\" DROP constraint #{table}_pkey") + """ + end - """ - #{remove_old} - execute("ALTER TABLE \\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") - """ + """ + #{remove_old} + execute("ALTER TABLE \\\"#{table}\\\" ADD PRIMARY KEY (#{keys})") + """ end end end @@ -1117,11 +1145,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do @moduledoc false defstruct [:schema, :table, no_phase: true] - def up(%{schema: schema, table: table}) do - if schema do - "drop constraint(#{inspect(table)}, \"#{table}_pkey\", prefix: \"#{schema}\")" - else - "drop constraint(#{inspect(table)}, \"#{table}_pkey\")" + def up(%{schema: schema, table: table, multitenancy: multitenancy}) do + cond do + multitenancy.strategy == :context -> + "drop constraint(#{inspect(table)}, \"#{table}_pkey\", prefix: prefix())" + + schema -> + "drop constraint(#{inspect(table)}, \"#{table}_pkey\", prefix: \"#{schema}\")" + + true -> + "drop constraint(#{inspect(table)}, \"#{table}_pkey\")" end end @@ -1138,7 +1171,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do "" end - def down(%{schema: schema, table: table, commented?: commented?}) do + def down(%{schema: schema, table: table, commented?: commented?, multitenancy: multitenancy}) do comment = if commented? do """ @@ -1149,10 +1182,15 @@ defmodule AshPostgres.MigrationGenerator.Operation do "" end - if schema do - "#{comment}drop constraint(#{inspect(table)}, \"#{table}_pkey\", prefix: \"#{schema}\")" - else - "#{comment}drop constraint(#{inspect(table)}, \"#{table}_pkey\")" + cond do + multitenancy.strategy == :context -> + "#{comment}drop constraint(#{inspect(table)}, \"#{table}_pkey\", prefix: prefix())" + + schema -> + "#{comment}drop constraint(#{inspect(table)}, \"#{table}_pkey\", prefix: \"#{schema}\")" + + true -> + "#{comment}drop constraint(#{inspect(table)}, \"#{table}_pkey\")" end end end diff --git a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json new file mode 100644 index 00000000..b2b0cb0c --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json @@ -0,0 +1,68 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": true, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "bigint" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "name": "composite_key_org_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_orgs" + }, + "size": null, + "source": "org_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "163B8B70E51926917188C902BA9E759A56F2C295D84FAA2AC02BF4F602139FA3", + "identities": [], + "multitenancy": { + "attribute": null, + "global": false, + "strategy": "context" + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "composite_key" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json new file mode 100644 index 00000000..253fe8fb --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json @@ -0,0 +1,68 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": true, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "bigint" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "title", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "name": "composite_key_org_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_orgs" + }, + "size": null, + "source": "org_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "4A793B2AE363407E93E81FA4CABF458C1F403432634A400B84ADDD7486D986BD", + "identities": [], + "multitenancy": { + "attribute": null, + "global": false, + "strategy": "context" + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "composite_key" +} \ No newline at end of file diff --git a/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs b/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs new file mode 100644 index 00000000..923ba511 --- /dev/null +++ b/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs @@ -0,0 +1,32 @@ +defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources5 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:composite_key, primary_key: false, prefix: prefix()) do + add(:id, :bigserial, null: false, primary_key: true) + add(:title, :text, null: false) + + add( + :org_id, + references(:multitenant_orgs, + column: :id, + prefix: "public", + name: "composite_key_org_id_fkey", + type: :uuid + ) + ) + end + end + + def down do + drop(constraint(:composite_key, "composite_key_org_id_fkey")) + + drop(table(:composite_key, prefix: prefix())) + end +end diff --git a/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs b/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs new file mode 100644 index 00000000..f5018509 --- /dev/null +++ b/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs @@ -0,0 +1,29 @@ +defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources6 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + drop(constraint("composite_key", "composite_key_pkey", prefix: prefix())) + + alter table(:composite_key, prefix: prefix()) do + modify(:title, :text) + end + + execute("ALTER TABLE \"#{prefix()}\".\"composite_key\" ADD PRIMARY KEY (id, title)") + end + + def down do + drop(constraint("composite_key", "composite_key_pkey", prefix: prefix())) + + alter table(:composite_key, prefix: prefix()) do + modify(:title, :text) + end + + execute("ALTER TABLE \"#{prefix()}\".\"composite_key\" ADD PRIMARY KEY (id)") + end +end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index c39a1578..88f76f67 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -492,6 +492,89 @@ defmodule AshPostgres.MigrationGeneratorTest do end end + describe "creating a multitenancy resource without composite key, adding it later" do + setup do + on_exit(fn -> + nil + File.rm_rf!("test_snapshots_path") + File.rm_rf!("test_migration_path") + File.rm_rf!("test_tenant_migration_path") + end) + + :ok + end + + test "create without composite key, then add extra key" do + defposts do + postgres do + schema("example") + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true, allow_nil?: false) + end + + multitenancy do + strategy(:context) + end + end + + defdomain([Post]) + + send(self(), {:mix_shell_input, :yes?, true}) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + tenant_migration_path: "test_tenant_migration_path", + quiet: false, + format: false + ) + + defposts do + postgres do + schema("example") + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true, primary_key?: true, allow_nil?: false) + end + + multitenancy do + strategy(:context) + end + end + + defdomain([Post]) + + send(self(), {:mix_shell_input, :yes?, true}) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + tenant_migration_path: "test_tenant_migration_path", + quiet: false, + format: false + ) + + assert [_file1, file2] = + Enum.sort(Path.wildcard("test_tenant_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + contents = File.read!(file2) + + [up_side, down_side] = String.split(contents, "def down", parts: 2) + + assert up_side =~ + ~S[execute("ALTER TABLE \"#{prefix()}\".\"posts\" ADD PRIMARY KEY (id, title)")] + + assert down_side =~ + ~S[execute("ALTER TABLE \"#{prefix()}\".\"posts\" ADD PRIMARY KEY (id)")] + end + end + describe "creating follow up migrations with a schema" do setup do on_exit(fn -> @@ -1156,7 +1239,7 @@ defmodule AshPostgres.MigrationGeneratorTest do test "returns code(1) if snapshots and resources don't fit", %{domain: domain} do assert catch_exit( AshPostgres.MigrationGenerator.generate(domain, - snapshot_path: "test_snapshot_path", + snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", check: true ) diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index afd5cbe5..73f9cb52 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -2,7 +2,7 @@ defmodule AshPostgres.Test.MultitenancyTest do use AshPostgres.RepoCase, async: false require Ash.Query - alias AshPostgres.MultitenancyTest.{Org, Post, User} + alias AshPostgres.MultitenancyTest.{CompositeKeyPost, Org, Post, User} alias AshPostgres.Test.Post, as: GlobalPost setup do @@ -125,6 +125,16 @@ defmodule AshPostgres.Test.MultitenancyTest do ) end + test "composite key multitenancy works", %{org1: org1} do + CompositeKeyPost + |> Ash.Changeset.for_create(:create, %{title: "foo"}) + |> Ash.Changeset.manage_relationship(:org, org1, type: :append_and_remove) + |> Ash.Changeset.set_tenant(org1) + |> Ash.create!() + + assert [_] = CompositeKeyPost |> Ash.Query.set_tenant(org1) |> Ash.read!() + end + test "loading attribute multitenant resources from context multitenant resources works" do org = Org diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 2394c234..85f078da 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -9,6 +9,7 @@ defmodule AshPostgres.MultitenancyTest.Domain do resource(AshPostgres.MultitenancyTest.PostLink) resource(AshPostgres.MultitenancyTest.NonMultitenantPostLink) resource(AshPostgres.MultitenancyTest.CrossTenantPostLink) + resource(AshPostgres.MultitenancyTest.CompositeKeyPost) end authorization do diff --git a/test/support/multitenancy/resources/composite_key_post.ex b/test/support/multitenancy/resources/composite_key_post.ex new file mode 100644 index 00000000..84f7881a --- /dev/null +++ b/test/support/multitenancy/resources/composite_key_post.ex @@ -0,0 +1,32 @@ +defmodule AshPostgres.MultitenancyTest.CompositeKeyPost do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.MultitenancyTest.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "composite_key" + repo AshPostgres.TestRepo + end + + multitenancy do + strategy(:context) + end + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + end + + attributes do + integer_primary_key(:id) + attribute(:title, :string, public?: true, allow_nil?: false, primary_key?: true) + end + + relationships do + belongs_to(:org, AshPostgres.MultitenancyTest.Org) do + public?(true) + end + end +end diff --git a/test_snapshot_path/test_repo/extensions.json b/test_snapshot_path/test_repo/extensions.json deleted file mode 100644 index e084bbff..00000000 --- a/test_snapshot_path/test_repo/extensions.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "installed": [ - "ash-functions", - "uuid-ossp", - "pg_trgm", - "citext", - "demo-functions_v1" - ], - "ash_functions_version": 3 -} \ No newline at end of file From 562caa2eec60ecfc6ec258bd884bb4c591151635 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 21 Feb 2025 09:07:19 -0500 Subject: [PATCH 391/690] test: add test for ash_sql aggregate fix --- test/aggregate_test.exs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 14ff389b..6838a0b1 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -16,6 +16,10 @@ defmodule AshSql.AggregateTest do Organization |> Ash.read!(load: [:no_cast_open_posts_count]) end + test "count aggregate on resource with no primary key with no field specified" do + assert Ash.count!(AshPostgres.Test.PostView) == 0 + end + test "relates to actor via has_many and with an aggregate" do org = Organization From 88035fe5c125b38f762238bdfaa09eae1bff4075 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 21 Feb 2025 09:09:03 -0500 Subject: [PATCH 392/690] chore: update deps --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 86d790a2..65d1af6b 100644 --- a/mix.lock +++ b/mix.lock @@ -23,7 +23,7 @@ "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"}, "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.25", "a9e26794efe4b5619edd112b2ce8ffa3931f1e4d558dfebcd344553024e359b5", [: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", "d944d3ed8439bb2d98391f39b86305d109f4123c947061db54c1c0f9ecad890e"}, + "igniter": {:hex, :igniter, "0.5.27", "7c633dd99150e9cad68285ec8ad7e15833ff0c72d46774ed3be7728c661ec4cb", [: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", "3042a71d4466e9c9b98a23d182eb02014a1c4802a35de0fa8233263d27c99550"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,7 +39,7 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.13.2", "8260c8c7159748891298b05527b754d31c8d305a00497d03e638ba84654b8797", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2ec44588d61763da544382942c0218d7f7eab454b709756c1b1b9d70ed8821a"}, + "reactor": {:hex, :reactor, "0.13.3", "8d49362564970c3331ba306213bc2416c682a04bfab0f710ac3c740060bbdc71", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b8227ed82a2aabaedc24a09e347002bb14c58701989d7383c51e941e03085180"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, From 82dd4d0346e2c7e325867d9bd8c491e0947c77dd Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 24 Feb 2025 12:15:38 -0500 Subject: [PATCH 393/690] fix: start lateral join source query bindings at 500 --- lib/data_layer.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 5fbcaa71..82142e0c 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1296,6 +1296,9 @@ defmodule AshPostgres.DataLayer do true ) }) + # This is a hack, but surely there is just no way someone writes + # a 500 binding query as the base of a lateral join query... + |> Ash.Query.set_context(%{data_layer: %{start_bindings_at: 500}}) |> Ash.Query.set_tenant(source_query.tenant) |> filter_for_records(root_data) |> set_lateral_join_prefix(query) From 5004faa6fb0775ef4e55505cc43d2f9a2b3ff1eb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 24 Feb 2025 12:25:52 -0500 Subject: [PATCH 394/690] improvement: support SKIP LOCKED in locks --- lib/data_layer.ex | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 82142e0c..17fd1110 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3214,6 +3214,13 @@ defmodule AshPostgres.DataLayer do def lock(query, unquote(lock), _) do {:ok, Ecto.Query.lock(query, [{^0, a}], fragment(unquote(frag), a))} end + + frag = "#{lock} OF ? SKIP LOCKED" + lock = "#{lock} SKIP LOCKED" + + def lock(query, unquote(lock), _) do + {:ok, Ecto.Query.lock(query, [{^0, a}], fragment(unquote(frag), a))} + end end @impl true From 89326d442377a6bf14ae35e597cf33c9c8989f43 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 24 Feb 2025 20:54:01 -0500 Subject: [PATCH 395/690] chore: update for ash_sql/ash compatibility --- lib/data_layer.ex | 38 +++++++++++++++++++++++++++++--------- test/load_test.exs | 7 +++++-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 17fd1110..b66cdfc7 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1159,10 +1159,12 @@ defmodule AshPostgres.DataLayer do {:ok, data_layer_query} -> data_layer_query = Ecto.Query.exclude(data_layer_query, :select) + through_binding = Map.get(query, :__ash_bindings__)[:current] + through_resource |> Ash.Query.new() |> Ash.Query.put_context(:data_layer, %{ - start_bindings_at: Map.get(data_layer_query, :__ash_bindings__)[:current] + start_bindings_at: through_binding }) |> Ash.Query.set_context(through_relationship.context) |> Ash.Query.do_filter(through_relationship.filter) @@ -1192,7 +1194,7 @@ defmodule AshPostgres.DataLayer do source_query, relationship.through ), - as: ^Map.get(data_layer_query, :__ash_bindings__)[:current], + as: ^through_binding, on: field(through, ^destination_attribute_on_join_resource) == field(destination, ^destination_attribute), @@ -1230,7 +1232,7 @@ defmodule AshPostgres.DataLayer do source_query, relationship.through ), - as: ^Map.get(data_layer_query, :__ash_bindings__)[:current], + as: ^through_binding, on: field(through, ^destination_attribute_on_join_resource) == field(destination, ^destination_attribute), @@ -1295,10 +1297,8 @@ defmodule AshPostgres.DataLayer do :no_inner_join?, true ) + |> Map.delete(:lateral_join_source) }) - # This is a hack, but surely there is just no way someone writes - # a 500 binding query as the base of a lateral join query... - |> Ash.Query.set_context(%{data_layer: %{start_bindings_at: 500}}) |> Ash.Query.set_tenant(source_query.tenant) |> filter_for_records(root_data) |> set_lateral_join_prefix(query) @@ -3259,12 +3259,20 @@ defmodule AshPostgres.DataLayer do def filter(query, filter, resource, opts \\ []) do used_aggregates = Ash.Filter.used_aggregates(filter, []) + query = + AshSql.Bindings.default_bindings(query, resource, AshPostgres.SqlImplementation) + query |> AshSql.Join.join_all_relationships(filter, opts) |> case do {:ok, query} -> query - |> AshSql.Aggregate.add_aggregates(used_aggregates, resource, false, 0) + |> AshSql.Aggregate.add_aggregates( + used_aggregates, + resource, + false, + query.__ash_bindings__.root_binding + ) |> case do {:ok, query} -> {:ok, AshSql.Filter.add_filter_expression(query, filter)} @@ -3280,12 +3288,24 @@ defmodule AshPostgres.DataLayer do @impl true def add_aggregates(query, aggregates, resource) do - AshSql.Aggregate.add_aggregates(query, aggregates, resource, true, 0) + AshSql.Aggregate.add_aggregates( + query, + aggregates, + resource, + true, + query.__ash_bindings__.root_binding + ) end @impl true def add_calculations(query, calculations, resource, select? \\ true) do - AshSql.Calculation.add_calculations(query, calculations, resource, 0, select?) + AshSql.Calculation.add_calculations( + query, + calculations, + resource, + query.__ash_bindings__.root_binding, + select? + ) end def add_known_binding(query, data, known_binding) do diff --git a/test/load_test.exs b/test/load_test.exs index 9261e084..63b142cd 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -990,8 +990,11 @@ defmodule AshPostgres.Test.LoadTest do |> Ash.Query.load(posts: paginated_posts) |> Ash.read!(page: [limit: 1, count: true]) - assert %Ash.Page.Offset{count: 5, results: [%{followers: %Ash.Page.Offset{count: 3}}]} = - author1.posts + assert %Ash.Page.Offset{} = page = author1.posts + assert [result] = page.results + assert %Ash.Page.Offset{} = nested_page = result.followers + assert length(nested_page.results) == 1 + assert nested_page.count == 3 end test "doesn't leak the internal count aggregate when counting" do From 545de455f098a2d0c671e3a4514bbab90c2b0afd Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 25 Feb 2025 15:16:59 -0500 Subject: [PATCH 396/690] chore: update ash & ash_sql --- mix.exs | 4 ++-- mix.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.exs b/mix.exs index c7463e23..f29966ca 100644 --- a/mix.exs +++ b/mix.exs @@ -165,8 +165,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.64")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.43")}, + {:ash, ash_version("~> 3.4 and >= 3.4.65")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.57")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index 65d1af6b..7a5ba41f 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.64", "cbc337173fada2c094aa7f852fbb82d16f7090c06272aa34feb7479d1ff91162", [: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", "f29472b64cec1c340a3f2f32ef3542b4d719a041a86678d0793442922f365709"}, + "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"}, "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"}, @@ -23,7 +23,7 @@ "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"}, "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.27", "7c633dd99150e9cad68285ec8ad7e15833ff0c72d46774ed3be7728c661ec4cb", [: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", "3042a71d4466e9c9b98a23d182eb02014a1c4802a35de0fa8233263d27c99550"}, + "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"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From e5b0acf9744548fdf19e4b1519cb718025d9d11b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 25 Feb 2025 15:19:42 -0500 Subject: [PATCH 397/690] chore: release version v2.5.6 --- CHANGELOG.md | 19 +++++++++++++++++++ mix.exs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1da8e75..18b3864e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.6](https://github.com/ash-project/ash_postgres/compare/v2.5.5...v2.5.6) (2025-02-25) + + + + +### Bug Fixes: + +* start lateral join source query bindings at 500 + +* Ensure primary key migrations use prefix for multitenancy (#488) + +* don't rewrite identities when only global? is changed + +* don't modify an attribute when it only needs to be renamed + +### Improvements: + +* support SKIP LOCKED in locks + ## [v2.5.5](https://github.com/ash-project/ash_postgres/compare/v2.5.4...v2.5.5) (2025-02-17) diff --git a/mix.exs b/mix.exs index f29966ca..1662f41b 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.5" + @version "2.5.6" def project do [ From 66293980f6118d719b258b769aacfcedaa030d81 Mon Sep 17 00:00:00 2001 From: Peter Shoukry Date: Wed, 26 Feb 2025 01:23:11 +0200 Subject: [PATCH 398/690] tests: Schema multitenancy fails (#434) --- test/aggregate_test.exs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 6838a0b1..d451f549 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -65,6 +65,40 @@ defmodule AshSql.AggregateTest do assert read_post.count_of_comments == 1 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) + |> then(& &1.total_posts) == 4 + + 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 From 01e066ecdcd59be46558138766fd980b0dda6f4b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 25 Feb 2025 18:35:53 -0500 Subject: [PATCH 399/690] chore: update tests --- mix.lock | 2 +- test/aggregate_test.exs | 34 ---------------------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/mix.lock b/mix.lock index 7a5ba41f..1985058d 100644 --- a/mix.lock +++ b/mix.lock @@ -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.58", "99eef5b24bd61432ba3b096217d034071f44afc99343a81963960fb21ccde87f", [: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", "21547dedfb8c265bf78e38645a12435bad765bf62d63fcf7a50a1a7eee91e549"}, "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"}, diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index d451f549..6838a0b1 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -65,40 +65,6 @@ defmodule AshSql.AggregateTest do assert read_post.count_of_comments == 1 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) - |> then(& &1.total_posts) == 4 - - 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 From 4202334809ee01af289d374907fb42a96f1454a1 Mon Sep 17 00:00:00 2001 From: capoccias <156086649+capoccias@users.noreply.github.com> Date: Thu, 27 Feb 2025 05:07:12 +1030 Subject: [PATCH 400/690] fix: don't rely on private function from `Ecto.Repo` (#492) --- lib/repo.ex | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/repo.ex b/lib/repo.ex index a0bb292d..02d8c703 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -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() From 9774a81d9ff0e8394b38e27f364386840cc7188d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 09:46:58 -0500 Subject: [PATCH 401/690] 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](https://github.com/ash-project/ash_sql/compare/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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 1985058d..7d624634 100644 --- a/mix.lock +++ b/mix.lock @@ -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.58", "99eef5b24bd61432ba3b096217d034071f44afc99343a81963960fb21ccde87f", [: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", "21547dedfb8c265bf78e38645a12435bad765bf62d63fcf7a50a1a7eee91e549"}, + "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"}, From 97e7a059ec601a842c78790696b83962e3128412 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 09:47:08 -0500 Subject: [PATCH 402/690] 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](https://github.com/zachdaniel/git_ops/compare/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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 7d624634..8c25021d 100644 --- a/mix.lock +++ b/mix.lock @@ -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"}, From f70cd7016cbda5794f21c894f8879b5f43c745ef Mon Sep 17 00:00:00 2001 From: Peter Shoukry Date: Thu, 27 Feb 2025 19:13:08 +0200 Subject: [PATCH 403/690] test: schema multitenant aggregates wrong tenant (#491) --- test/aggregate_test.exs | 34 +++++++++++++++++++++ test/support/multitenancy/resources/org.ex | 5 +++ test/support/multitenancy/resources/user.ex | 1 + 3 files changed, 40 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 6838a0b1..d451f549 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -65,6 +65,40 @@ defmodule AshSql.AggregateTest do assert read_post.count_of_comments == 1 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) + |> then(& &1.total_posts) == 4 + + 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 diff --git a/test/support/multitenancy/resources/org.ex b/test/support/multitenancy/resources/org.ex index 15c24e05..aa68daf4 100644 --- a/test/support/multitenancy/resources/org.ex +++ b/test/support/multitenancy/resources/org.ex @@ -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) diff --git a/test/support/multitenancy/resources/user.ex b/test/support/multitenancy/resources/user.ex index d164c28b..77149182 100644 --- a/test/support/multitenancy/resources/user.ex +++ b/test/support/multitenancy/resources/user.ex @@ -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 From 55d9b9553795f73394af7c6dfe28203c6db4ae54 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 27 Feb 2025 13:27:57 -0500 Subject: [PATCH 404/690] test: add tenant in aggregate test --- test/aggregate_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index d451f549..567edd10 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -91,8 +91,8 @@ defmodule AshSql.AggregateTest do assert Ash.load!(user, :count_visited, tenant: "org_#{org.id}") |> then(& &1.count_visited) == 4 - assert Ash.load!(org, :total_posts) - |> then(& &1.total_posts) == 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 From 8bfbcefd2a0796f0fa9ec683026e742d57a2cb1d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 28 Feb 2025 18:22:42 -0500 Subject: [PATCH 405/690] fix: check for stale record errors on destroy fixes #1831 --- lib/data_layer.ex | 13 +++++++++++-- test/destroy_test.exs | 25 +++++++++++++++++++++++++ test/support/resources/post.ex | 4 ++++ test/update_test.exs | 20 +++++++++++++++++--- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index b66cdfc7..38ceb56a 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3170,9 +3170,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) diff --git a/test/destroy_test.exs b/test/destroy_test.exs index 87ed72d0..974f2cb3 100644 --- a/test/destroy_test.exs +++ b/test/destroy_test.exs @@ -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 diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 926e3caa..93a4e0d3 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -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)) diff --git a/test/update_test.exs b/test/update_test.exs index ef6f1384..cf93b0f1 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -50,9 +50,12 @@ 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, %{ @@ -60,6 +63,17 @@ defmodule AshPostgres.UpdateTest do } ) |> 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 From 1ec8d822a3bd65401f374525a1694ab06106e35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Sun, 2 Mar 2025 23:04:36 +0100 Subject: [PATCH 406/690] fix: Use exclusion_constraint instead of check_constraint in add_exclusion_constraints (#495) --- lib/data_layer.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 38ceb56a..c0eb1cdd 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2555,13 +2555,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 +2570,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 From 20a8631ab759fe659d3296b697930c217b31c9a1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 3 Mar 2025 17:54:49 -0500 Subject: [PATCH 407/690] test: add tests for fix in `ash_sql` --- test/aggregate_test.exs | 29 +++++++++++++++++++++++++++++ test/support/resources/post.ex | 7 +++++++ 2 files changed, 36 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 567edd10..0bb25e81 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -65,6 +65,35 @@ defmodule AshSql.AggregateTest do assert read_post.count_of_comments == 1 end + test "nested filters on aggregates works" do + 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} diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 93a4e0d3..9fb97cdd 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -850,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 From de3724220047650f5e6b5826a926a70349ec3500 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Mon, 3 Mar 2025 22:09:39 -0600 Subject: [PATCH 408/690] fix: handle errors from identities in polymorphic resources properly (#497) --- lib/data_layer.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index c0eb1cdd..d09c88e2 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -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, From 9a047a23a98e2649527b88fb897ffa56f09be0e0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 4 Mar 2025 10:52:13 -0500 Subject: [PATCH 409/690] chore: release version v2.5.7 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18b3864e..fc401cfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [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) diff --git a/mix.exs b/mix.exs index 1662f41b..0cb046cd 100644 --- a/mix.exs +++ b/mix.exs @@ -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 [ From b368150aceff8bb5d2f24f100a2cbd147640fc67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 07:30:50 -0800 Subject: [PATCH 410/690] chore(deps): bump the production-dependencies group with 3 updates (#499) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.4.65 to 3.4.67 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.65...v3.4.67) Updates `ash_sql` from 0.2.59 to 0.2.60 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.59...v0.2.60) Updates `igniter` from 0.5.29 to 0.5.31 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.29...v0.5.31) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 8c25021d..dd709088 100644 --- a/mix.lock +++ b/mix.lock @@ -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.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"}, + "ash": {:hex, :ash, "3.4.67", "b2e3e65ddff550998a5c8dd1fc7f8ef4d7ebfe75a474c1e620e9b51b3ff5f70d", [: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", "770a637208ef0be5b9778687efb55be7b4f75d0202f80ddc4b1b918a8282ba28"}, + "ash_sql": {:hex, :ash_sql, "0.2.60", "3920e05ba34df913f4e32c7395480687a0372db7c2725b7c7c390b432e28be08", [: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", "dcc3eb8277ccb456cd9ff1e4d9b06699ce9f0502c1dfefee388eb1850817e77e"}, "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"}, @@ -23,7 +23,7 @@ "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"}, + "igniter": {:hex, :igniter, "0.5.31", "efee5efb94bcfce37d317ab54c54b979d8864bf9b76aafded82f7bb52a306076", [: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", "4f0c9456135444286ae89b22db10f8f1ad18932ccd4935bc14a5ad41704e5a1f"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,7 +39,7 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.13.3", "8d49362564970c3331ba306213bc2416c682a04bfab0f710ac3c740060bbdc71", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b8227ed82a2aabaedc24a09e347002bb14c58701989d7383c51e941e03085180"}, + "reactor": {:hex, :reactor, "0.14.0", "8dc5d4946391010bf9fa7b58dd1e75d3c1cf97315e5489b7797cf64b82ae27a4", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9cf5068e4042791c150f0dfbc00f4f435433eb948036b44b95b940e457b35a6a"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, @@ -47,7 +47,7 @@ "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, "spark": {:hex, :spark, "2.2.45", "19e3a879e80d02853ded85ed7b4c0a84a5d2e395f9d0c884e1a13afbe026929d", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "70b272d0ee16e3c10a4f8cf0ef6152840828152e68f2f8e3046e89567f2b49ad"}, "spitfire": {:hex, :spitfire, "0.1.5", "10b041e781bff9544d2fdf00893e1a325758408c5366a9bfa4333072568659b1", [:mix], [], "hexpm", "866a55d21fe827934ff38200111335c9dd311df13cbf2580ed71d84b0a783150"}, - "splode": {:hex, :splode, "0.2.8", "289d4eec13e7a83061bc44827877eb4c575e1fdf198bd1a9c6449f9b64805059", [:mix], [], "hexpm", "dbe92fa526589416435e12203b56db1f74c834d207bc474016cedf930d987284"}, + "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.3", "15fdb14c64e84437901258bb56fc7d80aaf6ceaf85b9324f359e219241353bfb", [:mix], [], "hexpm", "859eb2be72d74be26c1c4f272905667672a52e44f743839c57c7ee73a1a66420"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, From 4bc657cf53e4e4021081adc3da951c6d1eb6b0a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 07:31:08 -0800 Subject: [PATCH 411/690] chore(deps-dev): bump git_ops in the dev-dependencies group (#500) Bumps the dev-dependencies group with 1 update: [git_ops](https://github.com/zachdaniel/git_ops). Updates `git_ops` from 2.7.1 to 2.7.2 - [Changelog](https://github.com/zachdaniel/git_ops/blob/master/CHANGELOG.md) - [Commits](https://github.com/zachdaniel/git_ops/compare/v2.7.1...v2.7.2) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index dd709088..be0b5734 100644 --- a/mix.lock +++ b/mix.lock @@ -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.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"}, + "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "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.31", "efee5efb94bcfce37d317ab54c54b979d8864bf9b76aafded82f7bb52a306076", [: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", "4f0c9456135444286ae89b22db10f8f1ad18932ccd4935bc14a5ad41704e5a1f"}, From 78b75a4295ae268b0b9b68ea8312cb8766662b51 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 08:21:03 -0800 Subject: [PATCH 412/690] fix: compose check constraints and base filters properly check constraints should ignore anything ignored by the base filter fixes #501 --- lib/migration_generator/operation.ex | 2 +- test/migration_generator_test.exs | 41 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 1dc72ad7..b3d4a28e 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1335,7 +1335,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do table: table }) do if base_filter do - "create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{base_filter} AND #{check}\")", option(:prefix, schema)])}" + "create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"(#{check}) OR NOT (#{base_filter})\")", option(:prefix, schema)])}" else "create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{check}\")", option(:prefix, schema)])}" end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 88f76f67..706967fb 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -1967,6 +1967,47 @@ defmodule AshPostgres.MigrationGeneratorTest do ~S[create constraint(:posts, :price_must_be_positive, check: "price > 0")] end + test "base filters are taken into account, negated" do + defposts do + attributes do + uuid_primary_key(:id) + attribute(:price, :integer, public?: true) + end + + resource do + base_filter(expr(price > 10)) + end + + postgres do + base_filter_sql "price > -10" + + check_constraints do + check_constraint(:price, "price_must_be_positive", check: "price > 0") + end + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert file = + "test_migration_path/**/*_migrate_resources*.exs" + |> Path.wildcard() + |> Enum.reject(&String.contains?(&1, "extensions")) + |> Enum.sort() + |> Enum.at(0) + |> File.read!() + + assert file =~ + ~S[create constraint(:posts, :price_must_be_positive, check: "(price > 0) OR NOT (price > -10)")] + end + test "when removed, the constraint is dropped before modification" do defposts do attributes do From 8be23b4a17f4b95b07d6f489ed808dc902ffca7f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 10:54:08 -0800 Subject: [PATCH 413/690] fix: handle CLI args better for ash_postgres.gen.resources --- lib/mix/tasks/ash_postgres.gen.resources.ex | 8 +++++--- lib/resource_generator/resource_generator.ex | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index bd6c4a36..03d87bfe 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -73,9 +73,11 @@ if Code.ensure_loaded?(Igniter) do options = options!(argv) repos = - options[:repo] || - Mix.Project.config()[:app] - |> Application.get_env(:ecto_repos, []) + case options[:repo] do + [] -> + Mix.Project.config()[:app] + |> Application.get_env(:ecto_repos, []) + end repos = repos diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index f67e79c3..ea03a95e 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -16,6 +16,24 @@ if Code.ensure_loaded?(Igniter) do opts = handle_csv_opts(opts, [:tables, :skip_tables, :extend]) + opts = + Keyword.update(opts, :tables, nil, fn tables -> + if tables == [] do + nil + else + tables + end + end) + + opts = + Keyword.update(opts, :skip_tables, nil, fn tables -> + if tables == [] do + nil + else + tables + end + end) + specs = repos |> Enum.flat_map(&Spec.tables(&1, skip_tables: opts[:skip_tables], tables: opts[:tables])) From d0cf6c2b8abc1271b961474f3bad3c0205e90897 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 10:54:55 -0800 Subject: [PATCH 414/690] chore: release version v2.5.8 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc401cfa..ea5995bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.8](https://github.com/ash-project/ash_postgres/compare/v2.5.7...v2.5.8) (2025-03-06) + + + + +### Bug Fixes: + +* handle CLI args better for ash_postgres.gen.resources + +* compose check constraints and base filters properly + ## [v2.5.7](https://github.com/ash-project/ash_postgres/compare/v2.5.6...v2.5.7) (2025-03-04) diff --git a/mix.exs b/mix.exs index 0cb046cd..f4214c34 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.7" + @version "2.5.8" def project do [ From 78d7fdda6ed01225b0ac115f6d8db7cf4d97de8b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 11:08:56 -0800 Subject: [PATCH 415/690] improvement: add `--public` option to `gen.resources`, default `true` this defaults attributes and relationships to public improvement: add `--default-actions` option to `gen.resources`, default `true` this adds default CRUD actions to the generated tables --- lib/mix/tasks/ash_postgres.gen.resources.ex | 8 +++ lib/resource_generator/resource_generator.ex | 59 ++++++++++++++++---- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 03d87bfe..f6044062 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -26,6 +26,8 @@ if Code.ensure_loaded?(Igniter) do - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. - `extend`, `e` - Extension or extensions to apply to the generated resources. See `mix ash.patch.extend` for more. - `yes`, `y` - Answer yes (or skip) to all questions. + - `default-actions` - Add default actions for each resource. Defaults to `true`. + - `public` - Mark all attributes and relationships as `public? true`. Defaults to `true`. ## Tables @@ -47,6 +49,8 @@ if Code.ensure_loaded?(Igniter) do yes: :boolean, tables: :keep, skip_tables: :keep, + default_actions: :boolean, + public: :boolean, extend: :keep, snapshots_only: :boolean, domain: :keep @@ -58,6 +62,10 @@ if Code.ensure_loaded?(Igniter) do e: :extend, d: :domain, s: :skip_tables + ], + defaults: [ + default_actions: true, + public: true ] } end diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index ea03a95e..f7845211 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -103,6 +103,8 @@ if Code.ensure_loaded?(Igniter) do domain: #{inspect(domain)}, data_layer: AshPostgres.DataLayer + #{default_actions(opts)} + postgres do table #{inspect(table_spec.table_name)} repo #{inspect(table_spec.repo)} @@ -115,11 +117,11 @@ if Code.ensure_loaded?(Igniter) do end attributes do - #{attributes(table_spec)} + #{attributes(table_spec, opts)} end """ |> add_identities(table_spec) - |> add_relationships(table_spec) + |> add_relationships(table_spec, opts) igniter |> Ash.Domain.Igniter.add_resource_reference(domain, table_spec.resource) @@ -135,6 +137,27 @@ if Code.ensure_loaded?(Igniter) do end) end + defp default_actions(opts) do + cond do + opts[:default_actions] && opts[:public] -> + """ + actions do + defaults [:read, :destroy, create: :*, update: :*] + end + """ + + opts[:default_actions] -> + """ + actions do + defaults [:read, :destroy, create: :*, update: :*] + end + """ + + true -> + "" + end + end + defp check_constraints(%{check_constraints: _check_constraints}, true) do "" end @@ -257,14 +280,14 @@ if Code.ensure_loaded?(Igniter) do defp add_nils_distinct?(str, _), do: str - defp add_relationships(str, %{relationships: []}) do + defp add_relationships(str, %{relationships: []}, _opts) do str end - defp add_relationships(str, %{relationships: relationships} = spec) do + defp add_relationships(str, %{relationships: relationships} = spec, opts) do relationships |> Enum.map_join("\n", fn relationship -> - case relationship_options(spec, relationship) do + case relationship_options(spec, relationship, opts) do "" -> "#{relationship.type} :#{relationship.name}, #{inspect(relationship.destination)}" @@ -287,7 +310,7 @@ if Code.ensure_loaded?(Igniter) do end) end - defp relationship_options(spec, %{type: :belongs_to} = rel) do + defp relationship_options(spec, %{type: :belongs_to} = rel, opts) do case Enum.find(spec.attributes, fn attribute -> attribute.name == rel.source_attribute end) do @@ -303,6 +326,7 @@ if Code.ensure_loaded?(Igniter) do |> add_source_attribute(rel, "#{rel.name}_id") |> add_allow_nil(rel) |> add_filter(rel) + |> add_public(opts) attribute -> "" @@ -312,10 +336,11 @@ if Code.ensure_loaded?(Igniter) do |> add_primary_key(attribute.primary_key?) |> add_attribute_type(attribute) |> add_filter(rel) + |> add_public(opts) end end - defp relationship_options(_spec, rel) do + defp relationship_options(_spec, rel, opts) do default_destination_attribute = rel.source |> Module.split() @@ -327,6 +352,7 @@ if Code.ensure_loaded?(Igniter) do |> add_destination_attribute(rel, default_destination_attribute) |> add_source_attribute(rel, "id") |> add_filter(rel) + |> add_public(opts) end defp add_filter(str, %{match_with: []}), do: str @@ -544,7 +570,7 @@ if Code.ensure_loaded?(Igniter) do defp add_include(str, include), do: str <> "\ninclude [#{Enum.map_join(include, ", ", &inspect/1)}]" - defp attributes(table_spec) do + defp attributes(table_spec, opts) do table_spec.attributes |> Enum.split_with(& &1.default) |> then(fn {l, r} -> r ++ l end) @@ -560,10 +586,10 @@ if Code.ensure_loaded?(Igniter) do end) end end) - |> Enum.map_join("\n", &attribute(&1)) + |> Enum.map_join("\n", &attribute(&1, opts)) end - defp attribute(attribute) do + defp attribute(attribute, opts) do now_default = &DateTime.utc_now/0 uuid_default = &Ash.UUID.generate/0 @@ -593,7 +619,7 @@ if Code.ensure_loaded?(Igniter) do {"attribute", attribute, true, false} end - case String.trim(options(attribute, type_option?)) do + case String.trim(options(attribute, type_option?, opts)) do "" -> if type? do "#{constructor} :#{attribute.name}, #{inspect(attribute.attr_type)}" @@ -618,7 +644,7 @@ if Code.ensure_loaded?(Igniter) do end end - defp options(attribute, type_option?) do + defp options(attribute, type_option?, opts) do "" |> add_primary_key(attribute) |> add_allow_nil(attribute) @@ -626,9 +652,18 @@ if Code.ensure_loaded?(Igniter) do |> add_default(attribute) |> add_type(attribute, type_option?) |> add_generated(attribute) + |> add_public(opts) |> add_source(attribute) end + defp add_public(str, options) do + if options[:public] do + str <> "\n public? true" + else + str + end + end + defp add_type(str, %{attr_type: attr_type}, true) do str <> "\n type #{inspect(attr_type)}" end From a7fbfe38a843e1618be8ec9846a4e8675d3e02ea Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 11:17:01 -0800 Subject: [PATCH 416/690] fix: match on non-empty repo options --- lib/mix/tasks/ash_postgres.gen.resources.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index f6044062..dbe31377 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -85,6 +85,9 @@ if Code.ensure_loaded?(Igniter) do [] -> Mix.Project.config()[:app] |> Application.get_env(:ecto_repos, []) + + repos -> + repos end repos = From 0f9a0130608b45bd5828c387027cf8feed73775d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 11:19:36 -0800 Subject: [PATCH 417/690] chore: fix tests --- test/resource_generator_test.exs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index 30a14a1a..c50292aa 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -32,18 +32,31 @@ defmodule AshPostgres.ResourceGeenratorTests do domain: MyApp.Accounts, data_layer: AshPostgres.DataLayer + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + postgres do table("example_table") repo(AshPostgres.TestRepo) end attributes do - uuid_primary_key(:id) - attribute(:name, :string) - attribute(:age, :integer) + uuid_primary_key :id do + public?(true) + end + + attribute :name, :string do + public?(true) + end + + attribute :age, :integer do + public?(true) + end attribute :email, :string do sensitive?(true) + public?(true) end end end From f61fa269246bbcc0d0f1d5db06ebb47a4ebf4167 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 11:19:45 -0800 Subject: [PATCH 418/690] chore: release version v2.5.9 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea5995bf..47c09f98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.9](https://github.com/ash-project/ash_postgres/compare/v2.5.8...v2.5.9) (2025-03-06) + + + + +### Bug Fixes: + +* match on non-empty repo options + +### Improvements: + +* add `--public` option to `gen.resources`, default `true` + +* add `--default-actions` option to `gen.resources`, default `true` + ## [v2.5.8](https://github.com/ash-project/ash_postgres/compare/v2.5.7...v2.5.8) (2025-03-06) diff --git a/mix.exs b/mix.exs index f4214c34..0a9982c8 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.8" + @version "2.5.9" def project do [ From c3d7adbe59efe6a053cf497a238b97bc4448cd73 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 14:26:27 -0800 Subject: [PATCH 419/690] improvement: never import `schema_migrations` table --- lib/mix/tasks/ash_postgres.gen.resources.ex | 2 +- lib/resource_generator/resource_generator.ex | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index dbe31377..44af31cf 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -22,7 +22,7 @@ if Code.ensure_loaded?(Igniter) do - `repo`, `r` - The repo or repos to generate resources for, comma separated. Can be specified multiple times. Defaults to all repos. - `tables`, `t` - Defaults to `public.*`. The tables to generate resources for, comma separated. Can be specified multiple times. See the section on tables for more. - - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. + - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. `schema_migrations` is always skipped. - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. - `extend`, `e` - Extension or extensions to apply to the generated resources. See `mix ash.patch.extend` for more. - `yes`, `y` - Answer yes (or skip) to all questions. diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index f7845211..d44cc296 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -28,10 +28,11 @@ if Code.ensure_loaded?(Igniter) do opts = Keyword.update(opts, :skip_tables, nil, fn tables -> if tables == [] do - nil + [] else tables end + |> Enum.concat("schema_migrations") end) specs = From f1d2815ca39ea5c5be8a427b7a2451e5b5db0d0d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 14:32:24 -0800 Subject: [PATCH 420/690] fix: honor skip_tables --- lib/resource_generator/resource_generator.ex | 3 ++- lib/resource_generator/spec.ex | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index d44cc296..c6a7c5e3 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -32,8 +32,9 @@ if Code.ensure_loaded?(Igniter) do else tables end - |> Enum.concat("schema_migrations") + |> Enum.concat(["schema_migrations"]) end) + |> IO.inspect() specs = repos diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index a813e600..5df21716 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -114,6 +114,9 @@ defmodule AshPostgres.ResourceGenerator.Spec do |> add_indexes() |> add_check_constraints() end) + |> Enum.reject(fn spec -> + spec.table_name in List.wrap(opts[:skip_tables]) + end) end) result From e9b544534b4b47d30881feddfab42d62d34c65fb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 14:32:55 -0800 Subject: [PATCH 421/690] chore: remove IO.inspect --- lib/resource_generator/resource_generator.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index c6a7c5e3..3b917d4c 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -34,7 +34,6 @@ if Code.ensure_loaded?(Igniter) do end |> Enum.concat(["schema_migrations"]) end) - |> IO.inspect() specs = repos From 17406f34e48db57b4cb232aac2a886f7457d85f9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 14:34:14 -0800 Subject: [PATCH 422/690] chore: release version v2.5.10 --- CHANGELOG.md | 13 +++++++++++++ mix.exs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47c09f98..b80e9117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.10](https://github.com/ash-project/ash_postgres/compare/v2.5.9...v2.5.10) (2025-03-06) + + + + +### Bug Fixes: + +* honor skip_tables + +### Improvements: + +* never import `schema_migrations` table + ## [v2.5.9](https://github.com/ash-project/ash_postgres/compare/v2.5.8...v2.5.9) (2025-03-06) diff --git a/mix.exs b/mix.exs index 0a9982c8..34035006 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.9" + @version "2.5.10" def project do [ From ccbb2a80380b181110880f85a81d0a1148ffd2b1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 17:36:34 -0800 Subject: [PATCH 423/690] fix: only configure repo in installer if not already configured fix: install ash if not installed already --- lib/mix/tasks/ash_postgres.install.ex | 330 +++++++++++++++----------- 1 file changed, 193 insertions(+), 137 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 636fe999..0a14c370 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -35,6 +35,26 @@ if Code.ensure_loaded?(Igniter) do otp_app = Igniter.Project.Application.app_name(igniter) + igniter = + if Igniter.Project.Deps.has_dep?(igniter, :ash) do + igniter + |> Igniter.Project.Deps.add_dep({:ash, "~> 3.0"}, yes: opts[:yes]) + |> then(fn + %{assigns: %{test_mode?: true}} = igniter -> + igniter + + igniter -> + Igniter.apply_and_fetch_dependencies(igniter, + error_on_abort?: true, + yes: opts[:yes], + yes_to_deps: true + ) + end) + |> Igniter.compose_task("ash.install", argv) + else + igniter + end + igniter |> Igniter.Project.Formatter.import_dep(:ash_postgres) |> setup_aliases() @@ -117,75 +137,97 @@ if Code.ensure_loaded?(Igniter) do end defp configure_runtime(igniter, otp_app, repo) do - default_runtime = """ - import Config - - if config_env() == :prod do - database_url = - System.get_env("DATABASE_URL") || - raise \"\"\" - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - \"\"\" - - config #{inspect(otp_app)}, #{inspect(repo)}, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") - end - """ - - igniter - |> Igniter.create_or_update_elixir_file("config/runtime.exs", default_runtime, fn zipper -> - if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo, :url]) do - zipper - else - patterns = [ - """ - if config_env() == :prod do - __cursor__() - end - """, - """ - if :prod == config_env() do - __cursor__() - end - """ - ] + if Igniter.Project.Config.configures_key?(igniter, "runtime.exs", otp_app, [repo]) do + igniter + else + default_runtime = """ + import Config + + if config_env() == :prod do + database_url = + System.get_env("DATABASE_URL") || + raise \"\"\" + environment variable DATABASE_URL is missing. + For example: ecto://USER:PASS@HOST/DATABASE + \"\"\" + + config #{inspect(otp_app)}, #{inspect(repo)}, + url: database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + end + """ - zipper - |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) - |> case do - {:ok, zipper} -> - case Igniter.Code.Function.move_to_function_call_in_current_scope( - zipper, - :=, - 2, - fn call -> - Igniter.Code.Function.argument_matches_pattern?( - call, - 0, - {:database_url, _, ctx} when is_atom(ctx) - ) - end - ) do - {:ok, _zipper} -> - zipper - |> Igniter.Project.Config.modify_configuration_code( - [repo, :url], - otp_app, - {:database_url, [], nil} - ) - |> Igniter.Project.Config.modify_configuration_code( - [repo, :pool_size], - otp_app, - Sourceror.parse_string!(""" - String.to_integer(System.get_env("POOL_SIZE") || "10") - """) - ) - |> then(&{:ok, &1}) - - _ -> + igniter + |> Igniter.create_or_update_elixir_file( + "config/runtime.exs", + default_runtime, + fn zipper -> + if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo, :url]) do + zipper + else + patterns = [ + """ + if config_env() == :prod do + __cursor__() + end + """, + """ + if :prod == config_env() do + __cursor__() + end + """ + ] + + zipper + |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) + |> case do + {:ok, zipper} -> + case Igniter.Code.Function.move_to_function_call_in_current_scope( + zipper, + :=, + 2, + fn call -> + Igniter.Code.Function.argument_matches_pattern?( + call, + 0, + {:database_url, _, ctx} when is_atom(ctx) + ) + end + ) do + {:ok, _zipper} -> + zipper + |> Igniter.Project.Config.modify_configuration_code( + [repo, :url], + otp_app, + {:database_url, [], nil} + ) + |> Igniter.Project.Config.modify_configuration_code( + [repo, :pool_size], + otp_app, + Sourceror.parse_string!(""" + String.to_integer(System.get_env("POOL_SIZE") || "10") + """) + ) + |> then(&{:ok, &1}) + + _ -> + Igniter.Code.Common.add_code(zipper, """ + database_url = + System.get_env("DATABASE_URL") || + raise \"\"\" + environment variable DATABASE_URL is missing. + For example: ecto://USER:PASS@HOST/DATABASE + \"\"\" + + config #{inspect(otp_app)}, Helpdesk.Repo, + url: database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + """) + end + + :error -> Igniter.Code.Common.add_code(zipper, """ + if config_env() == :prod do database_url = System.get_env("DATABASE_URL") || raise \"\"\" @@ -196,86 +238,100 @@ if Code.ensure_loaded?(Igniter) do config #{inspect(otp_app)}, Helpdesk.Repo, url: database_url, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + end """) end - - :error -> - Igniter.Code.Common.add_code(zipper, """ - if config_env() == :prod do - database_url = - System.get_env("DATABASE_URL") || - raise \"\"\" - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - \"\"\" - - config #{inspect(otp_app)}, Helpdesk.Repo, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") - end - """) + end end - end - end) + ) + end end defp configure_dev(igniter, otp_app, repo) do - igniter - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :username], "postgres") - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :password], "postgres") - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :hostname], "localhost") - |> Igniter.Project.Config.configure_new( - "dev.exs", - otp_app, - [repo, :database], - "#{otp_app}_dev" - ) - |> Igniter.Project.Config.configure_new( - "dev.exs", - otp_app, - [repo, :show_sensitive_data_on_connection_error], - true - ) - |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :pool_size], 10) + if Igniter.Project.Config.configures_key?(igniter, "dev.exs", otp_app, [repo]) do + igniter + else + igniter + |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :username], "postgres") + |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :password], "postgres") + |> Igniter.Project.Config.configure_new( + "dev.exs", + otp_app, + [repo, :hostname], + "localhost" + ) + |> Igniter.Project.Config.configure_new( + "dev.exs", + otp_app, + [repo, :database], + "#{otp_app}_dev" + ) + |> Igniter.Project.Config.configure_new( + "dev.exs", + otp_app, + [repo, :show_sensitive_data_on_connection_error], + true + ) + |> Igniter.Project.Config.configure_new("dev.exs", otp_app, [repo, :pool_size], 10) + end end defp configure_test(igniter, otp_app, repo) do - database = - {:<<>>, [], - [ - "#{otp_app}_test", - {:"::", [], - [ - {{:., [], [Kernel, :to_string]}, [from_interpolation: true], - [ - {{:., [], [{:__aliases__, [alias: false], [:System]}, :get_env]}, [], - ["MIX_TEST_PARTITION"]} - ]}, - {:binary, [], Elixir} - ]} - ]} - |> Sourceror.to_string() - |> Sourceror.parse_string!() + if Igniter.Project.Config.configures_key?(igniter, "test.exs", otp_app, [repo]) do + igniter + else + database = + {:<<>>, [], + [ + "#{otp_app}_test", + {:"::", [], + [ + {{:., [], [Kernel, :to_string]}, [from_interpolation: true], + [ + {{:., [], [{:__aliases__, [alias: false], [:System]}, :get_env]}, [], + ["MIX_TEST_PARTITION"]} + ]}, + {:binary, [], Elixir} + ]} + ]} + |> Sourceror.to_string() + |> Sourceror.parse_string!() - igniter - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :username], "postgres") - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :password], "postgres") - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :hostname], "localhost") - |> Igniter.Project.Config.configure_new( - "test.exs", - otp_app, - [repo, :database], - {:code, database} - ) - |> Igniter.Project.Config.configure_new( - "test.exs", - otp_app, - [repo, :pool], - Ecto.Adapters.SQL.Sandbox - ) - |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :pool_size], 10) - |> Igniter.Project.Config.configure_new("test.exs", :ash, [:disable_async?], true) - |> Igniter.Project.Config.configure_new("test.exs", :logger, [:level], :warning) + igniter + |> Igniter.Project.Config.configure_new( + "test.exs", + otp_app, + [repo, :username], + "postgres" + ) + |> Igniter.Project.Config.configure_new( + "test.exs", + otp_app, + [repo, :password], + "postgres" + ) + |> Igniter.Project.Config.configure_new( + "test.exs", + otp_app, + [repo, :hostname], + "localhost" + ) + |> Igniter.Project.Config.configure_new( + "test.exs", + otp_app, + [repo, :database], + {:code, database} + ) + |> Igniter.Project.Config.configure_new( + "test.exs", + otp_app, + [repo, :pool], + Ecto.Adapters.SQL.Sandbox + ) + |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :pool_size], 10) + |> Igniter.Project.Config.configure_new("test.exs", :ash, [:disable_async?], true) + |> Igniter.Project.Config.configure_new("test.exs", :logger, [:level], :warning) + end end defp setup_data_case(igniter) do From fd1aaea4e4d48e35ecae828d43520162d2184ef5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 17:45:14 -0800 Subject: [PATCH 424/690] =?UTF-8?q?fix:=20don't=20modify=20repo=20in=20run?= =?UTF-8?q?time.exs=20fix:=20remove=20Helpdesk.Repo=20from=20installer=20?= =?UTF-8?q?=F0=9F=A4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/mix/tasks/ash_postgres.install.ex | 90 ++++++++++++++------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 0a14c370..25edef3a 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -162,8 +162,8 @@ if Code.ensure_loaded?(Igniter) do "config/runtime.exs", default_runtime, fn zipper -> - if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo, :url]) do - zipper + if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo]) do + {:ok, zipper} else patterns = [ """ @@ -182,47 +182,51 @@ if Code.ensure_loaded?(Igniter) do |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do {:ok, zipper} -> - case Igniter.Code.Function.move_to_function_call_in_current_scope( - zipper, - :=, - 2, - fn call -> - Igniter.Code.Function.argument_matches_pattern?( - call, - 0, - {:database_url, _, ctx} when is_atom(ctx) - ) - end - ) do - {:ok, _zipper} -> - zipper - |> Igniter.Project.Config.modify_configuration_code( - [repo, :url], - otp_app, - {:database_url, [], nil} - ) - |> Igniter.Project.Config.modify_configuration_code( - [repo, :pool_size], - otp_app, - Sourceror.parse_string!(""" - String.to_integer(System.get_env("POOL_SIZE") || "10") + if Igniter.Project.Config.configures_key?(zipper, "runtime.exs", otp_app, [repo]) do + {:ok, zipper} + else + case Igniter.Code.Function.move_to_function_call_in_current_scope( + zipper, + :=, + 2, + fn call -> + Igniter.Code.Function.argument_matches_pattern?( + call, + 0, + {:database_url, _, ctx} when is_atom(ctx) + ) + end + ) do + {:ok, _zipper} -> + zipper + |> Igniter.Project.Config.modify_configuration_code( + [repo, :url], + otp_app, + {:database_url, [], nil} + ) + |> Igniter.Project.Config.modify_configuration_code( + [repo, :pool_size], + otp_app, + Sourceror.parse_string!(""" + String.to_integer(System.get_env("POOL_SIZE") || "10") + """) + ) + |> then(&{:ok, &1}) + + _ -> + Igniter.Code.Common.add_code(zipper, """ + database_url = + System.get_env("DATABASE_URL") || + raise \"\"\" + environment variable DATABASE_URL is missing. + For example: ecto://USER:PASS@HOST/DATABASE + \"\"\" + + config #{inspect(otp_app)}, #{inspect(repo)}, + url: database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") """) - ) - |> then(&{:ok, &1}) - - _ -> - Igniter.Code.Common.add_code(zipper, """ - database_url = - System.get_env("DATABASE_URL") || - raise \"\"\" - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - \"\"\" - - config #{inspect(otp_app)}, Helpdesk.Repo, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") - """) + end end :error -> @@ -235,7 +239,7 @@ if Code.ensure_loaded?(Igniter) do For example: ecto://USER:PASS@HOST/DATABASE \"\"\" - config #{inspect(otp_app)}, Helpdesk.Repo, + config #{inspect(otp_app)}, #{inspect(repo)}, url: database_url, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") end From c9dba9f011d351093ac4460d92a2934210889f8d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 17:49:39 -0800 Subject: [PATCH 425/690] fix: use `configures_key?/3` --- lib/mix/tasks/ash_postgres.install.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 25edef3a..d2587f7d 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -169,6 +169,7 @@ if Code.ensure_loaded?(Igniter) do """ if config_env() == :prod do __cursor__() + end """, """ @@ -182,7 +183,7 @@ if Code.ensure_loaded?(Igniter) do |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do {:ok, zipper} -> - if Igniter.Project.Config.configures_key?(zipper, "runtime.exs", otp_app, [repo]) do + if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo]) do {:ok, zipper} else case Igniter.Code.Function.move_to_function_call_in_current_scope( From bfd0100b1d6fc68077d2df124bdc025de0ac2003 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 17:54:31 -0800 Subject: [PATCH 426/690] fix: go to top of if block --- lib/mix/tasks/ash_postgres.install.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index d2587f7d..dabc3ac0 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -169,7 +169,6 @@ if Code.ensure_loaded?(Igniter) do """ if config_env() == :prod do __cursor__() - end """, """ @@ -179,6 +178,8 @@ if Code.ensure_loaded?(Igniter) do """ ] + zipper = zipper |> Sourceror.Zipper.up() |> Sourceror.Zipper.down() + zipper |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do From 3264f3b19c6962083be224b19ec67a7eef9211ce Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 17:56:19 -0800 Subject: [PATCH 427/690] fix: put move up/down in the right place --- lib/mix/tasks/ash_postgres.install.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index dabc3ac0..ddec5373 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -178,12 +178,12 @@ if Code.ensure_loaded?(Igniter) do """ ] - zipper = zipper |> Sourceror.Zipper.up() |> Sourceror.Zipper.down() - zipper |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do {:ok, zipper} -> + zipper = zipper |> Sourceror.Zipper.up() |> Sourceror.Zipper.down() + if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo]) do {:ok, zipper} else From a2f53b43c50fa171884389be4dc77a2bd8fb7552 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 6 Mar 2025 17:58:17 -0800 Subject: [PATCH 428/690] chore: undo bad fix --- lib/mix/tasks/ash_postgres.install.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index ddec5373..555d89e7 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -182,8 +182,6 @@ if Code.ensure_loaded?(Igniter) do |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) |> case do {:ok, zipper} -> - zipper = zipper |> Sourceror.Zipper.up() |> Sourceror.Zipper.down() - if Igniter.Project.Config.configures_key?(zipper, otp_app, [repo]) do {:ok, zipper} else From a0ca24250407a3d38333521b7333dcff8df493c8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Mar 2025 09:41:07 -0800 Subject: [PATCH 429/690] fix: allow optional input for relationship name guesser fixes #503 --- lib/resource_generator/spec.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 5df21716..6f90b53f 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -777,7 +777,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do |> String.trim_trailing() end - Owl.IO.input(label: label) + Owl.IO.input(label: label, optional: true) |> String.trim() # common typo |> String.trim_leading(":") From c0b49720fecb4ac6f784aeebe1f31b1d22eb1d9e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Mar 2025 09:48:52 -0800 Subject: [PATCH 430/690] improvement: add `skip_unknown` option to `ash_postgres.gen.resources` --- lib/mix/tasks/ash_postgres.gen.resources.ex | 1 + lib/resource_generator/spec.ex | 88 +++++++++++---------- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 44af31cf..a47a0048 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -52,6 +52,7 @@ if Code.ensure_loaded?(Igniter) do default_actions: :boolean, public: :boolean, extend: :keep, + skip_unknown: :boolean, snapshots_only: :boolean, domain: :keep ], diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 6f90b53f..95aab278 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -738,57 +738,61 @@ defmodule AshPostgres.ResourceGenerator.Spec do defp name_all_relationships(_type, _opts, _spec, _name, [], acc), do: acc defp name_all_relationships(type, opts, spec, name, [relationship | rest], acc) do - label = - case type do - :belongs_to -> - """ - Multiple foreign keys found from `#{inspect(spec.resource)}` to `#{inspect(relationship.destination)}` with the guessed name `#{name}`. + if opts[:yes?] || opts[:skip_unknown] do + name_all_relationships(type, opts, spec, name, rest, acc) + else + label = + case type do + :belongs_to -> + """ + Multiple foreign keys found from `#{inspect(spec.resource)}` to `#{inspect(relationship.destination)}` with the guessed name `#{name}`. - Provide a relationship name for the one with the following info: + Provide a relationship name for the one with the following info: - Resource: `#{inspect(spec.resource)}` - Relationship Type: :belongs_to - Guessed Name: `:#{name}` - Relationship Destination: `#{inspect(relationship.destination)}` - Constraint Name: `#{inspect(relationship.constraint_name)}`. + Resource: `#{inspect(spec.resource)}` + Relationship Type: :belongs_to + Guessed Name: `:#{name}` + Relationship Destination: `#{inspect(relationship.destination)}` + Constraint Name: `#{inspect(relationship.constraint_name)}`. - Leave empty to skip adding this relationship. + Leave empty to skip adding this relationship. - Name: - """ - |> String.trim_trailing() + Name: + """ + |> String.trim_trailing() - _ -> - """ - Multiple foreign keys found from `#{inspect(relationship.source)}` to `#{inspect(spec.resource)}` with the guessed name `#{name}`. + _ -> + """ + Multiple foreign keys found from `#{inspect(relationship.source)}` to `#{inspect(spec.resource)}` with the guessed name `#{name}`. - Provide a relationship name for the one with the following info: + Provide a relationship name for the one with the following info: - Resource: `#{inspect(relationship.source)}` - Relationship Type: :#{relationship.type} - Guessed Name: `:#{name}` - Relationship Destination: `#{inspect(spec.resource)}` - Constraint Name: `#{inspect(relationship.constraint_name)}`. + Resource: `#{inspect(relationship.source)}` + Relationship Type: :#{relationship.type} + Guessed Name: `:#{name}` + Relationship Destination: `#{inspect(spec.resource)}` + Constraint Name: `#{inspect(relationship.constraint_name)}`. - Leave empty to skip adding this relationship. + Leave empty to skip adding this relationship. - Name: - """ - |> String.trim_trailing() - end + Name: + """ + |> String.trim_trailing() + end - Owl.IO.input(label: label, optional: true) - |> String.trim() - # common typo - |> String.trim_leading(":") - |> case do - "" -> - name_all_relationships(type, opts, spec, name, rest, acc) - - new_name -> - name_all_relationships(type, opts, spec, name, rest, [ - %{relationship | name: new_name} | acc - ]) + Owl.IO.input(label: label, optional: true) + |> String.trim() + # common typo + |> String.trim_leading(":") + |> case do + "" -> + name_all_relationships(type, opts, spec, name, rest, acc) + + new_name -> + name_all_relationships(type, opts, spec, name, rest, [ + %{relationship | name: new_name} | acc + ]) + end end end @@ -888,7 +892,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do # sobelow_skip ["RCE.CodeModule", "DOS.StringToAtom"] defp get_type(attribute, opts) do result = - if opts[:yes?] do + if opts[:yes?] || opts[:skip_unknown] do "skip" else Mix.shell().prompt(""" From 4dc86d6d38b0fd61706ee4ac8514954c48cec5d3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Mar 2025 09:57:26 -0800 Subject: [PATCH 431/690] improvement: document options, add `--no-migrations` --- lib/mix/tasks/ash_postgres.gen.resources.ex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index a47a0048..17960544 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -28,6 +28,9 @@ if Code.ensure_loaded?(Igniter) do - `yes`, `y` - Answer yes (or skip) to all questions. - `default-actions` - Add default actions for each resource. Defaults to `true`. - `public` - Mark all attributes and relationships as `public? true`. Defaults to `true`. + - `no-migrations` - Do not generate snapshots & migrations for the resources. Defaults to `false`. + - `skip-unknown` - Skip any attributes with types that we don't have a corresponding Elixir type for, and relationships that we can't assume the name of. + - `public` - Mark all attributes and relationships as `public? true`. Defaults to `true`. ## Tables @@ -53,6 +56,7 @@ if Code.ensure_loaded?(Igniter) do public: :boolean, extend: :keep, skip_unknown: :boolean, + migrations: :boolean, snapshots_only: :boolean, domain: :keep ], @@ -66,6 +70,7 @@ if Code.ensure_loaded?(Igniter) do ], defaults: [ default_actions: true, + migrations: true, public: true ] } @@ -141,7 +146,7 @@ if Code.ensure_loaded?(Igniter) do """ options = - if options[:yes] || Mix.shell().yes?(prompt) do + if options[:migrations] || options[:yes] || Mix.shell().yes?(prompt) do Keyword.put(options, :no_migrations, false) else Keyword.put(options, :no_migrations, true) From 36a11efbcb3d182ae35fc8060e01da4d563dc67b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Mar 2025 10:17:55 -0800 Subject: [PATCH 432/690] fix: honor --no-migrations flag --- lib/mix/tasks/ash_postgres.gen.resources.ex | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 17960544..99c6a158 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -146,10 +146,15 @@ if Code.ensure_loaded?(Igniter) do """ options = - if options[:migrations] || options[:yes] || Mix.shell().yes?(prompt) do - Keyword.put(options, :no_migrations, false) - else - Keyword.put(options, :no_migrations, true) + cond do + options[:migrations] == false -> + Keyword.put(options, :no_migrations, false) + + options[:migrations] || options[:yes] || Mix.shell().yes?(prompt) -> + Keyword.put(options, :no_migrations, false) + + true -> + Keyword.put(options, :no_migrations, true) end migration_opts = From b7580fe07e4bb915adcdbc1c894780b6588f816c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Mar 2025 10:24:20 -0800 Subject: [PATCH 433/690] fix: honor skip_unknown option in spec table generator --- lib/resource_generator/resource_generator.ex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 3b917d4c..dbc8df14 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -37,7 +37,13 @@ if Code.ensure_loaded?(Igniter) do specs = repos - |> Enum.flat_map(&Spec.tables(&1, skip_tables: opts[:skip_tables], tables: opts[:tables])) + |> Enum.flat_map( + &Spec.tables(&1, + skip_tables: opts[:skip_tables], + tables: opts[:tables], + skip_unknown: opts[:skip_unknown] + ) + ) |> Enum.map(fn %{table_name: table} = spec -> resource = table From f9120f6b4f212be4ff661fd18eb5191a9e5e1ca4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Mar 2025 10:40:12 -0800 Subject: [PATCH 434/690] fix: ignore attributes with no known type --- lib/resource_generator/spec.ex | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 95aab278..6e3d17dc 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -872,19 +872,23 @@ defmodule AshPostgres.ResourceGenerator.Spec do def set_types(attributes, opts) do attributes - |> Enum.map(fn attribute -> + |> Enum.flat_map(fn attribute -> case Process.get({:type_cache, attribute.type}) do nil -> case type(attribute.type) do {:ok, type} -> - %{attribute | attr_type: type} + [%{attribute | attr_type: type}] :error -> - get_type(attribute, opts) + case get_type(attribute, opts) do + :skip -> [] + {:ok, type} -> [%{attribute | attr_type: type}] + :error -> [] + end end type -> - %{attribute | attr_type: type} + [%{attribute | attr_type: type}] end end) end @@ -895,6 +899,8 @@ defmodule AshPostgres.ResourceGenerator.Spec do if opts[:yes?] || opts[:skip_unknown] do "skip" else + raise "what" + Mix.shell().prompt(""" Unknown type: #{attribute.type}. What should we use as the type? @@ -911,20 +917,20 @@ defmodule AshPostgres.ResourceGenerator.Spec do case result do skip when skip in ["skip", "skip\n"] -> - attribute + :skip new_type -> case String.trim(new_type) do ":" <> type -> new_type = String.to_atom(type) Process.put({:type_cache, attribute.type}, new_type) - %{attribute | attr_type: new_type} + {:ok, %{attribute | attr_type: new_type}} type -> try do Code.eval_string(type) Process.put({:type_cache, attribute.type}, new_type) - %{attribute | attr_type: new_type} + {:ok, %{attribute | attr_type: new_type}} rescue _e -> get_type(attribute, opts) From 20cbf92160bf374566836157af12c694c8b88fa1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 7 Mar 2025 10:46:36 -0800 Subject: [PATCH 435/690] chore: fix typo --- lib/mix/tasks/ash_postgres.gen.resources.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 99c6a158..9a36d7a9 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -148,7 +148,7 @@ if Code.ensure_loaded?(Igniter) do options = cond do options[:migrations] == false -> - Keyword.put(options, :no_migrations, false) + Keyword.put(options, :no_migrations, true) options[:migrations] || options[:yes] || Mix.shell().yes?(prompt) -> Keyword.put(options, :no_migrations, false) From fe13e0823626c163a8d79f318f3d847edd9d79f5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 11 Mar 2025 13:28:20 -0400 Subject: [PATCH 436/690] chore: release version v2.5.11 --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b80e9117..0b241858 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,41 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.11](https://github.com/ash-project/ash_postgres/compare/v2.5.10...v2.5.11) (2025-03-11) + + + + +### Bug Fixes: + +* ignore attributes with no known type + +* honor skip_unknown option in spec table generator + +* honor --no-migrations flag + +* allow optional input for relationship name guesser + +* put move up/down in the right place + +* go to top of if block + +* use `configures_key?/3` + +* don't modify repo in runtime.exs + +* remove Helpdesk.Repo from installer 🤦 + +* only configure repo in installer if not already configured + +* install ash if not installed already + +### Improvements: + +* document options, add `--no-migrations` + +* add `skip_unknown` option to `ash_postgres.gen.resources` + ## [v2.5.10](https://github.com/ash-project/ash_postgres/compare/v2.5.9...v2.5.10) (2025-03-06) diff --git a/mix.exs b/mix.exs index 34035006..0eb1a171 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.10" + @version "2.5.11" def project do [ From 2b767bee8ce32db18c7c9b76d8dd9cd0a62d81b1 Mon Sep 17 00:00:00 2001 From: Mike Wilson Date: Tue, 11 Mar 2025 10:35:42 -0700 Subject: [PATCH 437/690] Don't use multitenancy attribute in composite index key when setting up tenant reference (#507) --- lib/migration_generator/operation.ex | 20 ++++++---- test/migration_generator_test.exs | 58 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index b3d4a28e..87cea347 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1012,10 +1012,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do multitenancy: multitenancy }) do keys = - if multitenancy.strategy == :attribute do - [multitenancy.attribute, source] - else - [source] + case multitenancy do + %{strategy: :attribute, attribute: attribute} when attribute != source -> + [attribute, source] + + _ -> + [source] end opts = @@ -1032,10 +1034,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do def down(%{schema: schema, source: source, table: table, multitenancy: multitenancy}) do keys = - if multitenancy.strategy == :attribute do - [multitenancy.attribute, source] - else - [source] + case multitenancy do + %{strategy: :attribute, attribute: attribute} when attribute != source -> + [attribute, source] + + _ -> + [source] end opts = diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 706967fb..2e9bd9e9 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -1500,6 +1500,64 @@ defmodule AshPostgres.MigrationGeneratorTest do assert File.read!(file) =~ ~S{create index(:posts, [:org_id, :post_id])} end + test "index generated by index? true does not duplicate tenant column when using attribute multitenancy if reference is same as tenant column" do + defresource Org, "orgs" do + attributes do + uuid_primary_key(:id, writable?: true, public?: true) + attribute(:name, :string, public?: true) + end + + multitenancy do + strategy(:attribute) + attribute(:id) + end + end + + defposts do + attributes do + uuid_primary_key(:id) + attribute(:key_id, :uuid, allow_nil?: false, public?: true) + attribute(:foobar, :string, public?: true) + end + + multitenancy do + strategy(:attribute) + attribute(:org_id) + end + + relationships do + belongs_to(:org, Org) do + public?(true) + end + end + + postgres do + references do + reference(:org, index?: true) + end + end + end + + defdomain([Org, Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert file = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) + |> File.read!() + + assert [up_code, down_code] = String.split(file, "def down do") + + assert up_code =~ ~S{create index(:posts, [:org_id])} + assert down_code =~ ~S{drop_if_exists index(:posts, [:org_id])} + end + test "references merge :match_with and multitenancy attribute" do defresource Org, "orgs" do attributes do From c14c160b815ff8aec5ce78dbbc319c84e88fe9e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 06:26:35 -0400 Subject: [PATCH 438/690] chore(deps): bump the production-dependencies group with 3 updates (#508) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.4.67 to 3.4.68 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.67...v3.4.68) Updates `ash_sql` from 0.2.60 to 0.2.61 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.60...v0.2.61) Updates `igniter` from 0.5.31 to 0.5.35 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.31...v0.5.35) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mix.lock b/mix.lock index be0b5734..6195ddff 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.67", "b2e3e65ddff550998a5c8dd1fc7f8ef4d7ebfe75a474c1e620e9b51b3ff5f70d", [: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", "770a637208ef0be5b9778687efb55be7b4f75d0202f80ddc4b1b918a8282ba28"}, - "ash_sql": {:hex, :ash_sql, "0.2.60", "3920e05ba34df913f4e32c7395480687a0372db7c2725b7c7c390b432e28be08", [: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", "dcc3eb8277ccb456cd9ff1e4d9b06699ce9f0502c1dfefee388eb1850817e77e"}, + "ash": {:hex, :ash, "3.4.68", "d6478880cf11500d4cc15a23c73ef78dc0471a4c59891ec925124a0922df2746", [: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", "bb8249b45a48de04664fa73ab2cbbc3ba56b792ced4997bdc6862c39f3fe47b4"}, + "ash_sql": {:hex, :ash_sql, "0.2.61", "ef6de767e67613b6b1cf39da525cf72c3581f367506c38624e6a8f4506192d3c", [: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", "8555d1e68c3fe7408cd3a5383e5a881b55204ce0c95cddf18dddf8c0fe7e9ca2"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "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.31", "efee5efb94bcfce37d317ab54c54b979d8864bf9b76aafded82f7bb52a306076", [: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", "4f0c9456135444286ae89b22db10f8f1ad18932ccd4935bc14a5ad41704e5a1f"}, + "igniter": {:hex, :igniter, "0.5.35", "ebc02429d7ea80b44c861018051f2cd6ca5e45297ed1e5041ee3ed82f39ffd92", [: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", "0d0dc13cc22636649d9e5dfd7ac13207f179523673fc0d097aa9ea98e29189c2"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,14 +39,14 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.14.0", "8dc5d4946391010bf9fa7b58dd1e75d3c1cf97315e5489b7797cf64b82ae27a4", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9cf5068e4042791c150f0dfbc00f4f435433eb948036b44b95b940e457b35a6a"}, + "reactor": {:hex, :reactor, "0.15.0", "556937d9310e1a6dd06083592b9eb9e0d212540b6d82faecba70823ee7a0747d", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "f634383a7760ba3106d31a3185f2e2c39e1485d899d884d94c22c62c9b5e7a4a"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.45", "19e3a879e80d02853ded85ed7b4c0a84a5d2e395f9d0c884e1a13afbe026929d", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "70b272d0ee16e3c10a4f8cf0ef6152840828152e68f2f8e3046e89567f2b49ad"}, - "spitfire": {:hex, :spitfire, "0.1.5", "10b041e781bff9544d2fdf00893e1a325758408c5366a9bfa4333072568659b1", [:mix], [], "hexpm", "866a55d21fe827934ff38200111335c9dd311df13cbf2580ed71d84b0a783150"}, + "spark": {:hex, :spark, "2.2.46", "39a1e6b793a754f6a23a1cf12911006125fae0b233250400ad6157991669642d", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "39e4ebfd5bac0c0090e548301680481ed41c1886b0874873363ec22de2bb8a61"}, + "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.1.3", "15fdb14c64e84437901258bb56fc7d80aaf6ceaf85b9324f359e219241353bfb", [:mix], [], "hexpm", "859eb2be72d74be26c1c4f272905667672a52e44f743839c57c7ee73a1a66420"}, @@ -55,4 +55,5 @@ "tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, + "ymlr": {:hex, :ymlr, "5.1.3", "a8061add5a378e20272a31905be70209a5680fdbe0ad51f40cb1af4bdd0a010b", [:mix], [], "hexpm", "8663444fa85101a117887c170204d4c5a2182567e5f84767f0071cf15f2efb1e"}, } From b03bc135fa582d4bb96531ba42d054340bbcaab0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 06:26:46 -0400 Subject: [PATCH 439/690] chore(deps-dev): bump ex_doc in the dev-dependencies group (#509) Bumps the dev-dependencies group with 1 update: [ex_doc](https://github.com/elixir-lang/ex_doc). Updates `ex_doc` from 0.37.2 to 0.37.3 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.37.2...v0.37.3) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 6195ddff..e31f301a 100644 --- a/mix.lock +++ b/mix.lock @@ -8,7 +8,7 @@ "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, @@ -16,7 +16,7 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.37.2", "2a3aa7014094f0e4e286a82aa5194a34dd17057160988b8509b15aa6c292720c", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "4dfa56075ce4887e4e8b1dcc121cd5fcb0f02b00391fd367ff5336d98fa49049"}, + "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, "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"}, From 95aec5eed01689e922b4b9fa16cfd152f29c2760 Mon Sep 17 00:00:00 2001 From: Theron Boerner Date: Sat, 15 Mar 2025 21:44:06 -0500 Subject: [PATCH 440/690] docs: Add docs for read replicas (#511) --- README.md | 1 + .../topics/advanced/using-multiple-repos.md | 56 +++++++++++++++++++ mix.exs | 1 + 3 files changed, 58 insertions(+) create mode 100644 documentation/topics/advanced/using-multiple-repos.md diff --git a/README.md b/README.md index da0136ae..51f74e61 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Welcome! `AshPostgres` is the PostgreSQL data layer for [Ash Framework](https:// - [Expressions](documentation/topics/advanced/expressions.md) - [Manual Relationships](documentation/topics/advanced/manual-relationships.md) - [Schema Based Multitenancy](documentation/topics/advanced/schema-based-multitenancy.md) +- [Read Replicas](documentation/topics/advanced/using-multiple-repos.md) ## Reference diff --git a/documentation/topics/advanced/using-multiple-repos.md b/documentation/topics/advanced/using-multiple-repos.md new file mode 100644 index 00000000..3c85ff5c --- /dev/null +++ b/documentation/topics/advanced/using-multiple-repos.md @@ -0,0 +1,56 @@ +# Using Multiple Repos + +When scaling PostgreSQL you may want to setup _read_ replicas to improve +performance and availability. This can be achieved by configuring multiple +repositories in your application. + +## Setup Read Replicas + +Following the [ecto docs](https://hexdocs.pm/ecto/replicas-and-dynamic-repositories.html), change your Repo configuration: + +```elixir +defmodule MyApp.Repo do + use Ecto.Repo, + otp_app: :my_app, + adapter: Ecto.Adapters.Postgres + + @replicas [ + MyApp.Repo.Replica1, + MyApp.Repo.Replica2, + MyApp.Repo.Replica3, + MyApp.Repo.Replica4 + ] + + def replica do + Enum.random(@replicas) + end + + for repo <- @replicas do + defmodule repo do + use Ecto.Repo, + otp_app: :my_app, + adapter: Ecto.Adapters.Postgres, + read_only: true + end + end +end +``` + +## Configure AshPostgres + +Now change the `repo` argument for your `postgres` block as such: + +```elixir +defmodule MyApp.MyDomain.MyResource do + use Ash.Resource, + date_layer: AshPostgres.DataLayer + + postgres do + table "my_resources" + repo fn + _resource, :read -> MyApp.Repo.replica() + _resource, :mutate -> MyApp.Repo + end + end +end +``` diff --git a/mix.exs b/mix.exs index 0eb1a171..232ce1cb 100644 --- a/mix.exs +++ b/mix.exs @@ -97,6 +97,7 @@ defmodule AshPostgres.MixProject do "documentation/topics/development/upgrading-to-2.0.md", "documentation/topics/advanced/expressions.md", "documentation/topics/advanced/schema-based-multitenancy.md", + "documentation/topics/advanced/using-multiple-repos.md", "documentation/topics/advanced/manual-relationships.md", {"documentation/dsls/DSL-AshPostgres.DataLayer.md", search_data: Spark.Docs.search_data_for(AshPostgres.DataLayer)}, From 9c8987aba061058b45b8701046b14b37bde104ad Mon Sep 17 00:00:00 2001 From: quartz Date: Fri, 14 Mar 2025 19:25:39 +0100 Subject: [PATCH 441/690] test: custom types in joins (#510) --- .../test_repo/points/20250313112823.json | 47 ++ .../test_repo/posts/20250313112823.json | 580 ++++++++++++++++++ .../string_points/20250313112823.json | 44 ++ .../20250313112823_migrate_resources51.exs | 67 ++ test/support/domain.ex | 2 + test/support/resources/db_point.ex | 34 + test/support/resources/db_string_point.ex | 34 + test/support/resources/post.ex | 25 + test/support/types/string_point.ex | 60 ++ test/type_test.exs | 49 ++ 10 files changed, 942 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/points/20250313112823.json create mode 100644 priv/resource_snapshots/test_repo/posts/20250313112823.json create mode 100644 priv/resource_snapshots/test_repo/string_points/20250313112823.json create mode 100644 priv/test_repo/migrations/20250313112823_migrate_resources51.exs create mode 100644 test/support/resources/db_point.ex create mode 100644 test/support/resources/db_string_point.ex create mode 100644 test/support/types/string_point.ex diff --git a/priv/resource_snapshots/test_repo/points/20250313112823.json b/priv/resource_snapshots/test_repo/points/20250313112823.json new file mode 100644 index 00000000..83a5bc87 --- /dev/null +++ b/priv/resource_snapshots/test_repo/points/20250313112823.json @@ -0,0 +1,47 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": [ + "array", + "float" + ] + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "1E2378D30CF657B673E7EE140FDD4CA067E23FB8862A8F05D35A3F680EBA06B4", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "points_id_index", + "keys": [ + { + "type": "atom", + "value": "id" + } + ], + "name": "id", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "points" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/posts/20250313112823.json b/priv/resource_snapshots/test_repo/posts/20250313112823.json new file mode 100644 index 00000000..cd1bb56d --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250313112823.json @@ -0,0 +1,580 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "limited_score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "metadata", + "type": "map" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "string_point", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "points" + }, + "size": null, + "source": "db_point_id", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_string_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "string_points" + }, + "size": null, + "source": "db_string_point_id", + "type": "text" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "8254859F1DED84E83F9565AB104579D5DEF7B9C756EFC3A2F156CC614B87164F", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/string_points/20250313112823.json b/priv/resource_snapshots/test_repo/string_points/20250313112823.json new file mode 100644 index 00000000..cfdf889c --- /dev/null +++ b/priv/resource_snapshots/test_repo/string_points/20250313112823.json @@ -0,0 +1,44 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "43DADF8B94BBDBD802AE3D70ED67791CC968478B7EE6AEBE5B5F8F676DB323BE", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "string_points_id_index", + "keys": [ + { + "type": "atom", + "value": "id" + } + ], + "name": "id", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "string_points" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250313112823_migrate_resources51.exs b/priv/test_repo/migrations/20250313112823_migrate_resources51.exs new file mode 100644 index 00000000..fe51caf5 --- /dev/null +++ b/priv/test_repo/migrations/20250313112823_migrate_resources51.exs @@ -0,0 +1,67 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources51 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:string_points, primary_key: false) do + add(:id, :text, null: false, primary_key: true) + end + + create(unique_index(:string_points, [:id], name: "string_points_id_index")) + + create table(:points, primary_key: false) do + add(:id, {:array, :float}, null: false, primary_key: true) + end + + create(unique_index(:points, [:id], name: "points_id_index")) + + alter table(:posts) do + add(:string_point, :text) + + add( + :db_point_id, + references(:points, + column: :id, + name: "posts_db_point_id_fkey", + type: {:array, :float}, + prefix: "public" + ) + ) + + add( + :db_string_point_id, + references(:string_points, + column: :id, + name: "posts_db_string_point_id_fkey", + type: :text, + prefix: "public" + ) + ) + end + end + + def down do + drop(constraint(:posts, "posts_db_point_id_fkey")) + + drop(constraint(:posts, "posts_db_string_point_id_fkey")) + + alter table(:posts) do + remove(:db_string_point_id) + remove(:db_point_id) + remove(:string_point) + end + + drop_if_exists(unique_index(:points, [:id], name: "points_id_index")) + + drop(table(:points)) + + drop_if_exists(unique_index(:string_points, [:id], name: "string_points_id_index")) + + drop(table(:string_points)) + end +end diff --git a/test/support/domain.ex b/test/support/domain.ex index c2d867a7..8af874e4 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -32,6 +32,8 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.PostFollower) resource(AshPostgres.Test.StatefulPostFollower) resource(AshPostgres.Test.PostWithEmptyUpdate) + resource(AshPostgres.Test.DbPoint) + resource(AshPostgres.Test.DbStringPoint) end authorization do diff --git a/test/support/resources/db_point.ex b/test/support/resources/db_point.ex new file mode 100644 index 00000000..25b9ca93 --- /dev/null +++ b/test/support/resources/db_point.ex @@ -0,0 +1,34 @@ +defmodule AshPostgres.Test.DbPoint do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("points") + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:read, :destroy]) + + create :create do + primary?(true) + accept([:id]) + upsert?(true) + upsert_identity(:id) + end + end + + attributes do + attribute(:id, AshPostgres.Test.Point) do + public?(true) + primary_key?(true) + allow_nil?(false) + end + end + + identities do + identity(:id, [:id]) + end +end diff --git a/test/support/resources/db_string_point.ex b/test/support/resources/db_string_point.ex new file mode 100644 index 00000000..8908527b --- /dev/null +++ b/test/support/resources/db_string_point.ex @@ -0,0 +1,34 @@ +defmodule AshPostgres.Test.DbStringPoint do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("string_points") + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:read, :destroy]) + + create :create do + primary?(true) + accept([:id]) + upsert?(true) + upsert_identity(:id) + end + end + + attributes do + attribute(:id, AshPostgres.Test.StringPoint) do + public?(true) + primary_key?(true) + allow_nil?(false) + end + end + + identities do + identity(:id, [:id]) + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 9fb97cdd..098d0ccf 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -456,6 +456,7 @@ defmodule AshPostgres.Test.Post do attribute(:point, AshPostgres.Test.Point, public?: true) attribute(:composite_point, AshPostgres.Test.CompositePoint, public?: true) + attribute(:string_point, AshPostgres.Test.StringPoint, public?: true) attribute(:stuff, :map, public?: true) attribute(:list_of_stuff, {:array, :map}, public?: true) attribute(:uniq_one, :string, public?: true) @@ -541,6 +542,18 @@ defmodule AshPostgres.Test.Post do filter(expr(parent(title) == title and parent(id) != id)) end + has_many :posts_with_matching_point, __MODULE__ do + public?(true) + no_attributes?(true) + filter(expr(parent(point) == point and parent(id) != id)) + end + + has_many :posts_with_matching_string_point, __MODULE__ do + public?(true) + no_attributes?(true) + filter(expr(parent(string_point) == string_point and parent(id) != id)) + end + has_many(:comments, AshPostgres.Test.Comment, destination_attribute: :post_id, public?: true) has_one :latest_comment, AshPostgres.Test.Comment do @@ -658,6 +671,18 @@ defmodule AshPostgres.Test.Post do end has_many(:permalinks, AshPostgres.Test.Permalink) + + belongs_to :db_point, AshPostgres.Test.DbPoint do + public?(true) + allow_nil?(true) + attribute_type(AshPostgres.Test.Point) + end + + belongs_to :db_string_point, AshPostgres.Test.DbStringPoint do + public?(true) + allow_nil?(true) + attribute_type(AshPostgres.Test.StringPoint) + end end validations do diff --git a/test/support/types/string_point.ex b/test/support/types/string_point.ex new file mode 100644 index 00000000..0550a904 --- /dev/null +++ b/test/support/types/string_point.ex @@ -0,0 +1,60 @@ +defmodule AshPostgres.Test.StringPoint do + @moduledoc false + use Ash.Type + + defstruct [:x, :y, :z] + + @type t :: %__MODULE__{ + x: float(), + y: float(), + z: float() + } + + def storage_type(_), do: :string + + def cast_input(nil, _), do: {:ok, nil} + + def cast_input(%__MODULE__{} = a, _) do + {:ok, a} + end + + def cast_input({x, y, z}, _) when is_float(x) and is_float(y) and is_float(z) do + {:ok, %__MODULE__{x: x, y: y, z: z}} + end + + def cast_input(enc, _) when is_binary(enc) do + {:ok, parse!(enc)} + end + + def cast_input(_, _), do: :error + + def cast_stored(nil, _), do: {:ok, nil} + + def cast_stored(enc, _) when is_binary(enc) do + {:ok, parse!(enc)} + end + + def cast_stored(_, _) do + :error + end + + def dump_to_native(nil, _), do: {:ok, nil} + + def dump_to_native(%__MODULE__{x: x, y: y, z: z}, _) do + enc = Enum.map_join([x, y, z], ",", &Float.to_string/1) + + {:ok, enc} + end + + def dump_to_native(_, _) do + :error + end + + defp parse!(enc) when is_binary(enc) do + [x, y, z] = + String.split(enc, ",") + |> Enum.map(&String.to_float/1) + + %__MODULE__{x: x, y: y, z: z} + end +end diff --git a/test/type_test.exs b/test/type_test.exs index 856a2da3..428fcab1 100644 --- a/test/type_test.exs +++ b/test/type_test.exs @@ -51,4 +51,53 @@ defmodule AshPostgres.Test.TypeTest do |> Ash.Query.filter(point == ^{1.0, 2.0, 3.0}) |> Ash.read!() end + + test "complex custom types can be used in relationships" do + [p | _] = + for _ <- 1..4//1 do + Post + |> Ash.Changeset.for_create(:create, %{ + point: {1.0, 2.0, 3.0}, + string_point: "1.0,2.0,3.0" + }) + |> Ash.create!() + end + + p = p |> Ash.load!([:posts_with_matching_point, :posts_with_matching_string_point]) + + assert Enum.count(p.posts_with_matching_point) == 3 + assert Enum.count(p.posts_with_matching_string_point) == 3 + + %{id: id} = + Post + |> Ash.Changeset.for_create(:create) + |> Ash.Changeset.manage_relationship(:db_point, %{id: {2.0, 3.0, 4.0}}, type: :create) + |> Ash.create!() + + [p] = + Post + |> Ash.Query.for_read(:read) + |> Ash.Query.load(:db_point) + |> Ash.Query.filter(id == ^id) + |> Ash.read!() + + assert p.db_point_id == {2.0, 3.0, 4.0} + assert p.db_point.id == {2.0, 3.0, 4.0} + + %{id: id} = + Post + |> Ash.Changeset.for_create(:create) + |> Ash.Changeset.manage_relationship(:db_string_point, %{id: "2.0,3.0,4.0"}, type: :create) + |> Ash.create!() + + [p] = + Post + |> Ash.Query.for_read(:read) + |> Ash.Query.load(:db_string_point) + |> Ash.Query.filter(id == ^id) + |> Ash.read!() + + assert %{x: 2.0, y: 3.0, z: 4.0} = p.db_string_point_id + assert %{x: 2.0, y: 3.0, z: 4.0} = p.db_string_point.id + end end From 487d7acd1a71877d8d2a4a0fe8fa2adfdf431437 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 16 Mar 2025 01:54:16 -0400 Subject: [PATCH 442/690] improvement: include error detail in constraint violation errors --- lib/data_layer.ex | 51 +++++++++++++---------------------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index d09c88e2..54022305 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2187,14 +2187,6 @@ defmodule AshPostgres.DataLayer do end) end - defp to_ash_error({field, {message, vars}}) do - Ash.Error.Changes.InvalidAttribute.exception( - field: field, - message: message, - private_vars: vars - ) - end - defp ecto_changeset(record, changeset, type, repo, table_error?) do attributes = changeset.resource @@ -2332,7 +2324,7 @@ defmodule AshPostgres.DataLayer do constraints -> {:error, fake_changeset - |> constraints_to_errors(:insert, constraints, resource) + |> constraints_to_errors(:insert, constraints, resource, error) |> Ash.Error.to_ash_error()} end end @@ -2349,35 +2341,18 @@ defmodule AshPostgres.DataLayer do defp handle_raised_error( %Postgrex.Error{} = error, stacktrace, - %{constraints: user_constraints}, - _resource + changeset, + resource ) do case Ecto.Adapters.Postgres.Connection.to_constraints(error, []) do - [{type, constraint}] -> - user_constraint = - Enum.find(user_constraints, fn c -> - case {c.type, c.constraint, c.match} do - {^type, ^constraint, :exact} -> true - {^type, cc, :suffix} -> String.ends_with?(constraint, cc) - {^type, cc, :prefix} -> String.starts_with?(constraint, cc) - {^type, %Regex{} = r, _match} -> Regex.match?(r, constraint) - _ -> false - end - end) - - case user_constraint do - %{field: field, error_message: error_message, error_type: error_type} -> - {:error, - to_ash_error( - {field, {error_message, [constraint: error_type, constraint_name: constraint]}} - )} - - nil -> - reraise error, stacktrace - end + [] -> + {:error, Ash.Error.to_ash_error(error, stacktrace)} - _ -> - reraise error, stacktrace + constraints -> + {:error, + changeset + |> constraints_to_errors(:insert, constraints, resource, error) + |> Ash.Error.to_ash_error()} end end @@ -2389,7 +2364,8 @@ defmodule AshPostgres.DataLayer do %{constraints: user_constraints} = changeset, action, constraints, - resource + resource, + error ) do Enum.map(constraints, fn {type, constraint} -> user_constraint = @@ -2421,7 +2397,8 @@ defmodule AshPostgres.DataLayer do message: error_message, private_vars: [ constraint: constraint, - constraint_type: type + constraint_type: type, + detail: error.postgres.detail ] ) end) From bfd98a79dbcc2a02124278a89a2fcec1568c914f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 17 Mar 2025 16:54:30 -0400 Subject: [PATCH 443/690] test: test for recent ash_sql aggregate fix --- test/aggregate_test.exs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 0bb25e81..dc784612 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -20,6 +20,37 @@ defmodule AshSql.AggregateTest do assert Ash.count!(AshPostgres.Test.PostView) == 0 end + test "can sum count aggregates" do + org = + Organization + |> Ash.Changeset.for_create(:create, %{name: "The Org"}) + |> Ash.create!() + + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert Decimal.eq?(Ash.sum!(Post, :count_of_comments), Decimal.new("2")) + end + test "relates to actor via has_many and with an aggregate" do org = Organization From 3e91cfb2c32c784bb03474a41c28332a0ba50845 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 18 Mar 2025 13:00:44 -0400 Subject: [PATCH 444/690] test: test for present validation --- test/support/resources/post.ex | 11 +++++++++++ test/update_test.exs | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 098d0ccf..602007aa 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -159,6 +159,17 @@ defmodule AshPostgres.Test.Post do change(atomic_update(:limited_score, expr((limited_score || 0) + ^arg(:amount)))) end + update :validate_absent_non_atomically do + require_atomic?(false) + accept([:title]) + validate(absent(:title)) + end + + update :validate_absent do + accept([:title]) + validate(absent(:title)) + end + update :change_nothing do accept([]) require_atomic?(false) diff --git a/test/update_test.exs b/test/update_test.exs index cf93b0f1..eb656490 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -76,6 +76,29 @@ defmodule AshPostgres.UpdateTest do end end + test "absent validations behave the same atomically and non-atomically" do + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "match"}) + |> Ash.create!() + + assert_raise Ash.Error.Invalid, ~r/must be absent/, fn -> + Ash.update!(post, %{title: "title"}, action: :validate_absent_non_atomically) + end + + assert_raise Ash.Error.Invalid, ~r/must be absent/, fn -> + Ash.update!(post, %{}, action: :validate_absent_non_atomically) + end + + assert_raise Ash.Error.Invalid, ~r/must be absent/, fn -> + Ash.update!(post, %{title: "title"}, action: :validate_absent) + end + + assert_raise Ash.Error.Invalid, ~r/must be absent/, fn -> + Ash.update!(post, %{}, action: :validate_absent) + end + end + test "timestamps arent updated if there are no changes non-atomically" do post = AshPostgres.Test.Post From 68fc923a78fa296fd7ae6b56b8be5872b737387b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 18 Mar 2025 16:44:45 -0400 Subject: [PATCH 445/690] chore: fix dialyzer and update deps --- lib/resource_generator/spec.ex | 1 - mix.exs | 4 ++-- mix.lock | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 6e3d17dc..12535bbb 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -883,7 +883,6 @@ defmodule AshPostgres.ResourceGenerator.Spec do case get_type(attribute, opts) do :skip -> [] {:ok, type} -> [%{attribute | attr_type: type}] - :error -> [] end end diff --git a/mix.exs b/mix.exs index 232ce1cb..1a1b5b6a 100644 --- a/mix.exs +++ b/mix.exs @@ -166,8 +166,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.65")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.57")}, + {:ash, ash_version("~> 3.4 and >= 3.4.69")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.62")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index e31f301a..0d392deb 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.68", "d6478880cf11500d4cc15a23c73ef78dc0471a4c59891ec925124a0922df2746", [: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", "bb8249b45a48de04664fa73ab2cbbc3ba56b792ced4997bdc6862c39f3fe47b4"}, - "ash_sql": {:hex, :ash_sql, "0.2.61", "ef6de767e67613b6b1cf39da525cf72c3581f367506c38624e6a8f4506192d3c", [: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", "8555d1e68c3fe7408cd3a5383e5a881b55204ce0c95cddf18dddf8c0fe7e9ca2"}, + "ash": {:hex, :ash, "3.4.69", "7edc8c91b228e133cf6669026a769862387cbc105bf22b5fc76d7e3a2211cb7d", [: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", "7b33d0d16c9d18d09978c43eb43996326a83f010166bf374a4d84553b2b554b1"}, + "ash_sql": {:hex, :ash_sql, "0.2.62", "fcf1dde5a453cb024799bd43ab25aee3a7cc4ce7a48f1456310a65aec9e7ea7a", [: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", "df8c72b9b1c7b2c3147334eb63e819bc8d15288e1c6f0ddcd7691530db272ce0"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "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.35", "ebc02429d7ea80b44c861018051f2cd6ca5e45297ed1e5041ee3ed82f39ffd92", [: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", "0d0dc13cc22636649d9e5dfd7ac13207f179523673fc0d097aa9ea98e29189c2"}, + "igniter": {:hex, :igniter, "0.5.37", "e677c009fcad535759dfb8fec0214af38acf1f27b7d6d0277d6be61d6bb391e8", [: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", "ca4e5f7c1edead2c6b8955886b010878660c69f3a3f97bf46641b3c39ed339ce"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -40,7 +40,7 @@ "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, "reactor": {:hex, :reactor, "0.15.0", "556937d9310e1a6dd06083592b9eb9e0d212540b6d82faecba70823ee7a0747d", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "f634383a7760ba3106d31a3185f2e2c39e1485d899d884d94c22c62c9b5e7a4a"}, - "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, + "req": {:hex, :req, "0.5.9", "09072dcd91a70c58734c4dd4fa878a9b6d36527291152885100ec33a5a07f1d6", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "2f027043003275918f5e79e6a4e57b10cb17161a1ab41c959aa40ecfb2142e5a"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, From ce7207689d3aed1a6d901c7fb30484ab38853383 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 18 Mar 2025 16:45:04 -0400 Subject: [PATCH 446/690] chore: release version v2.5.12 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b241858..3839c5d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.12](https://github.com/ash-project/ash_postgres/compare/v2.5.11...v2.5.12) (2025-03-18) + + + + +### Improvements: + +* include error detail in constraint violation errors + ## [v2.5.11](https://github.com/ash-project/ash_postgres/compare/v2.5.10...v2.5.11) (2025-03-11) diff --git a/mix.exs b/mix.exs index 1a1b5b6a..b1d53a58 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.11" + @version "2.5.12" def project do [ From 76c3ce1ae6cbb230270266817beb4bfa345616fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:46:40 -0400 Subject: [PATCH 447/690] chore(deps): bump ash in the production-dependencies group (#512) Bumps the production-dependencies group with 1 update: [ash](https://github.com/ash-project/ash). Updates `ash` from 3.4.69 to 3.4.70 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.4.69...v3.4.70) --- updated-dependencies: - dependency-name: ash dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 0d392deb..6bb05593 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.69", "7edc8c91b228e133cf6669026a769862387cbc105bf22b5fc76d7e3a2211cb7d", [: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", "7b33d0d16c9d18d09978c43eb43996326a83f010166bf374a4d84553b2b554b1"}, + "ash": {:hex, :ash, "3.4.70", "3c104de892a2e31ffb7fe8adf96c10759466d0bdeda7adff8907bf09e56fcca0", [: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", "6e006e8c88c0eb3cdae3b6c15764c03290820429e1a4b40f700767ce689eb671"}, "ash_sql": {:hex, :ash_sql, "0.2.62", "fcf1dde5a453cb024799bd43ab25aee3a7cc4ce7a48f1456310a65aec9e7ea7a", [: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", "df8c72b9b1c7b2c3147334eb63e819bc8d15288e1c6f0ddcd7691530db272ce0"}, "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"}, From f3fb42c9bd0d4d287b32542260247080a807b582 Mon Sep 17 00:00:00 2001 From: Diogo Martins <39999027+diogomrts@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:19:57 +0000 Subject: [PATCH 448/690] test: test for bulk update jsonb attribute errors (#513) --- .../test_repo/csv/20250320225052.json | 55 ++++++++++ .../test_repo/users/20250320225052.json | 101 ++++++++++++++++++ .../20250320225052_add_csv_resource.exs | 42 ++++++++ test/bulk_update_test.exs | 20 +++- test/support/domain.ex | 1 + test/support/resources/csv.ex | 56 ++++++++++ 6 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/csv/20250320225052.json create mode 100644 priv/resource_snapshots/test_repo/users/20250320225052.json create mode 100644 priv/test_repo/migrations/20250320225052_add_csv_resource.exs create mode 100644 test/support/resources/csv.ex diff --git a/priv/resource_snapshots/test_repo/csv/20250320225052.json b/priv/resource_snapshots/test_repo/csv/20250320225052.json new file mode 100644 index 00000000..122327c5 --- /dev/null +++ b/priv/resource_snapshots/test_repo/csv/20250320225052.json @@ -0,0 +1,55 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "column_mapping_embedded", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "column_mapping_new_type", + "type": [ + "array", + "map" + ] + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "B336E8AA99A8DCB5D4FB2965D41E33F6E4F172A10CE24F5DA5E4A5912DD5C87E", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "csv" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/users/20250320225052.json b/priv/resource_snapshots/test_repo/users/20250320225052.json new file mode 100644 index 00000000..b52adc81 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20250320225052.json @@ -0,0 +1,101 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "is_active", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": false, + "default": "\"user\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role", + "type": "text" + }, + { + "allow_nil?": false, + "default": "[]", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role_list", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "users_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "C7223D0C16D166EC2260C9B1125B9EDE6D38AD22B95A2280F71BD3069EC205C4", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "users" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250320225052_add_csv_resource.exs b/priv/test_repo/migrations/20250320225052_add_csv_resource.exs new file mode 100644 index 00000000..b02499d1 --- /dev/null +++ b/priv/test_repo/migrations/20250320225052_add_csv_resource.exs @@ -0,0 +1,42 @@ +defmodule AshPostgres.TestRepo.Migrations.AddCsvResource do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:users) do + remove(:org_id) + modify(:role_list, {:array, :text}, null: false) + modify(:role, :text, null: false) + end + + create table(:csv, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:column_mapping_embedded, :jsonb) + add(:column_mapping_new_type, :jsonb) + end + end + + def down do + drop(table(:csv)) + + alter table(:users) do + modify(:role, :text, null: true) + modify(:role_list, {:array, :text}, null: true) + + add( + :org_id, + references(:multitenant_orgs, + column: :id, + name: "users_org_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + end +end diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index 201595a7..242ba7f2 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -1,6 +1,6 @@ defmodule AshPostgres.BulkUpdateTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Post, Record} + alias AshPostgres.Test.{Post, Record, CSV} require Ash.Expr require Ash.Query @@ -263,4 +263,22 @@ defmodule AshPostgres.BulkUpdateTest do authorize?: false ) end + + @tag :wip + test "jsonb[] attribute with embedded Resource definition can be created and updated" do + %{status: :success} = + Ash.bulk_create!( + [%{column_mapping_embedded: [%{column: 1, attribute: "foo"}]}], + CSV, + :create, + return_records?: true, + return_errors?: true + ) + + %{status: :success} = + Ash.bulk_update(CSV, :update, %{ + column_mapping_embedded: [%{column: 1, attribute: "foo"}], + column_mapping_new_type: [%{column: 1, attribute: "foo"}] + }) + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index 8af874e4..36cdab5c 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -34,6 +34,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.PostWithEmptyUpdate) resource(AshPostgres.Test.DbPoint) resource(AshPostgres.Test.DbStringPoint) + resource(AshPostgres.Test.CSV) end authorization do diff --git a/test/support/resources/csv.ex b/test/support/resources/csv.ex new file mode 100644 index 00000000..59026cba --- /dev/null +++ b/test/support/resources/csv.ex @@ -0,0 +1,56 @@ +defmodule AshPostgres.Test.CSVColumnMatchingEmbedded do + use Ash.Resource, + data_layer: :embedded + + attributes do + attribute(:column, :integer, allow_nil?: true, public?: true) + attribute(:attribute, :string, allow_nil?: true, public?: true) + end +end + +defmodule AshPostgres.Test.CSVColumnMappingNewType do + use Ash.Type.NewType, + subtype_of: :map, + constraints: [ + fields: [ + attribute: [type: :string, allow_nil?: false], + column: [type: :integer, allow_nil?: false] + ] + ] +end + +defmodule AshPostgres.Test.CSV do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + alias AshPostgres.Test + + actions do + default_accept(:*) + + defaults([:create, :read, :destroy]) + + update :update do + primary?(true) + accept([:column_mapping_embedded, :column_mapping_new_type]) + # require_atomic?(false) + end + end + + attributes do + uuid_primary_key(:id) + + attribute(:column_mapping_embedded, {:array, Test.CSVColumnMatchingEmbedded}, public?: true) + attribute(:column_mapping_new_type, {:array, Test.CSVColumnMatchingEmbedded}, public?: true) + end + + postgres do + table "csv" + repo(AshPostgres.TestRepo) + + storage_types column_mapping_embedded: :jsonb + storage_types column_mapping_new_type: :jsonb + end +end From e1adfacfa7a086dc03d97fac1f1d430a9bcafea2 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 21 Mar 2025 10:25:09 -0400 Subject: [PATCH 449/690] test: add test for loading aggs on aggregate --- test/aggregate_test.exs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index dc784612..d3aeec87 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -128,6 +128,32 @@ defmodule AshSql.AggregateTest do describe "Context Multitenancy" do alias AshPostgres.MultitenancyTest.{Org, Post, User} + test "aggregating with a filter on an aggregate honors the tenant" do + 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 1 == + User + |> Ash.Query.set_tenant("org_#{org.id}") + |> Ash.Query.filter(count_visited > 1) + |> Ash.Query.load(:count_visited) + |> Ash.count!() + end + test "loading a nested aggregate honors tenant" do alias AshPostgres.MultitenancyTest.{Org, Post, User} From c228e0bcbd2bbe482353e3ac3416c9f428714423 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 21 Mar 2025 14:17:01 -0400 Subject: [PATCH 450/690] test: fix tests & update tag/regression test --- .../test_repo/users/20250321142835.json | 130 ++++++++++++++++++ .../20250321142835_migrate_resources52.exs | 36 +++++ test/bulk_update_test.exs | 11 +- test/support/resources/csv.ex | 3 +- 4 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/users/20250321142835.json create mode 100644 priv/test_repo/migrations/20250321142835_migrate_resources52.exs diff --git a/priv/resource_snapshots/test_repo/users/20250321142835.json b/priv/resource_snapshots/test_repo/users/20250321142835.json new file mode 100644 index 00000000..b1842600 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20250321142835.json @@ -0,0 +1,130 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "is_active", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "\"user\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role", + "type": "text" + }, + { + "allow_nil?": true, + "default": "[]", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role_list", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "users_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "name": "users_org_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_orgs" + }, + "size": null, + "source": "org_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "8DC96004D53169EA4AA3721AD7836DB2A230F30C55EE1B06DDB1D7505AE50210", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "users" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250321142835_migrate_resources52.exs b/priv/test_repo/migrations/20250321142835_migrate_resources52.exs new file mode 100644 index 00000000..a347e279 --- /dev/null +++ b/priv/test_repo/migrations/20250321142835_migrate_resources52.exs @@ -0,0 +1,36 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources52 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:users) do + modify(:role_list, {:array, :text}, null: true) + modify(:role, :text, null: true) + + add( + :org_id, + references(:multitenant_orgs, + column: :id, + name: "users_org_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + end + + def down do + drop(constraint(:users, "users_org_id_fkey")) + + alter table(:users) do + remove(:org_id) + modify(:role, :text, null: false) + modify(:role_list, {:array, :text}, null: false) + end + end +end diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index 242ba7f2..5a086645 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -264,7 +264,7 @@ defmodule AshPostgres.BulkUpdateTest do ) end - @tag :wip + @tag :regression test "jsonb[] attribute with embedded Resource definition can be created and updated" do %{status: :success} = Ash.bulk_create!( @@ -275,10 +275,9 @@ defmodule AshPostgres.BulkUpdateTest do return_errors?: true ) - %{status: :success} = - Ash.bulk_update(CSV, :update, %{ - column_mapping_embedded: [%{column: 1, attribute: "foo"}], - column_mapping_new_type: [%{column: 1, attribute: "foo"}] - }) + Ash.bulk_update!(CSV, :update, %{ + column_mapping_embedded: [%{column: 1, attribute: "foo"}], + column_mapping_new_type: [%{column: 1, attribute: "foo"}] + }) end end diff --git a/test/support/resources/csv.ex b/test/support/resources/csv.ex index 59026cba..8a76e703 100644 --- a/test/support/resources/csv.ex +++ b/test/support/resources/csv.ex @@ -50,7 +50,6 @@ defmodule AshPostgres.Test.CSV do table "csv" repo(AshPostgres.TestRepo) - storage_types column_mapping_embedded: :jsonb - storage_types column_mapping_new_type: :jsonb + storage_types column_mapping_embedded: :jsonb, column_mapping_new_type: :jsonb end end From f3c32782b80c4d108f64fdb43a4d5880c18f7ddb Mon Sep 17 00:00:00 2001 From: artiom Date: Fri, 21 Mar 2025 19:04:47 +0000 Subject: [PATCH 451/690] fix: order when renaming attribute with an index (#514) --- .../migration_generator.ex | 13 +++ test/migration_generator_test.exs | 81 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 1c35b6b0..73fe1d3d 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -1375,6 +1375,19 @@ defmodule AshPostgres.MigrationGenerator do true end + defp after?( + %Operation.AddCustomIndex{ + table: table, + schema: schema + }, + %Operation.RenameAttribute{ + table: table, + schema: schema + } + ) do + true + end + defp after?( %Operation.AddReferenceIndex{ table: table, diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 2e9bd9e9..f36418a0 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -393,6 +393,87 @@ defmodule AshPostgres.MigrationGeneratorTest do end end + describe "custom_indexes with follow up migrations" do + setup do + on_exit(fn -> + File.rm_rf!("test_snapshots_path") + File.rm_rf!("test_migration_path") + end) + + defposts do + postgres do + custom_indexes do + index([:title]) + end + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true) + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + end + + test "it changes attribute and index in the correct order" do + defposts do + postgres do + custom_indexes do + index([:title_short]) + end + end + + attributes do + uuid_primary_key(:id) + attribute(:title_short, :string, public?: true) + end + end + + defdomain([Post]) + + send(self(), {:mix_shell_input, :yes?, true}) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [_file1, file2] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + contents = File.read!(file2) + + [up_side, down_side] = String.split(contents, "def down", parts: 2) + + up_side_parts = String.split(up_side, "\n", trim: true) + + assert Enum.find_index(up_side_parts, fn x -> + x == "rename table(:posts), :title, to: :title_short" + end) < + Enum.find_index(up_side_parts, fn x -> + x == "create index(:posts, [:title_short])" + end) + + down_side_parts = String.split(down_side, "\n", trim: true) + + assert Enum.find_index(down_side_parts, fn x -> + x == "rename table(:posts), :title_short, to: :title" + end) < + Enum.find_index(down_side_parts, fn x -> x == "create index(:posts, [:title])" end) + end + end + describe "creating follow up migrations with a composite primary key" do setup do on_exit(fn -> From 33c39d24afd6c7b752d754ec436644b36d1d81eb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 21 Mar 2025 15:05:37 -0400 Subject: [PATCH 452/690] chore: fix credo --- test/bulk_update_test.exs | 2 +- test/support/resources/csv.ex | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index 5a086645..092f964d 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -1,6 +1,6 @@ defmodule AshPostgres.BulkUpdateTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Post, Record, CSV} + alias AshPostgres.Test.{CSV, Post, Record} require Ash.Expr require Ash.Query diff --git a/test/support/resources/csv.ex b/test/support/resources/csv.ex index 8a76e703..91894ed4 100644 --- a/test/support/resources/csv.ex +++ b/test/support/resources/csv.ex @@ -1,4 +1,5 @@ defmodule AshPostgres.Test.CSVColumnMatchingEmbedded do + @moduledoc false use Ash.Resource, data_layer: :embedded @@ -9,6 +10,7 @@ defmodule AshPostgres.Test.CSVColumnMatchingEmbedded do end defmodule AshPostgres.Test.CSVColumnMappingNewType do + @moduledoc false use Ash.Type.NewType, subtype_of: :map, constraints: [ From 762a283f8c15255a4de5526258b8adc8e4e12f9c Mon Sep 17 00:00:00 2001 From: Oliver Severin Mulelid-Tynes Date: Mon, 24 Mar 2025 15:40:31 +0100 Subject: [PATCH 453/690] fix parsing of constraints and indexes that are wrapped in quotes (#515) --- lib/resource_generator/spec.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 12535bbb..d7b83fef 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -397,7 +397,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do |> String.trim_leading("CREATE ") |> String.trim_leading("UNIQUE ") |> String.trim_leading("INDEX ") - |> String.replace(~r/^[a-zA-Z0-9_\.]+\s/, "") + |> String.replace(~r/^"?[a-zA-Z0-9_\.]+"?\s/, "") |> String.trim_leading("ON ") |> String.replace(~r/^[\S]+/, "") |> String.trim_leading() From 14302a4e308d3065ddca359ddaf6de39e956374d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 24 Mar 2025 12:39:54 -0400 Subject: [PATCH 454/690] chore: use atomic --- mix.lock | 8 ++++---- test/atomics_test.exs | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/mix.lock b/mix.lock index 6bb05593..8d6a54cc 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.4.70", "3c104de892a2e31ffb7fe8adf96c10759466d0bdeda7adff8907bf09e56fcca0", [: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", "6e006e8c88c0eb3cdae3b6c15764c03290820429e1a4b40f700767ce689eb671"}, + "ash": {:hex, :ash, "3.4.71", "ce8fa3c38bb59d067647bdc87aa9198335fdeeab36660c869b72c47339fc9d69", [: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", "f255da731b5b3ec4d916b5282faecbbbe9beb64a3641b4a45ac91160ffea3cc9"}, "ash_sql": {:hex, :ash_sql, "0.2.62", "fcf1dde5a453cb024799bd43ab25aee3a7cc4ce7a48f1456310a65aec9e7ea7a", [: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", "df8c72b9b1c7b2c3147334eb63e819bc8d15288e1c6f0ddcd7691530db272ce0"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "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.37", "e677c009fcad535759dfb8fec0214af38acf1f27b7d6d0277d6be61d6bb391e8", [: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", "ca4e5f7c1edead2c6b8955886b010878660c69f3a3f97bf46641b3c39ed339ce"}, + "igniter": {:hex, :igniter, "0.5.38", "436a6414abc9245e539d6c92a6f4854f62270fbf6547c4acf1e5a65c0e4f4d4b", [: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", "e5f1474a2a7ad186f3b71074d9d1ef25d306634e12af4ea01beae06ba958491d"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -40,12 +40,12 @@ "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, "reactor": {:hex, :reactor, "0.15.0", "556937d9310e1a6dd06083592b9eb9e0d212540b6d82faecba70823ee7a0747d", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "f634383a7760ba3106d31a3185f2e2c39e1485d899d884d94c22c62c9b5e7a4a"}, - "req": {:hex, :req, "0.5.9", "09072dcd91a70c58734c4dd4fa878a9b6d36527291152885100ec33a5a07f1d6", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "2f027043003275918f5e79e6a4e57b10cb17161a1ab41c959aa40ecfb2142e5a"}, + "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, - "spark": {:hex, :spark, "2.2.46", "39a1e6b793a754f6a23a1cf12911006125fae0b233250400ad6157991669642d", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "39e4ebfd5bac0c0090e548301680481ed41c1886b0874873363ec22de2bb8a61"}, + "spark": {:hex, :spark, "2.2.48", "dd1005c26c7f98ea686a951f7ae58fffb54eff19c47830e6ff68b93f87433baa", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "379912647b9ddcc5265e91a82a235a264a727123d1f9e90052d91ad8cebbb2d0"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 2b77815a..e3e13395 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -118,9 +118,11 @@ defmodule AshPostgres.AtomicsTest do post |> Ash.Changeset.for_update(:update, %{}) |> Ash.Changeset.atomic_update(%{ - list_of_stuff: [ - %{foo: [%{a: 1, b: %{c: [1, 2, expr(type(fragment("3"), :integer))]}}]} - ] + list_of_stuff: + {:atomic, + [ + %{foo: [%{a: 1, b: %{c: [1, 2, expr(type(fragment("3"), :integer))]}}]} + ]} }) |> Ash.update!() end From b830abc4cf53fc3af3dea73ddd73069d634f57b2 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 25 Mar 2025 11:17:00 -0400 Subject: [PATCH 455/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 8d6a54cc..8415722b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.71", "ce8fa3c38bb59d067647bdc87aa9198335fdeeab36660c869b72c47339fc9d69", [: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", "f255da731b5b3ec4d916b5282faecbbbe9beb64a3641b4a45ac91160ffea3cc9"}, - "ash_sql": {:hex, :ash_sql, "0.2.62", "fcf1dde5a453cb024799bd43ab25aee3a7cc4ce7a48f1456310a65aec9e7ea7a", [: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", "df8c72b9b1c7b2c3147334eb63e819bc8d15288e1c6f0ddcd7691530db272ce0"}, + "ash": {:hex, :ash, "3.4.72", "34596fcfd91822a774495097ce531d92040b629c69d2eca2626ce35e0fea6bb9", [: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", "dce62c275efbfc5e82b35dc5e2a8c655523416079433cf186204f68b39fbc337"}, + "ash_sql": {:hex, :ash_sql, "0.2.63", "1b3c9e9d59d17cccf7b105c96ed15f7236ade502c91432c581bb8ce16507cf29", [: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", "66b99e314ba6fe60bf80a6a4999df50af9ac4053e24b0742225bcd187def44c1"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "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.38", "436a6414abc9245e539d6c92a6f4854f62270fbf6547c4acf1e5a65c0e4f4d4b", [: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", "e5f1474a2a7ad186f3b71074d9d1ef25d306634e12af4ea01beae06ba958491d"}, + "igniter": {:hex, :igniter, "0.5.39", "57b18dff11d929e6f41aba76b3cf92a08393fed2e9a5b1dff5590186572e9040", [: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", "1d962b7062b303e1123cb460b07b6c778bfea4c249c7d4f37fce465ed409ea86"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From b9c38f985d009211548159f603447c07e101b3f4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 25 Mar 2025 11:17:06 -0400 Subject: [PATCH 456/690] chore: release version v2.5.13 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3839c5d9..476609be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.13](https://github.com/ash-project/ash_postgres/compare/v2.5.12...v2.5.13) (2025-03-25) + + + + +### Bug Fixes: + +* order when renaming attribute with an index (#514) + ## [v2.5.12](https://github.com/ash-project/ash_postgres/compare/v2.5.11...v2.5.12) (2025-03-18) diff --git a/mix.exs b/mix.exs index b1d53a58..15a15fd5 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.12" + @version "2.5.13" def project do [ From 05f4220c7f4ca9c627bd4d92a081a4c5a466e87d Mon Sep 17 00:00:00 2001 From: Jechol Lee Date: Wed, 26 Mar 2025 10:42:36 +0900 Subject: [PATCH 457/690] test: loaded relationships remain loaded after update (#516) --- test/update_test.exs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/update_test.exs b/test/update_test.exs index eb656490..d05f9863 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -218,4 +218,25 @@ defmodule AshPostgres.UpdateTest do assert is_nil(post.author) end + + test "loaded relationships remain loaded after update" do + author = + AshPostgres.Test.Author + |> Ash.Changeset.for_create(:create, %{first_name: "foo", last_name: "bar"}) + |> Ash.create!() + + _post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{title: "baz"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + author = author |> Ash.load!(:posts) + + assert [%Post{}] = author.posts + + author = author |> Ash.Changeset.for_update(:update, %{first_name: "foo2"}) |> Ash.update!() + + assert [%Post{}] = author.posts + end end From 72eeb126286584a995645300cea1dadc8ba87cba Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 25 Mar 2025 22:25:28 -0400 Subject: [PATCH 458/690] fix: retain loads on atomic upgrade update actions fixes #517 --- lib/data_layer.ex | 26 +++++++++++++++++--------- test/support/resources/author.ex | 6 +++++- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 54022305..10e69221 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1512,7 +1512,23 @@ defmodule AshPostgres.DataLayer do end) if options[:return_records?] do - {:ok, AshSql.Query.remap_mapped_fields(results, query)} + results = AshSql.Query.remap_mapped_fields(results, query) + + if changeset.context[:data_layer][:use_atomic_update_data?] && + Enum.count_until(results, 2) == 1 do + modifying = + Map.keys(changeset.attributes) ++ + Keyword.keys(changeset.atomics) ++ Ash.Resource.Info.primary_key(resource) + + result = hd(results) + + Map.merge(changeset.data, Map.take(result, modifying)) + |> Map.update!(:aggregates, &Map.merge(&1, result.aggregates)) + |> Map.update!(:calculations, &Map.merge(&1, result.calculations)) + |> then(&{:ok, [&1]}) + else + {:ok, results} + end else :ok end @@ -3042,10 +3058,6 @@ defmodule AshPostgres.DataLayer do def update(resource, changeset) do source = resolve_source(resource, changeset) - modifying = - Map.keys(changeset.attributes) ++ - Keyword.keys(changeset.atomics) ++ Ash.Resource.Info.primary_key(resource) - query = from(row in source, as: ^0) |> AshSql.Bindings.default_bindings( @@ -3075,10 +3087,6 @@ defmodule AshPostgres.DataLayer do )} {:ok, [record]} -> - record = - changeset.data - |> Map.merge(Map.take(record, modifying)) - maybe_update_tenant(resource, changeset, record) {:ok, record} diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index d3beca51..acf9310a 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -35,7 +35,11 @@ defmodule AshPostgres.Test.Author do actions do default_accept(:*) - defaults([:create, :read, :update, :destroy]) + defaults([:create, :read, :destroy]) + + update :update do + primary?(true) + end end relationships do From 5d0d63bb6375636529d541b87a000e042afa1816 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 26 Mar 2025 17:31:37 -0400 Subject: [PATCH 459/690] chore: update deps --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 8415722b..a7225498 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.4.72", "34596fcfd91822a774495097ce531d92040b629c69d2eca2626ce35e0fea6bb9", [: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", "dce62c275efbfc5e82b35dc5e2a8c655523416079433cf186204f68b39fbc337"}, - "ash_sql": {:hex, :ash_sql, "0.2.63", "1b3c9e9d59d17cccf7b105c96ed15f7236ade502c91432c581bb8ce16507cf29", [: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", "66b99e314ba6fe60bf80a6a4999df50af9ac4053e24b0742225bcd187def44c1"}, + "ash": {:hex, :ash, "3.5.0", "8b2342b1a048bdde5cde7bb2696ba0f90ff754785a25648785e706b5f632ae10", [: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", "0c5a9aec7e0f611858bcce933d6677445ae0a63d45cc0c56f02f4aea7fff6cc2"}, + "ash_sql": {:hex, :ash_sql, "0.2.66", "7021417635367802eaeef0efbfe3116ad1c9e5f690d469708ce0bf97b13d7bbf", [:mix], [{:ash, "~> 3.5", [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", "a49b9acb0c14090329ffbe1df8e7b9e8713b377448680c7c204a7483c0ee4899"}, "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"}, @@ -22,8 +22,8 @@ "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "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.39", "57b18dff11d929e6f41aba76b3cf92a08393fed2e9a5b1dff5590186572e9040", [: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", "1d962b7062b303e1123cb460b07b6c778bfea4c249c7d4f37fce465ed409ea86"}, + "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, + "igniter": {:hex, :igniter, "0.5.40", "c5ad8094852173187eeef7dfabd6110df49047ed649d68a549584d9ede0118fc", [: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", "161155d1ed443b60d52c84f01b31130d2156f6ddce581e6c46f496f93de1d804"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 325aa9a65f3d4820b6fb32215e35946fa49ddcd9 Mon Sep 17 00:00:00 2001 From: artiom Date: Thu, 27 Mar 2025 15:13:40 +0000 Subject: [PATCH 460/690] improvement: create schema before table creation (#518) --- lib/migration_generator/phase.ex | 10 ++++++---- test/migration_generator_test.exs | 11 +++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/migration_generator/phase.ex b/lib/migration_generator/phase.ex index b1e3e2b3..d743810d 100644 --- a/lib/migration_generator/phase.ex +++ b/lib/migration_generator/phase.ex @@ -13,14 +13,16 @@ defmodule AshPostgres.MigrationGenerator.Phase do Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <> "\nend" else - opts = + {pre_create, opts} = if schema do - ", prefix: \"#{schema}\"" + {"execute(\"CREATE SCHEMA IF NOT EXISTS #{schema}\")" <> "\n\n", + ", prefix: \"#{schema}\""} else - "" + {"", ""} end - "create table(:#{as_atom(table)}, primary_key: false#{opts}) do\n" <> + pre_create <> + "create table(:#{as_atom(table)}, primary_key: false#{opts}) do\n" <> Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <> "\nend" end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index f36418a0..d9efc296 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -243,14 +243,6 @@ defmodule AshPostgres.MigrationGeneratorTest do defdomain([Post]) - {:ok, _} = - Ecto.Adapters.SQL.query( - AshPostgres.TestRepo, - """ - CREATE SCHEMA IF NOT EXISTS example; - """ - ) - AshPostgres.MigrationGenerator.generate(Domain, snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", @@ -272,6 +264,9 @@ defmodule AshPostgres.MigrationGeneratorTest do file_contents = File.read!(file) + # the migration creates the schema + assert file_contents =~ "execute(\"CREATE SCHEMA IF NOT EXISTS example\")" + # the migration creates the table assert file_contents =~ "create table(:posts, primary_key: false, prefix: \"example\") do" From eb72aaef868db1b43c663e14f17136190356d51e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 28 Mar 2025 08:35:23 -0400 Subject: [PATCH 461/690] fix: remove debugging code accidentally committed --- lib/resource_generator/spec.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index d7b83fef..a0f91cac 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -898,8 +898,6 @@ defmodule AshPostgres.ResourceGenerator.Spec do if opts[:yes?] || opts[:skip_unknown] do "skip" else - raise "what" - Mix.shell().prompt(""" Unknown type: #{attribute.type}. What should we use as the type? From a72ad7e48c9b8fe98140d8ebe3f0ba11b5d4d44c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 28 Mar 2025 08:36:03 -0400 Subject: [PATCH 462/690] chore: release version v2.5.14 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 476609be..31b78a98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.14](https://github.com/ash-project/ash_postgres/compare/v2.5.13...v2.5.14) (2025-03-28) + + + + +### Bug Fixes: + +* remove debugging code accidentally committed + +* retain loads on atomic upgrade update actions + +### Improvements: + +* create schema before table creation (#518) + ## [v2.5.13](https://github.com/ash-project/ash_postgres/compare/v2.5.12...v2.5.13) (2025-03-25) diff --git a/mix.exs b/mix.exs index 15a15fd5..9567037f 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.13" + @version "2.5.14" def project do [ From 8fd3bfbf282d5d142c6004b538b3dbc4c7b59b4e Mon Sep 17 00:00:00 2001 From: artiom Date: Fri, 28 Mar 2025 13:40:00 +0000 Subject: [PATCH 463/690] fix: use schema when changing reference deferrability (#519) --- lib/migration_generator/operation.ex | 30 ++++++++-- test/migration_generator_test.exs | 84 ++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 6 deletions(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 87cea347..14f7b52b 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -454,16 +454,34 @@ defmodule AshPostgres.MigrationGenerator.Operation do @moduledoc false defstruct [:table, :schema, :references, :direction, no_phase: true] - def up(%{direction: :up, table: table, references: %{name: name, deferrable: true}}) do - "execute(\"ALTER TABLE #{table} alter CONSTRAINT #{name} DEFERRABLE INITIALLY IMMEDIATE\");" + defp prefix_name(name, prefix) do + if prefix do + "#{prefix}.#{name}" + else + name + end + end + + def up(%{ + direction: :up, + schema: schema, + table: table, + references: %{name: name, deferrable: true} + }) do + "execute(\"ALTER TABLE #{prefix_name(table, schema)} ALTER CONSTRAINT #{name} DEFERRABLE INITIALLY IMMEDIATE\");" end - def up(%{direction: :up, table: table, references: %{name: name, deferrable: :initially}}) do - "execute(\"ALTER TABLE #{table} alter CONSTRAINT #{name} DEFERRABLE INITIALLY DEFERRED\");" + def up(%{ + direction: :up, + schema: schema, + table: table, + references: %{name: name, deferrable: :initially} + }) do + "execute(\"ALTER TABLE #{prefix_name(table, schema)} ALTER CONSTRAINT #{name} DEFERRABLE INITIALLY DEFERRED\");" end - def up(%{direction: :up, table: table, references: %{name: name}}) do - "execute(\"ALTER TABLE #{table} alter CONSTRAINT #{name} NOT DEFERRABLE\");" + def up(%{direction: :up, schema: schema, table: table, references: %{name: name}}) do + "execute(\"ALTER TABLE #{prefix_name(table, schema)} ALTER CONSTRAINT #{name} NOT DEFERRABLE\");" end def up(_), do: "" diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index d9efc296..8c613055 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -1499,6 +1499,90 @@ defmodule AshPostgres.MigrationGeneratorTest do assert File.read!(file) =~ ~S{create index(:posts, [:post_id])} end + test "references with deferrable modifications generate changes with the correct schema" do + defposts do + attributes do + uuid_primary_key(:id) + attribute(:key_id, :uuid, allow_nil?: false, public?: true) + attribute(:foobar, :string, public?: true) + end + + postgres do + schema "example" + end + end + + defposts Post2 do + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + attribute(:related_key_id, :uuid, public?: true) + end + + relationships do + belongs_to(:post, Post) do + public?(true) + end + end + + postgres do + schema "example" + + references do + reference(:post, index?: true, deferrable: :initially) + end + end + end + + defdomain([Post, Post2]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + defposts Post2 do + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + attribute(:related_key_id, :uuid, public?: true) + end + + relationships do + belongs_to(:post, Post) do + public?(true) + end + end + + postgres do + schema "example" + + references do + reference(:post, index?: true, deferrable: true) + end + end + end + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert file = + "test_migration_path/**/*_migrate_resources*.exs" + |> Path.wildcard() + |> Enum.reject(&String.contains?(&1, "extensions")) + |> Enum.sort() + |> Enum.at(1) + |> File.read!() + + assert file =~ ~S{execute("ALTER TABLE example.posts ALTER CONSTRAINT} + end + test "index generated by index? true also adds column when using attribute multitenancy" do defresource Org, "orgs" do attributes do From ea546a6e278369d2930c6476c93c784d43d30388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Sat, 29 Mar 2025 20:39:08 +0100 Subject: [PATCH 464/690] docs: Use proper flag in ash postgres drop example (#520) --- lib/mix/tasks/ash_postgres.drop.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.drop.ex b/lib/mix/tasks/ash_postgres.drop.ex index 5180d1d3..06d9441d 100644 --- a/lib/mix/tasks/ash_postgres.drop.ex +++ b/lib/mix/tasks/ash_postgres.drop.ex @@ -24,7 +24,7 @@ defmodule Mix.Tasks.AshPostgres.Drop do ## Examples mix ash_postgres.drop - mix ash_postgres.drop -r MyApp.Repo1,MyApp.Repo2 + mix ash_postgres.drop --domains MyApp.Domain1,MyApp.Domain2 ## Command line options From 800900b09311ca2f87321c232a93ca0c082a8c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Sun, 30 Mar 2025 00:20:59 +0100 Subject: [PATCH 465/690] improvement: propagate `-r` flag to Ecto (#521) * Propagate r flag to ecto * Make repos helper function return opts repos when provided --- lib/mix/helpers.ex | 126 +++++++++++++++---------- lib/mix/tasks/ash_postgres.create.ex | 7 +- lib/mix/tasks/ash_postgres.drop.ex | 6 +- lib/mix/tasks/ash_postgres.migrate.ex | 6 +- lib/mix/tasks/ash_postgres.rollback.ex | 5 +- 5 files changed, 91 insertions(+), 59 deletions(-) diff --git a/lib/mix/helpers.ex b/lib/mix/helpers.ex index 26abfabd..2eb2d40b 100644 --- a/lib/mix/helpers.ex +++ b/lib/mix/helpers.ex @@ -38,61 +38,81 @@ defmodule AshPostgres.Mix.Helpers do end def repos!(opts, args) do - if opts[:domains] && opts[:domains] != "" do - domains = domains!(opts, args) + cond do + opts[:repo] && opts[:repo] != "" -> + ensure_load(args) - resources = - domains - |> Enum.flat_map(&Ash.Domain.Info.resources/1) - |> Enum.filter(&(Ash.DataLayer.data_layer(&1) == AshPostgres.DataLayer)) + opts[:repo] + |> Kernel.||("") + |> String.split(",") + |> Enum.flat_map(fn + "" -> + [] + + repo -> + [Module.concat([repo])] + end) + |> Enum.map(fn repo -> + case Code.ensure_compiled(repo) do + {:module, _} -> + repo + + {:error, error} -> + Mix.raise("Could not load #{inspect(repo)}, error: #{inspect(error)}. ") + end + end) + + opts[:domains] && opts[:domains] != "" -> + domains = domains!(opts, args) + + resources = + domains + |> Enum.flat_map(&Ash.Domain.Info.resources/1) + |> Enum.filter(&(Ash.DataLayer.data_layer(&1) == AshPostgres.DataLayer)) + |> case do + [] -> + raise """ + No resources with `data_layer: AshPostgres.DataLayer` found in the domains #{Enum.map_join(domains, ",", &inspect/1)}. + + Must be able to find at least one resource with `data_layer: AshPostgres.DataLayer`. + """ + + resources -> + resources + end + + resources + |> Enum.flat_map( + &[ + AshPostgres.DataLayer.Info.repo(&1, :read), + AshPostgres.DataLayer.Info.repo(&1, :mutate) + ] + ) + |> Enum.uniq() |> case do [] -> raise """ - No resources with `data_layer: AshPostgres.DataLayer` found in the domains #{Enum.map_join(domains, ",", &inspect/1)}. + No repos could be found configured on the resources in the domains: #{Enum.map_join(domains, ",", &inspect/1)} - Must be able to find at least one resource with `data_layer: AshPostgres.DataLayer`. - """ + At least one resource must have a repo configured. - resources -> - resources - end + The following resources were found with `data_layer: AshPostgres.DataLayer`: - resources - |> Enum.flat_map( - &[ - AshPostgres.DataLayer.Info.repo(&1, :read), - AshPostgres.DataLayer.Info.repo(&1, :mutate) - ] - ) - |> Enum.uniq() - |> case do - [] -> - raise """ - No repos could be found configured on the resources in the domains: #{Enum.map_join(domains, ",", &inspect/1)} - - At least one resource must have a repo configured. + #{Enum.map_join(resources, "\n", &"* #{inspect(&1)}")} + """ - The following resources were found with `data_layer: AshPostgres.DataLayer`: + repos -> + repos + end - #{Enum.map_join(resources, "\n", &"* #{inspect(&1)}")} - """ + true -> + ensure_load(args) - repos -> - repos - end - else - if Code.ensure_loaded?(Mix.Tasks.App.Config) do - Mix.Task.run("app.config", args) - else - Mix.Task.run("loadpaths", args) - "--no-compile" not in args && Mix.Task.run("compile", args) - end - - Mix.Project.config()[:app] - |> Application.get_env(:ecto_repos, []) - |> Enum.filter(fn repo -> - Spark.implements_behaviour?(repo, AshPostgres.Repo) - end) + Mix.Project.config()[:app] + |> Application.get_env(:ecto_repos, []) + |> Enum.filter(fn repo -> + Spark.implements_behaviour?(repo, AshPostgres.Repo) + end) end end @@ -117,12 +137,7 @@ defmodule AshPostgres.Mix.Helpers do end defp ensure_compiled(domain, args) do - if Code.ensure_loaded?(Mix.Tasks.App.Config) do - Mix.Task.run("app.config", args) - else - Mix.Task.run("loadpaths", args) - "--no-compile" not in args && Mix.Task.run("compile", args) - end + ensure_load(args) case Code.ensure_compiled(domain) do {:module, _} -> @@ -139,6 +154,15 @@ defmodule AshPostgres.Mix.Helpers do end end + defp ensure_load(args) do + if Code.ensure_loaded?(Mix.Tasks.App.Config) do + Mix.Task.run("app.config", args) + else + Mix.Task.run("loadpaths", args) + "--no-compile" not in args && Mix.Task.run("compile", args) + end + end + def tenants(repo, opts) do tenants = repo.all_tenants() diff --git a/lib/mix/tasks/ash_postgres.create.ex b/lib/mix/tasks/ash_postgres.create.ex index e8b67469..bfe117b1 100644 --- a/lib/mix/tasks/ash_postgres.create.ex +++ b/lib/mix/tasks/ash_postgres.create.ex @@ -7,11 +7,14 @@ defmodule Mix.Tasks.AshPostgres.Create do quiet: :boolean, domains: :string, no_compile: :boolean, - no_deps_check: :boolean + no_deps_check: :boolean, + repo: :string, + r: :string ] @aliases [ - q: :quiet + q: :quiet, + r: :repo ] @moduledoc """ diff --git a/lib/mix/tasks/ash_postgres.drop.ex b/lib/mix/tasks/ash_postgres.drop.ex index 06d9441d..a79a1025 100644 --- a/lib/mix/tasks/ash_postgres.drop.ex +++ b/lib/mix/tasks/ash_postgres.drop.ex @@ -6,7 +6,8 @@ defmodule Mix.Tasks.AshPostgres.Drop do @aliases [ f: :force, - q: :quiet + q: :quiet, + r: :repo ] @switches [ @@ -15,7 +16,8 @@ defmodule Mix.Tasks.AshPostgres.Drop do quiet: :boolean, domains: :string, no_compile: :boolean, - no_deps_check: :boolean + no_deps_check: :boolean, + repo: :string ] @moduledoc """ diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index 1db3965d..81e4d63f 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -7,7 +7,8 @@ defmodule Mix.Tasks.AshPostgres.Migrate do @shortdoc "Runs the repository migrations for all repositories in the provided (or congigured) domains" @aliases [ - n: :step + n: :step, + r: :repo ] @switches [ @@ -26,7 +27,8 @@ defmodule Mix.Tasks.AshPostgres.Migrate do no_deps_check: :boolean, migrations_path: :keep, only_tenants: :string, - except_tenants: :string + except_tenants: :string, + repo: :string ] @moduledoc """ diff --git a/lib/mix/tasks/ash_postgres.rollback.ex b/lib/mix/tasks/ash_postgres.rollback.ex index afdb3c8d..211dbdff 100644 --- a/lib/mix/tasks/ash_postgres.rollback.ex +++ b/lib/mix/tasks/ash_postgres.rollback.ex @@ -59,9 +59,10 @@ defmodule Mix.Tasks.AshPostgres.Rollback do log_migrations_sql: :boolean, log_migrator_sql: :boolean, only_tenants: :string, - except_tenants: :string + except_tenants: :string, + repo: :string ], - aliases: [n: :step, v: :to] + aliases: [n: :step, v: :to, r: :repo] ) repos = AshPostgres.Mix.Helpers.repos!(opts, args) From a5d69cd8d6fbf7b0bc045c4792caabb62de3e65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Sun, 30 Mar 2025 00:55:08 +0100 Subject: [PATCH 466/690] docs: Document r flag in tasks docs (#522) --- lib/mix/tasks/ash_postgres.create.ex | 1 + lib/mix/tasks/ash_postgres.drop.ex | 1 + lib/mix/tasks/ash_postgres.migrate.ex | 2 ++ lib/mix/tasks/ash_postgres.rollback.ex | 1 + 4 files changed, 5 insertions(+) diff --git a/lib/mix/tasks/ash_postgres.create.ex b/lib/mix/tasks/ash_postgres.create.ex index bfe117b1..a99baf33 100644 --- a/lib/mix/tasks/ash_postgres.create.ex +++ b/lib/mix/tasks/ash_postgres.create.ex @@ -28,6 +28,7 @@ defmodule Mix.Tasks.AshPostgres.Create do ## Command line options * `--domains` - the domains who's repos you want to migrate. + * `-r, --repo` - the repo to create * `--quiet` - do not log output * `--no-compile` - do not compile before creating * `--no-deps-check` - do not compile before creating diff --git a/lib/mix/tasks/ash_postgres.drop.ex b/lib/mix/tasks/ash_postgres.drop.ex index a79a1025..43028c38 100644 --- a/lib/mix/tasks/ash_postgres.drop.ex +++ b/lib/mix/tasks/ash_postgres.drop.ex @@ -31,6 +31,7 @@ defmodule Mix.Tasks.AshPostgres.Drop do ## Command line options * `--domains` - the domains who's repos should be dropped + * `-r, --repo` - the repo to drop * `-q`, `--quiet` - run the command quietly * `-f`, `--force` - do not ask for confirmation when dropping the database. Configuration is asked only when `:start_permanent` is set to true diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index 81e4d63f..36b9187d 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -74,6 +74,8 @@ defmodule Mix.Tasks.AshPostgres.Migrate do * `--all` - run all pending migrations + * `--repo`, `-r` - the repo to migrate + * `--step`, `-n` - run n number of pending migrations * `--to` - run all migrations up to and including version diff --git a/lib/mix/tasks/ash_postgres.rollback.ex b/lib/mix/tasks/ash_postgres.rollback.ex index 211dbdff..b9a8354a 100644 --- a/lib/mix/tasks/ash_postgres.rollback.ex +++ b/lib/mix/tasks/ash_postgres.rollback.ex @@ -32,6 +32,7 @@ defmodule Mix.Tasks.AshPostgres.Rollback do ## Command line options * `--domains` - the domains who's repos should be rolledback * `--all` - revert all applied migrations + * `--repo`, `-r` - the repo to rollback * `--step` / `-n` - revert n number of applied migrations * `--to` / `-v` - revert all migrations down to and including version * `--quiet` - do not log migration commands From 305b7ccccb0494f46b758f22572439ead6dcf6f2 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 31 Mar 2025 00:06:00 +0100 Subject: [PATCH 467/690] fix: use subqueries for join resources --- lib/data_layer.ex | 8 ++++---- test/support/resources/post.ex | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 10e69221..00801cb0 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1189,11 +1189,11 @@ defmodule AshPostgres.DataLayer do destination in query, select_merge: %{__order__: over(row_number(), :order)}, join: - through in ^set_subquery_prefix( + through in subquery(set_subquery_prefix( through_query, source_query, relationship.through - ), + )), as: ^through_binding, on: field(through, ^destination_attribute_on_join_resource) == @@ -1227,11 +1227,11 @@ defmodule AshPostgres.DataLayer do from( destination in query, join: - through in ^set_subquery_prefix( + through in subquery(set_subquery_prefix( through_query, source_query, relationship.through - ), + )), as: ^through_binding, on: field(through, ^destination_attribute_on_join_resource) == diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 602007aa..03cffb30 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -533,6 +533,7 @@ defmodule AshPostgres.Test.Post do public?(true) destination_attribute(:post_id) + filter expr(not is_nil(post.id)) end many_to_many :co_authors, AshPostgres.Test.Author do From 202d55b86ddb6f2963f53893617a94bec2bd4af0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 31 Mar 2025 00:09:00 +0100 Subject: [PATCH 468/690] chore: only use subquery for through resource if it has joins --- lib/data_layer.ex | 26 +++++++++++++++----------- test/support/resources/post.ex | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 00801cb0..5cb460f8 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1182,18 +1182,26 @@ defmodule AshPostgres.DataLayer do {:ok, through_query} -> through_query = Ecto.Query.exclude(through_query, :select) + through_query = + if through_query.joins && through_query.joins != [] do + subquery( + set_subquery_prefix( + through_query, + source_query, + relationship.through + ) + ) + else + through_query + end + if query.__ash_bindings__[:__order__?] do subquery = subquery( from( destination in query, select_merge: %{__order__: over(row_number(), :order)}, - join: - through in subquery(set_subquery_prefix( - through_query, - source_query, - relationship.through - )), + join: through in ^through_query, as: ^through_binding, on: field(through, ^destination_attribute_on_join_resource) == @@ -1227,11 +1235,7 @@ defmodule AshPostgres.DataLayer do from( destination in query, join: - through in subquery(set_subquery_prefix( - through_query, - source_query, - relationship.through - )), + through in ^through_query, as: ^through_binding, on: field(through, ^destination_attribute_on_join_resource) == diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 03cffb30..1173f5f4 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -533,7 +533,7 @@ defmodule AshPostgres.Test.Post do public?(true) destination_attribute(:post_id) - filter expr(not is_nil(post.id)) + filter(expr(not is_nil(post.id))) end many_to_many :co_authors, AshPostgres.Test.Author do From f573576a236331659af0c02a5186543382f9cdeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:26:51 +0100 Subject: [PATCH 469/690] chore(deps): bump the production-dependencies group with 2 updates (#523) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.5.0 to 3.5.2 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/commits/v3.5.2) Updates `igniter` from 0.5.40 to 0.5.43 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.40...v0.5.43) --- updated-dependencies: - dependency-name: ash dependency-version: 3.5.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-version: 0.5.43 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index a7225498..7255eb9b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.0", "8b2342b1a048bdde5cde7bb2696ba0f90ff754785a25648785e706b5f632ae10", [: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", "0c5a9aec7e0f611858bcce933d6677445ae0a63d45cc0c56f02f4aea7fff6cc2"}, + "ash": {:hex, :ash, "3.5.2", "953aebdaca92a00c5ec88988463ff80dc5ea06908b51e7b0e7e843f68bf7cb6c", [: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", "b5cdc43ee58e87380476ec54a6222dc408ccc9580ebcaa3b3e24fd18cc507fd2"}, "ash_sql": {:hex, :ash_sql, "0.2.66", "7021417635367802eaeef0efbfe3116ad1c9e5f690d469708ce0bf97b13d7bbf", [:mix], [{:ash, "~> 3.5", [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", "a49b9acb0c14090329ffbe1df8e7b9e8713b377448680c7c204a7483c0ee4899"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.40", "c5ad8094852173187eeef7dfabd6110df49047ed649d68a549584d9ede0118fc", [: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", "161155d1ed443b60d52c84f01b31130d2156f6ddce581e6c46f496f93de1d804"}, + "igniter": {:hex, :igniter, "0.5.43", "92dcc3e58f7cc78bacc0e560516020e14d5f01b3ac3761e32816e1e8d101eea7", [: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", "d206f9699b4e94d133abaeadbd18a2b2a89bcb3456facb2e1f4d79cd03327bdc"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -44,12 +44,12 @@ "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, + "sourceror": {:hex, :sourceror, "1.8.0", "945d6cda4125f54df9def93b83b7fc8dc52008f9cb69b5883c8bd3ef86769a7d", [:mix], [], "hexpm", "0bb5186726261dece0a13a7f509d389239c23a9447ca612140f5497707452980"}, "spark": {:hex, :spark, "2.2.48", "dd1005c26c7f98ea686a951f7ae58fffb54eff19c47830e6ff68b93f87433baa", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "379912647b9ddcc5265e91a82a235a264a727123d1f9e90052d91ad8cebbb2d0"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, - "stream_data": {:hex, :stream_data, "1.1.3", "15fdb14c64e84437901258bb56fc7d80aaf6ceaf85b9324f359e219241353bfb", [:mix], [], "hexpm", "859eb2be72d74be26c1c4f272905667672a52e44f743839c57c7ee73a1a66420"}, + "stream_data": {:hex, :stream_data, "1.2.0", "58dd3f9e88afe27dc38bef26fce0c84a9e7a96772b2925c7b32cd2435697a52b", [:mix], [], "hexpm", "eb5c546ee3466920314643edf68943a5b14b32d1da9fe01698dc92b73f89a9ed"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, "tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"}, From 21347dc6101e9623f9a3c6ecdfb18a5c91729e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ska=C5=82ecki?= Date: Wed, 9 Apr 2025 10:27:56 +0200 Subject: [PATCH 470/690] docs: Added link to all supported reference options (#525) --- documentation/topics/resources/references.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/documentation/topics/resources/references.md b/documentation/topics/resources/references.md index 91328ddc..10ed6575 100644 --- a/documentation/topics/resources/references.md +++ b/documentation/topics/resources/references.md @@ -14,6 +14,8 @@ postgres do end ``` +All supported DSL options can be found in a [datalayer documentation](https://hexdocs.pm/ash_postgres/dsl-ashpostgres-datalayer.html#postgres-references). + > ### Actions are not used for this behavior {: .warning} > > No resource logic is applied with these operations! No authorization rules or validations take place, and no notifications are issued. This operation happens _directly_ in the database. From 69e610b1370637e3f071f7e8d4ba4e678b2c0aaa Mon Sep 17 00:00:00 2001 From: artiom Date: Thu, 10 Apr 2025 00:08:38 +0100 Subject: [PATCH 471/690] fix: ash postgres subquery usage (#524) --- lib/data_layer.ex | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 5cb460f8..c4295a7a 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1041,12 +1041,16 @@ defmodule AshPostgres.DataLayer do Map.get(relationship, :manual) -> {module, opts} = relationship.manual - module.ash_postgres_subquery( - opts, - 0, - 0, - base_query - ) + case module.ash_postgres_subquery(opts, 0, 0, base_query) do + {:ok, subquery} -> + subquery + + {:error, error} -> + {:error, error} + + subquery -> + subquery + end Map.get(relationship, :no_attributes?) -> base_query @@ -1234,8 +1238,7 @@ defmodule AshPostgres.DataLayer do subquery( from( destination in query, - join: - through in ^through_query, + join: through in ^through_query, as: ^through_binding, on: field(through, ^destination_attribute_on_join_resource) == From bb14fc0f7fdb923f4120e8efebfa0ad3ab44ac7c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 9 Apr 2025 19:15:44 -0400 Subject: [PATCH 472/690] chore: release version v2.5.15 --- CHANGELOG.md | 17 +++++++++++++++++ mix.exs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31b78a98..4a02f4f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.15](https://github.com/ash-project/ash_postgres/compare/v2.5.14...v2.5.15) (2025-04-09) + + + + +### Bug Fixes: + +* ash postgres subquery usage (#524) + +* use subqueries for join resources + +* use schema when changing reference deferrability (#519) + +### Improvements: + +* propagate `-r` flag to Ecto (#521) + ## [v2.5.14](https://github.com/ash-project/ash_postgres/compare/v2.5.13...v2.5.14) (2025-03-28) diff --git a/mix.exs b/mix.exs index 9567037f..f9c27376 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.14" + @version "2.5.15" def project do [ From f0283e893877a7995a4381c496ee8ec13bd00d6f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 9 Apr 2025 23:41:07 -0400 Subject: [PATCH 473/690] fix: use proper migrations path configuration --- lib/migration_generator/migration_generator.ex | 2 +- lib/repo.ex | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 73fe1d3d..ada1b7b7 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -912,7 +912,7 @@ defmodule AshPostgres.MigrationGenerator do Path.join(priv, "tenant_migrations") end else - if path = opts.migration_path || config[:tenant_migrations_path] do + if path = opts.migration_path || config[:migrations_path] do path else priv = diff --git a/lib/repo.ex b/lib/repo.ex index 02d8c703..eb1beebf 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -304,6 +304,7 @@ defmodule AshPostgres.Repo do prefer_transaction?: 0, prefer_transaction_for_atomic_updates?: 0, tenant_migrations_path: 0, + migrations_path: 0, default_prefix: 0, override_migration_type: 1, create?: 0, From a9131244e077b9da2eda2ec239054e071d59d085 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 14:14:15 -0400 Subject: [PATCH 474/690] chore(deps): bump the production-dependencies group with 3 updates (#526) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.5.2 to 3.5.3 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.5.2...v3.5.3) Updates `ash_sql` from 0.2.66 to 0.2.67 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.66...v0.2.67) Updates `igniter` from 0.5.43 to 0.5.44 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.43...v0.5.44) --- updated-dependencies: - dependency-name: ash dependency-version: 3.5.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-version: 0.2.67 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-version: 0.5.44 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mix.lock b/mix.lock index 7255eb9b..25487300 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.2", "953aebdaca92a00c5ec88988463ff80dc5ea06908b51e7b0e7e843f68bf7cb6c", [: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", "b5cdc43ee58e87380476ec54a6222dc408ccc9580ebcaa3b3e24fd18cc507fd2"}, - "ash_sql": {:hex, :ash_sql, "0.2.66", "7021417635367802eaeef0efbfe3116ad1c9e5f690d469708ce0bf97b13d7bbf", [:mix], [{:ash, "~> 3.5", [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", "a49b9acb0c14090329ffbe1df8e7b9e8713b377448680c7c204a7483c0ee4899"}, + "ash": {:hex, :ash, "3.5.3", "4ac587b12d5862adeae3d46961cd42bd51de3d1b8417e367fefcb213579759be", [: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", "bb5ba4451d8cd80a2988cf5126402dd385a9fc7967aa29b4746cd0098f58e8f5"}, + "ash_sql": {:hex, :ash_sql, "0.2.67", "d84ca5432aa6195ba14499ee338e42505e5c7cf217e1d3a48d857c18ba65116c", [:mix], [{:ash, "~> 3.5", [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", "9147993d3740ee12096562610f4df3662a6e61e66b5e2a03846f6764d1a9451e"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.43", "92dcc3e58f7cc78bacc0e560516020e14d5f01b3ac3761e32816e1e8d101eea7", [: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", "d206f9699b4e94d133abaeadbd18a2b2a89bcb3456facb2e1f4d79cd03327bdc"}, + "igniter": {:hex, :igniter, "0.5.44", "a66eb1c74af98c5020ceab5520bbacb55f5f7ffa81854c2dcc1bfe682fd4a75d", [: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", "c47d09b8edb58b092674235e7a9cf1c5ec26f9d45b7afc18fe458f0790251608"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,13 +39,13 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.15.0", "556937d9310e1a6dd06083592b9eb9e0d212540b6d82faecba70823ee7a0747d", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "f634383a7760ba3106d31a3185f2e2c39e1485d899d884d94c22c62c9b5e7a4a"}, + "reactor": {:hex, :reactor, "0.15.1", "91e17d275f268bc33cb02bbf3d9438704073a20b29a5008c594ddf4c01b307f3", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "40bba308c099ddad237211a7f1b1f500f5dec5f4dd6f775f1a63b0a1b80e50ba"}, "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.8.0", "945d6cda4125f54df9def93b83b7fc8dc52008f9cb69b5883c8bd3ef86769a7d", [:mix], [], "hexpm", "0bb5186726261dece0a13a7f509d389239c23a9447ca612140f5497707452980"}, - "spark": {:hex, :spark, "2.2.48", "dd1005c26c7f98ea686a951f7ae58fffb54eff19c47830e6ff68b93f87433baa", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "379912647b9ddcc5265e91a82a235a264a727123d1f9e90052d91ad8cebbb2d0"}, + "sourceror": {:hex, :sourceror, "1.8.2", "f486ddded3b884175583413b431178b691b42d3e616f1ee80bed15503c5f7fd7", [:mix], [], "hexpm", "3f3126d50c222e1029c31861165e73e9c89ebcd543d2896192e2c1d792688fef"}, + "spark": {:hex, :spark, "2.2.49", "6307ddd0359d40a48ad224e5bcb602f2984da036778c4c074dc66110374b5a7a", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "45c0efdf23334f89fa80a4303196902029c73b219b06830bb906ccf21e440cd0"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From a8e385e607c41e4c74ecc6fd1704166858c978d8 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 12 Apr 2025 10:35:32 -0400 Subject: [PATCH 475/690] fix: fixes for map types nested in expressions requires latest ash_sql for build to pass --- lib/sql_implementation.ex | 52 ++++++++++++++-------------------- test/calculation_test.exs | 12 ++++++++ test/support/resources/post.ex | 19 +++++++++++++ 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 8f530861..6648a7e4 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -23,16 +23,16 @@ defmodule AshPostgres.SqlImplementation do nil {:array, type} -> - parameterized_type({:array, Ash.Type.get_type(type)}, [], false) + parameterized_type({:array, Ash.Type.get_type(type)}, []) {:array, type, constraints} -> - parameterized_type({:array, Ash.Type.get_type(type)}, constraints, false) + parameterized_type({:array, Ash.Type.get_type(type)}, constraints) {type, constraints} -> - parameterized_type(type, constraints, false) + parameterized_type(type, constraints) type -> - parameterized_type(type, [], false) + parameterized_type(type, []) end end @@ -241,22 +241,20 @@ defmodule AshPostgres.SqlImplementation do end @impl true - def parameterized_type(type, constraints, no_maps? \\ true) - - def parameterized_type({:parameterized, _} = type, _, _) do + def parameterized_type({:parameterized, _} = type, _) do type end - def parameterized_type({:parameterized, _, _} = type, _, _) do + def parameterized_type({:parameterized, _, _} = type, _) do type end - def parameterized_type({:in, type}, constraints, no_maps?) do - parameterized_type({:array, type}, constraints, no_maps?) + def parameterized_type({:in, type}, constraints) do + parameterized_type({:array, type}, constraints) end - def parameterized_type({:array, type}, constraints, _) do - case parameterized_type(type, constraints[:items] || [], false) do + def parameterized_type({:array, type}, constraints) do + case parameterized_type(type, constraints[:items] || []) do nil -> nil @@ -265,31 +263,23 @@ defmodule AshPostgres.SqlImplementation do end end - def parameterized_type({type, constraints}, [], no_maps?) do - parameterized_type(type, constraints, no_maps?) + def parameterized_type({type, constraints}, []) do + parameterized_type(type, constraints) end - def parameterized_type(Ash.Type.CiString, constraints, no_maps?) do - parameterized_type(AshPostgres.Type.CiStringWrapper, constraints, no_maps?) + def parameterized_type(Ash.Type.CiString, constraints) do + parameterized_type(AshPostgres.Type.CiStringWrapper, constraints) end - def parameterized_type(Ash.Type.String, constraints, no_maps?) do - parameterized_type(AshPostgres.Type.StringWrapper, constraints, no_maps?) + def parameterized_type(Ash.Type.String, constraints) do + parameterized_type(AshPostgres.Type.StringWrapper, constraints) end - def parameterized_type(:tsquery, constraints, no_maps?) do - parameterized_type(AshPostgres.Tsquery, constraints, no_maps?) + def parameterized_type(:tsquery, constraints) do + parameterized_type(AshPostgres.Tsquery, constraints) end - def parameterized_type(type, _constraints, false) - when type in [Ash.Type.Map, Ash.Type.Map.EctoType], - do: :map - - def parameterized_type(type, _constraints, true) - when type in [Ash.Type.Map, Ash.Type.Map.EctoType], - do: nil - - def parameterized_type(type, constraints, no_maps?) do + def parameterized_type(type, constraints) do if Ash.Type.ash_type?(type) do cast_in_query? = if function_exported?(Ash.Type, :cast_in_query?, 2) do @@ -301,7 +291,7 @@ defmodule AshPostgres.SqlImplementation do if cast_in_query? do type = Ash.Type.ecto_type(type) - parameterized_type(type, constraints, no_maps?) + parameterized_type(type, constraints) else nil end @@ -312,7 +302,7 @@ defmodule AshPostgres.SqlImplementation do else case type.type(constraints || []) do :ci_string -> - parameterized_type(AshPostgres.Type.CiStringWrapper, constraints, no_maps?) + parameterized_type(AshPostgres.Type.CiStringWrapper, constraints) _ -> Ecto.ParameterizedType.init(type, constraints || []) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 94d5e5ec..017ca25a 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -776,6 +776,18 @@ defmodule AshPostgres.CalculationTest do end describe "maps" do + test "literal maps inside of conds can be loaded" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "match", score: 42}) + |> Ash.create!() + + assert Ash.load!(post, :literal_map_in_expr).literal_map_in_expr == %{ + match: true, + of: "match" + } + end + test "maps can reference filtered aggregates" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 1173f5f4..97e6131c 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -789,6 +789,25 @@ defmodule AshPostgres.Test.Post do load: [:count_of_comments, :count_of_linked_posts] ) + calculate( + :literal_map_in_expr, + :map, + expr( + cond do + title == "match" -> + %{match: true, of: "match"} + + title == "not-match" -> + %{match: true, of: "not-match"} + + true -> + %{match: false} + end + ) + ) do + constraints(fields: [match: [type: :boolean], of: [type: :string]]) + end + calculate :similarity, :boolean, expr(fragment("(to_tsvector(?) @@ ?)", title, ^arg(:search))) do From 123d137389a138ebaa3702e85f0a0e3e91993840 Mon Sep 17 00:00:00 2001 From: Rebecca Le <543859+sevenseacat@users.noreply.github.com> Date: Sun, 13 Apr 2025 11:08:56 +0800 Subject: [PATCH 476/690] chore: Add `@impl true` to all callback functions in generated Repo module All functions such as `installed_extensions/0` and `min_pg_version/0` are callbacks, and should be marked as such --- lib/mix/tasks/ash_postgres.install.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 555d89e7..364237dd 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -571,6 +571,7 @@ if Code.ensure_loaded?(Igniter) do _ -> {:ok, Igniter.Code.Common.add_code(zipper, """ + @impl true def installed_extensions do # Add extensions here, and the migration generator will install them. ["ash-functions"] @@ -589,6 +590,7 @@ if Code.ensure_loaded?(Igniter) do Igniter.Code.Common.add_code(zipper, """ # Don't open unnecessary transactions # will default to `false` in 4.0 + @impl true def prefer_transaction? do false end @@ -604,6 +606,7 @@ if Code.ensure_loaded?(Igniter) do _ -> {:ok, Igniter.Code.Common.add_code(zipper, """ + @impl true def min_pg_version do %Version{major: #{version.major}, minor: #{version.minor}, patch: #{version.patch}} end From 0e38376e7c6418ea4ca926faebeee8580a7b67d1 Mon Sep 17 00:00:00 2001 From: Oliver Severin Mulelid-Tynes Date: Sun, 13 Apr 2025 22:23:24 +0200 Subject: [PATCH 477/690] test: Add test that provokes filter alias collision with aggregates (#529) --- mix.exs | 3 +- mix.lock | 8 +- .../test_repo/comedians/20250413141328.json | 88 ++++++++++++ .../test_repo/jokes/20250413141328.json | 127 ++++++++++++++++++ .../test_repo/punchlines/20250413141328.json | 78 +++++++++++ .../standup_clubs/20250413141328.json | 59 ++++++++ ...41328_add_punchlines_and_standup_clubs.exs | 119 ++++++++++++++++ test/aggregate_test.exs | 56 ++++++++ test/support/domain.ex | 2 + test/support/resources/comedian.ex | 5 + test/support/resources/joke.ex | 6 + test/support/resources/punchline.ex | 26 ++++ test/support/resources/standup_club.ex | 32 +++++ 13 files changed, 604 insertions(+), 5 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/comedians/20250413141328.json create mode 100644 priv/resource_snapshots/test_repo/jokes/20250413141328.json create mode 100644 priv/resource_snapshots/test_repo/punchlines/20250413141328.json create mode 100644 priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json create mode 100644 priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs create mode 100644 test/support/resources/punchline.ex create mode 100644 test/support/resources/standup_club.ex diff --git a/mix.exs b/mix.exs index f9c27376..a1e5afe9 100644 --- a/mix.exs +++ b/mix.exs @@ -167,7 +167,8 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.62")}, + # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.62")}, + {:ash_sql, github: "ash-project/ash_sql", branch: "main", override: true}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index 25487300..8549a3af 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.3", "4ac587b12d5862adeae3d46961cd42bd51de3d1b8417e367fefcb213579759be", [: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", "bb5ba4451d8cd80a2988cf5126402dd385a9fc7967aa29b4746cd0098f58e8f5"}, - "ash_sql": {:hex, :ash_sql, "0.2.67", "d84ca5432aa6195ba14499ee338e42505e5c7cf217e1d3a48d857c18ba65116c", [:mix], [{:ash, "~> 3.5", [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", "9147993d3740ee12096562610f4df3662a6e61e66b5e2a03846f6764d1a9451e"}, + "ash": {:hex, :ash, "3.5.4", "c401c978a3107c1763143841673ba2b26e007916754fffe67f1b797131db900e", [: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", "7712253e960921f26b6a873e6b50d6ef747f14f2d7a41e19882ac9dd5ac353f8"}, + "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "eceb23ed9440a967d329e7021aa5e6f3fdb05f1b", [branch: "main"]}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.44", "a66eb1c74af98c5020ceab5520bbacb55f5f7ffa81854c2dcc1bfe682fd4a75d", [: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", "c47d09b8edb58b092674235e7a9cf1c5ec26f9d45b7afc18fe458f0790251608"}, + "igniter": {:hex, :igniter, "0.5.45", "9307c6b466b6f6525b5ec7e4d8728bfbdaa376a241f70e09a40d4bb5fe095cfb", [: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", "c34aa1aba378c21cd7969d7463cb76b7b02c51c134a75f68ca758d108ffa7736"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -44,7 +44,7 @@ "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.8.2", "f486ddded3b884175583413b431178b691b42d3e616f1ee80bed15503c5f7fd7", [:mix], [], "hexpm", "3f3126d50c222e1029c31861165e73e9c89ebcd543d2896192e2c1d792688fef"}, + "sourceror": {:hex, :sourceror, "1.9.0", "3bf5fe2d017aaabe3866d8a6da097dd7c331e0d2d54e59e21c2b066d47f1e08e", [:mix], [], "hexpm", "d20a9dd5efe162f0d75a307146faa2e17b823ea4f134f662358d70f0332fed82"}, "spark": {:hex, :spark, "2.2.49", "6307ddd0359d40a48ad224e5bcb602f2984da036778c4c074dc66110374b5a7a", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "45c0efdf23334f89fa80a4303196902029c73b219b06830bb906ccf21e440cd0"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, diff --git a/priv/resource_snapshots/test_repo/comedians/20250413141328.json b/priv/resource_snapshots/test_repo/comedians/20250413141328.json new file mode 100644 index 00000000..01af0669 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comedians/20250413141328.json @@ -0,0 +1,88 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "comedians_standup_club_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "standup_clubs" + }, + "size": null, + "source": "standup_club_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "6F2F271F1118A34E36898BF810B56D211D82E38CF11852AFF656FAB8E6DF3C24", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "comedians" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/jokes/20250413141328.json b/priv/resource_snapshots/test_repo/jokes/20250413141328.json new file mode 100644 index 00000000..7a2dcac1 --- /dev/null +++ b/priv/resource_snapshots/test_repo/jokes/20250413141328.json @@ -0,0 +1,127 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "text", + "type": "text" + }, + { + "allow_nil?": true, + "default": "false", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "is_good", + "type": "boolean" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "jokes_standup_club_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "standup_clubs" + }, + "size": null, + "source": "standup_club_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "jokes_comedian_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "comedians" + }, + "size": null, + "source": "comedian_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "D91D184F68DA42DC309DEBA727AF7FC08A625E89CA3DBD9DD191DF83433F8685", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "jokes" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/punchlines/20250413141328.json b/priv/resource_snapshots/test_repo/punchlines/20250413141328.json new file mode 100644 index 00000000..44a77094 --- /dev/null +++ b/priv/resource_snapshots/test_repo/punchlines/20250413141328.json @@ -0,0 +1,78 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "punchlines_joke_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "jokes" + }, + "size": null, + "source": "joke_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "0262D383DEF61B2296F47C93580740F8FD2A23A30E80B5929133F3C9E7AB13B2", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "punchlines" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json b/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json new file mode 100644 index 00000000..e0342b9a --- /dev/null +++ b/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json @@ -0,0 +1,59 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "1EAC09FCC489E3F2F6A9904F4D59369CC5EAA0C3B821F1F4B0D58B1650DC44CB", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "standup_clubs" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs b/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs new file mode 100644 index 00000000..1e565f40 --- /dev/null +++ b/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs @@ -0,0 +1,119 @@ +defmodule AshPostgres.TestRepo.Migrations.AddPunchlinesAndStandupClubs do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:jokes) do + add(:standup_club_id, :uuid) + end + + alter table(:comedians) do + add(:standup_club_id, :uuid) + end + + create table(:standup_clubs, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + end + + alter table(:jokes) do + modify( + :standup_club_id, + references(:standup_clubs, + column: :id, + name: "jokes_standup_club_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + + alter table(:comedians) do + modify( + :standup_club_id, + references(:standup_clubs, + column: :id, + name: "comedians_standup_club_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + + alter table(:standup_clubs) do + add(:name, :text) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + end + + create table(:punchlines, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + + add(:inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add(:updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + + add( + :joke_id, + references(:jokes, + column: :id, + name: "punchlines_joke_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + end + + def down do + drop(constraint(:punchlines, "punchlines_joke_id_fkey")) + + drop(table(:punchlines)) + + alter table(:standup_clubs) do + remove(:updated_at) + remove(:inserted_at) + remove(:name) + end + + drop(constraint(:comedians, "comedians_standup_club_id_fkey")) + + alter table(:comedians) do + modify(:standup_club_id, :uuid) + end + + drop(constraint(:jokes, "jokes_standup_club_id_fkey")) + + alter table(:jokes) do + modify(:standup_club_id, :uuid) + end + + drop(table(:standup_clubs)) + + alter table(:comedians) do + remove(:standup_club_id) + end + + alter table(:jokes) do + remove(:standup_club_id) + end + end +end diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index d3aeec87..68a52483 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1579,4 +1579,60 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end end + + test "filter and aggregate names do not collide with the same names" do + club = Ash.Seed.seed!(AshPostgres.Test.StandupClub, %{name: "Studio 54"}) + + club_comedians = + Enum.map([1, 2, 3], fn idx -> + Ash.Seed.seed!(AshPostgres.Test.Comedian, %{ + name: "Bill Burr-#{idx}", + standup_club_id: club.id + }) + end) + + # |> IO.inspect() + + Enum.each(club_comedians, fn comedian -> + Range.new(1, Enum.random([2, 3, 4, 5, 6])) + |> Enum.each(fn joke_idx -> + joke = + Ash.Seed.seed!(AshPostgres.Test.Joke, %{ + comedian_id: comedian.id, + text: "Haha I am a joke number #{joke_idx}" + }) + + Range.new(1, Enum.random([2, 3, 4, 5, 6])) + |> Enum.each(fn idx -> + Ash.Seed.seed!(AshPostgres.Test.Punchline, %{joke_id: joke.id}) + end) + end) + end) + + Range.new(1, Enum.random([2, 3, 4, 5, 6])) + |> Enum.each(fn joke_idx -> + joke = + Ash.Seed.seed!(AshPostgres.Test.Joke, %{ + standup_club_id: club.id, + text: "Haha I am a club joke number #{joke_idx}" + }) + + Range.new(1, Enum.random([2, 3, 4, 5, 6])) + |> Enum.each(fn idx -> + Ash.Seed.seed!(AshPostgres.Test.Punchline, %{joke_id: joke.id}) + end) + end) + + filter = %{ + comedians: %{ + jokes: %{ + punchline_count: %{ + greater_than: 0 + } + } + } + } + Ash.Query.filter_input(AshPostgres.Test.StandupClub, filter) + |> Ash.read!(load: [:punchline_count, comedians: [jokes: :punchline_count]]) + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index 36cdab5c..eb1f047c 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -35,6 +35,8 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.DbPoint) resource(AshPostgres.Test.DbStringPoint) resource(AshPostgres.Test.CSV) + resource(AshPostgres.Test.StandupClub) + resource(AshPostgres.Test.Punchline) end authorization do diff --git a/test/support/resources/comedian.ex b/test/support/resources/comedian.ex index a210270c..a61f3c41 100644 --- a/test/support/resources/comedian.ex +++ b/test/support/resources/comedian.ex @@ -13,6 +13,7 @@ defmodule AshPostgres.Test.Comedian do end relationships do + belongs_to(:standup_club, AshPostgres.Test.StandupClub, public?: true) has_many(:jokes, AshPostgres.Test.Joke, public?: true) end @@ -21,6 +22,10 @@ defmodule AshPostgres.Test.Comedian do calculate(:has_jokes_expr, :boolean, expr(has_jokes_mod == true)) end + aggregates do + count(:punchline_count, [:jokes, :punchlines], public?: true) + end + actions do defaults([:read]) diff --git a/test/support/resources/joke.ex b/test/support/resources/joke.ex index a97b1e3f..7f6318f8 100644 --- a/test/support/resources/joke.ex +++ b/test/support/resources/joke.ex @@ -14,13 +14,19 @@ defmodule AshPostgres.Test.Joke do end relationships do + belongs_to(:standup_club, AshPostgres.Test.StandupClub, public?: true) belongs_to(:comedian, AshPostgres.Test.Comedian, public?: true) + has_many(:punchlines, AshPostgres.Test.Punchline, public?: true) end actions do defaults([:read]) end + aggregates do + count(:punchline_count, :punchlines, public?: true) + end + postgres do table("jokes") repo(AshPostgres.TestRepo) diff --git a/test/support/resources/punchline.ex b/test/support/resources/punchline.ex new file mode 100644 index 00000000..90e905d9 --- /dev/null +++ b/test/support/resources/punchline.ex @@ -0,0 +1,26 @@ +defmodule AshPostgres.Test.Punchline do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + attributes do + uuid_primary_key(:id) + create_timestamp(:inserted_at, public?: true) + update_timestamp(:updated_at, public?: true) + end + + relationships do + belongs_to(:joke, AshPostgres.Test.Joke, public?: true) + end + + actions do + defaults([:read]) + end + + postgres do + table("punchlines") + repo(AshPostgres.TestRepo) + end +end diff --git a/test/support/resources/standup_club.ex b/test/support/resources/standup_club.ex new file mode 100644 index 00000000..3dd2e075 --- /dev/null +++ b/test/support/resources/standup_club.ex @@ -0,0 +1,32 @@ +defmodule AshPostgres.Test.StandupClub do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + create_timestamp(:inserted_at, public?: true) + update_timestamp(:updated_at, public?: true) + end + + relationships do + has_many(:comedians, AshPostgres.Test.Comedian, public?: true) + has_many(:jokes, AshPostgres.Test.Joke, public?: true) + end + + actions do + defaults([:read]) + end + + aggregates do + count(:punchline_count, [:jokes, :punchlines], public?: true) + end + + postgres do + table("standup_clubs") + repo(AshPostgres.TestRepo) + end +end From 0a3086242b2f2ec92bdc42aee2a54b6b4745a2e9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 13 Apr 2025 16:23:52 -0400 Subject: [PATCH 478/690] chore: put deps back --- mix.exs | 3 +-- mix.lock | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index a1e5afe9..f9c27376 100644 --- a/mix.exs +++ b/mix.exs @@ -167,8 +167,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.62")}, - {:ash_sql, github: "ash-project/ash_sql", branch: "main", override: true}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.62")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index 8549a3af..42a61fc0 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.4", "c401c978a3107c1763143841673ba2b26e007916754fffe67f1b797131db900e", [: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", "7712253e960921f26b6a873e6b50d6ef747f14f2d7a41e19882ac9dd5ac353f8"}, - "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "eceb23ed9440a967d329e7021aa5e6f3fdb05f1b", [branch: "main"]}, + "ash_sql": {:hex, :ash_sql, "0.2.67", "d84ca5432aa6195ba14499ee338e42505e5c7cf217e1d3a48d857c18ba65116c", [:mix], [{:ash, "~> 3.5", [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", "9147993d3740ee12096562610f4df3662a6e61e66b5e2a03846f6764d1a9451e"}, "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"}, From 2897072324bb1e734e9b7ec17a2fbcf469e51a55 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 15 Apr 2025 14:40:27 -0400 Subject: [PATCH 479/690] chore: update test --- test/aggregate_test.exs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 68a52483..efae1cfa 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1580,6 +1580,7 @@ defmodule AshSql.AggregateTest do end end + @tag :regression test "filter and aggregate names do not collide with the same names" do club = Ash.Seed.seed!(AshPostgres.Test.StandupClub, %{name: "Studio 54"}) @@ -1591,8 +1592,6 @@ defmodule AshSql.AggregateTest do }) end) - # |> IO.inspect() - Enum.each(club_comedians, fn comedian -> Range.new(1, Enum.random([2, 3, 4, 5, 6])) |> Enum.each(fn joke_idx -> @@ -1603,7 +1602,7 @@ defmodule AshSql.AggregateTest do }) Range.new(1, Enum.random([2, 3, 4, 5, 6])) - |> Enum.each(fn idx -> + |> Enum.each(fn _idx -> Ash.Seed.seed!(AshPostgres.Test.Punchline, %{joke_id: joke.id}) end) end) @@ -1618,7 +1617,7 @@ defmodule AshSql.AggregateTest do }) Range.new(1, Enum.random([2, 3, 4, 5, 6])) - |> Enum.each(fn idx -> + |> Enum.each(fn _idx -> Ash.Seed.seed!(AshPostgres.Test.Punchline, %{joke_id: joke.id}) end) end) @@ -1632,7 +1631,8 @@ defmodule AshSql.AggregateTest do } } } + Ash.Query.filter_input(AshPostgres.Test.StandupClub, filter) - |> Ash.read!(load: [:punchline_count, comedians: [jokes: :punchline_count]]) + |> Ash.read!(load: [:punchline_count]) end end From edf5139a7b14c5307dbcea4f53011aac58944e6e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 15 Apr 2025 15:26:37 -0400 Subject: [PATCH 480/690] chore: update dependencies --- mix.exs | 2 +- mix.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mix.exs b/mix.exs index f9c27376..4112123a 100644 --- a/mix.exs +++ b/mix.exs @@ -167,7 +167,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.62")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.68")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index 42a61fc0..9fd68d6c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.4", "c401c978a3107c1763143841673ba2b26e007916754fffe67f1b797131db900e", [: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", "7712253e960921f26b6a873e6b50d6ef747f14f2d7a41e19882ac9dd5ac353f8"}, - "ash_sql": {:hex, :ash_sql, "0.2.67", "d84ca5432aa6195ba14499ee338e42505e5c7cf217e1d3a48d857c18ba65116c", [:mix], [{:ash, "~> 3.5", [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", "9147993d3740ee12096562610f4df3662a6e61e66b5e2a03846f6764d1a9451e"}, + "ash": {:hex, :ash, "3.5.6", "2f187150110b4c280c8551ad411f56d95862fcb37c067a0b8b94eb682bcc43e8", [: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", "d0d9aeb5aacfdc12253fae1e7e4720991868c5f69632c2766afb03b2b1830f55"}, + "ash_sql": {:hex, :ash_sql, "0.2.68", "43ac2cae2d78d273542032f9176d452d70954ec59e427ba87f83882353759c43", [:mix], [{:ash, "~> 3.5", [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", "a9cc1261b956e9a691b84ece66a8fe6d050a993d4d479021e2578ee926d8e843"}, "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"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.45", "9307c6b466b6f6525b5ec7e4d8728bfbdaa376a241f70e09a40d4bb5fe095cfb", [: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", "c34aa1aba378c21cd7969d7463cb76b7b02c51c134a75f68ca758d108ffa7736"}, + "igniter": {:hex, :igniter, "0.5.46", "e3ad5b07a194b6e550ddd303bac45a126a65c6157c8acb664b22011cac8e34fd", [: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", "64c59b696b678b2b83e2ee923f5254ac6479aff6c65dd513383bc0e4cdaeeeb7"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -39,13 +39,13 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.15.1", "91e17d275f268bc33cb02bbf3d9438704073a20b29a5008c594ddf4c01b307f3", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "40bba308c099ddad237211a7f1b1f500f5dec5f4dd6f775f1a63b0a1b80e50ba"}, + "reactor": {:hex, :reactor, "0.15.2", "8c1b3fe0527b7a92b0b22c3f33f2e66858dd069bf1dd51d1031f63cd8cbd1fd5", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "091435a1fa0cab9bc2ed3934b203a0fd190f62e8b6aca63741f9242b8c7631ac"}, "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.9.0", "3bf5fe2d017aaabe3866d8a6da097dd7c331e0d2d54e59e21c2b066d47f1e08e", [:mix], [], "hexpm", "d20a9dd5efe162f0d75a307146faa2e17b823ea4f134f662358d70f0332fed82"}, - "spark": {:hex, :spark, "2.2.49", "6307ddd0359d40a48ad224e5bcb602f2984da036778c4c074dc66110374b5a7a", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "45c0efdf23334f89fa80a4303196902029c73b219b06830bb906ccf21e440cd0"}, + "spark": {:hex, :spark, "2.2.51", "7ed629fc46cdb87c36796c6abf6361f20ee3c7c9a19204e9f4e02a4ce239ce7e", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "996487c3913a4a32c39134e7e7654f0e7fe90d182eb47f3f4933bdeb6792b9b1"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 0afec6a07d44bf093f0ab8bdca2b2be272b35a23 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 15 Apr 2025 15:26:47 -0400 Subject: [PATCH 481/690] chore: release version v2.5.16 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a02f4f0..13990a90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.16](https://github.com/ash-project/ash_postgres/compare/v2.5.15...v2.5.16) (2025-04-15) + + + + +### Bug Fixes: + +* fixes for map types nested in expressions + +* use proper migrations path configuration + ## [v2.5.15](https://github.com/ash-project/ash_postgres/compare/v2.5.14...v2.5.15) (2025-04-09) diff --git a/mix.exs b/mix.exs index 4112123a..878ba703 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.15" + @version "2.5.16" def project do [ From 5c5b64056ea5375ea854b76b05010c5b9b445e3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 09:59:43 -0400 Subject: [PATCH 482/690] chore(deps): bump ash_sql in the production-dependencies group (#530) Bumps the production-dependencies group with 1 update: [ash_sql](https://github.com/ash-project/ash_sql). Updates `ash_sql` from 0.2.68 to 0.2.71 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.68...v0.2.71) --- updated-dependencies: - dependency-name: ash_sql dependency-version: 0.2.71 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 9fd68d6c..ea418a1c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.6", "2f187150110b4c280c8551ad411f56d95862fcb37c067a0b8b94eb682bcc43e8", [: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", "d0d9aeb5aacfdc12253fae1e7e4720991868c5f69632c2766afb03b2b1830f55"}, - "ash_sql": {:hex, :ash_sql, "0.2.68", "43ac2cae2d78d273542032f9176d452d70954ec59e427ba87f83882353759c43", [:mix], [{:ash, "~> 3.5", [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", "a9cc1261b956e9a691b84ece66a8fe6d050a993d4d479021e2578ee926d8e843"}, + "ash_sql": {:hex, :ash_sql, "0.2.71", "40cabdd0c7af2eaa0096b2b0eae886085fed1e3b326e20434274120e11dec2c5", [:mix], [{:ash, "~> 3.5", [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", "6e22da3d020aecaca9858f430828c12988c3418d252fa39be3f43fde9fd4224d"}, "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"}, @@ -45,7 +45,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.9.0", "3bf5fe2d017aaabe3866d8a6da097dd7c331e0d2d54e59e21c2b066d47f1e08e", [:mix], [], "hexpm", "d20a9dd5efe162f0d75a307146faa2e17b823ea4f134f662358d70f0332fed82"}, - "spark": {:hex, :spark, "2.2.51", "7ed629fc46cdb87c36796c6abf6361f20ee3c7c9a19204e9f4e02a4ce239ce7e", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "996487c3913a4a32c39134e7e7654f0e7fe90d182eb47f3f4933bdeb6792b9b1"}, + "spark": {:hex, :spark, "2.2.52", "50094275c9bbafa8e5e9eed0ab61983ee209a500e7044914ccf88e9921ae5082", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "f8de8c298bbbf7abd2a80d0ecabcefef65941f397cdbe94ce6165a121b09084f"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From eb0bc97ddb2a759eab9f34514e23b83bfab23ea4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 10:05:39 -0400 Subject: [PATCH 483/690] chore(deps-dev): bump the dev-dependencies group with 2 updates (#531) Bumps the dev-dependencies group with 2 updates: [benchee](https://github.com/bencheeorg/benchee) and [credo](https://github.com/rrrene/credo). Updates `benchee` from 1.3.1 to 1.4.0 - [Release notes](https://github.com/bencheeorg/benchee/releases) - [Changelog](https://github.com/bencheeorg/benchee/blob/main/CHANGELOG.md) - [Commits](https://github.com/bencheeorg/benchee/compare/1.3.1...1.4.0) Updates `credo` from 1.7.11 to 1.7.12 - [Release notes](https://github.com/rrrene/credo/releases) - [Changelog](https://github.com/rrrene/credo/blob/master/CHANGELOG.md) - [Commits](https://github.com/rrrene/credo/compare/v1.7.11...v1.7.12) --- updated-dependencies: - dependency-name: benchee dependency-version: 1.4.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: credo dependency-version: 1.7.12 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index ea418a1c..2f1ba954 100644 --- a/mix.lock +++ b/mix.lock @@ -1,9 +1,9 @@ %{ "ash": {:hex, :ash, "3.5.6", "2f187150110b4c280c8551ad411f56d95862fcb37c067a0b8b94eb682bcc43e8", [: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", "d0d9aeb5aacfdc12253fae1e7e4720991868c5f69632c2766afb03b2b1830f55"}, "ash_sql": {:hex, :ash_sql, "0.2.71", "40cabdd0c7af2eaa0096b2b0eae886085fed1e3b326e20434274120e11dec2c5", [:mix], [{:ash, "~> 3.5", [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", "6e22da3d020aecaca9858f430828c12988c3418d252fa39be3f43fde9fd4224d"}, - "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"}, + "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "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"}, + "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, @@ -17,7 +17,7 @@ "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, - "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, + "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "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.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, From 77a75fa29024a86f84e85b543c759521be54e7ad Mon Sep 17 00:00:00 2001 From: artiom Date: Fri, 18 Apr 2025 21:42:43 +0100 Subject: [PATCH 484/690] fix: correct order, when renaming attribute with an identity (#533) --- .../migration_generator.ex | 28 +++++++ test/migration_generator_test.exs | 77 +++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index ada1b7b7..a0c04a02 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -1474,6 +1474,21 @@ defmodule AshPostgres.MigrationGenerator do false end + defp after?( + %Operation.RenameAttribute{ + old_attribute: %{source: source}, + table: table, + schema: schema + }, + %Operation.RemoveUniqueIndex{ + identity: %{keys: keys}, + table: table, + schema: schema + } + ) do + source in List.wrap(keys) + end + defp after?( %Operation.RemoveUniqueIndex{table: table, schema: schema}, %{table: table, schema: schema} @@ -1701,6 +1716,19 @@ defmodule AshPostgres.MigrationGenerator do destination_attribute in keys end + defp after?( + %Operation.AlterAttribute{ + old_attribute: %{ + source: source + }, + table: table, + schema: schema + }, + %Operation.RemoveUniqueIndex{identity: %{keys: keys}, table: table, schema: schema} + ) do + source in List.wrap(keys) + end + defp after?( %Operation.AlterAttribute{ new_attribute: %{references: %{table: table, destination_attribute: source}} diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 8c613055..1ef76978 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -1062,6 +1062,83 @@ defmodule AshPostgres.MigrationGeneratorTest do assert File.read!(file2) =~ ~S[rename table(:posts), :subject, to: :title] end + test "when renaming a field with an identity, it asks which field you are renaming it to, and updates indexes in the correct order" do + defposts do + identities do + identity(:subject, [:subject]) + end + + attributes do + uuid_primary_key(:id) + attribute(:subject, :string, public?: true) + end + end + + defdomain([Post]) + + send(self(), {:mix_shell_input, :yes?, true}) + send(self(), {:mix_shell_input, :prompt, "subject"}) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [_file1, file2] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + contents = File.read!(file2) + [up_side, down_side] = String.split(contents, "def down", parts: 2) + + up_side_parts = + String.split(up_side, "\n", trim: true) + |> Enum.map(&String.trim/1) + + drop_index = + Enum.find_index(up_side_parts, fn x -> + x == "drop_if_exists unique_index(:posts, [:title], name: \"posts_title_index\")" + end) + + rename_table = + Enum.find_index(up_side_parts, fn x -> + x == "rename table(:posts), :title, to: :subject" + end) + + create_index = + Enum.find_index(up_side_parts, fn x -> + x == "create unique_index(:posts, [:subject], name: \"posts_subject_index\")" + end) + + assert drop_index < rename_table + assert rename_table < create_index + + down_side_parts = + String.split(down_side, "\n", trim: true) + |> Enum.map(&String.trim/1) + + drop_index = + Enum.find_index(down_side_parts, fn x -> + x == + "drop_if_exists unique_index(:posts, [:subject], name: \"posts_subject_index\")" + end) + + rename_table = + Enum.find_index(down_side_parts, fn x -> + x == "rename table(:posts), :subject, to: :title" + end) + + create_index = + Enum.find_index(down_side_parts, fn x -> + x == "create unique_index(:posts, [:title], name: \"posts_title_index\")" + end) + + assert drop_index < rename_table + assert rename_table < create_index + end + test "when renaming a field, it asks which field you are renaming it to, and adds it if you arent" do defposts do attributes do From 74439d5d8f99f5b9a6d0b27fb245f6d4e53c6721 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 18 Apr 2025 18:11:41 -0400 Subject: [PATCH 485/690] chore: temporarily use main of ash_sql --- mix.exs | 31 ++++++++++++++++--------------- mix.lock | 2 +- test/support/resources/post.ex | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/mix.exs b/mix.exs index 878ba703..56b71df6 100644 --- a/mix.exs +++ b/mix.exs @@ -167,7 +167,8 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.68")}, + # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.68")}, + {:ash_sql, github: "ash-project/ash_sql"}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, @@ -208,24 +209,24 @@ defmodule AshPostgres.MixProject do end end - defp ash_sql_version(default_version) do - case System.get_env("ASH_SQL_VERSION") do - nil -> - default_version + # defp ash_sql_version(default_version) do + # case System.get_env("ASH_SQL_VERSION") do + # nil -> + # default_version - "local" -> - [path: "../ash_sql", override: true] + # "local" -> + # [path: "../ash_sql", override: true] - "main" -> - [git: "https://github.com/ash-project/ash_sql.git"] + # "main" -> + # [git: "https://github.com/ash-project/ash_sql.git"] - version when is_binary(version) -> - "~> #{version}" + # version when is_binary(version) -> + # "~> #{version}" - version -> - version - end - end + # version -> + # version + # end + # end defp aliases do [ diff --git a/mix.lock b/mix.lock index 2f1ba954..60a1e8ac 100644 --- a/mix.lock +++ b/mix.lock @@ -1,7 +1,7 @@ %{ "ash": {:hex, :ash, "3.5.6", "2f187150110b4c280c8551ad411f56d95862fcb37c067a0b8b94eb682bcc43e8", [: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", "d0d9aeb5aacfdc12253fae1e7e4720991868c5f69632c2766afb03b2b1830f55"}, - "ash_sql": {:hex, :ash_sql, "0.2.71", "40cabdd0c7af2eaa0096b2b0eae886085fed1e3b326e20434274120e11dec2c5", [:mix], [{:ash, "~> 3.5", [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", "6e22da3d020aecaca9858f430828c12988c3418d252fa39be3f43fde9fd4224d"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, + "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "91d990700d18055759004a60cc35f3074da3d1a9", []}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 97e6131c..4c251555 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -862,7 +862,7 @@ defmodule AshPostgres.Test.Post do calculate( :start_of_day, :datetime, - expr(start_of_day(fragment("now() AT TIME ZONE 'UTC'"), "EST")) + expr(start_of_day(fragment("now()"), "EST")) ) calculate(:author_count_of_posts, :integer, expr(author.count_of_posts_with_calc)) From 87820a51c325f6467844f51344f7bd8f254e2f62 Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Wed, 23 Apr 2025 00:42:10 +0200 Subject: [PATCH 486/690] fix: add tenant to ash bindings in update (#534) --- lib/data_layer.ex | 7 +++++++ mix.exs | 31 ++++++++++++++-------------- mix.lock | 2 +- test/atomics_test.exs | 47 ++++++++++++++++++++++--------------------- 4 files changed, 47 insertions(+), 40 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index c4295a7a..3d5f7275 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3073,6 +3073,13 @@ defmodule AshPostgres.DataLayer do changeset.context ) |> pkey_filter(changeset.data) + |> then(fn query -> + Map.put( + query, + :__ash_bindings__, + Map.put_new(query.__ash_bindings__, :tenant, changeset.tenant) + ) + end) changeset = Ash.Changeset.set_context(changeset, %{ diff --git a/mix.exs b/mix.exs index 56b71df6..690bfcdd 100644 --- a/mix.exs +++ b/mix.exs @@ -167,8 +167,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.68")}, - {:ash_sql, github: "ash-project/ash_sql"}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, @@ -209,24 +208,24 @@ defmodule AshPostgres.MixProject do end end - # defp ash_sql_version(default_version) do - # case System.get_env("ASH_SQL_VERSION") do - # nil -> - # default_version + defp ash_sql_version(default_version) do + case System.get_env("ASH_SQL_VERSION") do + nil -> + default_version - # "local" -> - # [path: "../ash_sql", override: true] + "local" -> + [path: "../ash_sql", override: true] - # "main" -> - # [git: "https://github.com/ash-project/ash_sql.git"] + "main" -> + [git: "https://github.com/ash-project/ash_sql.git"] - # version when is_binary(version) -> - # "~> #{version}" + version when is_binary(version) -> + "~> #{version}" - # version -> - # version - # end - # end + version -> + version + end + end defp aliases do [ diff --git a/mix.lock b/mix.lock index 60a1e8ac..e282ca96 100644 --- a/mix.lock +++ b/mix.lock @@ -1,7 +1,7 @@ %{ "ash": {:hex, :ash, "3.5.6", "2f187150110b4c280c8551ad411f56d95862fcb37c067a0b8b94eb682bcc43e8", [: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", "d0d9aeb5aacfdc12253fae1e7e4720991868c5f69632c2766afb03b2b1830f55"}, + "ash_sql": {:hex, :ash_sql, "0.2.72", "3c353fd3361257310864dce131acd93e407379439cf8667d7ddb4cba99a3fe2c", [:mix], [{:ash, "~> 3.5", [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", "0a802299580b8406258f9d72ec8c2a39b4d4b9ad49a2631d47a15d3290d7b0eb"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, - "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "91d990700d18055759004a60cc35f3074da3d1a9", []}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, diff --git a/test/atomics_test.exs b/test/atomics_test.exs index e3e13395..301cf8e3 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -3,6 +3,7 @@ defmodule AshPostgres.AtomicsTest do alias AshPostgres.Test.Comment use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Invite alias AshPostgres.Test.Post alias AshPostgres.Test.User @@ -367,29 +368,29 @@ defmodule AshPostgres.AtomicsTest do |> Ash.update!() end - # assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> - # post - # |> Ash.Changeset.new() - # |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) - # |> Ash.Changeset.for_update(:update_if_no_comments_non_atomic, %{title: "bar"}) - # |> Ash.update!() - # end - - # assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - # post - # |> Ash.Changeset.new() - # |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) - # |> Ash.Changeset.for_destroy(:destroy_if_no_comments_non_atomic, %{}) - # |> Ash.destroy!() - # end - - # assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - # post - # |> Ash.Changeset.new() - # |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) - # |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) - # |> Ash.destroy!() - # end + assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_update(:update_if_no_comments_non_atomic, %{title: "bar"}) + |> Ash.update!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_destroy(:destroy_if_no_comments_non_atomic, %{}) + |> Ash.destroy!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) + |> Ash.destroy!() + end end end ) From 0124cb4c82f9327c3565103f0a3f135f1292a04f Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Wed, 23 Apr 2025 00:44:22 +0200 Subject: [PATCH 487/690] chore: release version v2.5.17 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13990a90..bdd05904 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.17](https://github.com/ash-project/ash_postgres/compare/v2.5.16...v2.5.17) (2025-04-22) + + + + +### Bug Fixes: + +* add tenant to ash bindings in update (#534) + +* correct order, when renaming attribute with an identity (#533) + ## [v2.5.16](https://github.com/ash-project/ash_postgres/compare/v2.5.15...v2.5.16) (2025-04-15) diff --git a/mix.exs b/mix.exs index 690bfcdd..7fbd4dac 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.16" + @version "2.5.17" def project do [ From 074b580f77dd47dac463eb6815d40627ea4fe7e3 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Wed, 23 Apr 2025 12:56:25 -0600 Subject: [PATCH 488/690] fix: use old multitenancy in generated removals of previous indexes (#536) --- lib/migration_generator/operation.ex | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 14f7b52b..475b88e5 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1219,29 +1219,38 @@ defmodule AshPostgres.MigrationGenerator.Operation do defmodule RemoveCustomIndex do @moduledoc false - defstruct [:schema, :table, :index, :base_filter, :multitenancy, no_phase: true] + defstruct [ + :schema, + :table, + :index, + :base_filter, + :multitenancy, + :old_multitenancy, + no_phase: true + ] + import Helper def up(operation) do - AddCustomIndex.down(operation) + AddCustomIndex.down(%{operation | multitenancy: operation.old_multitenancy}) end def down(operation) do - AddCustomIndex.up(operation) + AddCustomIndex.up(%{operation | multitenancy: operation.old_multitenancy}) end end defmodule RemoveReferenceIndex do @moduledoc false - defstruct [:schema, :table, :source, :multitenancy, no_phase: true] + defstruct [:schema, :table, :source, :multitenancy, :old_multitenancy, no_phase: true] import Helper def up(operation) do - AddReferenceIndex.down(operation) + AddReferenceIndex.down(%{operation | multitenancy: operation.old_multitenancy}) end def down(operation) do - AddReferenceIndex.up(operation) + AddReferenceIndex.up(%{operation | multitenancy: operation.old_multitenancy}) end end From 64c3c82f0910db410441a9a5d63a388e736b74a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 09:48:10 -0400 Subject: [PATCH 489/690] chore(deps): bump igniter in the production-dependencies group (#537) Bumps the production-dependencies group with 1 update: [igniter](https://github.com/ash-project/igniter). Updates `igniter` from 0.5.46 to 0.5.47 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.46...v0.5.47) --- updated-dependencies: - dependency-name: igniter dependency-version: 0.5.47 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index e282ca96..ee0a5788 100644 --- a/mix.lock +++ b/mix.lock @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.46", "e3ad5b07a194b6e550ddd303bac45a126a65c6157c8acb664b22011cac8e34fd", [: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", "64c59b696b678b2b83e2ee923f5254ac6479aff6c65dd513383bc0e4cdaeeeb7"}, + "igniter": {:hex, :igniter, "0.5.47", "7a1041d5e38303e526fa6b6de37c9e78013f5cb573833ed51183d18e3a152f10", [: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", "53a900909e20f217a25d15a34fef629c562b4822c1fb39cfa5d6999bc72992ed"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 448ac31756a5e6c130888292526acfa2de767162 Mon Sep 17 00:00:00 2001 From: Dmitry Maganov Date: Mon, 28 Apr 2025 15:03:15 -0600 Subject: [PATCH 490/690] fix: fix some issues in migration generator related to tenancy (#539) --- lib/migration_generator/operation.ex | 92 ++++++---------------------- 1 file changed, 18 insertions(+), 74 deletions(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 475b88e5..62b3b3a6 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -127,6 +127,14 @@ defmodule AshPostgres.MigrationGenerator.Operation do end def match_type(_), do: nil + + def index_keys(keys, all_tenants?, multitenancy) do + if multitenancy.strategy == :attribute and not all_tenants? do + [multitenancy.attribute | keys] + else + keys + end + end end defmodule CreateTable do @@ -851,18 +859,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do schema: schema, multitenancy: multitenancy }) do - keys = - if all_tenants? do - keys - else - case multitenancy.strategy do - :attribute -> - [multitenancy.attribute | keys] - - _ -> - keys - end - end + keys = index_keys(keys, all_tenants?, multitenancy) index_name = index_name || "#{table}_#{name}_index" @@ -888,19 +885,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do end def down(%{ - identity: %{name: name, keys: keys, index_name: index_name}, + identity: %{name: name, keys: keys, index_name: index_name, all_tenants?: all_tenants?}, table: table, schema: schema, multitenancy: multitenancy }) do - keys = - case multitenancy.strategy do - :attribute -> - [multitenancy.attribute | keys] - - _ -> - keys - end + keys = index_keys(keys, all_tenants?, multitenancy) index_name = index_name || "#{table}_#{name}_index" @@ -962,12 +952,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do base_filter: base_filter, multitenancy: multitenancy }) do - keys = - if !index.all_tenants? and multitenancy.strategy == :attribute do - [multitenancy.attribute | index.fields] - else - index.fields - end + keys = index_keys(index.fields, index.all_tenants?, multitenancy) index = case {index.where, base_filter} do @@ -997,12 +982,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do end def down(%{schema: schema, index: index, table: table, multitenancy: multitenancy}) do - keys = - if !index.all_tenants? and multitenancy.strategy == :attribute do - [multitenancy.attribute | index.fields] - else - index.fields - end + keys = index_keys(index.fields, index.all_tenants?, multitenancy) opts = join([ @@ -1167,7 +1147,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do @moduledoc false defstruct [:schema, :table, no_phase: true] - def up(%{schema: schema, table: table, multitenancy: multitenancy}) do + def up(%{schema: schema, table: table, old_multitenancy: multitenancy}) do cond do multitenancy.strategy == :context -> "drop constraint(#{inspect(table)}, \"#{table}_pkey\", prefix: prefix())" @@ -1305,48 +1285,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do import Helper - def up(%{ - identity: %{name: name, keys: keys, index_name: index_name}, - table: table, - schema: schema, - old_multitenancy: multitenancy - }) do - keys = - case multitenancy.strategy do - :attribute -> - [multitenancy.attribute | keys] - - _ -> - keys - end - - index_name = index_name || "#{table}_#{name}_index" - - "drop_if_exists unique_index(:#{as_atom(table)}, [#{Enum.map_join(keys, ", ", &inspect/1)}], #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})" + def up(operation) do + AddUniqueIndex.down(%{operation | multitenancy: operation.old_multitenancy}) end - def down(%{ - identity: %{name: name, keys: keys, base_filter: base_filter, index_name: index_name}, - table: table, - schema: schema, - multitenancy: multitenancy - }) do - keys = - case multitenancy.strategy do - :attribute -> - [multitenancy.attribute | keys] - - _ -> - keys - end - - index_name = index_name || "#{table}_#{name}_index" - - if base_filter do - "create unique_index(:#{as_atom(table)}, [#{Enum.map_join(keys, ", ", &inspect/1)}], where: \"#{base_filter}\", #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})" - else - "create unique_index(:#{as_atom(table)}, [#{Enum.map_join(keys, ", ", &inspect/1)}], #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})" - end + def down(operation) do + AddUniqueIndex.up(%{operation | multitenancy: operation.old_multitenancy}) end end From eed58bab9a86b1da4cde4f62cb1959bbaca81bc9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 29 Apr 2025 12:33:59 -0400 Subject: [PATCH 491/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index ee0a5788..f91933a6 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.6", "2f187150110b4c280c8551ad411f56d95862fcb37c067a0b8b94eb682bcc43e8", [: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", "d0d9aeb5aacfdc12253fae1e7e4720991868c5f69632c2766afb03b2b1830f55"}, + "ash": {:hex, :ash, "3.5.7", "bec34ca7c779f034c48df1251c293507c2f1ee707d95656c6b7daed7379bcbbc", [: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", "390b86a3e2f1ef4219d36a254a9a1be279b5387f4a6da551b41f864816e6ea0c"}, "ash_sql": {:hex, :ash_sql, "0.2.72", "3c353fd3361257310864dce131acd93e407379439cf8667d7ddb4cba99a3fe2c", [:mix], [{:ash, "~> 3.5", [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", "0a802299580b8406258f9d72ec8c2a39b4d4b9ad49a2631d47a15d3290d7b0eb"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.47", "7a1041d5e38303e526fa6b6de37c9e78013f5cb573833ed51183d18e3a152f10", [: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", "53a900909e20f217a25d15a34fef629c562b4822c1fb39cfa5d6999bc72992ed"}, + "igniter": {:hex, :igniter, "0.5.48", "2873c71d344c7ab342d08703668581aa48461bf2ebcbf634d03efc222016e426", [: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", "33b4c6cd884f04f9a6ea8774a2f6b71b4504eadff8b9aa2ca9a98c1c4234c0f9"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -45,7 +45,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "sourceror": {:hex, :sourceror, "1.9.0", "3bf5fe2d017aaabe3866d8a6da097dd7c331e0d2d54e59e21c2b066d47f1e08e", [:mix], [], "hexpm", "d20a9dd5efe162f0d75a307146faa2e17b823ea4f134f662358d70f0332fed82"}, - "spark": {:hex, :spark, "2.2.52", "50094275c9bbafa8e5e9eed0ab61983ee209a500e7044914ccf88e9921ae5082", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "f8de8c298bbbf7abd2a80d0ecabcefef65941f397cdbe94ce6165a121b09084f"}, + "spark": {:hex, :spark, "2.2.55", "5a6f6c43fe6528a82bedc397a19561db221f35c64dac8399f5a65c7b14bd15da", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d1a4b295d69ebf49494f9f7c78e5001688888e8e95214c7c4bc2495490330ef3"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 097509c7433afa735d2326cbed1388cce2803cc0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 29 Apr 2025 12:35:04 -0400 Subject: [PATCH 492/690] chore: release version v2.5.18 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdd05904..4d1f872c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.18](https://github.com/ash-project/ash_postgres/compare/v2.5.17...v2.5.18) (2025-04-29) + + + + +### Bug Fixes: + +* fix some issues in migration generator related to tenancy (#539) + +* use old multitenancy in generated removals of previous indexes (#536) + +* add tenant to ash bindings in update (#534) + +* correct order, when renaming attribute with an identity (#533) + ## [v2.5.17](https://github.com/ash-project/ash_postgres/compare/v2.5.16...v2.5.17) (2025-04-22) diff --git a/mix.exs b/mix.exs index 7fbd4dac..02628a3a 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.17" + @version "2.5.18" def project do [ From f74a60be85619b346aafa4e3aaf9bb0127729f57 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 30 Apr 2025 21:44:49 -0400 Subject: [PATCH 493/690] test: add test for https://github.com/ash-project/ash_sql/issues/127 --- test/aggregate_test.exs | 22 ++++++++++++++++++++++ test/support/resources/post.ex | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index efae1cfa..bd34f579 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1025,6 +1025,28 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end + @tag :regression + test "aggregates with parent expressions in their filters are not grouped" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "something else"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + assert %{count_of_comments: 2, count_of_comments_with_same_name: 1} = + post + |> Ash.load!([:count_of_comments, :count_of_comments_with_same_name]) + end + describe "sum" do test "with no related data it returns nil" do post = diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 4c251555..6ddcb160 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -896,6 +896,11 @@ defmodule AshPostgres.Test.Post do aggregates do sum(:sum_of_comment_ratings_calc, [:comments, :ratings], :double_score) count(:count_of_comments, :comments) + + count :count_of_comments_with_same_name, :comments do + filter(expr(title == parent(title))) + end + count(:count_of_linked_posts, :linked_posts) count :count_of_comments_called_match, :comments do From 13b67c6c3c25b1ff2cd3446dbafd73d32549d076 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 30 Apr 2025 21:48:00 -0400 Subject: [PATCH 494/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index f91933a6..9f049d0e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.7", "bec34ca7c779f034c48df1251c293507c2f1ee707d95656c6b7daed7379bcbbc", [: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", "390b86a3e2f1ef4219d36a254a9a1be279b5387f4a6da551b41f864816e6ea0c"}, - "ash_sql": {:hex, :ash_sql, "0.2.72", "3c353fd3361257310864dce131acd93e407379439cf8667d7ddb4cba99a3fe2c", [:mix], [{:ash, "~> 3.5", [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", "0a802299580b8406258f9d72ec8c2a39b4d4b9ad49a2631d47a15d3290d7b0eb"}, + "ash": {:hex, :ash, "3.5.8", "8c9fbc72b9739cd4659595f87685039a3ee373d87933399a6c14596962898989", [: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", "f9a5196152b526795b1650972621b50c3ee0b45d10d6b200dd70e50e7407eb31"}, + "ash_sql": {:hex, :ash_sql, "0.2.74", "f1e1effeb402c2e27680b9629b7ac5f6639474b4f8c074402209bd76ff07f56e", [:mix], [{:ash, "~> 3.5", [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", "16a1e57cc0a6616229630f2dae5be1f4e54d05ef87ad29d073174f15bbcf0edf"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.48", "2873c71d344c7ab342d08703668581aa48461bf2ebcbf634d03efc222016e426", [: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", "33b4c6cd884f04f9a6ea8774a2f6b71b4504eadff8b9aa2ca9a98c1c4234c0f9"}, + "igniter": {:hex, :igniter, "0.5.49", "625bfd1cb8886a3fb729ea67515618e06fc890ef438baca56e5f3a12449510f0", [: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", "a332d5700116d12517d4c2ddce225f0337429fd8cb2cb857dd530a720fa5df3b"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, From 6c67749e674a021adbf6366c0c8f8efb6f62dd3a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 2 May 2025 14:46:54 -0400 Subject: [PATCH 495/690] chore: fix manual relationships example closes #540 --- documentation/topics/advanced/manual-relationships.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/documentation/topics/advanced/manual-relationships.md b/documentation/topics/advanced/manual-relationships.md index 62291adb..8e28bc2d 100644 --- a/documentation/topics/advanced/manual-relationships.md +++ b/documentation/topics/advanced/manual-relationships.md @@ -122,6 +122,9 @@ defmodule MyApp.Employee.ManagedEmployees do |> where([l], l.manager_id in ^employee_ids) |> recursive_cte_query("employee_tree", Employee) |> Repo.all() + |> Map.new(fn employee -> + {employee.id, employee} + end) employees |> with_descendants(all_descendants) From c9269f6b8ef0bcdab3d8bef092e14007c6cd5910 Mon Sep 17 00:00:00 2001 From: user20230119 <123089799+user20230119@users.noreply.github.com> Date: Fri, 2 May 2025 16:19:43 -0400 Subject: [PATCH 496/690] docs: edit manual relationships example with group_by and relationship name (#542) --- .../topics/advanced/manual-relationships.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/documentation/topics/advanced/manual-relationships.md b/documentation/topics/advanced/manual-relationships.md index 8e28bc2d..2da54328 100644 --- a/documentation/topics/advanced/manual-relationships.md +++ b/documentation/topics/advanced/manual-relationships.md @@ -114,7 +114,9 @@ defmodule MyApp.Employee.ManagedEmployees do @impl true @spec load([Employee.t()], keyword, map) :: {:ok, %{Ash.UUID.t() => [Employee.t()]}} | {:error, any} - def load(employees, _opts, _context) do + def load(employees, _opts, context) do + relationship_name = context.relationship.name + employee_ids = Enum.map(employees, & &1.id) all_descendants = @@ -122,23 +124,21 @@ defmodule MyApp.Employee.ManagedEmployees do |> where([l], l.manager_id in ^employee_ids) |> recursive_cte_query("employee_tree", Employee) |> Repo.all() - |> Map.new(fn employee -> - {employee.id, employee} - end) + |> Enum.group_by(& &1.manager_id, & &1) employees - |> with_descendants(all_descendants) - |> Map.new(&{&1.id, &1.descendants}) + |> with_descendants(all_descendants, relationship_name) + |> Map.new(&{&1.id, Map.get(&1, relationship_name)}) |> then(&{:ok, &1}) end - defp with_descendants([], _), do: [] + defp with_descendants([], _, _), do: [] - defp with_descendants(employees, all_descendants) do + defp with_descendants(employees, all_descendants, relationship_name) do Enum.map(employees, fn employee -> descendants = Map.get(all_descendants, employee.id, []) - %{employee | descendants: with_descendants(descendants, all_descendants)} + Map.put(employee, relationship_name, with_descendants(descendants, all_descendants, relationship_name)) end) end From 3205706322b064d039d31613abd8d7eb351ee8af Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 2 May 2025 21:04:25 -0400 Subject: [PATCH 497/690] improvement: support unions (#543) --- lib/data_layer.ex | 48 +++- mix.exs | 6 +- mix.lock | 6 +- test/combination_test.exs | 393 +++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 30 +++ 5 files changed, 470 insertions(+), 13 deletions(-) create mode 100644 test/combination_test.exs diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 3d5f7275..e8d9ca03 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -615,6 +615,8 @@ defmodule AshPostgres.DataLayer do @impl true def can?(_, :async_engine), do: true + def can?(_, :combine), do: true + def can?(_, {:combine, _}), do: true def can?(_, :bulk_create), do: true def can?(_, :action_select), do: true @@ -781,12 +783,24 @@ defmodule AshPostgres.DataLayer do repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, query) with_savepoint(repo, query, fn -> - {:ok, - repo.all( - query, - AshSql.repo_opts(repo, AshPostgres.SqlImplementation, nil, nil, resource) - ) - |> AshSql.Query.remap_mapped_fields(query)} + repo.all( + query, + AshSql.repo_opts(repo, AshPostgres.SqlImplementation, nil, nil, resource) + ) + |> AshSql.Query.remap_mapped_fields(query) + |> then(fn results -> + if query.__ash_bindings__.context[:data_layer][:combination_of_queries?] do + Enum.map(results, fn result -> + struct(resource, result) + |> Map.put(:__meta__, %Ecto.Schema.Metadata{ + state: :loaded + }) + end) + else + results + end + end) + |> then(&{:ok, &1}) end) end rescue @@ -1423,6 +1437,11 @@ defmodule AshPostgres.DataLayer do AshSql.Query.resource_to_query(resource, AshPostgres.SqlImplementation, domain) end + @impl true + def combination_of(combination_of, resource, domain) do + AshSql.Query.combination_of(combination_of, resource, domain, AshPostgres.SqlImplementation) + end + @impl true def update_query(query, changeset, resource, options) do repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset) @@ -1627,7 +1646,7 @@ defmodule AshPostgres.DataLayer do needs_to_join? = requires_adding_inner_join? || query.distinct || - query.limit || query.offset || has_exists? + query.limit || query.offset || has_exists? || query.combinations != [] query = if needs_to_join? do @@ -3253,7 +3272,20 @@ defmodule AshPostgres.DataLayer do @impl true def select(query, select, _resource) do - {:ok, from(row in query, select: struct(row, ^Enum.uniq(select)))} + if query.__ash_bindings__.context[:data_layer][:combination_query?] || + query.__ash_bindings__.context[:data_layer][:combination_of_queries?] do + binding = query.__ash_bindings__.root_binding + + query = + from(row in Ecto.Query.exclude(query, :select), select: %{}) + + Enum.reduce(select, query, fn field, query -> + from(row in query, select_merge: %{^field => field(as(^binding), ^field)}) + end) + |> then(&{:ok, &1}) + else + {:ok, from(row in query, select: struct(row, ^Enum.uniq(select)))} + end end @impl true diff --git a/mix.exs b/mix.exs index 02628a3a..67a6d34f 100644 --- a/mix.exs +++ b/mix.exs @@ -166,8 +166,10 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, + # {:ash, ash_version("~> 3.4 and >= 3.4.69")}, + # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, + {:ash, ash_version(github: "ash-project/ash")}, + {:ash_sql, ash_sql_version(github: "ash-project/ash_sql")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index 9f049d0e..c24b1dc8 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.8", "8c9fbc72b9739cd4659595f87685039a3ee373d87933399a6c14596962898989", [: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", "f9a5196152b526795b1650972621b50c3ee0b45d10d6b200dd70e50e7407eb31"}, - "ash_sql": {:hex, :ash_sql, "0.2.74", "f1e1effeb402c2e27680b9629b7ac5f6639474b4f8c074402209bd76ff07f56e", [:mix], [{:ash, "~> 3.5", [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", "16a1e57cc0a6616229630f2dae5be1f4e54d05ef87ad29d073174f15bbcf0edf"}, + "ash": {:git, "https://github.com/ash-project/ash.git", "ef0a5193d142e004bb5af27c11c8a4e352cff478", []}, + "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "4cc9f2af6385300d14b51a5b104cd1ec64bed6ae", []}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.49", "625bfd1cb8886a3fb729ea67515618e06fc890ef438baca56e5f3a12449510f0", [: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", "a332d5700116d12517d4c2ddce225f0337429fd8cb2cb857dd530a720fa5df3b"}, + "igniter": {:hex, :igniter, "0.5.50", "2f6f3a50e02835e961b6228bfcdebe96cd6e9371042939e7f080c83049057e57", [: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", "2e992df458c044f3a18ff6347275743b21092d6677368fdb8dfded321b85cc7b"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, diff --git a/test/combination_test.exs b/test/combination_test.exs new file mode 100644 index 00000000..e5156ca2 --- /dev/null +++ b/test/combination_test.exs @@ -0,0 +1,393 @@ +defmodule AshPostgres.CombinationTest do + use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Post + + require Ash.Query + import Ash.Expr + + describe "combinations in actions" do + test "with no data" do + Post + |> Ash.Query.for_read(:first_and_last_post) + |> Ash.read!() + end + + test "with data" do + Post + |> Ash.Changeset.for_create(:create, %{title: "title1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title3"}) + |> Ash.create!() + + assert [%{title: "title1"}, %{title: "title3"}] = + Post + |> Ash.Query.for_read(:first_and_last_post) + |> Ash.read!() + end + + test "with data and sort" do + Post + |> Ash.Changeset.for_create(:create, %{title: "title1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title3"}) + |> Ash.create!() + + assert [%{title: "title3"}, %{title: "title1"}] = + Post + |> Ash.Query.for_read(:first_and_last_post) + |> Ash.Query.sort(title: :desc) + |> Ash.read!() + end + + test "with data and sort, limit and filter" do + Post + |> Ash.Changeset.for_create(:create, %{title: "title1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title3"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title4"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "title5"}) + |> Ash.create!() + + assert ["title5", "title4", "title1"] = + Post + |> Ash.Query.for_read(:first_and_last_two_posts) + |> Ash.Query.sort(title: :desc) + |> Ash.Query.filter(title in ["title4", "title5", "title1"]) + |> Ash.Query.limit(3) + |> Ash.read!() + |> Enum.map(& &1.title) + + assert ["title5", "title4", "title2"] = + Post + |> Ash.Query.for_read(:first_and_last_two_posts) + |> Ash.Query.sort(title: :desc) + |> Ash.Query.filter(title in ["title4", "title5", "title2"]) + |> Ash.Query.limit(3) + |> Ash.read!() + |> Enum.map(& &1.title) + end + end + + describe "combinations" do + test "it combines multiple queries into one result set" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post3"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post4"}) + |> Ash.create!() + + assert [%Post{title: "post4"}, %Post{title: "post1"}] = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(title == "post4"), + limit: 1 + ), + Ash.Query.Combination.union_all( + filter: expr(title == "post1"), + limit: 1 + ) + ]) + |> Ash.read!() + end + + test "you can define computed properties" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post3"}) + |> Ash.create!() + + assert [%Post{title: "post3", calculations: %{post_group: 1}}] = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(title == "post3"), + limit: 1, + calculations: %{ + post_group: calc(1, type: :integer), + common_value: calc(1, type: :integer) + } + ), + Ash.Query.Combination.union_all( + filter: expr(title == "post1"), + calculations: %{ + post_group: calc(2, type: :integer), + common_value: calc(1, type: :integer) + }, + limit: 1 + ) + ]) + |> Ash.Query.distinct_sort([{calc(^combinations(:common_value)), :asc}]) + |> Ash.Query.sort([{calc(^combinations(:post_group)), :desc}]) + |> Ash.Query.distinct([{calc(^combinations(:common_value)), :asc}]) + |> Ash.Query.calculate(:post_group, :integer, expr(^combinations(:post_group))) + |> Ash.read!() + end + + test "it handles combinations with intersect" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "shared"}) + |> Ash.create!() + + assert [%Post{title: "shared"}] = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base(filter: expr(title in ["post1", "shared"])), + Ash.Query.Combination.intersect(filter: expr(title in ["post2", "shared"])) + ]) + |> Ash.read!() + end + + test "it handles combinations with except" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "shared"}) + |> Ash.create!() + + result = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base(filter: expr(title in ["post1", "shared"])), + Ash.Query.Combination.except(filter: expr(title == "shared")) + ]) + |> Ash.read!() + + assert length(result) == 1 + assert hd(result).title == "post1" + end + + test "combinations with multiple union_all" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post3"}) + |> Ash.create!() + + result = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base(filter: expr(title == "post1")), + Ash.Query.Combination.union_all(filter: expr(title == "post2")), + Ash.Query.Combination.union_all(filter: expr(title == "post3")) + ]) + |> Ash.read!() + + assert length(result) == 3 + assert Enum.any?(result, &(&1.title == "post1")) + assert Enum.any?(result, &(&1.title == "post2")) + assert Enum.any?(result, &(&1.title == "post3")) + end + + test "combination with offset" do + # Create posts with increasing title numbers for predictable sort order + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post3"}) + |> Ash.create!() + + result = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(contains(title, "post")), + offset: 1, + limit: 2, + sort: [title: :asc] + ) + ]) + |> Ash.read!() + + assert length(result) == 2 + assert hd(result).title == "post2" + assert List.last(result).title == "post3" + end + + test "combinations with complex calculations" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + result = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(title == "post1"), + calculations: %{ + prefix: calc("first", type: :string), + full_title: calc("first-" <> title, type: :string) + } + ), + Ash.Query.Combination.union_all( + filter: expr(title == "post2"), + calculations: %{ + prefix: calc("second", type: :string), + full_title: calc("second-" <> title, type: :string) + } + ) + ]) + |> Ash.Query.calculate(:title_prefix, :string, expr(^combinations(:prefix))) + |> Ash.Query.calculate(:display_title, :string, expr(^combinations(:full_title))) + |> Ash.read!() + + post1 = Enum.find(result, &(&1.title == "post1")) + post2 = Enum.find(result, &(&1.title == "post2")) + + assert post1.calculations.title_prefix == "first" + assert post1.calculations.display_title == "first-post1" + assert post2.calculations.title_prefix == "second" + assert post2.calculations.display_title == "second-post2" + end + + test "combinations with sorting by calculation" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post3"}) + |> Ash.create!() + + result = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base(calculations: %{sort_order: calc(3, type: :integer)}), + Ash.Query.Combination.union_all( + filter: expr(title == "post2"), + calculations: %{sort_order: calc(1, type: :integer)} + ), + Ash.Query.Combination.union_all( + filter: expr(title == "post3"), + calculations: %{sort_order: calc(2, type: :integer)} + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :asc}, {:title, :asc}]) + |> Ash.Query.distinct(:title) + |> Ash.read!() + + assert [first, second, third | _] = result + assert first.title == "post2" + assert second.title == "post3" + assert third.title == "post1" + end + + test "combination with distinct" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1", score: 10}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2", score: 10}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post3", score: 20}) + |> Ash.create!() + + result = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(score == 10), + select: [:id, :score], + calculations: %{score_group: calc("low", type: :string)} + ), + Ash.Query.Combination.union_all( + filter: expr(score == 20), + select: [:id, :score], + calculations: %{score_group: calc("high", type: :string)} + ) + ]) + |> Ash.Query.distinct([{calc(^combinations(:score_group)), :asc}]) + |> Ash.Query.calculate(:upper_title, :string, expr(fragment("UPPER(?)", title))) + |> Ash.read!() + + assert Enum.all?(result, &(&1.calculations.upper_title == String.upcase(&1.title))) + + # Should only have 2 results since we're distinct on score group + assert length(result) == 2 + + groups = + Enum.map(result, & &1.calculations[:score_group]) + + assert "low" in groups + assert "high" in groups + end + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 6ddcb160..e459cfa1 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -154,6 +154,36 @@ defmodule AshPostgres.Test.Post do defaults([:read, :destroy]) + read :first_and_last_post do + prepare(fn query, _ -> + Ash.Query.combination_of(query, [ + Ash.Query.Combination.base( + limit: 1, + sort: [created_at: :desc] + ), + Ash.Query.Combination.union( + limit: 1, + sort: [created_at: :asc] + ) + ]) + end) + end + + read :first_and_last_two_posts do + prepare(fn query, _ -> + Ash.Query.combination_of(query, [ + Ash.Query.Combination.base( + limit: 2, + sort: [created_at: :desc] + ), + Ash.Query.Combination.union( + limit: 2, + sort: [created_at: :asc] + ) + ]) + end) + end + update :add_to_limited_score do argument(:amount, :integer, allow_nil?: false) change(atomic_update(:limited_score, expr((limited_score || 0) + ^arg(:amount)))) From 85790977ddb4323ada6081da0a9dafa4f9a2daf2 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 3 May 2025 02:52:01 -0400 Subject: [PATCH 498/690] chore: update ash_sql --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index c24b1dc8..cfdbd288 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:git, "https://github.com/ash-project/ash.git", "ef0a5193d142e004bb5af27c11c8a4e352cff478", []}, - "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "4cc9f2af6385300d14b51a5b104cd1ec64bed6ae", []}, + "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "6a8fd8559a2a7ecaba439d88101a76ff85f72d31", []}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From 7302636e77e4b6818027038a2beafb64d40c1ddb Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Tue, 6 May 2025 15:46:33 +0200 Subject: [PATCH 499/690] test: that shows that parent stacking works in general but not with filter (#544) --- test/rel_with_parent_filter_test.exs | 46 ++++++++++++++++++++++++++++ test/support/resources/post.ex | 6 ++++ 2 files changed, 52 insertions(+) diff --git a/test/rel_with_parent_filter_test.exs b/test/rel_with_parent_filter_test.exs index 20a4082e..d8fa5161 100644 --- a/test/rel_with_parent_filter_test.exs +++ b/test/rel_with_parent_filter_test.exs @@ -2,6 +2,7 @@ defmodule AshPostgres.RelWithParentFilterTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Author + alias AshPostgres.Test.Post require Ash.Query @@ -75,4 +76,49 @@ defmodule AshPostgres.RelWithParentFilterTest do assert length(authors) == 1 end + + test "can stack parents" do + author = + Author + |> Ash.Changeset.for_create(:create, %{ + first_name: "abc" + }) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "the one", author_id: author.id}) + |> Ash.create!() + + assert %{author_from_exists: author_from_exists} = + Post + |> Ash.Query.for_read(:read) + |> Ash.Query.filter(title == "the one") + |> Ash.Query.load(:author_from_exists) + |> Ash.Query.limit(1) + |> Ash.read_one!() + + assert author_from_exists.id == author.id + end + + test "can filter with stack parents" do + author = + Author + |> Ash.Changeset.for_create(:create, %{ + first_name: "abc" + }) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "the one", author_id: author.id}) + |> Ash.create!() + + assert %{author_from_exists: author_from_exists} = + Post + |> Ash.Query.for_read(:read) + |> Ash.Query.filter(author_from_exists.first_name == "abc") + |> Ash.Query.load(:author_from_exists) + |> Ash.read_one!() + + assert author_from_exists.id == author.id + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index e459cfa1..b6f4e3a5 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -559,6 +559,12 @@ defmodule AshPostgres.Test.Post do public?(true) end + has_one :author_from_exists, AshPostgres.Test.Author do + public?(true) + no_attributes?(true) + filter(expr(exists(posts, id == parent(parent(id))))) + end + has_many :co_author_posts, AshPostgres.Test.CoAuthorPost do public?(true) From 2701fc2017d5bc0a7e04edae770f020d4f500cfa Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 6 May 2025 09:48:23 -0400 Subject: [PATCH 500/690] chore: update deps --- mix.exs | 6 ++---- mix.lock | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mix.exs b/mix.exs index 67a6d34f..02628a3a 100644 --- a/mix.exs +++ b/mix.exs @@ -166,10 +166,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - # {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, - {:ash, ash_version(github: "ash-project/ash")}, - {:ash_sql, ash_sql_version(github: "ash-project/ash_sql")}, + {:ash, ash_version("~> 3.4 and >= 3.4.69")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, diff --git a/mix.lock b/mix.lock index cfdbd288..22e5f67d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:git, "https://github.com/ash-project/ash.git", "ef0a5193d142e004bb5af27c11c8a4e352cff478", []}, - "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "6a8fd8559a2a7ecaba439d88101a76ff85f72d31", []}, + "ash": {:hex, :ash, "3.5.9", "4956f2b0056524757ba23f335f452ce88e8d21daea2c347bfc1c287fdaca7b67", [: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", "a60a6098b23f65cbba54eb376a51f9f0d5937930a9e57999d83cfe7f8ada52ee"}, + "ash_sql": {:hex, :ash_sql, "0.2.75", "94252b460db2e14b778fa542684811c48fa08b4b2a2916db6a05a33e4272c361", [:mix], [{:ash, "~> 3.5", [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", "966226cd5b368258d05359c9a3f37cf86b412f5822a59c85ac27f047ca9e95cb"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From 8d412ce8f458a53f5c2724358bc7cf6c52cb9e3f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 6 May 2025 09:49:05 -0400 Subject: [PATCH 501/690] chore: release version v2.5.19 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d1f872c..1f5bc056 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.19](https://github.com/ash-project/ash_postgres/compare/v2.5.18...v2.5.19) (2025-05-06) + + + + +### Improvements: + +* support unions (#543) + ## [v2.5.18](https://github.com/ash-project/ash_postgres/compare/v2.5.17...v2.5.18) (2025-04-29) diff --git a/mix.exs b/mix.exs index 02628a3a..d0f3950c 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.18" + @version "2.5.19" def project do [ From e963ea0ccdcf2c5733be674d99279877b09d42dc Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 9 May 2025 23:31:13 -0400 Subject: [PATCH 502/690] chore: fix warnings around installers --- lib/mix/tasks/ash_postgres.gen.resources.ex | 7 +-- lib/mix/tasks/ash_postgres.install.ex | 17 +++--- lib/mix/tasks/ash_postgres.setup_vector.ex | 66 +++++++++++++++++++++ 3 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 lib/mix/tasks/ash_postgres.setup_vector.ex diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 9a36d7a9..2196c2f0 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -77,15 +77,14 @@ if Code.ensure_loaded?(Igniter) do end @impl Igniter.Mix.Task - def igniter(igniter, argv) do + def igniter(igniter) do Mix.Task.run("compile") - {%{domain: domain}, argv} = positional_args!(argv) + options = igniter.args.options + domain = igniter.args.positional.domain domain = Igniter.Project.Module.parse(domain) - options = options!(argv) - repos = case options[:repo] do [] -> diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 364237dd..73f50db0 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -21,8 +21,9 @@ if Code.ensure_loaded?(Igniter) do end @impl true - def igniter(igniter, argv) do - opts = options!(argv) + def igniter(igniter) do + argv = igniter.args.argv + opts = igniter.args.options repo = case opts[:repo] do @@ -465,22 +466,22 @@ if Code.ensure_loaded?(Igniter) do notice = if min_pg_version do """ - A `min_pg_version/0` function has been defined + A `min_pg_version/0` function has been defined in `#{inspect(repo)}` as `#{min_pg_version}`. This was based on running `postgres -V`. - You may wish to update this configuration. It should - be set to the lowest version that your application + You may wish to update this configuration. It should + be set to the lowest version that your application expects to be run against. """ else """ - A `min_pg_version/0` function has been defined in + A `min_pg_version/0` function has been defined in `#{inspect(repo)}` automatically. - You may wish to update this configuration. It should - be set to the lowest version that your application + You may wish to update this configuration. It should + be set to the lowest version that your application expects to be run against. """ end diff --git a/lib/mix/tasks/ash_postgres.setup_vector.ex b/lib/mix/tasks/ash_postgres.setup_vector.ex new file mode 100644 index 00000000..c58b6f56 --- /dev/null +++ b/lib/mix/tasks/ash_postgres.setup_vector.ex @@ -0,0 +1,66 @@ +defmodule Mix.Tasks.AshPostgres.SetupVector.Docs do + @moduledoc false + + def short_doc do + "Sets up pgvector for AshPostgres" + end + + def example do + "mix ash_postgres.setup_vector" + end + + def long_doc do + """ + #{short_doc()} + + ## Example + + ```bash + #{example()} + ``` + """ + end +end + +if Code.ensure_loaded?(Igniter) do + defmodule Mix.Tasks.AshPostgres.SetupVector do + @shortdoc "#{__MODULE__.Docs.short_doc()}" + + @moduledoc __MODULE__.Docs.long_doc() + + use Igniter.Mix.Task + + @impl Igniter.Mix.Task + def info(_argv, _composing_task) do + %Igniter.Mix.Task.Info{ + group: :ash_postgres, + example: __MODULE__.Docs.example() + } + end + + @impl Igniter.Mix.Task + def igniter(igniter) do + # Do your work here and return an updated igniter + igniter + # |> Igniter.add_warning("mix ash_postgres.setup_vector is not yet implemented") + end + end +else + defmodule Mix.Tasks.AshPostgres.SetupVector do + @shortdoc "#{__MODULE__.Docs.short_doc()} | Install `igniter` to use" + + @moduledoc __MODULE__.Docs.long_doc() + + use Mix.Task + + def run(_argv) do + Mix.shell().error(""" + The task 'ash_postgres.setup_vector' requires igniter. Please install igniter and try again. + + For more information, see: https://hexdocs.pm/igniter/readme.html#installation + """) + + exit({:shutdown, 1}) + end + end +end From 578a63a8413ea51c6a7bae413e9fec163285ac22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 13:20:08 +0200 Subject: [PATCH 503/690] chore(deps): bump the production-dependencies group with 2 updates (#546) Bumps the production-dependencies group with 2 updates: [ash](https://github.com/ash-project/ash) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.5.9 to 3.5.10 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.5.9...v3.5.10) Updates `igniter` from 0.5.50 to 0.5.51 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.5.50...v0.5.51) --- updated-dependencies: - dependency-name: ash dependency-version: 3.5.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-version: 0.5.51 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 22e5f67d..38ebed66 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.9", "4956f2b0056524757ba23f335f452ce88e8d21daea2c347bfc1c287fdaca7b67", [: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", "a60a6098b23f65cbba54eb376a51f9f0d5937930a9e57999d83cfe7f8ada52ee"}, + "ash": {:hex, :ash, "3.5.10", "123d5f5840326e2aa60204c9dc74b43c1eb35258bffb630d3f4190ee2a123ef1", [: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", "79217d9017bdc3ce5e32f429b9f32b03ef77e07337ccf41f95ac79fe0b3851e0"}, "ash_sql": {:hex, :ash_sql, "0.2.75", "94252b460db2e14b778fa542684811c48fa08b4b2a2916db6a05a33e4272c361", [:mix], [{:ash, "~> 3.5", [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", "966226cd5b368258d05359c9a3f37cf86b412f5822a59c85ac27f047ca9e95cb"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.50", "2f6f3a50e02835e961b6228bfcdebe96cd6e9371042939e7f080c83049057e57", [: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", "2e992df458c044f3a18ff6347275743b21092d6677368fdb8dfded321b85cc7b"}, + "igniter": {:hex, :igniter, "0.5.51", "21c3f9b425bd88572034644781057a793205b401ffd09e1c9498c528f14ef335", [: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", "9f1468d156145b463c6649c61e542befbf75f9d76055456d05c5f6adf7cfb272"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -31,7 +31,7 @@ "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, - "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, @@ -44,8 +44,8 @@ "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, - "sourceror": {:hex, :sourceror, "1.9.0", "3bf5fe2d017aaabe3866d8a6da097dd7c331e0d2d54e59e21c2b066d47f1e08e", [:mix], [], "hexpm", "d20a9dd5efe162f0d75a307146faa2e17b823ea4f134f662358d70f0332fed82"}, - "spark": {:hex, :spark, "2.2.55", "5a6f6c43fe6528a82bedc397a19561db221f35c64dac8399f5a65c7b14bd15da", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d1a4b295d69ebf49494f9f7c78e5001688888e8e95214c7c4bc2495490330ef3"}, + "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, + "spark": {:hex, :spark, "2.2.56", "9426f6b992b13cd2a83ba3567d7a9f8cf8e2f264d019983da12882b43351c9b6", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "ecdc66a91bfd9155047c4f36d594fdf7e72c5f721b451e5aa6967c5439fa2b65"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 4651aa646530aaa19dd58dd24d46fb26e6183ad8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 13:24:46 +0200 Subject: [PATCH 504/690] chore(deps-dev): bump the dev-dependencies group with 2 updates (#547) Bumps the dev-dependencies group with 2 updates: [ex_doc](https://github.com/elixir-lang/ex_doc) and [sobelow](https://github.com/sobelow/sobelow). Updates `ex_doc` from 0.37.3 to 0.38.1 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.37.3...v0.38.1) Updates `sobelow` from 0.13.0 to 0.14.0 - [Changelog](https://github.com/sobelow/sobelow/blob/main/CHANGELOG.md) - [Commits](https://github.com/sobelow/sobelow/commits) --- updated-dependencies: - dependency-name: ex_doc dependency-version: 0.38.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: sobelow dependency-version: 0.14.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 38ebed66..2805978e 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, + "ex_doc": {:hex, :ex_doc, "0.38.1", "bae0a0bd5b5925b1caef4987e3470902d072d03347114ffe03a55dbe206dd4c2", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "754636236d191b895e1e4de2ebb504c057fe1995fdfdd92e9d75c4b05633008b"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "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"}, @@ -43,7 +43,7 @@ "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, - "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, + "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, "spark": {:hex, :spark, "2.2.56", "9426f6b992b13cd2a83ba3567d7a9f8cf8e2f264d019983da12882b43351c9b6", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "ecdc66a91bfd9155047c4f36d594fdf7e72c5f721b451e5aa6967c5439fa2b65"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, From cc6929d98a2cf148311ad78a763c820e709987f5 Mon Sep 17 00:00:00 2001 From: Marc Planelles Date: Mon, 19 May 2025 07:35:47 +0200 Subject: [PATCH 505/690] docs: add example all_tenants implementation (#548) --- .../topics/advanced/schema-based-multitenancy.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/documentation/topics/advanced/schema-based-multitenancy.md b/documentation/topics/advanced/schema-based-multitenancy.md index 2393ebaa..69d7add1 100644 --- a/documentation/topics/advanced/schema-based-multitenancy.md +++ b/documentation/topics/advanced/schema-based-multitenancy.md @@ -10,6 +10,22 @@ The generated migrations include a lot of niceties around multitenancy. Specific Migrations in the tenant directory will call `repo().all_tenants()`, which is a callback you will need to implement in your repo that should return a list of all schemas that need to be migrated. +For example, if you use the `manage_tenant` directive described below, you could do: + +```elixir +defmodule Myapp.Repo do + use AshPostgres.Repo, ... + + import Ecto.Query, only: [from: 2] + + ... + + def all_tenants do + all(from(row in "organizations", select: fragment("? || ?", "org_", row.id))) + end +end +``` + ## Automatically managing tenants By setting the `template` configuration, in the `manage_tenant` section, you can cause the creation/updating of a given resource to create/rename tenants. For example: From dcdafd9ea9735cec0bb2c6098789b0aec4bad4c5 Mon Sep 17 00:00:00 2001 From: Marc Planelles Date: Mon, 19 May 2025 22:59:03 +0200 Subject: [PATCH 506/690] fix: enforce tenant name rules at creation (#550) Closes #549 --- lib/multitenancy.ex | 1 + .../20250519103535.json | 29 +++++++++++++ .../20250519103535_migrate_resources53.exs | 19 +++++++++ test/multitenancy_test.exs | 31 +++++++++++++- test/support/multitenancy/domain.ex | 1 + .../multitenancy/resources/named_org.ex | 41 +++++++++++++++++++ 6 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json create mode 100644 priv/test_repo/migrations/20250519103535_migrate_resources53.exs create mode 100644 test/support/multitenancy/resources/named_org.ex diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 20e67c0c..6927a960 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -5,6 +5,7 @@ defmodule AshPostgres.MultiTenancy do @tenant_name_regex ~r/^[a-zA-Z0-9_-]+$/ def create_tenant!(tenant_name, repo) do + validate_tenant_name!(tenant_name) Ecto.Adapters.SQL.query!(repo, "CREATE SCHEMA IF NOT EXISTS \"#{tenant_name}\"", []) migrate_tenant(tenant_name, repo) diff --git a/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json b/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json new file mode 100644 index 00000000..982b3edb --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json @@ -0,0 +1,29 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "name", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "63124167427BA3C61197814348217EFC967CDAA398102552836E26BD93E198C8", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "multitenant_named_orgs" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250519103535_migrate_resources53.exs b/priv/test_repo/migrations/20250519103535_migrate_resources53.exs new file mode 100644 index 00000000..6059ae3e --- /dev/null +++ b/priv/test_repo/migrations/20250519103535_migrate_resources53.exs @@ -0,0 +1,19 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources53 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:multitenant_named_orgs, primary_key: false) do + add(:name, :text, null: false, primary_key: true) + end + end + + def down do + drop(table(:multitenant_named_orgs)) + end +end diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 73f9cb52..0dd99520 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -2,7 +2,7 @@ defmodule AshPostgres.Test.MultitenancyTest do use AshPostgres.RepoCase, async: false require Ash.Query - alias AshPostgres.MultitenancyTest.{CompositeKeyPost, Org, Post, User} + alias AshPostgres.MultitenancyTest.{CompositeKeyPost, NamedOrg, Org, Post, User} alias AshPostgres.Test.Post, as: GlobalPost setup do @@ -292,4 +292,33 @@ defmodule AshPostgres.Test.MultitenancyTest do |> Ash.create!() end end + + test "rejects characters other than alphanumericals, - and _ on tenant creation" do + assert_raise( + Ash.Error.Unknown, + ~r/Tenant name must match ~r\/\^\[a-zA-Z0-9_-]\+\$\/, got:/, + fn -> + NamedOrg + |> Ash.Changeset.for_create(:create, %{name: "🚫"}) + |> Ash.create!() + end + ) + end + + test "rejects characters other than alphanumericals, - and _ when renaming tenant" do + org = + NamedOrg + |> Ash.Changeset.for_create(:create, %{name: "toto"}) + |> Ash.create!() + + assert_raise( + Ash.Error.Unknown, + ~r/Tenant name must match ~r\/\^\[a-zA-Z0-9_-]\+\$\/, got:/, + fn -> + org + |> Ash.Changeset.for_update(:update, %{name: "🚫"}) + |> Ash.update!() + end + ) + end end diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 85f078da..9ad6f881 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -4,6 +4,7 @@ defmodule AshPostgres.MultitenancyTest.Domain do resources do resource(AshPostgres.MultitenancyTest.Org) + resource(AshPostgres.MultitenancyTest.NamedOrg) resource(AshPostgres.MultitenancyTest.User) resource(AshPostgres.MultitenancyTest.Post) resource(AshPostgres.MultitenancyTest.PostLink) diff --git a/test/support/multitenancy/resources/named_org.ex b/test/support/multitenancy/resources/named_org.ex new file mode 100644 index 00000000..537ea337 --- /dev/null +++ b/test/support/multitenancy/resources/named_org.ex @@ -0,0 +1,41 @@ +defmodule AshPostgres.MultitenancyTest.NamedOrg do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.MultitenancyTest.Domain, + data_layer: AshPostgres.DataLayer + + defimpl Ash.ToTenant do + def to_tenant(%{name: name}, resource) do + if Ash.Resource.Info.data_layer(resource) == AshPostgres.DataLayer && + Ash.Resource.Info.multitenancy_strategy(resource) == :context do + "org_#{name}" + else + name + end + end + end + + attributes do + attribute(:name, :string, + primary_key?: true, + allow_nil?: false, + public?: true, + writable?: true + ) + end + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + end + + postgres do + table "multitenant_named_orgs" + repo(AshPostgres.TestRepo) + + manage_tenant do + template(["org_", :name]) + end + end +end From 391b8cb5bd2c69a0bcf4c1032492d60ca78c250e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 19 May 2025 16:22:04 +0200 Subject: [PATCH 507/690] fix: self-join if combination queries require more fields In a query like this: ```elixir Post |> Ash.Query.combination_of([ Ash.Query.Combination.base( filter: expr(score == 10), select: [:id, :score], ), Ash.Query.Combination.union_all( filter: expr(score == 20), select: [:id, :score], ) ]) |> Ash.Query.filter(category == "category1") |> Ash.read!() ``` you'd get a SQL query something like this (before my fix): ```sql SELECT id, score FROM ( SELECT id, score FROM posts WHERE score = 10 UNION ALL SELECT id, score FROM posts WHERE score = 20 ) AS posts WHERE posts.category = "category1" ``` Which wouldn't work because `category` is not a part of the inner selects. Now we add a `JOIN` on primary key to the table, and then include all the fields we're missing from that table, in any conditions that we would reference a field that wasn't selected in the combinations. --- lib/data_layer.ex | 123 +++++++++++++++++++++++++++++++++++++- test/combination_test.exs | 45 ++++++++++++-- 2 files changed, 162 insertions(+), 6 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index e8d9ca03..5383ac26 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3262,6 +3262,8 @@ defmodule AshPostgres.DataLayer do @impl true def sort(query, sort, _resource) do + query = maybe_subquery_upgrade(query, {:sort, sort}) + {:ok, Map.update!( query, @@ -3272,12 +3274,18 @@ defmodule AshPostgres.DataLayer do @impl true def select(query, select, _resource) do + query = maybe_subquery_upgrade(query, {:select, select}) + if query.__ash_bindings__.context[:data_layer][:combination_query?] || query.__ash_bindings__.context[:data_layer][:combination_of_queries?] do binding = query.__ash_bindings__.root_binding - query = - from(row in Ecto.Query.exclude(query, :select), select: %{}) + {query, select} = + if field_set = query.__ash_bindings__[:already_selected] do + {query, select -- field_set} + else + {from(row in Ecto.Query.exclude(query, :select), select: %{}), select} + end Enum.reduce(select, query, fn field, query -> from(row in query, select_merge: %{^field => field(as(^binding), ^field)}) @@ -3294,6 +3302,7 @@ defmodule AshPostgres.DataLayer do end def distinct_sort(query, sort, _) do + query = maybe_subquery_upgrade(query, {:distinct_sort, sort}) {:ok, Map.update!(query, :__ash_bindings__, &Map.put(&1, :distinct_sort, sort))} end @@ -3302,11 +3311,13 @@ defmodule AshPostgres.DataLayer do # to come up with alternatives here. @impl true def distinct(query, distinct, resource) do + query = maybe_subquery_upgrade(query, {:distinct, distinct}) AshSql.Distinct.distinct(query, distinct, resource) end @impl true def filter(query, filter, resource, opts \\ []) do + query = maybe_subquery_upgrade(query, {:filter, filter}) used_aggregates = Ash.Filter.used_aggregates(filter, []) query = @@ -3336,6 +3347,112 @@ defmodule AshPostgres.DataLayer do end end + defp maybe_subquery_upgrade( + %{__ash_bindings__: %{subquery_upgrade?: true}} = query, + _ + ) do + query + end + + defp maybe_subquery_upgrade(query, type) do + fieldset = query.__ash_bindings__.context[:data_layer][:combination_fieldset] + + if query.__ash_bindings__.context[:data_layer][:combination_of_queries?] && fieldset do + requires_join? = + case type do + {:filter, contents} -> + Enum.any?( + Ash.Filter.list_refs(contents), + &(&1.relationship_path != [] || &1.attribute.name not in fieldset) + ) + + {:calculations, calculations} -> + Enum.any?(calculations, fn {_, expr} -> + Enum.any?( + Ash.Filter.list_refs(expr), + &(&1.relationship_path != [] || &1.attribute.name not in fieldset) + ) + end) + + {sort, sorts} when sort in [:sort, :distinct, :distinct_sort] -> + Enum.any?(sorts, fn + {atom, _} when is_atom(atom) -> + atom not in fieldset + + {%Ash.Query.Calculation{} = calc, _} -> + calc.opts + |> calc.module.expression(calc.context) + |> Ash.Filter.hydrate_refs(%{ + resource: query.__ash_bindings__.resource, + parent_stack: query.__ash_bindings__[:parent_resources] || [], + public?: false + }) + |> Ash.Filter.list_refs() + |> Enum.any?(&(&1.relationship_path != [] || &1.attribute.name not in fieldset)) + + _ -> + true + end) + + {:select, select} -> + Enum.any?(select, &(&1 not in fieldset)) + end + + resource = query.__ash_bindings__.resource + + if requires_join? do + primary_key = Ash.Resource.Info.primary_key(query.__ash_bindings__.resource) + + if primary_key != [] && primary_key -- fieldset == [] do + dynamic = + Enum.reduce(primary_key, nil, fn key, expr -> + if is_nil(expr) do + Ecto.Query.dynamic([l, r], field(l, ^key) == field(r, ^key)) + else + Ecto.Query.dynamic([l, r], field(l, ^key) == field(r, ^key) and ^expr) + end + end) + + default_select = + MapSet.to_list( + Ash.Resource.Info.selected_by_default_attribute_names( + query.__ash_bindings__.resource + ) + ) + + query_with_select = + from(sub in query, + join: row in ^query.__ash_bindings__.resource, + # why doesn't `.root_binding` work the way I expect it to here? + on: ^dynamic, + select: map(row, ^default_select), + select_merge: map(sub, ^fieldset) + ) + + from(row in subquery(query_with_select), as: ^0) + |> AshSql.Bindings.default_bindings(resource, AshPostgres.SqlImplementation) + |> Map.update!( + :__ash_bindings__, + &Map.merge(&1, %{ + already_selected: fieldset, + subquery_upgrade?: true, + context: query.__ash_bindings__.context + }) + ) + else + raise """ + Unsupported combination query. Combinations must select the primary key if referencing + any fields that are *not* selected by the combinations in filter, sort & distinct. + """ + end + else + query + end + else + query + end + end + @impl true def add_aggregates(query, aggregates, resource) do AshSql.Aggregate.add_aggregates( @@ -3349,6 +3466,8 @@ defmodule AshPostgres.DataLayer do @impl true def add_calculations(query, calculations, resource, select? \\ true) do + query = maybe_subquery_upgrade(query, {:calculations, calculations}) + AshSql.Calculation.add_calculations( query, calculations, diff --git a/test/combination_test.exs b/test/combination_test.exs index e5156ca2..086ae91d 100644 --- a/test/combination_test.exs +++ b/test/combination_test.exs @@ -110,7 +110,7 @@ defmodule AshPostgres.CombinationTest do |> Ash.Changeset.for_create(:create, %{title: "post4"}) |> Ash.create!() - assert [%Post{title: "post4"}, %Post{title: "post1"}] = + assert [%{title: "post4"}, %{title: "post1"}] = Post |> Ash.Query.combination_of([ Ash.Query.Combination.base( @@ -122,7 +122,9 @@ defmodule AshPostgres.CombinationTest do limit: 1 ) ]) + |> Ash.Query.sort(title: :desc) |> Ash.read!() + |> Enum.map(&Map.take(&1, [:title])) end test "you can define computed properties" do @@ -143,6 +145,7 @@ defmodule AshPostgres.CombinationTest do |> Ash.Query.combination_of([ Ash.Query.Combination.base( filter: expr(title == "post3"), + select: [:id], limit: 1, calculations: %{ post_group: calc(1, type: :integer), @@ -151,6 +154,7 @@ defmodule AshPostgres.CombinationTest do ), Ash.Query.Combination.union_all( filter: expr(title == "post1"), + select: [:id], calculations: %{ post_group: calc(2, type: :integer), common_value: calc(1, type: :integer) @@ -158,9 +162,8 @@ defmodule AshPostgres.CombinationTest do limit: 1 ) ]) - |> Ash.Query.distinct_sort([{calc(^combinations(:common_value)), :asc}]) - |> Ash.Query.sort([{calc(^combinations(:post_group)), :desc}]) - |> Ash.Query.distinct([{calc(^combinations(:common_value)), :asc}]) + |> Ash.Query.sort([{calc(^combinations(:post_group)), :asc}]) + |> Ash.Query.distinct([calc(^combinations(:common_value))]) |> Ash.Query.calculate(:post_group, :integer, expr(^combinations(:post_group))) |> Ash.read!() end @@ -389,5 +392,39 @@ defmodule AshPostgres.CombinationTest do assert "low" in groups assert "high" in groups end + + test "combination with filters not included in the field set" do + Post + |> Ash.Changeset.for_create(:create, %{title: "post1", score: 10, category: "category1"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post2", score: 10, category: "category2"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "post3", score: 20, category: "category3"}) + |> Ash.create!() + + assert ["category1"] = + Post + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(score == 10), + select: [:id, :score], + calculations: %{score_group: calc("low", type: :string)} + ), + Ash.Query.Combination.union_all( + filter: expr(score == 20), + select: [:id, :score], + calculations: %{score_group: calc("high", type: :string)} + ) + ]) + |> Ash.Query.filter(category == "category1") + |> Ash.Query.distinct([{calc(^combinations(:score_group)), :asc}]) + |> Ash.Query.calculate(:upper_title, :string, expr(fragment("UPPER(?)", title))) + |> Ash.read!() + |> Enum.map(&to_string(&1.category)) + end end end From 6f287776b9c1324a277d3befc38f06ceacc4dacb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 20 May 2025 09:35:24 -0400 Subject: [PATCH 508/690] test: add tests for tuple type --- .../test_repo/posts/20250520130634.json | 590 ++++++++++++++++++ .../20250520130634_migrate_resources53.exs | 21 + test/support/resources/post.ex | 1 + test/support/types/person_detail.ex | 13 + test/tuple_test.exs | 139 +++++ 5 files changed, 764 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/posts/20250520130634.json create mode 100644 priv/test_repo/migrations/20250520130634_migrate_resources53.exs create mode 100644 test/support/types/person_detail.ex create mode 100644 test/tuple_test.exs diff --git a/priv/resource_snapshots/test_repo/posts/20250520130634.json b/priv/resource_snapshots/test_repo/posts/20250520130634.json new file mode 100644 index 00000000..55ae3d4b --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250520130634.json @@ -0,0 +1,590 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "limited_score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "metadata", + "type": "map" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "string_point", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "person_detail", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "points" + }, + "size": null, + "source": "db_point_id", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_string_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "string_points" + }, + "size": null, + "source": "db_string_point_id", + "type": "text" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "28AA0D3E2E9C063A7E09A548781ADFBA9A421B0D29BBAF56F2DE4B828E79CEEB", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250520130634_migrate_resources53.exs b/priv/test_repo/migrations/20250520130634_migrate_resources53.exs new file mode 100644 index 00000000..cff5e211 --- /dev/null +++ b/priv/test_repo/migrations/20250520130634_migrate_resources53.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources53 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:person_detail, :map) + end + end + + def down do + alter table(:posts) do + remove(:person_detail) + end + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index b6f4e3a5..d2119d2a 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -498,6 +498,7 @@ defmodule AshPostgres.Test.Post do attribute(:point, AshPostgres.Test.Point, public?: true) attribute(:composite_point, AshPostgres.Test.CompositePoint, public?: true) attribute(:string_point, AshPostgres.Test.StringPoint, public?: true) + attribute(:person_detail, AshPostgres.Test.PersonDetail, public?: true) attribute(:stuff, :map, public?: true) attribute(:list_of_stuff, {:array, :map}, public?: true) attribute(:uniq_one, :string, public?: true) diff --git a/test/support/types/person_detail.ex b/test/support/types/person_detail.ex new file mode 100644 index 00000000..551d17d5 --- /dev/null +++ b/test/support/types/person_detail.ex @@ -0,0 +1,13 @@ +defmodule AshPostgres.Test.PersonDetail do + @moduledoc """ + A tuple type for testing Ash.Type.Tuple + """ + use Ash.Type.NewType, + subtype_of: :tuple, + constraints: [ + fields: [ + first_name: [type: :string, allow_nil?: false], + last_name: [type: :string, allow_nil?: false] + ] + ] +end diff --git a/test/tuple_test.exs b/test/tuple_test.exs new file mode 100644 index 00000000..83b412f6 --- /dev/null +++ b/test/tuple_test.exs @@ -0,0 +1,139 @@ +defmodule AshPostgres.Test.TupleTest do + use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Post + + require Ash.Query + + test "tuple type can be created with correct values" do + post = + Post + |> Ash.Changeset.for_create(:create, %{ + title: "Tuple Test", + person_detail: {"John", "Doe"} + }) + |> Ash.create!() + + assert post.person_detail == {"John", "Doe"} + assert elem(post.person_detail, 0) == "John" + assert elem(post.person_detail, 1) == "Doe" + end + + test "tuple type can be filtered by exact match" do + # Create first post + Post + |> Ash.Changeset.for_create(:create, %{ + title: "First Post", + person_detail: {"John", "Doe"} + }) + |> Ash.create!() + + # Create second post + Post + |> Ash.Changeset.for_create(:create, %{ + title: "Second Post", + person_detail: {"Jane", "Smith"} + }) + |> Ash.create!() + + # Find post with exact tuple match + results = + Post + |> Ash.Query.filter(person_detail == ^{"John", "Doe"}) + |> Ash.read!() + + assert length(results) == 1 + assert hd(results).title == "First Post" + end + + test "tuple type can be filtered by individual fields" do + # Create posts + Post + |> Ash.Changeset.for_create(:create, %{ + title: "John Post 1", + person_detail: {"John", "Doe"} + }) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{ + title: "John Post 2", + person_detail: {"John", "Smith"} + }) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{ + title: "Jane Post", + person_detail: {"Jane", "Doe"} + }) + |> Ash.create!() + + # Filter by equality + results = + Post + |> Ash.Query.filter(person_detail == {"John", "Doe"}) + |> Ash.read!() + + assert length(results) == 1 + + # Filter by first_name + results = + Post + |> Ash.Query.filter(person_detail["first_name"] == "John") + |> Ash.read!() + + assert length(results) == 2 + assert Enum.all?(results, fn post -> elem(post.person_detail, 0) == "John" end) + end + + test "tuple type can be updated" do + # Create post + post = + Post + |> Ash.Changeset.for_create(:create, %{ + title: "Original Post", + person_detail: {"Original", "Name"} + }) + |> Ash.create!() + + # Update the post + updated_post = + post + |> Ash.Changeset.for_update(:update, %{ + person_detail: {"Updated", "Name"} + }) + |> Ash.update!() + + assert updated_post.person_detail == {"Updated", "Name"} + + # Verify by reading from database + retrieved_post = + Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.read_one!() + + assert retrieved_post.person_detail == {"Updated", "Name"} + end + + test "tuple type validates constraints" do + # Try to create with empty first name (violates min_length constraint) + assert_raise Ash.Error.Invalid, fn -> + Post + |> Ash.Changeset.for_create(:create, %{ + title: "Invalid Post", + person_detail: {"", "Doe"} + }) + |> Ash.create!() + end + + # Try to create with empty last name (violates min_length constraint) + assert_raise Ash.Error.Invalid, fn -> + Post + |> Ash.Changeset.for_create(:create, %{ + title: "Invalid Post", + person_detail: {"John", ""} + }) + |> Ash.create!() + end + end +end From f05bc7a25ccbf2b0c75d3e66c97da7a854e5ccc5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 20 May 2025 10:33:47 -0400 Subject: [PATCH 509/690] chore: release version v2.5.20 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f5bc056..85c44395 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.20](https://github.com/ash-project/ash_postgres/compare/v2.5.19...v2.5.20) (2025-05-20) + + + + +### Bug Fixes: + +* self-join if combination queries require more fields + +* enforce tenant name rules at creation (#550) + ## [v2.5.19](https://github.com/ash-project/ash_postgres/compare/v2.5.18...v2.5.19) (2025-05-06) diff --git a/mix.exs b/mix.exs index d0f3950c..0379c96d 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.19" + @version "2.5.20" def project do [ From 0910f17978811818c346b1188eba197822a0d265 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 20 May 2025 20:53:00 -0400 Subject: [PATCH 510/690] chore: fix test migrations --- mix.lock | 6 +++--- ...sources53.exs => 20250520130634_migrate_resources54.exs} | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename priv/test_repo/migrations/{20250520130634_migrate_resources53.exs => 20250520130634_migrate_resources54.exs} (84%) diff --git a/mix.lock b/mix.lock index 2805978e..807d6691 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.10", "123d5f5840326e2aa60204c9dc74b43c1eb35258bffb630d3f4190ee2a123ef1", [: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", "79217d9017bdc3ce5e32f429b9f32b03ef77e07337ccf41f95ac79fe0b3851e0"}, + "ash": {:hex, :ash, "3.5.11", "6d20782aeeb99773bd6f4902883c4ff2ad18404b7ad84bfc464ee772133c7368", [: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", "f37122fe27f67a81624ba09de0fde56e84a3395ff41d457c075822427d741887"}, "ash_sql": {:hex, :ash_sql, "0.2.75", "94252b460db2e14b778fa542684811c48fa08b4b2a2916db6a05a33e4272c361", [:mix], [{:ash, "~> 3.5", [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", "966226cd5b368258d05359c9a3f37cf86b412f5822a59c85ac27f047ca9e95cb"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.51", "21c3f9b425bd88572034644781057a793205b401ffd09e1c9498c528f14ef335", [: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", "9f1468d156145b463c6649c61e542befbf75f9d76055456d05c5f6adf7cfb272"}, + "igniter": {:hex, :igniter, "0.5.52", "18777a36918e3bb91c70f07b69f6a6589d8fa5547a7d210b228d410a2453923f", [: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", "8d75f0f2307e21b53ad96bd746f1806da91859ec0d4a68b203b763da4d5ae567"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, @@ -45,7 +45,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.56", "9426f6b992b13cd2a83ba3567d7a9f8cf8e2f264d019983da12882b43351c9b6", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "ecdc66a91bfd9155047c4f36d594fdf7e72c5f721b451e5aa6967c5439fa2b65"}, + "spark": {:hex, :spark, "2.2.60", "1183d97cfd417d00902e3fafcaa154604f26e1d0ca558be0022006b7827a0ec8", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "130c68bbe7d45dfb0c3e357d9778c487def0d15339b0b09b40e683c4f18aa2a5"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, diff --git a/priv/test_repo/migrations/20250520130634_migrate_resources53.exs b/priv/test_repo/migrations/20250520130634_migrate_resources54.exs similarity index 84% rename from priv/test_repo/migrations/20250520130634_migrate_resources53.exs rename to priv/test_repo/migrations/20250520130634_migrate_resources54.exs index cff5e211..9d8a51cb 100644 --- a/priv/test_repo/migrations/20250520130634_migrate_resources53.exs +++ b/priv/test_repo/migrations/20250520130634_migrate_resources54.exs @@ -1,4 +1,4 @@ -defmodule AshPostgres.TestRepo.Migrations.MigrateResources53 do +defmodule AshPostgres.TestRepo.Migrations.MigrateResources54 do @moduledoc """ Updates resources based on their most recent snapshots. From 6ddc29e66b03d4184e96ca042c486e00fc5b2929 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 20 May 2025 21:57:16 -0400 Subject: [PATCH 511/690] chore: add `usage-rules.md` --- usage-rules.md | 309 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 usage-rules.md diff --git a/usage-rules.md b/usage-rules.md new file mode 100644 index 00000000..5c8ee524 --- /dev/null +++ b/usage-rules.md @@ -0,0 +1,309 @@ +# Rules for working with AshPostgres + +## Understanding AshPostgres + +AshPostgres is the PostgreSQL data layer for Ash Framework. It's the most fully-featured Ash data layer and should be your default choice unless you have specific requirements for another data layer. Any PostgreSQL version higher than 13 is fully supported. + +## Basic Configuration + +To use AshPostgres, add the data layer to your resource: + +```elixir +defmodule MyApp.Tweet do + use Ash.Resource, + data_layer: AshPostgres.DataLayer + + attributes do + integer_primary_key :id + attribute :text, :string + end + + relationships do + belongs_to :author, MyApp.User + end + + postgres do + table "tweets" + repo MyApp.Repo + end +end +``` + +## PostgreSQL Configuration + +### Table & Schema Configuration + +```elixir +postgres do + # Required: Define the table name for this resource + table "users" + + # Optional: Define the PostgreSQL schema + schema "public" + + # Required: Define the Ecto repo to use + repo MyApp.Repo + + # Optional: Control whether migrations are generated for this resource + migrate? true +end +``` + +## Foreign Key References + +Use the `references` section to configure foreign key behavior: + +```elixir +postgres do + table "comments" + repo MyApp.Repo + + references do + # Simple reference with defaults + reference :post + + # Fully configured reference + reference :user, + on_delete: :delete, # What happens when referenced row is deleted + on_update: :update, # What happens when referenced row is updated + name: "comments_to_users_fkey", # Custom constraint name + deferrable: true, # Make constraint deferrable + initially_deferred: false # Defer constraint check to end of transaction + end +end +``` + +### Foreign Key Actions + +For `on_delete` and `on_update` options: + +- `:nothing` or `:restrict` - Prevent the change to the referenced row +- `:delete` - Delete the row when the referenced row is deleted (for `on_delete` only) +- `:update` - Update the row according to changes in the referenced row (for `on_update` only) +- `:nilify` - Set all foreign key columns to NULL +- `{:nilify, columns}` - Set specific columns to NULL (Postgres 15.0+ only) + +> **Warning**: These operations happen directly at the database level. No resource logic, authorization rules, validations, or notifications are triggered. + +## Check Constraints + +Define database check constraints: + +```elixir +postgres do + check_constraints do + check_constraint :positive_amount, + check: "amount > 0", + name: "positive_amount_check", + message: "Amount must be positive" + + check_constraint :status_valid, + check: "status IN ('pending', 'active', 'completed')" + end +end +``` + +## Custom Indexes + +Define custom indexes beyond those automatically created for identities and relationships: + +```elixir +postgres do + custom_indexes do + index [:first_name, :last_name] + + index :email, + unique: true, + name: "users_email_index", + where: "email IS NOT NULL", + using: :gin + + index [:status, :created_at], + concurrently: true, + include: [:user_id] + end +end +``` + +## Custom SQL Statements + +Include custom SQL in migrations: + +```elixir +postgres do + custom_statements do + statement "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"" + + statement """ + CREATE TRIGGER update_updated_at + BEFORE UPDATE ON posts + FOR EACH ROW + EXECUTE FUNCTION trigger_set_timestamp(); + """ + + statement "DROP INDEX IF EXISTS posts_title_index", + on_destroy: true # Only run when resource is destroyed/dropped + end +end +``` + +## Migrations and Codegen + +### Generating Migrations + +After creating or modifying Ash resources: + +1. Run `mix ash.codegen add_feature_name` to generate migrations +2. Review the generated migrations in `priv/repo/migrations` +3. Run `mix ash.migrate` to apply the migrations + +## Multitenancy + +AshPostgres supports schema-based multitenancy: + +```elixir +defmodule MyApp.Tenant do + use Ash.Resource, + data_layer: AshPostgres.DataLayer + + # Resource definition... + + postgres do + table "tenants" + repo MyApp.Repo + + # Automatically create/manage tenant schemas + manage_tenant do + template ["tenant_", :id] + end + end +end +``` + +### Setting Up Multitenancy + +1. Configure your repo to support multitenancy: + +```elixir +defmodule MyApp.Repo do + use AshPostgres.Repo, otp_app: :my_app + + # Return all tenant schemas for migrations + def all_tenants do + import Ecto.Query, only: [from: 2] + all(from(t in "tenants", select: fragment("? || ?", "tenant_", t.id))) + end +end +``` + +2. Mark resources that should be multi-tenant: + +```elixir +defmodule MyApp.Post do + use Ash.Resource, + data_layer: AshPostgres.DataLayer + + multitenancy do + strategy :context + attribute :tenant + end + + # Resource definition... +end +``` + +3. When tenant migrations are generated, they'll be in `priv/repo/tenant_migrations` + +4. Run tenant migrations in addition to regular migrations: + +```bash +# Run regular migrations +mix ash.migrate + +# Run tenant migrations +mix ash_postgres.migrate --tenants +``` + +## Advanced Features + +### Manual Relationships + +For complex relationships that can't be expressed with standard relationship types: + +```elixir +defmodule MyApp.Post.Relationships.HighlyRatedComments do + use Ash.Resource.ManualRelationship + use AshPostgres.ManualRelationship + + def load(posts, _opts, context) do + post_ids = Enum.map(posts, & &1.id) + + {:ok, + MyApp.Comment + |> Ash.Query.filter(post_id in ^post_ids) + |> Ash.Query.filter(rating > 4) + |> MyApp.read!() + |> Enum.group_by(& &1.post_id)} + end + + def ash_postgres_join(query, _opts, current_binding, as_binding, :inner, destination_query) do + {:ok, + Ecto.Query.from(_ in query, + join: dest in ^destination_query, + as: ^as_binding, + on: dest.post_id == as(^current_binding).id, + on: dest.rating > 4 + )} + end + + # Other required callbacks... +end + +# In your resource: +relationships do + has_many :highly_rated_comments, MyApp.Comment do + manual MyApp.Post.Relationships.HighlyRatedComments + end +end +``` + +### Using Multiple Repos (Read Replicas) + +Configure different repos for reads vs mutations: + +```elixir +postgres do + repo fn resource, type -> + case type do + :read -> MyApp.ReadReplicaRepo + :mutate -> MyApp.WriteRepo + end + end +end +``` + +## Best Practices + +1. **Organize migrations**: Run `mix ash.codegen` after each meaningful set of resource changes with a descriptive name: + ```bash + mix ash.codegen --name add_user_roles + mix ash.codegen --name implement_post_tagging + ``` + +2. **Use check constraints for domain invariants**: Enforce data integrity at the database level: + ```elixir + check_constraints do + check_constraint :valid_status, check: "status IN ('pending', 'active', 'completed')" + check_constraint :positive_balance, check: "balance >= 0" + end + ``` + +3. **Use custom statements for schema-only changes**: If you need to add database objects not directly tied to resources: + ```elixir + custom_statements do + statement "CREATE EXTENSION IF NOT EXISTS \"pgcrypto\"" + statement "CREATE INDEX users_search_idx ON users USING gin(search_vector)" + end + ``` + +Remember that using AshPostgres provides a full-featured PostgreSQL data layer for your Ash application, giving you both the structure and declarative approach of Ash along with the power and flexibility of PostgreSQL. From b2a6aa7492568c84ac953ad7eb09bc2e1da9cc07 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 20 May 2025 23:19:10 -0400 Subject: [PATCH 512/690] chore: include usage-rules.md in files --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 0379c96d..1e6be3c6 100644 --- a/mix.exs +++ b/mix.exs @@ -57,7 +57,7 @@ defmodule AshPostgres.MixProject do name: :ash_postgres, licenses: ["MIT"], files: ~w(lib .formatter.exs mix.exs README* LICENSE* - CHANGELOG* documentation), + CHANGELOG* documentation usage-rules.md), links: %{ Changelog: "https://hexdocs.pm/ash_postgres/changelog.html", GitHub: "https://github.com/ash-project/ash_postgres" From 9f9a209372a2d4fbcac38b1822ff7d57d7f692bc Mon Sep 17 00:00:00 2001 From: Marce Coll Date: Wed, 21 May 2025 14:53:32 +0200 Subject: [PATCH 513/690] chore: Create reproduction test of tuple Invalid filter value (#551) --- .../test_repo/posts/20250521105654.json | 600 ++++++++++++++++++ ...20250521105654_add_model_tuple_to_post.exs | 21 + test/support/domain.ex | 4 +- test/support/resources/post.ex | 28 + test/tuple_test.exs | 14 + 5 files changed, 666 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/posts/20250521105654.json create mode 100644 priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs diff --git a/priv/resource_snapshots/test_repo/posts/20250521105654.json b/priv/resource_snapshots/test_repo/posts/20250521105654.json new file mode 100644 index 00000000..ade3092c --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250521105654.json @@ -0,0 +1,600 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "limited_score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "metadata", + "type": "map" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "string_point", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "person_detail", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "model", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "size": null, + "source": "author_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "points" + }, + "size": null, + "source": "db_point_id", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_string_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "string_points" + }, + "size": null, + "source": "db_string_point_id", + "type": "text" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "5925C6C41F5781689EA91BF2237C6F4E321FD0C969B2D7751265E448BF3236B7", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs b/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs new file mode 100644 index 00000000..bde744b0 --- /dev/null +++ b/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.AddModelTupleToPost do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:model, :map, null: false) + end + end + + def down do + alter table(:posts) do + remove(:model) + end + end +end diff --git a/test/support/domain.ex b/test/support/domain.ex index eb1f047c..805a1dce 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -4,7 +4,9 @@ defmodule AshPostgres.Test.Domain do resources do resource(AshPostgres.Test.CoAuthorPost) - resource(AshPostgres.Test.Post) + resource(AshPostgres.Test.Post) do + define :review, action: :review + end resource(AshPostgres.Test.Comedian) resource(AshPostgres.Test.Comment) resource(AshPostgres.Test.CommentLink) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index d2119d2a..ca293390 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -326,6 +326,9 @@ defmodule AshPostgres.Test.Post do require_atomic?(false) end + update :atomic_update do + end + update :update_if_author do require_atomic?(false) end @@ -413,6 +416,19 @@ defmodule AshPostgres.Test.Post do change(atomic_update(:score, expr((score || 0) + ^arg(:amount)))) end + update :review do + change(after_action(fn changeset, record, _context -> + new_model = {1.0, 2.0, 3.0} + + record + |> Ash.Changeset.for_update(:atomic_update) + |> Ash.Changeset.force_change_attribute(:model, new_model) + |> Ash.update() + end)) + + require_atomic?(false) + end + update :requires_initial_data do argument(:amount, :integer, default: 1) change(atomic_update(:score, expr((score || 0) + ^arg(:amount)))) @@ -508,6 +524,18 @@ defmodule AshPostgres.Test.Post do attribute(:uniq_on_upper, :string, public?: true) attribute(:uniq_if_contains_foo, :string, public?: true) + attribute :model, :tuple do + constraints [ + fields: [ + alpha: [type: :float, description: "The alpha field"], + beta: [type: :float, description: "The beta field"], + t: [type: :float, description: "The t field"] + ] + ] + allow_nil? false + default fn -> {3.0, 3.0, 1.0} end + end + attribute :list_containing_nils, {:array, :string} do public?(true) constraints(nil_items?: true) diff --git a/test/tuple_test.exs b/test/tuple_test.exs index 83b412f6..1233ac28 100644 --- a/test/tuple_test.exs +++ b/test/tuple_test.exs @@ -18,6 +18,20 @@ defmodule AshPostgres.Test.TupleTest do assert elem(post.person_detail, 1) == "Doe" end + test "tuple type with force_attribute_change can be updated" do + post = + Post + |> Ash.Changeset.for_create(:create, %{ + title: "Tuple Test", + score: 1 + }) + |> Ash.create!() + + post = AshPostgres.Test.Domain.review!(post) + + assert post.model == {1.0, 2.0, 3.0} + end + test "tuple type can be filtered by exact match" do # Create first post Post From 53514b1b272d6f47d2631ea0fc19aa7aa30680ce Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 21 May 2025 12:38:40 -0400 Subject: [PATCH 514/690] chore: fix tests --- test/support/resources/post.ex | 25 +++++++++++-------- .../resources/post_with_empty_update.ex | 13 ++++++++++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index ca293390..f996c324 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -417,14 +417,16 @@ defmodule AshPostgres.Test.Post do end update :review do - change(after_action(fn changeset, record, _context -> - new_model = {1.0, 2.0, 3.0} + change( + after_action(fn changeset, record, _context -> + new_model = {1.0, 2.0, 3.0} - record - |> Ash.Changeset.for_update(:atomic_update) - |> Ash.Changeset.force_change_attribute(:model, new_model) - |> Ash.update() - end)) + record + |> Ash.Changeset.for_update(:atomic_update) + |> Ash.Changeset.force_change_attribute(:model, new_model) + |> Ash.update() + end) + ) require_atomic?(false) end @@ -525,15 +527,16 @@ defmodule AshPostgres.Test.Post do attribute(:uniq_if_contains_foo, :string, public?: true) attribute :model, :tuple do - constraints [ + constraints( fields: [ alpha: [type: :float, description: "The alpha field"], beta: [type: :float, description: "The beta field"], t: [type: :float, description: "The t field"] ] - ] - allow_nil? false - default fn -> {3.0, 3.0, 1.0} end + ) + + allow_nil?(false) + default(fn -> {3.0, 3.0, 1.0} end) end attribute :list_containing_nils, {:array, :string} do diff --git a/test/support/resources/post_with_empty_update.ex b/test/support/resources/post_with_empty_update.ex index fcc1bace..da61629d 100644 --- a/test/support/resources/post_with_empty_update.ex +++ b/test/support/resources/post_with_empty_update.ex @@ -37,5 +37,18 @@ defmodule AshPostgres.Test.PostWithEmptyUpdate do public?(true) source(:title_column) end + + attribute :model, :tuple do + constraints( + fields: [ + alpha: [type: :float, description: "The alpha field"], + beta: [type: :float, description: "The beta field"], + t: [type: :float, description: "The t field"] + ] + ) + + allow_nil?(false) + default(fn -> {3.0, 3.0, 1.0} end) + end end end From 1ee37f9a1f760fff7d3bcad730217751141d56d0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 21 May 2025 17:57:17 -0400 Subject: [PATCH 515/690] improvement: update igniter, remove inflex --- lib/data_layer.ex | 2 +- lib/resource_generator/resource_generator.ex | 2 +- lib/resource_generator/spec.ex | 10 +++++----- mix.exs | 2 +- mix.lock | 3 +-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 5383ac26..ae642468 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3519,7 +3519,7 @@ defmodule AshPostgres.DataLayer do |> Module.split() |> List.last() |> Macro.underscore() - |> Inflex.pluralize() + |> Igniter.Inflex.pluralize() {options, _, _} = OptionParser.parse(argv, switches: [repo: :string]) diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index dbc8df14..99da8386 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -47,7 +47,7 @@ if Code.ensure_loaded?(Igniter) do |> Enum.map(fn %{table_name: table} = spec -> resource = table - |> Inflex.singularize() + |> Igniter.Inflex.singularize() |> Macro.camelize() |> then(&Module.concat([domain, &1])) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index a0f91cac..38eebac5 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -644,7 +644,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do [ %Relationship{ type: :belongs_to, - name: Inflex.singularize(references), + name: Igniter.Inflex.singularize(references), source: spec.resource, constraint_name: constraint_name, match_with: match_with, @@ -694,16 +694,16 @@ defmodule AshPostgres.ResourceGenerator.Spec do {name, type} = if has_unique_index? do - if Inflex.pluralize(table) == table do - {Inflex.singularize(table), :has_one} + if Igniter.Inflex.pluralize(table) == table do + {Igniter.Inflex.singularize(table), :has_one} else {table, :has_one} end else - if Inflex.pluralize(table) == table do + if Igniter.Inflex.pluralize(table) == table do {table, :has_many} else - {Inflex.pluralize(table), :has_many} + {Igniter.Inflex.pluralize(table), :has_many} end end diff --git a/mix.exs b/mix.exs index 1e6be3c6..fc97a6b3 100644 --- a/mix.exs +++ b/mix.exs @@ -168,7 +168,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.4 and >= 3.4.69")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, - {:igniter, "~> 0.5 and >= 0.5.16", optional: true}, + {:igniter, "~> 0.6", optional: true}, {:ecto_sql, "~> 3.12"}, {:ecto, "~> 3.12 and >= 3.12.1"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index 807d6691..d5fc1b67 100644 --- a/mix.lock +++ b/mix.lock @@ -23,8 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.5.52", "18777a36918e3bb91c70f07b69f6a6589d8fa5547a7d210b228d410a2453923f", [: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", "8d75f0f2307e21b53ad96bd746f1806da91859ec0d4a68b203b763da4d5ae567"}, - "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, + "igniter": {:hex, :igniter, "0.6.0", "ad1e794286519bd52a0bc645419cdab1b8bf0352903199f534ea369ea5623dc4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "424df02a8acaeaec9cd01412916f60148d3ec710cd7317787c6656067f168f8b"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From 0720514ba4e66231f8231a1e7e6eaecc3d601eb5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 21 May 2025 17:57:31 -0400 Subject: [PATCH 516/690] chore: release version v2.5.21 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c44395..498a0f43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.21](https://github.com/ash-project/ash_postgres/compare/v2.5.20...v2.5.21) (2025-05-21) + + + + +### Improvements: + +* update igniter, remove inflex + ## [v2.5.20](https://github.com/ash-project/ash_postgres/compare/v2.5.19...v2.5.20) (2025-05-20) diff --git a/mix.exs b/mix.exs index fc97a6b3..4d9fc3a6 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.20" + @version "2.5.21" def project do [ From 6d693ed4e40e22963545ef36b468ae98ffef3a1d Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 21 May 2025 15:50:24 -0700 Subject: [PATCH 517/690] fix: Convert sensitive patterns from module constant to function for OTP/28 (#552) compatibility --- lib/resource_generator/sensitive_data.ex | 113 ++++++++++++----------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/lib/resource_generator/sensitive_data.ex b/lib/resource_generator/sensitive_data.ex index 77b0e45b..7b720aef 100644 --- a/lib/resource_generator/sensitive_data.ex +++ b/lib/resource_generator/sensitive_data.ex @@ -2,72 +2,75 @@ defmodule AshPostgres.ResourceGenerator.SensitiveData do @moduledoc false # I got this from ChatGPT, but this is a best effort transformation # anyway. - @sensitive_patterns [ - # Password-related - ~r/password/i, - ~r/passwd/i, - ~r/pass/i, - ~r/pwd/i, - ~r/hash(ed)?(_password)?/i, - # Authentication-related - ~r/auth(_key)?/i, - ~r/token/i, - ~r/secret(_key)?/i, - ~r/api_key/i, + def sensitive_patterns do + [ + # Password-related + ~r/password/i, + ~r/passwd/i, + ~r/pass/i, + ~r/pwd/i, + ~r/hash(ed)?(_password)?/i, - # Personal Information - ~r/ssn/i, - ~r/social(_security)?(_number)?/i, - ~r/(credit_?card|cc)(_number)?/i, - ~r/passport(_number)?/i, - ~r/driver_?licen(s|c)e(_number)?/i, - ~r/national_id/i, + # Authentication-related + ~r/auth(_key)?/i, + ~r/token/i, + ~r/secret(_key)?/i, + ~r/api_key/i, - # Financial Information - ~r/account(_number)?/i, - ~r/routing(_number)?/i, - ~r/iban/i, - ~r/swift(_code)?/i, - ~r/tax_id/i, + # Personal Information + ~r/ssn/i, + ~r/social(_security)?(_number)?/i, + ~r/(credit_?card|cc)(_number)?/i, + ~r/passport(_number)?/i, + ~r/driver_?licen(s|c)e(_number)?/i, + ~r/national_id/i, - # Contact Information - ~r/phone(_number)?/i, - ~r/email(_address)?/i, - ~r/address/i, + # Financial Information + ~r/account(_number)?/i, + ~r/routing(_number)?/i, + ~r/iban/i, + ~r/swift(_code)?/i, + ~r/tax_id/i, - # Health Information - ~r/medical(_record)?/i, - ~r/health(_data)?/i, - ~r/diagnosis/i, - ~r/treatment/i, + # Contact Information + ~r/phone(_number)?/i, + ~r/email(_address)?/i, + ~r/address/i, - # Biometric Data - ~r/fingerprint/i, - ~r/retina_scan/i, - ~r/face_id/i, - ~r/dna/i, + # Health Information + ~r/medical(_record)?/i, + ~r/health(_data)?/i, + ~r/diagnosis/i, + ~r/treatment/i, - # Encrypted or Encoded Data - ~r/encrypt(ed)?/i, - ~r/encoded/i, - ~r/cipher/i, + # Biometric Data + ~r/fingerprint/i, + ~r/retina_scan/i, + ~r/face_id/i, + ~r/dna/i, - # Other Potentially Sensitive Data - ~r/private(_key)?/i, - ~r/confidential/i, - ~r/restricted/i, - ~r/sensitive/i, + # Encrypted or Encoded Data + ~r/encrypt(ed)?/i, + ~r/encoded/i, + ~r/cipher/i, - # General patterns - ~r/.*_salt/i, - ~r/.*_secret/i, - ~r/.*_key/i, - ~r/.*_token/i - ] + # Other Potentially Sensitive Data + ~r/private(_key)?/i, + ~r/confidential/i, + ~r/restricted/i, + ~r/sensitive/i, + + # General patterns + ~r/.*_salt/i, + ~r/.*_secret/i, + ~r/.*_key/i, + ~r/.*_token/i + ] + end def sensitive?(column_name) do - Enum.any?(@sensitive_patterns, fn pattern -> + Enum.any?(sensitive_patterns(), fn pattern -> Regex.match?(pattern, column_name) end) end From 0325b028f93a31ad775caf0f26ad379975667d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Thu, 22 May 2025 12:44:28 +0200 Subject: [PATCH 518/690] Expand aggregate test covering rem expression (#541) --- test/aggregate_test.exs | 10 ++++++++++ test/support/resources/post.ex | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index bd34f579..e3ad5fa1 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -957,6 +957,16 @@ defmodule AshSql.AggregateTest do assert %{sum_of_popular_comment_rating_scores_2: 80} = values + + values = + post + |> Ash.load!([ + :sum_of_odd_comment_rating_scores + ]) + |> Map.take([:sum_of_odd_comment_rating_scores]) + + assert %{sum_of_popular_comment_rating_scores_2: 120} = + values end test "can't define multidimensional array aggregate types" do diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index f996c324..c66c8680 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -1061,6 +1061,10 @@ defmodule AshPostgres.Test.Post do filter(expr(score > 5)) end + sum :sum_of_odd_comment_rating_scores, [:comments, :ratings], :score do + filter(expr(rem(score, 2) == 1)) + end + sum(:sum_of_popular_comment_rating_scores_2, [:comments, :popular_ratings], :score) sum :sum_of_comment_likes_called_match, :comments, :likes do From 593fa84cee9f7a36c070b364493d4fd3d4118790 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 22 May 2025 06:58:29 -0400 Subject: [PATCH 519/690] chore: format --- test/support/domain.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/support/domain.ex b/test/support/domain.ex index 805a1dce..25616374 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -4,9 +4,11 @@ defmodule AshPostgres.Test.Domain do resources do resource(AshPostgres.Test.CoAuthorPost) + resource(AshPostgres.Test.Post) do - define :review, action: :review + define(:review, action: :review) end + resource(AshPostgres.Test.Comedian) resource(AshPostgres.Test.Comment) resource(AshPostgres.Test.CommentLink) From 6b7336921731a8e0075a030f2c31a764bf3dc8bb Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 22 May 2025 08:37:16 -0400 Subject: [PATCH 520/690] chore: release version v2.5.22 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 498a0f43..63141775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.5.22](https://github.com/ash-project/ash_postgres/compare/v2.5.21...v2.5.22) (2025-05-22) + + + + +### Bug Fixes: + +* Convert sensitive patterns from module constant to function for OTP/28 (#552) + ## [v2.5.21](https://github.com/ash-project/ash_postgres/compare/v2.5.20...v2.5.21) (2025-05-21) diff --git a/mix.exs b/mix.exs index 4d9fc3a6..31424e80 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.21" + @version "2.5.22" def project do [ From f573c42889ce9e190dd816b8020ccd282b513f3d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 22 May 2025 23:24:31 -0400 Subject: [PATCH 521/690] chore: fix aggregate test --- test/aggregate_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index e3ad5fa1..167a00c9 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -965,7 +965,7 @@ defmodule AshSql.AggregateTest do ]) |> Map.take([:sum_of_odd_comment_rating_scores]) - assert %{sum_of_popular_comment_rating_scores_2: 120} = + assert %{sum_of_odd_comment_rating_scores: 120} = values end From 38691cb67cd29da4e359142236de56fd4e7b2bc2 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 22 May 2025 23:27:08 -0400 Subject: [PATCH 522/690] chore: update deps --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index d5fc1b67..648043ae 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.11", "6d20782aeeb99773bd6f4902883c4ff2ad18404b7ad84bfc464ee772133c7368", [: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", "f37122fe27f67a81624ba09de0fde56e84a3395ff41d457c075822427d741887"}, - "ash_sql": {:hex, :ash_sql, "0.2.75", "94252b460db2e14b778fa542684811c48fa08b4b2a2916db6a05a33e4272c361", [:mix], [{:ash, "~> 3.5", [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", "966226cd5b368258d05359c9a3f37cf86b412f5822a59c85ac27f047ca9e95cb"}, + "ash": {:hex, :ash, "3.5.12", "435a6916d47e4ed6eabce886de2443d17af9dd9ca9765a29c73d9e02507b86b3", [: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.6", [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.60 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", "503492989c56e33c300d731b3717d1df9eeebba2b9018e5dd9f330db727edb57"}, + "ash_sql": {:hex, :ash_sql, "0.2.76", "4afac3284194f3d7820b7edc1263ac1eb232a25734406ad7b2284683b9384205", [:mix], [{:ash, "~> 3.5", [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", "f6bc02d8c4cba3f8f9a532e6ff73eaf8a4f7685257646a58fe7a320cfaf10c39"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -20,10 +20,10 @@ "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "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.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [: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", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"}, + "git_ops": {:hex, :git_ops, "2.7.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.0", "ad1e794286519bd52a0bc645419cdab1b8bf0352903199f534ea369ea5623dc4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "424df02a8acaeaec9cd01412916f60148d3ec710cd7317787c6656067f168f8b"}, + "igniter": {:hex, :igniter, "0.6.1", "e683495de01cb3cb30943670fd93fc9f603093c380225a4a6dd1f468a393f891", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "81467df9d6e7210b262c41ccbbdb08c48491bd6fd3f2aee529a8ed730c6f84ba"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From c9f88460faf9341bf05fffa6f5d60006d46190ec Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 23 May 2025 17:26:48 -0400 Subject: [PATCH 523/690] improvement: support scale & precision in decimal types --- .../migration_generator.ex | 80 ++++- lib/migration_generator/operation.ex | 46 ++- lib/multitenancy.ex | 9 +- test/migration_generator_test.exs | 326 ++++++++++++++++++ 4 files changed, 446 insertions(+), 15 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index a0c04a02..231697ac 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -694,6 +694,8 @@ defmodule AshPostgres.MigrationGenerator do generated?: Enum.any?(attributes, & &1.generated?), references: merge_references(Enum.map(attributes, & &1.references), source, table), primary_key?: false, + scale: attributes |> Enum.map(& &1[:scale]) |> Enum.max(), + precision: attributes |> Enum.map(& &1[:precision]) |> Enum.max(), order: attributes |> Enum.map(& &1.order) |> Enum.min() } end) @@ -3012,19 +3014,25 @@ defmodule AshPostgres.MigrationGenerator do type end - {type, size} = + {type, size, precision, scale} = case type do {:varchar, size} -> - {:varchar, size} + {:varchar, size, nil, nil} {:binary, size} -> - {:binary, size} + {:binary, size, nil, nil} + + {:decimal, precision, scale} -> + {:decimal, nil, precision, scale} + + {:decimal, precision} -> + {:decimal, nil, precision, nil} {other, size} when is_atom(other) and is_integer(size) -> - {other, size} + {other, size, nil, nil} other -> - {other, nil} + {other, nil, nil, nil} end attribute @@ -3033,6 +3041,20 @@ defmodule AshPostgres.MigrationGenerator do |> Map.put(:type, type) |> Map.put(:source, attribute.source || attribute.name) |> Map.drop([:name, :constraints]) + |> then(fn map -> + if precision do + Map.put(map, :precision, precision) + else + map + end + end) + |> then(fn map -> + if scale do + Map.put(map, :scale, scale) + else + map + end + end) end) |> Enum.map(fn attribute -> references = find_reference(resource, table, attribute) @@ -3145,6 +3167,28 @@ defmodule AshPostgres.MigrationGenerator do end end + defp migration_type(Ash.Type.Decimal, constraints) do + precision = + case constraints[:precision] do + :arbitrary -> nil + nil -> nil + precision -> precision + end + + scale = + case constraints[:scale] do + :arbitrary -> nil + nil -> nil + scale -> scale + end + + cond do + precision && scale -> {:decimal, precision, scale} + precision -> {:decimal, precision} + true -> :decimal + end + end + defp migration_type(other, constraints) do type = Ash.Type.get_type(other) @@ -3451,19 +3495,25 @@ defmodule AshPostgres.MigrationGenerator do defp load_attribute(attribute, table) do type = load_type(attribute.type) - {type, size} = + {type, size, scale, precision} = case type do {:varchar, size} -> - {:varchar, size} + {:varchar, size, nil, nil} {:binary, size} -> - {:binary, size} + {:binary, size, nil, nil} {other, size} when is_atom(other) and is_integer(size) -> - {other, size} + {other, size, nil, nil} + + {:decimal, scale} -> + {:decimal, scale, nil, nil} + + {:decimal, scale, precision} -> + {:decimal, scale, precision, nil} other -> - {other, nil} + {other, nil, nil, nil} end attribute = @@ -3476,6 +3526,8 @@ defmodule AshPostgres.MigrationGenerator do attribute |> Map.put(:type, type) |> Map.put(:size, size) + |> Map.put(:precision, precision) + |> Map.put(:scale, scale) |> Map.put_new(:default, "nil") |> Map.update!(:default, &(&1 || "nil")) |> Map.update!(:references, fn @@ -3562,6 +3614,14 @@ defmodule AshPostgres.MigrationGenerator do {:binary, size} end + defp load_type(["decimal", scale]) do + {:decimal, scale} + end + + defp load_type(["decimal", scale, precision]) do + {:decimal, scale, precision} + end + defp load_type([string, size]) when is_binary(string) and is_integer(size) do {String.to_existing_atom(string), size} end diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 62b3b3a6..242a5db1 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -135,6 +135,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do keys end end + + def maybe_add_precision(nil), do: nil + def maybe_add_precision(precision), do: "precision: #{precision}" + + def maybe_add_scale(nil), do: nil + def maybe_add_scale(scale), do: "scale: #{scale}" end defmodule CreateTable do @@ -179,7 +185,9 @@ defmodule AshPostgres.MigrationGenerator.Operation do option("prefix", destination_schema), on_delete(reference), on_update(reference), - size + size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]) ], ")", maybe_add_default(attribute.default), @@ -219,6 +227,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do "name: #{inspect(reference.name)}", "type: #{inspect(reference_type(attribute, reference))}", size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), on_delete(reference), on_update(reference) ], @@ -250,6 +260,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do maybe_add_default(attribute.default), maybe_add_primary_key(attribute.primary_key?), size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), maybe_add_null(attribute.allow_nil?) ] |> join() @@ -275,6 +287,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do maybe_add_default(attribute.default), maybe_add_primary_key(attribute.primary_key?), size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), maybe_add_null(attribute.allow_nil?) ] |> join() @@ -309,6 +323,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do "type: #{inspect(reference_type(attribute, reference))}", "prefix: prefix()", size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), on_delete(reference), on_update(reference) ], @@ -355,6 +371,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do "type: #{inspect(reference_type(attribute, reference))}", option("prefix", destination_schema), size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), on_delete(reference), on_update(reference) ], @@ -394,6 +412,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do "type: #{inspect(reference_type(attribute, reference))}", option("prefix", destination_schema), size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), on_delete(reference), on_update(reference) ], @@ -437,6 +457,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do maybe_add_null(attribute.allow_nil?), maybe_add_default(attribute.default), size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), maybe_add_primary_key(attribute.primary_key?) ] |> join() @@ -538,7 +560,21 @@ defmodule AshPostgres.MigrationGenerator.Operation do ", null: #{attribute.allow_nil?}" end - "#{null}#{default}#{primary_key}" + precision = + if Map.get(attribute, :precision) != Map.get(old_attribute, :precision) do + if attribute.precision do + ", precision: #{attribute.precision}" + end + end + + scale = + if Map.get(attribute, :scale) != Map.get(old_attribute, :scale) do + if attribute.scale do + ", scale: #{attribute.scale}" + end + end + + "#{null}#{default}#{precision}#{scale}#{primary_key}" end def up(%{ @@ -587,6 +623,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do "name: #{inspect(reference.name)}", "type: #{inspect(reference_type(attribute, reference))}", size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), "prefix: prefix()", on_delete(reference), on_update(reference), @@ -625,6 +663,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do "name: #{inspect(reference.name)}", "type: #{inspect(reference_type(attribute, reference))}", size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), option("prefix", destination_schema), on_delete(reference), on_update(reference), @@ -699,6 +739,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do "name: #{inspect(reference.name)}", "type: #{inspect(reference_type(attribute, reference))}", size, + maybe_add_precision(attribute[:precision]), + maybe_add_scale(attribute[:scale]), option("prefix", destination_schema), on_delete(reference), on_update(reference), diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 6927a960..96cddafc 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -3,7 +3,6 @@ defmodule AshPostgres.MultiTenancy do @dialyzer {:nowarn_function, load_migration!: 1} - @tenant_name_regex ~r/^[a-zA-Z0-9_-]+$/ def create_tenant!(tenant_name, repo) do validate_tenant_name!(tenant_name) Ecto.Adapters.SQL.query!(repo, "CREATE SCHEMA IF NOT EXISTS \"#{tenant_name}\"", []) @@ -87,8 +86,8 @@ defmodule AshPostgres.MultiTenancy do end defp validate_tenant_name!(tenant_name) do - if !Regex.match?(@tenant_name_regex, tenant_name) do - raise "Tenant name must match #{inspect(@tenant_name_regex)}, got: #{tenant_name}" + if !Regex.match?(tenant_name_regex(), tenant_name) do + raise "Tenant name must match #{inspect(tenant_name_regex())}, got: #{tenant_name}" end end @@ -100,4 +99,8 @@ defmodule AshPostgres.MultiTenancy do |> Path.join(repo_name) |> Path.join("tenant_migrations") end + + defp tenant_name_regex do + ~r/^[a-zA-Z0-9_-]+$/ + end end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 1ef76978..5b564b5f 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -2634,4 +2634,330 @@ defmodule AshPostgres.MigrationGeneratorTest do ~S[modify :post_id, references(:posts, column: :id, name: "comments_post_id_fkey", type: :uuid, prefix: "public")] end end + + describe "decimal precision and scale" do + setup do + on_exit(fn -> + File.rm_rf!("test_snapshots_path") + File.rm_rf!("test_migration_path") + end) + end + + test "creates decimal columns with precision and scale" do + defresource Product do + postgres do + table "products" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + + attribute(:price, :decimal, + constraints: [precision: 10, scale: 2], + public?: true, + allow_nil?: false + ) + + attribute(:weight, :decimal, + constraints: [precision: 8], + public?: true, + allow_nil?: false + ) + + attribute(:rating, :decimal, public?: true, allow_nil?: false) + end + end + + defdomain([Product]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [file] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + file_content = File.read!(file) + + # Check that precision and scale are included for the price field + assert file_content =~ ~S[add :price, :decimal, null: false, precision: 10, scale: 2] + + # Check that only precision is included for the weight field + assert file_content =~ ~S[add :weight, :decimal, null: false, precision: 8] + + # Check that no precision or scale is included for the rating field + assert file_content =~ ~S[add :rating, :decimal, null: false] + end + + test "alters decimal columns with precision and scale changes" do + defresource Product do + postgres do + table "products" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + attribute(:price, :decimal, constraints: [precision: 8, scale: 2], public?: true) + end + end + + defdomain([Product]) + + # Generate initial migration + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + # Now update the precision and scale + defresource Product do + postgres do + table "products" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + attribute(:price, :decimal, constraints: [precision: 12, scale: 4], public?: true) + end + end + + # Generate follow-up migration + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + migration_files = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert length(migration_files) == 2 + + # Check the second migration file + second_migration = File.read!(Enum.at(migration_files, 1)) + + # Should contain the alter statement with new precision and scale + assert second_migration =~ ~S[modify :price, :decimal, precision: 12, scale: 4] + end + + test "handles arbitrary precision and scale constraints" do + defresource Product do + postgres do + table "products" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + + attribute(:price, :decimal, + constraints: [precision: :arbitrary, scale: :arbitrary], + public?: true, + allow_nil?: false + ) + end + end + + defdomain([Product]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [file] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + file_content = File.read!(file) + + # Check that no precision or scale is included when they are :arbitrary + assert file_content =~ ~S[add :price, :decimal, null: false] + refute file_content =~ ~S[precision:] + refute file_content =~ ~S[scale:] + end + + test "removes precision and scale when changing to arbitrary" do + defresource Product do + postgres do + table "products" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + + attribute(:price, :decimal, + constraints: [precision: 10, scale: 2], + public?: true, + allow_nil?: false + ) + end + end + + defdomain([Product]) + + # Generate initial migration + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + # Now change to arbitrary precision and scale + defresource Product do + postgres do + table "products" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + + attribute(:price, :decimal, + constraints: [precision: :arbitrary, scale: :arbitrary], + public?: true, + allow_nil?: false + ) + end + end + + # Generate follow-up migration + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + migration_files = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert length(migration_files) == 2 + + # Check the second migration file + second_migration = File.read!(Enum.at(migration_files, 1)) + + # Should contain the alter statement removing precision and scale + assert second_migration =~ ~S[modify :price, :decimal] + refute second_migration =~ ~S[precision:] + refute second_migration =~ ~S[scale:] + end + + test "works with decimal references that have precision and scale" do + defresource Category do + postgres do + table "categories" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + attribute(:id, :decimal, + constraints: [precision: 10, scale: 0], + primary_key?: true, + allow_nil?: false, + public?: true + ) + + attribute(:name, :string, public?: true) + end + end + + defresource Product do + postgres do + table "products" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + + attribute(:category_id, :decimal, + constraints: [precision: 10, scale: 0], + allow_nil?: false, + public?: true + ) + end + + relationships do + belongs_to(:category, Category) do + source_attribute(:category_id) + destination_attribute(:id) + public?(true) + end + end + end + + defdomain([Category, Product]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false + ) + + assert [file] = + Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) + |> Enum.reject(&String.contains?(&1, "extensions")) + + file_content = File.read!(file) + + # Check that both tables are created with proper decimal precision + assert file_content =~ + ~S[add :id, :decimal, null: false, precision: 10, scale: 0, primary_key: true] + + assert file_content =~ ~S[add :category_id, :decimal, null: false, precision: 10, scale: 0] + + assert file_content =~ + ~S[modify :category_id, references(:categories, column: :id, name: "products_category_id_fkey", type: :decimal, precision: 10, scale: 0] + end + end end From f0203458dd768cc2f7005f452e5a1ed03ea9bb20 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 25 May 2025 23:19:23 -0400 Subject: [PATCH 524/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 648043ae..10820741 100644 --- a/mix.lock +++ b/mix.lock @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.1", "e683495de01cb3cb30943670fd93fc9f603093c380225a4a6dd1f468a393f891", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "81467df9d6e7210b262c41ccbbdb08c48491bd6fd3f2aee529a8ed730c6f84ba"}, + "igniter": {:hex, :igniter, "0.6.2", "6263fa3d2b7698f8d9afc506e4e1bccef69f1b8a3288760fe749dc70a9f6b408", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "480c679066444459eecd371a41639cee365449e20cfb611457081394fd146b05"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -38,13 +38,13 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.15.2", "8c1b3fe0527b7a92b0b22c3f33f2e66858dd069bf1dd51d1031f63cd8cbd1fd5", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "091435a1fa0cab9bc2ed3934b203a0fd190f62e8b6aca63741f9242b8c7631ac"}, + "reactor": {:hex, :reactor, "0.15.3", "f1f05d5b0f229ad1a164b7a5543beee58c9975e7e146afc71821e5afc5c69a79", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "8a16a46163fcdeb1d1be06749f54bd71282126be27c9dc80010cf3b97fe7193c"}, "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.60", "1183d97cfd417d00902e3fafcaa154604f26e1d0ca558be0022006b7827a0ec8", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "130c68bbe7d45dfb0c3e357d9778c487def0d15339b0b09b40e683c4f18aa2a5"}, + "spark": {:hex, :spark, "2.2.61", "64745581832caf136cbd654c1ecef98d291f3d1b347a14411b7d0dc726e3822b", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "cb10300e17f74b41848954d61630fb627f4e0d5acf9aacd7d9f312d5b119d50f"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From d18f6c60b27face846a9b75c603ec7e716515a31 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 May 2025 00:38:40 -0400 Subject: [PATCH 525/690] fix: properly encode decimal scale & preicison into snapshots --- .../migration_generator.ex | 22 ++++++++++++------- test/migration_generator_test.exs | 8 ++++--- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 231697ac..ea395da9 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3384,29 +3384,35 @@ defmodule AshPostgres.MigrationGenerator do references |> Map.update!(:on_delete, &(&1 && references_on_delete_to_binary(&1))) end) - |> Map.update!(:type, fn type -> sanitize_type(type, attribute[:size]) end) + |> Map.update!(:type, fn type -> + sanitize_type(type, attribute[:size], attribute[:precision], attribute[:scale]) + end) end defp references_on_delete_to_binary(value) when is_atom(value), do: value defp references_on_delete_to_binary({:nilify, columns}), do: [:nilify, columns] - defp sanitize_type({:array, type}, size) do - ["array", sanitize_type(type, size)] + defp sanitize_type({:array, type}, size, scale, precision) do + ["array", sanitize_type(type, size, scale, precision)] end - defp sanitize_type(:varchar, size) when not is_nil(size) do + defp sanitize_type(:varchar, size, _scale, _precision) when not is_nil(size) do ["varchar", size] end - defp sanitize_type(:binary, size) when not is_nil(size) do + defp sanitize_type(:binary, size, _scale, _precision) when not is_nil(size) do ["binary", size] end - defp sanitize_type(type, size) when is_atom(type) and is_integer(size) do - [sanitize_type(type, nil), size] + defp sanitize_type(:decimal, _size, scale, precision) do + ["decimal", scale, precision] |> Enum.reject(&is_nil/1) + end + + defp sanitize_type(type, size, precision, decimal) when is_atom(type) and is_integer(size) do + [sanitize_type(type, nil, precision, decimal), size] end - defp sanitize_type(type, _) do + defp sanitize_type(type, _, _, _) do type end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 5b564b5f..a1168ccb 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -2877,10 +2877,12 @@ defmodule AshPostgres.MigrationGeneratorTest do # Check the second migration file second_migration = File.read!(Enum.at(migration_files, 1)) + [up, _down] = String.split(second_migration, "def down") + # Should contain the alter statement removing precision and scale - assert second_migration =~ ~S[modify :price, :decimal] - refute second_migration =~ ~S[precision:] - refute second_migration =~ ~S[scale:] + assert up =~ ~S[modify :price, :decimal] + refute up =~ ~S[precision:] + refute up =~ ~S[scale:] end test "works with decimal references that have precision and scale" do From dac674b53b5ed7f195c3ffb07cff14b478697859 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 May 2025 21:42:51 -0400 Subject: [PATCH 526/690] feat: --dev flag for codegen (#555) --------- Co-authored-by: ken-kost --- config/config.exs | 10 +- .../development/migrations-and-tasks.md | 9 +- .../migration_generator.ex | 289 ++++++++++++++---- .../tasks/ash_postgres.generate_migrations.ex | 14 +- lib/mix/tasks/ash_postgres.migrate.ex | 11 +- lib/mix/tasks/ash_postgres.rollback.ex | 25 +- lib/multitenancy.ex | 14 +- mix.exs | 2 +- ...6214825_migrate_resources_extensions_1.exs | 172 +++++++++++ .../20250526214827_migrate_resources1.exs | 29 ++ .../dev_test_repo/extensions.json | 11 + .../multitenant_orgs/20250526214827.json | 70 +++++ test/dev_migrations_test.exs | 234 ++++++++++++++ test/migration_generator_test.exs | 189 ++++++++---- test/mix_squash_snapshots_test.exs | 9 +- test/support/dev_test_repo.ex | 39 +++ test/support/multitenancy/domain.ex | 1 + .../resources/dev_migrations_org.ex | 91 ++++++ test/test_helper.exs | 2 + usage-rules.md | 19 +- 20 files changed, 1091 insertions(+), 149 deletions(-) create mode 100644 priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs create mode 100644 priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs create mode 100644 priv/resource_snapshots/dev_test_repo/extensions.json create mode 100644 priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json create mode 100644 test/dev_migrations_test.exs create mode 100644 test/support/dev_test_repo.ex create mode 100644 test/support/multitenancy/resources/dev_migrations_org.ex diff --git a/config/config.exs b/config/config.exs index ee88e028..0041c0ac 100644 --- a/config/config.exs +++ b/config/config.exs @@ -37,6 +37,14 @@ if Mix.env() == :test do hostname: "localhost", pool: Ecto.Adapters.SQL.Sandbox + config :ash_postgres, AshPostgres.DevTestRepo, + username: "postgres", + password: "postgres", + database: "ash_postgres_dev_test", + hostname: "localhost", + migration_primary_key: [name: :id, type: :binary_id], + pool: Ecto.Adapters.SQL.Sandbox + # sobelow_skip ["Config.Secrets"] config :ash_postgres, AshPostgres.TestRepo, password: "postgres" @@ -54,7 +62,7 @@ if Mix.env() == :test do migration_primary_key: [name: :id, type: :binary_id] config :ash_postgres, - ecto_repos: [AshPostgres.TestRepo, AshPostgres.TestNoSandboxRepo], + ecto_repos: [AshPostgres.TestRepo, AshPostgres.DevTestRepo, AshPostgres.TestNoSandboxRepo], ash_domains: [ AshPostgres.Test.Domain, AshPostgres.MultitenancyTest.Domain, diff --git a/documentation/topics/development/migrations-and-tasks.md b/documentation/topics/development/migrations-and-tasks.md index a9d6b951..04fefc93 100644 --- a/documentation/topics/development/migrations-and-tasks.md +++ b/documentation/topics/development/migrations-and-tasks.md @@ -7,9 +7,16 @@ Ash comes with its own tasks, and AshPostgres exposes lower level tasks that you ## Basic Workflow - Make resource changes -- Run `mix ash.codegen --name add_a_combobulator` to generate migrations and resource snapshots +- Run `mix ash.codegen --dev` to generate a migration tagged as a `dev` migration, which will later be squashed and does not require a name. +- Run `mix ash.migrate` to run the migrations. +- Make some more resource changes. +- Once you're all done, run `mix ash.codegen add_a_combobulator`, using a good name for your changes to generate migrations and resource snapshots. This will **rollback** the dev migrations, and squash them into a the new named migration (or sometimes migrations). - Run `mix ash.migrate` to run those migrations +The `--dev` workflow enables you to avoid having to think of a name for migrations while developing, and also enables some +upcoming workflows that will detect when code generation needs to be run on page load and will show you a button to generate +dev migrations and run them. + For more information on generating migrations, run `mix help ash_postgres.generate_migrations` (the underlying task that is called by `mix ash.migrate`) > ### list_tenants/0 {: .info} diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index ea395da9..2479d067 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -19,7 +19,9 @@ defmodule AshPostgres.MigrationGenerator do format: true, dry_run: false, check: false, + dev: false, snapshots_only: false, + auto_name: false, dont_drop_columns: false def generate(domains, opts \\ []) do @@ -226,11 +228,13 @@ defmodule AshPostgres.MigrationGenerator do Mix.shell().info("No extensions to install") :ok else + dev = if opts.dev, do: "_dev" + {module, migration_name} = case to_install do [{ext_name, version, _up_fn, _down_fn}] -> {"install_#{ext_name}_v#{version}_#{timestamp(true)}", - "#{timestamp(true)}_install_#{ext_name}_v#{version}_extension"} + "#{timestamp(true)}_install_#{ext_name}_v#{version}_extension#{dev}"} ["ash_functions"] -> {"install_ash_functions_extension_#{AshPostgres.MigrationGenerator.AshFunctions.latest_version()}_#{timestamp(true)}", @@ -239,6 +243,8 @@ defmodule AshPostgres.MigrationGenerator do _multiple -> migration_path = migration_path(opts, repo, false) + require_name!(opts) + if opts.name do count = migration_path @@ -262,7 +268,7 @@ defmodule AshPostgres.MigrationGenerator do |> Kernel.+(1) {"#{opts.name}_extensions_#{count}", - "#{timestamp(true)}_#{opts.name}_extensions_#{count}"} + "#{timestamp(true)}_#{opts.name}_extensions_#{count}#{dev}"} else count = migration_path @@ -286,7 +292,7 @@ defmodule AshPostgres.MigrationGenerator do |> Kernel.+(1) {"migrate_resources_extensions_#{count}", - "#{timestamp(true)}_migrate_resources_extensions_#{count}"} + "#{timestamp(true)}_migrate_resources_extensions_#{count}#{dev}"} end end @@ -452,6 +458,23 @@ defmodule AshPostgres.MigrationGenerator do :ok operations -> + dev_migrations = get_dev_migrations(opts, tenant?, repo) + + if !opts.dev and dev_migrations != [] do + if opts.check do + Mix.shell().error(""" + Generated migrations are from dev mode. + + Generate migrations without `--dev` flag. + """) + + exit({:shutdown, 1}) + else + remove_dev_migrations(dev_migrations, tenant?, repo, opts) + remove_dev_snapshots(snapshots, opts) + end + end + if opts.check do Mix.shell().error(""" Migrations would have been generated, but the --check flag was provided. @@ -491,6 +514,159 @@ defmodule AshPostgres.MigrationGenerator do end) end + defp get_dev_migrations(opts, tenant?, repo) do + opts + |> migration_path(repo, tenant?) + |> File.ls() + |> case do + {:error, _error} -> [] + {:ok, migrations} -> Enum.filter(migrations, &String.contains?(&1, "_dev.exs")) + end + end + + if Mix.env() == :test do + defp with_repo_not_in_test(repo, fun) do + fun.(repo) + end + else + defp with_repo_not_in_test(repo, fun) do + Ecto.Migrator.with_repo(repo, fun) + end + end + + defp require_name!(opts) do + if !opts.name && !opts.dry_run && !opts.check && !opts.snapshots_only && !opts.dev && + !opts.auto_name do + raise """ + Name must be provided when generating migrations, unless `--dry-run` or `--check` or `--dev` is also provided. + + Please provide a name. for example: + + mix ash_postgres.generate_migrations ...args + """ + end + + :ok + end + + defp remove_dev_migrations(dev_migrations, tenant?, repo, opts) do + dev_migrations = + Enum.map(dev_migrations, fn migration -> + opts + |> migration_path(repo, tenant?) + |> Path.join(migration) + end) + + if tenant? do + with_repo_not_in_test(repo, fn repo -> + for prefix <- repo.all_tenants() do + {repo, query, opts} = Ecto.Migration.SchemaMigration.versions(repo, [], prefix) + + versions = repo.all(query, opts) + + dev_migrations + |> Enum.map(&extract_migration_info/1) + |> Enum.filter(& &1) + |> Enum.map(&load_migration!/1) + |> Enum.filter(fn {version, _} -> + version in versions + end) + |> Enum.each(fn {version, mod} -> + Ecto.Migration.Runner.run( + repo, + [], + version, + mod, + :forward, + :down, + :down, + all: true, + prefix: prefix + ) + + Ecto.Migration.SchemaMigration.down(repo, repo.config(), version, prefix: prefix) + end) + end + end) + else + with_repo_not_in_test(repo, fn repo -> + {repo, query, opts} = Ecto.Migration.SchemaMigration.versions(repo, [], nil) + + versions = repo.all(query, opts) + + dev_migrations + |> Enum.map(&extract_migration_info/1) + |> Enum.filter(& &1) + |> Enum.map(&load_migration!/1) + |> Enum.sort() + |> Enum.filter(fn {version, _} -> + version in versions + end) + |> Enum.each(fn {version, mod} -> + Ecto.Migration.Runner.run( + repo, + [], + version, + mod, + :forward, + :down, + :down, + all: true + ) + + Ecto.Migration.SchemaMigration.down(repo, repo.config(), version, []) + end) + end) + end + + Enum.each(dev_migrations, &File.rm!/1) + end + + defp extract_migration_info(file) do + base = Path.basename(file) + + case Integer.parse(Path.rootname(base)) do + {integer, "_" <> name} -> {integer, name, file} + _ -> nil + end + end + + defp load_migration!({version, _, file}) when is_binary(file) do + loaded_modules = file |> compile_file() |> Enum.map(&elem(&1, 0)) + + if mod = Enum.find(loaded_modules, &migration?/1) do + {version, mod} + else + raise Ecto.MigrationError, + "file #{Path.relative_to_cwd(file)} does not define an Ecto.Migration" + end + end + + defp compile_file(file) do + AshPostgres.MigrationCompileCache.start_link() + AshPostgres.MigrationCompileCache.compile_file(file) + end + + defp migration?(mod) do + function_exported?(mod, :__migration__, 0) + end + + def remove_dev_snapshots(snapshots, opts) do + Enum.each(snapshots, fn snapshot -> + folder = get_snapshot_folder(snapshot, opts) + snapshot_path = get_snapshot_path(snapshot, folder) + + snapshot_path + |> File.ls!() + |> Enum.filter(&String.contains?(&1, "_dev.json")) + |> Enum.each(fn snapshot_name -> + snapshot_path + |> Path.join(snapshot_name) + |> File.rm!() + end) + end) + end + defp split_into_migrations(operations) do operations |> Enum.split_with(fn @@ -932,6 +1108,8 @@ defmodule AshPostgres.MigrationGenerator do defp write_migration!({up, down}, repo, opts, tenant?, run_without_transaction?) do migration_path = migration_path(opts, repo, tenant?) + require_name!(opts) + {migration_name, last_part} = if opts.name do {"#{timestamp(true)}_#{opts.name}", "#{opts.name}"} @@ -962,7 +1140,7 @@ defmodule AshPostgres.MigrationGenerator do migration_file = migration_path - |> Path.join(migration_name <> ".exs") + |> Path.join(migration_name <> "#{if opts.dev, do: "_dev"}.exs") module_name = if tenant? do @@ -1056,20 +1234,25 @@ defmodule AshPostgres.MigrationGenerator do |> Path.join(repo_name) end + dev = if opts.dev, do: "_dev" + snapshot_file = if snapshot.schema do - Path.join(snapshot_folder, "#{snapshot.schema}.#{snapshot.table}/#{timestamp()}.json") + Path.join( + snapshot_folder, + "#{snapshot.schema}.#{snapshot.table}/#{timestamp()}#{dev}.json" + ) else - Path.join(snapshot_folder, "#{snapshot.table}/#{timestamp()}.json") + Path.join(snapshot_folder, "#{snapshot.table}/#{timestamp()}#{dev}.json") end File.mkdir_p(Path.dirname(snapshot_file)) create_file(snapshot_file, snapshot_binary, force: true) - old_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}.json") + old_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}#{dev}.json") if File.exists?(old_snapshot_folder) do - new_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}/initial.json") + new_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}/initial#{dev}.json") File.rename(old_snapshot_folder, new_snapshot_folder) end end) @@ -2653,43 +2836,22 @@ defmodule AshPostgres.MigrationGenerator do end def get_existing_snapshot(snapshot, opts) do - repo_name = snapshot.repo |> Module.split() |> List.last() |> Macro.underscore() - - folder = - if snapshot.multitenancy.strategy == :context do - opts - |> snapshot_path(snapshot.repo) - |> Path.join(repo_name) - |> Path.join("tenants") - else - opts - |> snapshot_path(snapshot.repo) - |> Path.join(repo_name) - end - - snapshot_folder = - if snapshot.schema do - schema_dir = Path.join(folder, "#{snapshot.schema}.#{snapshot.table}") + folder = get_snapshot_folder(snapshot, opts) + snapshot_path = get_snapshot_path(snapshot, folder) - if File.dir?(schema_dir) do - schema_dir - else - Path.join(folder, snapshot.table) - end - else - Path.join(folder, snapshot.table) - end - - if File.exists?(snapshot_folder) do - snapshot_folder + if File.exists?(snapshot_path) do + snapshot_path |> File.ls!() - |> Enum.filter(&String.match?(&1, ~r/^\d{14}\.json$/)) + |> Enum.filter( + &(String.match?(&1, ~r/^\d{14}\.json$/) or + (opts.dev and String.match?(&1, ~r/^\d{14}\_dev.json$/))) + ) |> case do [] -> get_old_snapshot(folder, snapshot) snapshot_files -> - snapshot_folder + snapshot_path |> Path.join(Enum.max(snapshot_files)) |> File.read!() |> load_snapshot() @@ -2699,6 +2861,33 @@ defmodule AshPostgres.MigrationGenerator do end end + defp get_snapshot_folder(snapshot, opts) do + if snapshot.multitenancy.strategy == :context do + opts + |> snapshot_path(snapshot.repo) + |> Path.join(repo_name(snapshot.repo)) + |> Path.join("tenants") + else + opts + |> snapshot_path(snapshot.repo) + |> Path.join(repo_name(snapshot.repo)) + end + end + + defp get_snapshot_path(snapshot, folder) do + if snapshot.schema do + schema_dir = Path.join(folder, "#{snapshot.schema}.#{snapshot.table}") + + if File.dir?(schema_dir) do + schema_dir + else + Path.join(folder, snapshot.table) + end + else + Path.join(folder, snapshot.table) + end + end + defp get_old_snapshot(folder, snapshot) do schema_file = if snapshot.schema do @@ -3182,11 +3371,7 @@ defmodule AshPostgres.MigrationGenerator do scale -> scale end - cond do - precision && scale -> {:decimal, precision, scale} - precision -> {:decimal, precision} - true -> :decimal - end + {:decimal, precision, scale} end defp migration_type(other, constraints) do @@ -3405,7 +3590,7 @@ defmodule AshPostgres.MigrationGenerator do end defp sanitize_type(:decimal, _size, scale, precision) do - ["decimal", scale, precision] |> Enum.reject(&is_nil/1) + ["decimal", precision, scale] end defp sanitize_type(type, size, precision, decimal) when is_atom(type) and is_integer(size) do @@ -3512,11 +3697,11 @@ defmodule AshPostgres.MigrationGenerator do {other, size} when is_atom(other) and is_integer(size) -> {other, size, nil, nil} - {:decimal, scale} -> - {:decimal, scale, nil, nil} + {:decimal, precision} -> + {:decimal, nil, nil, precision} - {:decimal, scale, precision} -> - {:decimal, scale, precision, nil} + {:decimal, precision, scale} -> + {:decimal, nil, precision, scale} other -> {other, nil, nil, nil} @@ -3620,12 +3805,12 @@ defmodule AshPostgres.MigrationGenerator do {:binary, size} end - defp load_type(["decimal", scale]) do - {:decimal, scale} + defp load_type(["decimal", precision]) do + {:decimal, precision} end - defp load_type(["decimal", scale, precision]) do - {:decimal, scale, precision} + defp load_type(["decimal", precision, scale]) do + {:decimal, precision, scale} end defp load_type([string, size]) when is_binary(string) and is_integer(size) do diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index 065942c8..8431572c 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -21,6 +21,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do * `no-format` - files that are created will not be formatted with the code formatter * `dry-run` - no files are created, instead the new migration is printed * `check` - no files are created, returns an exit(1) code if the current snapshots and resources don't fit + * `dev` - dev files are created * `snapshots-only` - no migrations are generated, only snapshots are stored * `concurrent-indexes` - new identities will be run concurrently and in a separate migration (like concurrent custom indexes) @@ -93,10 +94,12 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do tenant_migration_path: :string, quiet: :boolean, snapshots_only: :boolean, + auto_name: :boolean, name: :string, no_format: :boolean, dry_run: :boolean, check: :boolean, + dev: :boolean, dont_drop_columns: :boolean, concurrent_indexes: :boolean ] @@ -110,17 +113,6 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do |> Keyword.delete(:no_format) |> Keyword.put_new(:name, name) - if !opts[:name] && !opts[:dry_run] && !opts[:check] && !opts[:snapshots_only] do - IO.warn(""" - Name must be provided when generating migrations, unless `--dry-run` or `--check` is also provided. - Using an autogenerated name will be deprecated in a future release. - - Please provide a name. for example: - - mix ash_postgres.generate_migrations #{Enum.join(args, " ")} - """) - end - AshPostgres.MigrationGenerator.generate(domains, opts) end end diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index 36b9187d..3299fc5b 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -119,6 +119,8 @@ defmodule Mix.Tasks.AshPostgres.Migrate do |> AshPostgres.Mix.Helpers.delete_flag("--tenants") |> AshPostgres.Mix.Helpers.delete_arg("--only-tenants") |> AshPostgres.Mix.Helpers.delete_arg("--except-tenants") + |> AshPostgres.Mix.Helpers.delete_arg("--repo") + |> AshPostgres.Mix.Helpers.delete_arg("-r") Mix.Task.reenable("ecto.migrate") @@ -128,9 +130,16 @@ defmodule Mix.Tasks.AshPostgres.Migrate do for tenant <- tenants(repo, opts) do rest_opts = AshPostgres.Mix.Helpers.delete_arg(rest_opts, "--prefix") + repo = + if is_atom(repo) do + inspect(repo) + else + repo + end + Mix.Task.run( "ecto.migrate", - ["-r", to_string(repo)] ++ + ["-r", repo] ++ rest_opts ++ ["--prefix", tenant, "--migrations-path", tenant_migrations_path(opts, repo)] ) diff --git a/lib/mix/tasks/ash_postgres.rollback.ex b/lib/mix/tasks/ash_postgres.rollback.ex index b9a8354a..add81d59 100644 --- a/lib/mix/tasks/ash_postgres.rollback.ex +++ b/lib/mix/tasks/ash_postgres.rollback.ex @@ -61,6 +61,7 @@ defmodule Mix.Tasks.AshPostgres.Rollback do log_migrator_sql: :boolean, only_tenants: :string, except_tenants: :string, + already_started: :boolean, repo: :string ], aliases: [n: :step, v: :to, r: :repo] @@ -76,25 +77,23 @@ defmodule Mix.Tasks.AshPostgres.Rollback do |> AshPostgres.Mix.Helpers.delete_flag("--only-tenants") |> AshPostgres.Mix.Helpers.delete_flag("--except-tenants") |> AshPostgres.Mix.Helpers.delete_arg("-r") + |> AshPostgres.Mix.Helpers.delete_arg("--already-started") Mix.Task.reenable("ecto.rollback") if opts[:tenants] do for repo <- repos do - Ecto.Migrator.with_repo(repo, fn repo -> - for tenant <- tenants(repo, opts) do - rest_opts = AshPostgres.Mix.Helpers.delete_arg(rest_opts, "--prefix") + for tenant <- tenants(repo, opts) do + Mix.Task.reenable("ecto.rollback") + rest_opts = AshPostgres.Mix.Helpers.delete_arg(rest_opts, "--prefix") - Mix.Task.run( - "ecto.rollback", - ["-r", to_string(repo)] ++ - rest_opts ++ - ["--prefix", tenant, "--migrations-path", tenant_migrations_path(opts, repo)] - ) - - Mix.Task.reenable("ecto.rollback") - end - end) + Mix.Task.run( + "ecto.rollback", + ["-r", to_string(repo)] ++ + rest_opts ++ + ["--prefix", tenant, "--migrations-path", tenant_migrations_path(opts, repo)] + ) + end end else for repo <- repos do diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 96cddafc..eac6d15a 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -3,6 +3,7 @@ defmodule AshPostgres.MultiTenancy do @dialyzer {:nowarn_function, load_migration!: 1} + # sobelow_skip ["SQL.Query"] def create_tenant!(tenant_name, repo) do validate_tenant_name!(tenant_name) Ecto.Adapters.SQL.query!(repo, "CREATE SCHEMA IF NOT EXISTS \"#{tenant_name}\"", []) @@ -10,7 +11,7 @@ defmodule AshPostgres.MultiTenancy do migrate_tenant(tenant_name, repo) end - def migrate_tenant(tenant_name, repo, migrations_path \\ nil) do + def migrate_tenant(tenant_name, repo, migrations_path \\ nil, after_file \\ nil) do tenant_migrations_path = migrations_path || repo.config()[:tenant_migrations_path] || default_tenant_migration_path(repo) @@ -24,6 +25,17 @@ defmodule AshPostgres.MultiTenancy do [tenant_migrations_path, "**", "*.exs"] |> Path.join() |> Path.wildcard() + |> then(fn files -> + if after_file do + files + |> Enum.drop_while(fn file -> + file != after_file + end) + |> Enum.drop(1) + else + files + end + end) |> Enum.map(&extract_migration_info/1) |> Enum.filter(& &1) |> Enum.map(&load_migration!/1) diff --git a/mix.exs b/mix.exs index 31424e80..fb84295b 100644 --- a/mix.exs +++ b/mix.exs @@ -240,7 +240,7 @@ defmodule AshPostgres.MixProject do format: "format --migrate", "spark.formatter": "spark.formatter --extensions AshPostgres.DataLayer", "spark.cheat_sheets": "spark.cheat_sheets --extensions AshPostgres.DataLayer", - "test.generate_migrations": "ash_postgres.generate_migrations", + "test.generate_migrations": "ash_postgres.generate_migrations --auto-name", "test.check_migrations": "ash_postgres.generate_migrations --check", "test.migrate_tenants": "ash_postgres.migrate --tenants", "test.migrate": "ash_postgres.migrate", diff --git a/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs b/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs new file mode 100644 index 00000000..389b0b27 --- /dev/null +++ b/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs @@ -0,0 +1,172 @@ +defmodule AshPostgres.DevTestRepo.Migrations.MigrateResourcesExtensions1 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_or(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) + AS $$ SELECT COALESCE(NULLIF($1, FALSE), $2) $$ + LANGUAGE SQL + SET search_path = '' + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_or(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) + AS $$ SELECT COALESCE($1, $2) $$ + LANGUAGE SQL + SET search_path = '' + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_and(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ + SELECT CASE + WHEN $1 IS TRUE THEN $2 + ELSE $1 + END $$ + LANGUAGE SQL + SET search_path = '' + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_and(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ + SELECT CASE + WHEN $1 IS NOT NULL THEN $2 + ELSE $1 + END $$ + LANGUAGE SQL + SET search_path = '' + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_trim_whitespace(arr text[]) + RETURNS text[] AS $$ + DECLARE + start_index INT = 1; + end_index INT = array_length(arr, 1); + BEGIN + WHILE start_index <= end_index AND arr[start_index] = '' LOOP + start_index := start_index + 1; + END LOOP; + + WHILE end_index >= start_index AND arr[end_index] = '' LOOP + end_index := end_index - 1; + END LOOP; + + IF start_index > end_index THEN + RETURN ARRAY[]::text[]; + ELSE + RETURN arr[start_index : end_index]; + END IF; + END; $$ + LANGUAGE plpgsql + SET search_path = '' + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error(json_data jsonb) + RETURNS BOOLEAN AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql + STABLE + SET search_path = ''; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error(json_data jsonb, type_signal ANYCOMPATIBLE) + RETURNS ANYCOMPATIBLE AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql + STABLE + SET search_path = ''; + """) + + execute(""" + CREATE OR REPLACE FUNCTION uuid_generate_v7() + RETURNS UUID + AS $$ + DECLARE + timestamp TIMESTAMPTZ; + microseconds INT; + BEGIN + timestamp = clock_timestamp(); + microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT; + + RETURN encode( + set_byte( + set_byte( + overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6 + ), + 6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int + ), + 7, microseconds::bit(8)::int + ), + 'hex')::UUID; + END + $$ + LANGUAGE PLPGSQL + SET search_path = '' + VOLATILE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid) + RETURNS TIMESTAMP WITHOUT TIME ZONE + AS $$ + SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); + $$ + LANGUAGE SQL + SET search_path = '' + IMMUTABLE PARALLEL SAFE STRICT; + """) + + execute("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"") + execute("CREATE EXTENSION IF NOT EXISTS \"pg_trgm\"") + execute("CREATE EXTENSION IF NOT EXISTS \"citext\"") + + execute(""" + CREATE OR REPLACE FUNCTION ash_demo_functions() + RETURNS boolean AS $$ SELECT TRUE $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute("CREATE EXTENSION IF NOT EXISTS \"ltree\"") + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute( + "DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[])" + ) + + # execute("DROP EXTENSION IF EXISTS \"uuid-ossp\"") + # execute("DROP EXTENSION IF EXISTS \"pg_trgm\"") + # execute("DROP EXTENSION IF EXISTS \"citext\"") + execute(""" + DROP FUNCTION IF EXISTS ash_demo_functions() + """) + + # execute("DROP EXTENSION IF EXISTS \"ltree\"") + end +end diff --git a/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs b/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs new file mode 100644 index 00000000..3a56462c --- /dev/null +++ b/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs @@ -0,0 +1,29 @@ +defmodule AshPostgres.DevTestRepo.Migrations.MigrateResources1 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:multitenant_orgs, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:name, :text) + add(:owner_id, :uuid) + end + + create( + unique_index(:multitenant_orgs, [:id, :name], name: "multitenant_orgs_unique_by_name_index") + ) + end + + def down do + drop_if_exists( + unique_index(:multitenant_orgs, [:id, :name], name: "multitenant_orgs_unique_by_name_index") + ) + + drop(table(:multitenant_orgs)) + end +end diff --git a/priv/resource_snapshots/dev_test_repo/extensions.json b/priv/resource_snapshots/dev_test_repo/extensions.json new file mode 100644 index 00000000..d1c5a122 --- /dev/null +++ b/priv/resource_snapshots/dev_test_repo/extensions.json @@ -0,0 +1,11 @@ +{ + "ash_functions_version": 5, + "installed": [ + "ash-functions", + "uuid-ossp", + "pg_trgm", + "citext", + "demo-functions_v1", + "ltree" + ] +} \ No newline at end of file diff --git a/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json b/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json new file mode 100644 index 00000000..072cfe57 --- /dev/null +++ b/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json @@ -0,0 +1,70 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "owner_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "979D7BEB5939EAD2706978B7914C561B5F6854EBBCFD1F2748AB4C98668304EB", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "multitenant_orgs_unique_by_name_index", + "keys": [ + { + "type": "atom", + "value": "name" + } + ], + "name": "unique_by_name", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": "id", + "global": true, + "strategy": "attribute" + }, + "repo": "Elixir.AshPostgres.DevTestRepo", + "schema": null, + "table": "multitenant_orgs" +} \ No newline at end of file diff --git a/test/dev_migrations_test.exs b/test/dev_migrations_test.exs new file mode 100644 index 00000000..475aa909 --- /dev/null +++ b/test/dev_migrations_test.exs @@ -0,0 +1,234 @@ +defmodule AshPostgres.DevMigrationsTest do + use AshPostgres.RepoCase, async: false + @moduletag :migration + + import ExUnit.CaptureLog + require Logger + + alias Ecto.Adapters.SQL.Sandbox + + setup do + current_shell = Mix.shell() + + :ok = Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(current_shell) + end) + + Sandbox.checkout(AshPostgres.DevTestRepo) + end + + defmacrop defresource(mod, do: body) do + quote do + Code.compiler_options(ignore_module_conflict: true) + + defmodule unquote(mod) do + use Ash.Resource, + domain: nil, + data_layer: AshPostgres.DataLayer + + unquote(body) + end + + Code.compiler_options(ignore_module_conflict: false) + end + end + + defmacrop defposts(do: body) do + quote do + defresource Post do + postgres do + table "posts" + repo(AshPostgres.DevTestRepo) + + custom_indexes do + # need one without any opts + index(["id"]) + index(["id"], unique: true, name: "test_unique_index") + end + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + unquote(body) + end + end + end + + defmacrop defdomain(resources) do + quote do + Code.compiler_options(ignore_module_conflict: true) + + defmodule Domain do + use Ash.Domain + + resources do + for resource <- unquote(resources) do + resource(resource) + end + end + end + + Code.compiler_options(ignore_module_conflict: false) + end + end + + setup do + resource_dev_path = "priv/resource_snapshots/dev_test_repo" + + initial_resource_files = + if File.exists?(resource_dev_path), do: File.ls!(resource_dev_path), else: [] + + migrations_dev_path = "priv/dev_test_repo/migrations" + + initial_migration_files = + if File.exists?(migrations_dev_path), do: File.ls!(migrations_dev_path), else: [] + + tenant_migrations_dev_path = "priv/dev_test_repo/tenant_migrations" + + initial_tenant_migration_files = + if File.exists?(tenant_migrations_dev_path), + do: File.ls!(tenant_migrations_dev_path), + else: [] + + on_exit(fn -> + if File.exists?(resource_dev_path) do + current_resource_files = File.ls!(resource_dev_path) + new_resource_files = current_resource_files -- initial_resource_files + Enum.each(new_resource_files, &File.rm_rf!(Path.join(resource_dev_path, &1))) + end + + if File.exists?(migrations_dev_path) do + current_migration_files = File.ls!(migrations_dev_path) + new_migration_files = current_migration_files -- initial_migration_files + Enum.each(new_migration_files, &File.rm!(Path.join(migrations_dev_path, &1))) + end + + if File.exists?(tenant_migrations_dev_path) do + current_tenant_migration_files = File.ls!(tenant_migrations_dev_path) + + new_tenant_migration_files = + current_tenant_migration_files -- initial_tenant_migration_files + + Enum.each( + new_tenant_migration_files, + &File.rm!(Path.join(tenant_migrations_dev_path, &1)) + ) + end + + AshPostgres.DevTestRepo.query!("DROP TABLE IF EXISTS posts") + end) + end + + describe "--dev option" do + test "rolls back dev migrations before deleting" do + defposts do + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true) + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "priv/resource_snapshots", + migration_path: "priv/dev_test_repo/migrations", + dev: true, + auto_name: true + ) + + assert [_extensions, migration, _migration] = + Path.wildcard("priv/dev_test_repo/migrations/**/*_migrate_resources*.exs") + + assert capture_log(fn -> migrate(migration) end) =~ "create table posts" + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "priv/resource_snapshots", + migration_path: "priv/dev_test_repo/migrations", + auto_name: true + ) + + assert capture_log(fn -> migrate(migration) end) =~ "create table posts" + end + end + + describe "--dev option tenant" do + test "rolls back dev migrations before deleting" do + defposts do + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true, primary_key?: true, allow_nil?: false) + end + + multitenancy do + strategy(:context) + end + end + + defdomain([Post]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "priv/resource_snapshots", + migration_path: "priv/dev_test_repo/migrations", + tenant_migration_path: "priv/dev_test_repo/tenant_migrations", + dev: true, + auto_name: true + ) + + org = + AshPostgres.MultitenancyTest.DevMigrationsOrg + |> Ash.Changeset.for_create(:create, %{name: "test1"}, authorize?: false) + |> Ash.create!() + + assert [_] = + Enum.sort( + Path.wildcard("priv/dev_test_repo/migrations/**/*_migrate_resources*.exs") + ) + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert [_tenant_migration] = + Enum.sort( + Path.wildcard("priv/dev_test_repo/tenant_migrations/**/*_migrate_resources*.exs") + ) + |> Enum.reject(&String.contains?(&1, "extensions")) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "priv/resource_snapshots", + migration_path: "priv/dev_test_repo/migrations", + tenant_migration_path: "priv/dev_test_repo/tenant_migrations", + auto_name: true + ) + + assert [_tenant_migration] = + Enum.sort( + Path.wildcard("priv/dev_test_repo/tenant_migrations/**/*_migrate_resources*.exs") + ) + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert capture_log(fn -> tenant_migrate() end) =~ "create table org_#{org.id}.posts" + end + end + + defp migrate(after_file) do + AshPostgres.MultiTenancy.migrate_tenant( + nil, + AshPostgres.DevTestRepo, + "priv/dev_test_repo/migrations", + after_file + ) + end + + defp tenant_migrate do + for tenant <- AshPostgres.DevTestRepo.all_tenants() do + AshPostgres.MultiTenancy.migrate_tenant( + tenant, + AshPostgres.DevTestRepo, + "priv/dev_test_repo/tenant_migrations" + ) + end + end +end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index a1168ccb..6a4d0ef5 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -147,7 +147,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -247,7 +248,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -326,7 +328,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) end @@ -371,7 +374,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) end @@ -414,7 +418,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) end @@ -440,7 +445,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -493,7 +499,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -518,7 +525,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -552,7 +560,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, _file2, file3] = @@ -605,7 +614,8 @@ defmodule AshPostgres.MigrationGeneratorTest do migration_path: "test_migration_path", tenant_migration_path: "test_tenant_migration_path", quiet: false, - format: false + format: false, + auto_name: true ) defposts do @@ -632,7 +642,8 @@ defmodule AshPostgres.MigrationGeneratorTest do migration_path: "test_migration_path", tenant_migration_path: "test_tenant_migration_path", quiet: false, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -675,7 +686,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -701,7 +713,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -731,7 +744,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -774,7 +788,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -805,7 +820,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1] = @@ -838,7 +854,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -864,7 +881,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -897,7 +915,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -930,7 +949,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -966,7 +986,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -993,7 +1014,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -1019,7 +1041,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -1048,7 +1071,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -1083,7 +1107,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -1156,7 +1181,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -1189,7 +1215,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -1232,7 +1259,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file1, file2] = @@ -1277,7 +1305,8 @@ defmodule AshPostgres.MigrationGeneratorTest do migration_path: "test_migration_path", quiet: true, concurrent_indexes: true, - format: false + format: false, + auto_name: true ) assert [_file1, _file2, file3] = @@ -1316,7 +1345,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -1356,7 +1386,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -1394,7 +1425,8 @@ defmodule AshPostgres.MigrationGeneratorTest do AshPostgres.MigrationGenerator.generate(domain, snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", - check: true + check: true, + auto_name: true ) ) == {:shutdown, 1} @@ -1437,7 +1469,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -1474,7 +1507,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -1520,7 +1554,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -1566,7 +1601,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -1617,7 +1653,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) defposts Post2 do @@ -1646,7 +1683,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert file = @@ -1727,7 +1765,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -1781,7 +1820,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert file = @@ -1863,7 +1903,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -1918,7 +1959,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -1957,7 +1999,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) defposts Post2 do @@ -1983,7 +2026,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert file = @@ -2089,7 +2133,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -2169,7 +2214,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -2209,7 +2255,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert file = @@ -2242,7 +2289,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert file = @@ -2288,7 +2336,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert file = @@ -2323,7 +2372,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) defposts do @@ -2337,7 +2387,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert file = @@ -2414,7 +2465,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) [domain: Domain] @@ -2471,7 +2523,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file1] = @@ -2527,7 +2580,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) end) @@ -2576,7 +2630,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -2614,7 +2669,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [_file1, file2] = @@ -2679,7 +2735,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -2722,7 +2779,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) # Now update the precision and scale @@ -2747,7 +2805,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) migration_files = @@ -2791,7 +2850,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = @@ -2835,7 +2895,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) # Now change to arbitrary precision and scale @@ -2865,7 +2926,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) migration_files = @@ -2943,7 +3005,8 @@ defmodule AshPostgres.MigrationGeneratorTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) assert [file] = diff --git a/test/mix_squash_snapshots_test.exs b/test/mix_squash_snapshots_test.exs index f2827228..dcdce819 100644 --- a/test/mix_squash_snapshots_test.exs +++ b/test/mix_squash_snapshots_test.exs @@ -94,7 +94,8 @@ defmodule AshPostgres.MixSquashSnapshotsTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) defposts do @@ -113,7 +114,8 @@ defmodule AshPostgres.MixSquashSnapshotsTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok @@ -179,7 +181,8 @@ defmodule AshPostgres.MixSquashSnapshotsTest do snapshot_path: "test_snapshots_path", migration_path: "test_migration_path", quiet: true, - format: false + format: false, + auto_name: true ) :ok diff --git a/test/support/dev_test_repo.ex b/test/support/dev_test_repo.ex new file mode 100644 index 00000000..2b1fe929 --- /dev/null +++ b/test/support/dev_test_repo.ex @@ -0,0 +1,39 @@ +defmodule AshPostgres.DevTestRepo do + @moduledoc false + use AshPostgres.Repo, + otp_app: :ash_postgres + + def on_transaction_begin(data) do + send(self(), data) + end + + def prefer_transaction?, do: false + + def prefer_transaction_for_atomic_updates?, do: false + + def installed_extensions do + ["ash-functions", "uuid-ossp", "pg_trgm", "citext", AshPostgres.TestCustomExtension, "ltree"] -- + Application.get_env(:ash_postgres, :no_extensions, []) + end + + def min_pg_version do + case System.get_env("PG_VERSION") do + nil -> + %Version{major: 16, minor: 0, patch: 0} + + version -> + case Integer.parse(version) do + {major, ""} -> %Version{major: major, minor: 0, patch: 0} + _ -> Version.parse!(version) + end + end + end + + def all_tenants do + Code.ensure_compiled(AshPostgres.MultitenancyTest.Org) + + AshPostgres.MultitenancyTest.DevMigrationsOrg + |> Ash.read!() + |> Enum.map(&"org_#{&1.id}") + end +end diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 9ad6f881..52ffbc63 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -4,6 +4,7 @@ defmodule AshPostgres.MultitenancyTest.Domain do resources do resource(AshPostgres.MultitenancyTest.Org) + resource(AshPostgres.MultitenancyTest.DevMigrationsOrg) resource(AshPostgres.MultitenancyTest.NamedOrg) resource(AshPostgres.MultitenancyTest.User) resource(AshPostgres.MultitenancyTest.Post) diff --git a/test/support/multitenancy/resources/dev_migrations_org.ex b/test/support/multitenancy/resources/dev_migrations_org.ex new file mode 100644 index 00000000..6ebd3394 --- /dev/null +++ b/test/support/multitenancy/resources/dev_migrations_org.ex @@ -0,0 +1,91 @@ +defmodule AshPostgres.MultitenancyTest.DevMigrationsOrg do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.MultitenancyTest.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + defimpl Ash.ToTenant do + def to_tenant(%{id: id}, resource) do + if Ash.Resource.Info.data_layer(resource) == AshPostgres.DataLayer && + Ash.Resource.Info.multitenancy_strategy(resource) == :context do + "org_#{id}" + else + id + end + end + end + + policies do + policy action(:has_policies) do + authorize_if(relates_to_actor_via(:owner)) + end + + # policy always() do + # authorize_if(always()) + # end + end + + identities do + identity(:unique_by_name, [:name]) + end + + attributes do + uuid_primary_key(:id, writable?: true) + attribute(:name, :string, public?: true) + end + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + + read(:has_policies) + end + + postgres do + table "multitenant_orgs" + repo(AshPostgres.DevTestRepo) + + manage_tenant do + template(["org_", :id]) + end + end + + multitenancy do + strategy(:attribute) + attribute(:id) + global?(true) + 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) + public?(false) + end + + has_many(:posts, AshPostgres.MultitenancyTest.Post, + destination_attribute: :org_id, + public?: true + ) + + has_many(:users, AshPostgres.MultitenancyTest.User, + destination_attribute: :org_id, + public?: true + ) + end + + def tenant("org_" <> tenant) do + tenant + end + + def tenant(tenant) do + tenant + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs index 056ebefd..6745f6eb 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -20,6 +20,7 @@ exclude_tags = ExUnit.configure(stacktrace_depth: 100, exclude: exclude_tags) AshPostgres.TestRepo.start_link() +AshPostgres.DevTestRepo.start_link() AshPostgres.TestNoSandboxRepo.start_link() format_sql_query = @@ -49,4 +50,5 @@ format_sql_query = end Ecto.DevLogger.install(AshPostgres.TestRepo, before_inline_callback: format_sql_query) +Ecto.DevLogger.install(AshPostgres.DevTestRepo, before_inline_callback: format_sql_query) Ecto.DevLogger.install(AshPostgres.TestNoSandboxRepo, before_inline_callback: format_sql_query) diff --git a/usage-rules.md b/usage-rules.md index 5c8ee524..632fc52d 100644 --- a/usage-rules.md +++ b/usage-rules.md @@ -149,14 +149,29 @@ end ## Migrations and Codegen -### Generating Migrations +### Development Migration Workflow (Recommended) -After creating or modifying Ash resources: +For development iterations, use the dev workflow to avoid naming migrations prematurely: + +1. Make resource changes +2. Run `mix ash.codegen --dev` to generate and run dev migrations +3. Review the migrations and run `mix ash.migrate` to run them +4. Continue making changes and running `mix ash.codegen --dev` as needed +5. When your feature is complete, run `mix ash.codegen add_feature_name` to generate final named migrations (this will rollback dev migrations and squash them) +3. Review the migrations and run `mix ash.migrate` to run them + +### Traditional Migration Generation + +For single-step changes or when you know the final feature name: 1. Run `mix ash.codegen add_feature_name` to generate migrations 2. Review the generated migrations in `priv/repo/migrations` 3. Run `mix ash.migrate` to apply the migrations +> **Tip**: The dev workflow (`--dev` flag) is preferred during development as it allows you to iterate without thinking of migration names and provides better development ergonomics. + +> **Warning**: Always review migrations before applying them to ensure they are correct and safe. + ## Multitenancy AshPostgres supports schema-based multitenancy: From 831940d3368e2db536a43928fad142c54b0da761 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 May 2025 22:09:49 -0400 Subject: [PATCH 527/690] chore: temporarily override ash dep --- mix.exs | 3 ++- mix.lock | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index fb84295b..a0399b50 100644 --- a/mix.exs +++ b/mix.exs @@ -166,7 +166,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.69")}, + # {:ash, ash_version("~> 3.4 and >= 3.4.69")}, + {:ash, github: "ash-project/ash", override: true}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, {:igniter, "~> 0.6", optional: true}, {:ecto_sql, "~> 3.12"}, diff --git a/mix.lock b/mix.lock index 10820741..624ec23b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.12", "435a6916d47e4ed6eabce886de2443d17af9dd9ca9765a29c73d9e02507b86b3", [: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.6", [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.60 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", "503492989c56e33c300d731b3717d1df9eeebba2b9018e5dd9f330db727edb57"}, + "ash": {:git, "https://github.com/ash-project/ash.git", "3eee4fa4fd836e8dad7bc8fb09df602221867565", []}, "ash_sql": {:hex, :ash_sql, "0.2.76", "4afac3284194f3d7820b7edc1263ac1eb232a25734406ad7b2284683b9384205", [:mix], [{:ash, "~> 3.5", [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", "f6bc02d8c4cba3f8f9a532e6ff73eaf8a4f7685257646a58fe7a320cfaf10c39"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -44,7 +44,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.61", "64745581832caf136cbd654c1ecef98d291f3d1b347a14411b7d0dc726e3822b", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "cb10300e17f74b41848954d61630fb627f4e0d5acf9aacd7d9f312d5b119d50f"}, + "spark": {:hex, :spark, "2.2.62", "610502559834465edce437de712bf7e6d59713ad48050789dbef69a798e71a3c", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "726df72e1b9c17401584b4657e75e08a27a1cf6a6effa2486bf1c074da6176a7"}, "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From d226fcd79d09d6aec926019ebc227d7d5eb9322f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 26 May 2025 22:25:16 -0400 Subject: [PATCH 528/690] ci: temporarily only have one postgres-version --- .github/workflows/elixir.yml | 2 +- mix.exs | 3 +-- mix.lock | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index 084df209..cb875c93 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - postgres-version: ["14", "15", "16"] + postgres-version: ["16"] uses: ash-project/ash/.github/workflows/ash-ci.yml@main with: postgres: true diff --git a/mix.exs b/mix.exs index a0399b50..fb84295b 100644 --- a/mix.exs +++ b/mix.exs @@ -166,8 +166,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - # {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - {:ash, github: "ash-project/ash", override: true}, + {:ash, ash_version("~> 3.4 and >= 3.4.69")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, {:igniter, "~> 0.6", optional: true}, {:ecto_sql, "~> 3.12"}, diff --git a/mix.lock b/mix.lock index 624ec23b..1f94b151 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:git, "https://github.com/ash-project/ash.git", "3eee4fa4fd836e8dad7bc8fb09df602221867565", []}, + "ash": {:hex, :ash, "3.5.12", "435a6916d47e4ed6eabce886de2443d17af9dd9ca9765a29c73d9e02507b86b3", [: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.6", [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.60 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", "503492989c56e33c300d731b3717d1df9eeebba2b9018e5dd9f330db727edb57"}, "ash_sql": {:hex, :ash_sql, "0.2.76", "4afac3284194f3d7820b7edc1263ac1eb232a25734406ad7b2284683b9384205", [:mix], [{:ash, "~> 3.5", [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", "f6bc02d8c4cba3f8f9a532e6ff73eaf8a4f7685257646a58fe7a320cfaf10c39"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, From cb7a216e3d59df03430cd5699b737965cc29a687 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 27 May 2025 22:05:47 -0400 Subject: [PATCH 529/690] chore: try to migrate in transaction to see if that helps --- .../migration_generator.ex | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 2479d067..7516aa96 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -562,12 +562,46 @@ defmodule AshPostgres.MigrationGenerator do for prefix <- repo.all_tenants() do {repo, query, opts} = Ecto.Migration.SchemaMigration.versions(repo, [], prefix) + repo.transaction(fn -> + versions = repo.all(query, Keyword.put(opts, :timeout, :infinity)) + + dev_migrations + |> Enum.map(&extract_migration_info/1) + |> Enum.filter(& &1) + |> Enum.map(&load_migration!/1) + |> Enum.filter(fn {version, _} -> + version in versions + end) + |> Enum.each(fn {version, mod} -> + Ecto.Migration.Runner.run( + repo, + [], + version, + mod, + :forward, + :down, + :down, + all: true, + prefix: prefix + ) + + Ecto.Migration.SchemaMigration.down(repo, repo.config(), version, prefix: prefix) + end) + end) + end + end) + else + with_repo_not_in_test(repo, fn repo -> + {repo, query, opts} = Ecto.Migration.SchemaMigration.versions(repo, [], nil) + + repo.transaction(fn -> versions = repo.all(query, opts) dev_migrations |> Enum.map(&extract_migration_info/1) |> Enum.filter(& &1) |> Enum.map(&load_migration!/1) + |> Enum.sort() |> Enum.filter(fn {version, _} -> version in versions end) @@ -580,41 +614,11 @@ defmodule AshPostgres.MigrationGenerator do :forward, :down, :down, - all: true, - prefix: prefix + all: true ) - Ecto.Migration.SchemaMigration.down(repo, repo.config(), version, prefix: prefix) + Ecto.Migration.SchemaMigration.down(repo, repo.config(), version, []) end) - end - end) - else - with_repo_not_in_test(repo, fn repo -> - {repo, query, opts} = Ecto.Migration.SchemaMigration.versions(repo, [], nil) - - versions = repo.all(query, opts) - - dev_migrations - |> Enum.map(&extract_migration_info/1) - |> Enum.filter(& &1) - |> Enum.map(&load_migration!/1) - |> Enum.sort() - |> Enum.filter(fn {version, _} -> - version in versions - end) - |> Enum.each(fn {version, mod} -> - Ecto.Migration.Runner.run( - repo, - [], - version, - mod, - :forward, - :down, - :down, - all: true - ) - - Ecto.Migration.SchemaMigration.down(repo, repo.config(), version, []) end) end) end From c52ec455889dbd9a8fb2223274306677eb852a11 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 27 May 2025 22:10:55 -0400 Subject: [PATCH 530/690] CI: add back in older pg versions --- .github/workflows/elixir.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index cb875c93..084df209 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - postgres-version: ["16"] + postgres-version: ["14", "15", "16"] uses: ash-project/ash/.github/workflows/ash-ci.yml@main with: postgres: true From 69b06eeba6754773b3a32eadc0cf526d5bea6142 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 27 May 2025 22:20:45 -0400 Subject: [PATCH 531/690] CI: add temporary logging for CI strangeness --- lib/multitenancy.ex | 4 ++++ test/dev_migrations_test.exs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index eac6d15a..3469b0f4 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -21,6 +21,7 @@ defmodule AshPostgres.MultiTenancy do repo.config(), prefix: tenant_name ) + |> tap(fn v -> Logger.warning(inspect(v, label: "ensure migraitons result")) end) [tenant_migrations_path, "**", "*.exs"] |> Path.join() @@ -39,6 +40,7 @@ defmodule AshPostgres.MultiTenancy do |> Enum.map(&extract_migration_info/1) |> Enum.filter(& &1) |> Enum.map(&load_migration!/1) + |> tap(fn v -> Logger.warning(inspect(v, label: "migrations")) end) |> Enum.each(fn {version, mod} -> Ecto.Migration.Runner.run( repo, @@ -51,8 +53,10 @@ defmodule AshPostgres.MultiTenancy do all: true, prefix: tenant_name ) + |> tap(fn v -> Logger.warning(inspect(v, label: "run result")) end) Ecto.Migration.SchemaMigration.up(repo, repo.config(), version, prefix: tenant_name) + |> tap(fn v -> Logger.warning(inspect(v, label: "schema run result")) end) end) end diff --git a/test/dev_migrations_test.exs b/test/dev_migrations_test.exs index 475aa909..0f7b93c0 100644 --- a/test/dev_migrations_test.exs +++ b/test/dev_migrations_test.exs @@ -220,6 +220,7 @@ defmodule AshPostgres.DevMigrationsTest do "priv/dev_test_repo/migrations", after_file ) + |> tap(fn v -> Logger.warning(inspect(v, label: "result")) end) end defp tenant_migrate do @@ -229,6 +230,7 @@ defmodule AshPostgres.DevMigrationsTest do AshPostgres.DevTestRepo, "priv/dev_test_repo/tenant_migrations" ) + |> tap(fn v -> Logger.warning(inspect(v, label: "result")) end) end end end From bb9024f5616e47f44a48ffbbfd6c19064565bb24 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 27 May 2025 22:21:46 -0400 Subject: [PATCH 532/690] chore: add require logger --- lib/multitenancy.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 3469b0f4..a8601209 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -2,6 +2,7 @@ defmodule AshPostgres.MultiTenancy do @moduledoc false @dialyzer {:nowarn_function, load_migration!: 1} + require Logger # sobelow_skip ["SQL.Query"] def create_tenant!(tenant_name, repo) do From 08b2e44391fe8b42fa063d0b49824daae21c1c0e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 27 May 2025 22:39:22 -0400 Subject: [PATCH 533/690] chore: try sorting migration files --- lib/multitenancy.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index a8601209..30abecbd 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -27,6 +27,7 @@ defmodule AshPostgres.MultiTenancy do [tenant_migrations_path, "**", "*.exs"] |> Path.join() |> Path.wildcard() + |> Enum.sort() |> then(fn files -> if after_file do files From 1ce6568271cae5ede04c1448e2ebed489ec108ab Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 27 May 2025 23:07:46 -0400 Subject: [PATCH 534/690] chore: add missing sort --- lib/migration_generator/migration_generator.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 7516aa96..57e0787e 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -569,6 +569,7 @@ defmodule AshPostgres.MigrationGenerator do |> Enum.map(&extract_migration_info/1) |> Enum.filter(& &1) |> Enum.map(&load_migration!/1) + |> Enum.sort() |> Enum.filter(fn {version, _} -> version in versions end) From bdd71d742772544c6250b0fea6e0e5e5f04541f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 10:29:24 -0400 Subject: [PATCH 535/690] chore(deps): bump igniter in the production-dependencies group (#556) Bumps the production-dependencies group with 1 update: [igniter](https://github.com/ash-project/igniter). Updates `igniter` from 0.6.2 to 0.6.3 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.6.2...v0.6.3) --- updated-dependencies: - dependency-name: igniter dependency-version: 0.6.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 1f94b151..3f532193 100644 --- a/mix.lock +++ b/mix.lock @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.2", "6263fa3d2b7698f8d9afc506e4e1bccef69f1b8a3288760fe749dc70a9f6b408", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "480c679066444459eecd371a41639cee365449e20cfb611457081394fd146b05"}, + "igniter": {:hex, :igniter, "0.6.3", "8bfaf5955ce83301da0f0a53455f73a0bc4dc5aacd6c311363089850a5dc2dd7", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "95d34d8280dea992e05dcbf9865414d69e421a76d743661eaf1d1337ea54fa80"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From e415d9e2fc5557dab9d4ffd1042b984d7b9a5922 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 10:29:35 -0400 Subject: [PATCH 536/690] chore(deps-dev): bump ex_doc in the dev-dependencies group (#557) Bumps the dev-dependencies group with 1 update: [ex_doc](https://github.com/elixir-lang/ex_doc). Updates `ex_doc` from 0.38.1 to 0.38.2 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.38.1...v0.38.2) --- updated-dependencies: - dependency-name: ex_doc dependency-version: 0.38.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 3f532193..4076ca19 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.38.1", "bae0a0bd5b5925b1caef4987e3470902d072d03347114ffe03a55dbe206dd4c2", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "754636236d191b895e1e4de2ebb504c057fe1995fdfdd92e9d75c4b05633008b"}, + "ex_doc": {:hex, :ex_doc, "0.38.2", "504d25eef296b4dec3b8e33e810bc8b5344d565998cd83914ffe1b8503737c02", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "732f2d972e42c116a70802f9898c51b54916e542cc50968ac6980512ec90f42b"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "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"}, From 3f837d14e80ece91aca6fd8ec7fc7c7be713d39f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 29 May 2025 22:15:50 -0400 Subject: [PATCH 537/690] improvement: assume not renaming when generating dev migrations --- lib/migration_generator/migration_generator.ex | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 57e0787e..2d5dfca1 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2960,10 +2960,14 @@ defmodule AshPostgres.MigrationGenerator do end defp renaming?(table, removing, opts) do - if opts.no_shell? do - raise "Unimplemented: cannot determine: Are you renaming #{table}.#{removing.source}? without shell input" + if opts.dev do + if opts.no_shell? do + raise "Unimplemented: cannot determine: Are you renaming #{table}.#{removing.source}? without shell input" + else + yes?(opts, "Are you renaming #{table}.#{removing.source}?") + end else - yes?(opts, "Are you renaming #{table}.#{removing.source}?") + false end end From 755c5564abd94f0b017e854cd0aaa2bb29e14c15 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 30 May 2025 00:25:24 -0400 Subject: [PATCH 538/690] improvement: use new `PendingCodegen` error --- .tool-versions | 2 +- lib/data_layer.ex | 1 + .../migration_generator.ex | 204 ++++++++---------- mix.exs | 31 +-- mix.lock | 2 +- test/migration_generator_test.exs | 18 +- 6 files changed, 118 insertions(+), 140 deletions(-) diff --git a/.tool-versions b/.tool-versions index cab727e0..005db769 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ erlang 27.0.1 -elixir 1.18.0-otp-27 +elixir 1.18.4-otp-27 diff --git a/lib/data_layer.ex b/lib/data_layer.ex index ae642468..40227e7f 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -568,6 +568,7 @@ defmodule AshPostgres.DataLayer do end def codegen(args) do + Mix.Task.reenable("ash_postgres.generate_migrations") Mix.Task.run("ash_postgres.generate_migrations", args) end diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 2d5dfca1..de411a97 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3,8 +3,6 @@ defmodule AshPostgres.MigrationGenerator do require Logger - import Mix.Generator - alias AshPostgres.MigrationGenerator.{Operation, Phase} defstruct snapshot_path: nil, @@ -52,12 +50,46 @@ defmodule AshPostgres.MigrationGenerator do |> Enum.concat(find_repos()) |> Enum.uniq() - Mix.shell().info("\nExtension Migrations: ") - create_extension_migrations(repos, opts) - Mix.shell().info("\nGenerating Tenant Migrations: ") - create_migrations(tenant_snapshots, opts, true, snapshots) - Mix.shell().info("\nGenerating Migrations:") - create_migrations(snapshots, opts, false) + extension_migration_files = + create_extension_migrations(repos, opts) + + tenant_migration_files = + create_migrations(tenant_snapshots, opts, true, snapshots) + + migration_files = + create_migrations(snapshots, opts, false) + + case extension_migration_files ++ tenant_migration_files ++ migration_files do + [] -> + if !opts.check || opts.dry_run do + Mix.shell().info( + "No changes detected, so no migrations or snapshots have been created." + ) + end + + :ok + + files -> + cond do + opts.check -> + raise Ash.Error.Framework.PendingCodegen, + diff: files + + opts.dry_run -> + Mix.shell().info( + files + |> Enum.sort_by(&elem(&1, 0)) + |> Enum.map_join("\n\n", fn {file, contents} -> + "#{file}\n#{contents}" + end) + ) + + true -> + Enum.each(files, fn {file, contents} -> + Mix.Generator.create_file(file, contents, force?: true) + end) + end + end end defp find_repos do @@ -225,8 +257,7 @@ defmodule AshPostgres.MigrationGenerator do |> Enum.map(fn {_name, extension} -> extension end) if Enum.empty?(to_install) do - Mix.shell().info("No extensions to install") - :ok + [] else dev = if opts.dev, do: "_dev" @@ -378,40 +409,13 @@ defmodule AshPostgres.MigrationGenerator do contents = format(migration_file, contents, opts) - if opts.dry_run do - Mix.shell().info(snapshot_contents) - Mix.shell().info(contents) - - if opts.check do - Mix.shell().error(""" - Migrations would have been generated, but the --check flag was provided. - - To see what migration would have been generated, run with the `--dry-run` - option instead. To generate those migrations, run without either flag. - """) - - exit({:shutdown, 1}) - end - else - if opts.check do - Mix.shell().error(""" - Migrations would have been generated, but the --check flag was provided. - - To see what migration would have been generated, run with the `--dry-run` - option instead. To generate those migrations, run without either flag. - """) - - exit({:shutdown, 1}) - end - - create_file(snapshot_file, snapshot_contents, force: true) - - if !opts.snapshots_only do - create_file(migration_file, contents) - end - end + [ + {snapshot_file, snapshot_contents}, + {migration_file, contents} + ] end end + |> List.flatten() end defp set_ash_functions(snapshot, installed_extensions) do @@ -429,7 +433,7 @@ defmodule AshPostgres.MigrationGenerator do defp create_migrations(snapshots, opts, tenant?, non_tenant_snapshots \\ []) do snapshots |> Enum.group_by(& &1.repo) - |> Enum.each(fn {repo, snapshots} -> + |> Enum.flat_map(fn {repo, snapshots} -> deduped = deduplicate_snapshots(snapshots, opts, non_tenant_snapshots) snapshots_with_operations = @@ -444,18 +448,7 @@ defmodule AshPostgres.MigrationGenerator do |> Enum.uniq() |> case do [] -> - tenant_str = - if tenant? do - "tenant " - else - "" - end - - Mix.shell().info( - "No #{tenant_str}changes detected, so no migrations or snapshots have been created." - ) - - :ok + [] operations -> dev_migrations = get_dev_migrations(opts, tenant?, repo) @@ -475,21 +468,12 @@ defmodule AshPostgres.MigrationGenerator do end end - if opts.check do - Mix.shell().error(""" - Migrations would have been generated, but the --check flag was provided. - - To see what migration would have been generated, run with the `--dry-run` - option instead. To generate those migrations, run without either flag. - """) - - exit({:shutdown, 1}) - end - - if !opts.snapshots_only do + if opts.snapshots_only do + [] + else operations |> split_into_migrations() - |> Enum.each(fn operations -> + |> Enum.map(fn operations -> run_without_transaction? = Enum.any?(operations, fn %Operation.AddCustomIndex{index: %{concurrently: true}} -> @@ -505,11 +489,10 @@ defmodule AshPostgres.MigrationGenerator do operations |> organize_operations |> build_up_and_down() - |> write_migration!(repo, opts, tenant?, run_without_transaction?) + |> migration(repo, opts, tenant?, run_without_transaction?) end) end - - create_new_snapshot(snapshots, repo_name(repo), opts, tenant?) + |> Enum.concat(create_new_snapshot(snapshots, repo_name(repo), opts, tenant?)) end end) end @@ -1110,7 +1093,7 @@ defmodule AshPostgres.MigrationGenerator do repo |> Module.split() |> List.last() |> Macro.underscore() end - defp write_migration!({up, down}, repo, opts, tenant?, run_without_transaction?) do + defp migration({up, down}, repo, opts, tenant?, run_without_transaction?) do migration_path = migration_path(opts, repo, tenant?) require_name!(opts) @@ -1185,13 +1168,7 @@ defmodule AshPostgres.MigrationGenerator do """ try do - contents = format(migration_file, contents, opts) - - if opts.dry_run do - Mix.shell().info(contents) - else - create_file(migration_file, contents) - end + {migration_file, format(migration_file, contents, opts)} rescue exception -> reraise( @@ -1223,45 +1200,44 @@ defmodule AshPostgres.MigrationGenerator do end defp create_new_snapshot(snapshots, repo_name, opts, tenant?) do - if !opts.dry_run do - Enum.each(snapshots, fn snapshot -> - snapshot_binary = snapshot_to_binary(snapshot) + Enum.map(snapshots, fn snapshot -> + snapshot_binary = snapshot_to_binary(snapshot) - snapshot_folder = - if tenant? do - opts - |> snapshot_path(snapshot.repo) - |> Path.join(repo_name) - |> Path.join("tenants") - else - opts - |> snapshot_path(snapshot.repo) - |> Path.join(repo_name) - end + snapshot_folder = + if tenant? do + opts + |> snapshot_path(snapshot.repo) + |> Path.join(repo_name) + |> Path.join("tenants") + else + opts + |> snapshot_path(snapshot.repo) + |> Path.join(repo_name) + end - dev = if opts.dev, do: "_dev" + dev = if opts.dev, do: "_dev" - snapshot_file = - if snapshot.schema do - Path.join( - snapshot_folder, - "#{snapshot.schema}.#{snapshot.table}/#{timestamp()}#{dev}.json" - ) - else - Path.join(snapshot_folder, "#{snapshot.table}/#{timestamp()}#{dev}.json") - end + snapshot_file = + if snapshot.schema do + Path.join( + snapshot_folder, + "#{snapshot.schema}.#{snapshot.table}/#{timestamp()}#{dev}.json" + ) + else + Path.join(snapshot_folder, "#{snapshot.table}/#{timestamp()}#{dev}.json") + end - File.mkdir_p(Path.dirname(snapshot_file)) - create_file(snapshot_file, snapshot_binary, force: true) + File.mkdir_p(Path.dirname(snapshot_file)) - old_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}#{dev}.json") + old_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}#{dev}.json") - if File.exists?(old_snapshot_folder) do - new_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}/initial#{dev}.json") - File.rename(old_snapshot_folder, new_snapshot_folder) - end - end) - end + if File.exists?(old_snapshot_folder) do + new_snapshot_folder = Path.join(snapshot_folder, "#{snapshot.table}/initial#{dev}.json") + File.rename(old_snapshot_folder, new_snapshot_folder) + end + + {snapshot_file, snapshot_binary} + end) end @doc false @@ -2961,13 +2937,13 @@ defmodule AshPostgres.MigrationGenerator do defp renaming?(table, removing, opts) do if opts.dev do + false + else if opts.no_shell? do raise "Unimplemented: cannot determine: Are you renaming #{table}.#{removing.source}? without shell input" else yes?(opts, "Are you renaming #{table}.#{removing.source}?") end - else - false end end diff --git a/mix.exs b/mix.exs index fb84295b..6cb94ca9 100644 --- a/mix.exs +++ b/mix.exs @@ -166,7 +166,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.4 and >= 3.4.69")}, + # {:ash, ash_version("~> 3.4 and >= 3.4.69")}, + {:ash, github: "ash-project/ash", override: true}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, {:igniter, "~> 0.6", optional: true}, {:ecto_sql, "~> 3.12"}, @@ -189,24 +190,24 @@ defmodule AshPostgres.MixProject do ] end - defp ash_version(default_version) do - case System.get_env("ASH_VERSION") do - nil -> - default_version + # defp ash_version(default_version) do + # case System.get_env("ASH_VERSION") do + # nil -> + # default_version - "local" -> - [path: "../ash", override: true] + # "local" -> + # [path: "../ash", override: true] - "main" -> - [git: "https://github.com/ash-project/ash.git", override: true] + # "main" -> + # [git: "https://github.com/ash-project/ash.git", override: true] - version when is_binary(version) -> - "~> #{version}" + # version when is_binary(version) -> + # "~> #{version}" - version -> - version - end - end + # version -> + # version + # end + # end defp ash_sql_version(default_version) do case System.get_env("ASH_SQL_VERSION") do diff --git a/mix.lock b/mix.lock index 4076ca19..89d5b5af 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.12", "435a6916d47e4ed6eabce886de2443d17af9dd9ca9765a29c73d9e02507b86b3", [: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.6", [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.60 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", "503492989c56e33c300d731b3717d1df9eeebba2b9018e5dd9f330db727edb57"}, + "ash": {:git, "https://github.com/ash-project/ash.git", "e7b1a738644e1092ed350115ebebf5da8ac2aec1", []}, "ash_sql": {:hex, :ash_sql, "0.2.76", "4afac3284194f3d7820b7edc1263ac1eb232a25734406ad7b2284683b9384205", [:mix], [{:ash, "~> 3.5", [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", "f6bc02d8c4cba3f8f9a532e6ff73eaf8a4f7685257646a58fe7a320cfaf10c39"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 6a4d0ef5..afbd4ed8 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -1420,15 +1420,15 @@ defmodule AshPostgres.MigrationGeneratorTest do [domain: Domain] end - test "returns code(1) if snapshots and resources don't fit", %{domain: domain} do - assert catch_exit( - AshPostgres.MigrationGenerator.generate(domain, - snapshot_path: "test_snapshots_path", - migration_path: "test_migration_path", - check: true, - auto_name: true - ) - ) == {:shutdown, 1} + test "raises an error on pending codegen", %{domain: domain} do + assert_raise Ash.Error.Framework.PendingCodegen, fn -> + AshPostgres.MigrationGenerator.generate(domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + check: true, + auto_name: true + ) + end refute File.exists?(Path.wildcard("test_migration_path2/**/*_migrate_resources*.exs")) refute File.exists?(Path.wildcard("test_snapshots_path2/test_repo/posts/*.json")) From 0f21c885f7072daf317108112ed83f31d3e5f93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Fri, 30 May 2025 18:33:51 +0200 Subject: [PATCH 539/690] chore: Bump erlang elixir version in tool versions (#559) --- .tool-versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.tool-versions b/.tool-versions index 005db769..32823875 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -erlang 27.0.1 -elixir 1.18.4-otp-27 +erlang 27.1.2 +elixir 1.18.4 \ No newline at end of file From de093d8f5683d5b9d848be0fb00244a4e06e6939 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 30 May 2025 01:33:29 -0400 Subject: [PATCH 540/690] chore: better dev mode check --- lib/migration_generator/migration_generator.ex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index de411a97..58a0ad71 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -456,9 +456,12 @@ defmodule AshPostgres.MigrationGenerator do if !opts.dev and dev_migrations != [] do if opts.check do Mix.shell().error(""" - Generated migrations are from dev mode. + Codegen check failed. - Generate migrations without `--dev` flag. + You have migrations remaining that were generated with the --dev flag. + + Run `mix ash.codegen ` to remove the dev migraitons and replace them + with production ready migrations. """) exit({:shutdown, 1}) From a6c2f2e18bd78dec40aa45acf8dcf7dead4b23e7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 30 May 2025 16:08:16 -0400 Subject: [PATCH 541/690] chore: update deps --- mix.exs | 31 +++++++++++++++---------------- mix.lock | 6 +++--- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/mix.exs b/mix.exs index 6cb94ca9..91eb50a7 100644 --- a/mix.exs +++ b/mix.exs @@ -166,8 +166,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - # {:ash, ash_version("~> 3.4 and >= 3.4.69")}, - {:ash, github: "ash-project/ash", override: true}, + {:ash, ash_version("~> 3.5 and >= 3.5.13")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, {:igniter, "~> 0.6", optional: true}, {:ecto_sql, "~> 3.12"}, @@ -190,24 +189,24 @@ defmodule AshPostgres.MixProject do ] end - # defp ash_version(default_version) do - # case System.get_env("ASH_VERSION") do - # nil -> - # default_version + defp ash_version(default_version) do + case System.get_env("ASH_VERSION") do + nil -> + default_version - # "local" -> - # [path: "../ash", override: true] + "local" -> + [path: "../ash", override: true] - # "main" -> - # [git: "https://github.com/ash-project/ash.git", override: true] + "main" -> + [git: "https://github.com/ash-project/ash.git", override: true] - # version when is_binary(version) -> - # "~> #{version}" + version when is_binary(version) -> + "~> #{version}" - # version -> - # version - # end - # end + version -> + version + end + end defp ash_sql_version(default_version) do case System.get_env("ASH_SQL_VERSION") do diff --git a/mix.lock b/mix.lock index 89d5b5af..1f3910ec 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:git, "https://github.com/ash-project/ash.git", "e7b1a738644e1092ed350115ebebf5da8ac2aec1", []}, + "ash": {:hex, :ash, "3.5.13", "1e2d15188dcf01a00f7c91180f6a0fb990c427828fdf9f014b8a6dde951f46a0", [: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.6", [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.61 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", "bdd52d10f95af357f37b61b74636226bf7c1082c4b815df94443d2aa2607c961"}, "ash_sql": {:hex, :ash_sql, "0.2.76", "4afac3284194f3d7820b7edc1263ac1eb232a25734406ad7b2284683b9384205", [:mix], [{:ash, "~> 3.5", [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", "f6bc02d8c4cba3f8f9a532e6ff73eaf8a4f7685257646a58fe7a320cfaf10c39"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.3", "8bfaf5955ce83301da0f0a53455f73a0bc4dc5aacd6c311363089850a5dc2dd7", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "95d34d8280dea992e05dcbf9865414d69e421a76d743661eaf1d1337ea54fa80"}, + "igniter": {:hex, :igniter, "0.6.4", "81b7442be9ae0b9107b715144f3633f72788644d13ffded612cb508861b2c726", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "e999fc4b883e5eacc07ca2823273880ab30108c7e6a0d1542a3c8e00605aef46"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -38,7 +38,7 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.15.3", "f1f05d5b0f229ad1a164b7a5543beee58c9975e7e146afc71821e5afc5c69a79", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "8a16a46163fcdeb1d1be06749f54bd71282126be27c9dc80010cf3b97fe7193c"}, + "reactor": {:hex, :reactor, "0.15.4", "ef0c56a901c132529a14ab59fed0ccb4fcecb24308fb189a94c908255d4fdafc", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "783bf62fd0c72ded033afabdb8b6190b7048769771a2a97256e6f0bf4fb0a891"}, "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, From ea9d09c8e675deac12b91f01ea110a58fe43b365 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 30 May 2025 16:08:24 -0400 Subject: [PATCH 542/690] chore: release version v2.6.0 --- CHANGELOG.md | 21 +++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63141775..b739ea7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,27 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.0](https://github.com/ash-project/ash_postgres/compare/v2.5.22...v2.6.0) (2025-05-30) + + + + +### Features: + +* --dev flag for codegen (#555) + +### Bug Fixes: + +* properly encode decimal scale & preicison into snapshots + +### Improvements: + +* use new `PendingCodegen` error + +* assume not renaming when generating dev migrations + +* support scale & precision in decimal types + ## [v2.5.22](https://github.com/ash-project/ash_postgres/compare/v2.5.21...v2.5.22) (2025-05-22) diff --git a/mix.exs b/mix.exs index 91eb50a7..306c04c6 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.5.22" + @version "2.6.0" def project do [ From be48da96af1d08614d725053b9ea8c088aee79b8 Mon Sep 17 00:00:00 2001 From: Frank Dugan III Date: Fri, 30 May 2025 17:03:44 -0500 Subject: [PATCH 543/690] fix: retain repo as atom in migrator task (#560) --- lib/mix/tasks/ash_postgres.migrate.ex | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index 3299fc5b..f8ab1d20 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -130,16 +130,9 @@ defmodule Mix.Tasks.AshPostgres.Migrate do for tenant <- tenants(repo, opts) do rest_opts = AshPostgres.Mix.Helpers.delete_arg(rest_opts, "--prefix") - repo = - if is_atom(repo) do - inspect(repo) - else - repo - end - Mix.Task.run( "ecto.migrate", - ["-r", repo] ++ + ["-r", to_string(repo)] ++ rest_opts ++ ["--prefix", tenant, "--migrations-path", tenant_migrations_path(opts, repo)] ) From 7f91cc87e8f0106c593dce6d9f8745fe9b71e733 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 30 May 2025 18:04:09 -0400 Subject: [PATCH 544/690] chore: release version v2.6.1 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b739ea7e..f627e950 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.1](https://github.com/ash-project/ash_postgres/compare/v2.6.0...v2.6.1) (2025-05-30) + + + + +### Bug Fixes: + +* retain repo as atom in migrator task (#560) + ## [v2.6.0](https://github.com/ash-project/ash_postgres/compare/v2.5.22...v2.6.0) (2025-05-30) diff --git a/mix.exs b/mix.exs index 306c04c6..036bf575 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.0" + @version "2.6.1" def project do [ From 57dbdb4bf52d4d27ec87b831a09ee7190c291a24 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 2 Jun 2025 17:24:44 -0400 Subject: [PATCH 545/690] test: add tests corresponding to #561 unable to reproduce --- test/atomics_test.exs | 21 +++++++++++++++++++++ test/support/resources/post.ex | 10 ++++++++++ 2 files changed, 31 insertions(+) diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 301cf8e3..2439ab9d 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -40,6 +40,27 @@ defmodule AshPostgres.AtomicsTest do |> Ash.update!() end + test "an atomic update on decimals works" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "foo", decimal: Decimal.new("1")}) + |> Ash.create!() + + assert %{decimal: result} = + post + |> Ash.Changeset.for_update(:subtract_integer_from_decimal, %{amount: 2}) + |> Ash.update!() + + assert Decimal.eq?(result, Decimal.new("-1")) + + assert %{decimal: result} = + post + |> Ash.Changeset.for_update(:subtract_from_decimal, %{amount: Decimal.new("2")}) + |> Ash.update!() + + assert Decimal.eq?(result, Decimal.new("-3")) + end + test "an atomic works on a constrained integer" do post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index c66c8680..4b893048 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -184,6 +184,16 @@ defmodule AshPostgres.Test.Post do end) end + update :subtract_integer_from_decimal do + argument(:amount, :integer, allow_nil?: false) + change(atomic_update(:decimal, expr(decimal + -(^arg(:amount))))) + end + + update :subtract_from_decimal do + argument(:amount, :decimal, allow_nil?: false) + change(atomic_update(:decimal, expr(decimal + -(^arg(:amount))))) + end + update :add_to_limited_score do argument(:amount, :integer, allow_nil?: false) change(atomic_update(:limited_score, expr((limited_score || 0) + ^arg(:amount)))) From b7d69500ec8fb7fa6cd7a1900b88a0ac41a9e841 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Jun 2025 22:32:55 -0400 Subject: [PATCH 546/690] chore: remove ash added content when running query --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 40227e7f..8196cbe7 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1532,7 +1532,7 @@ defmodule AshPostgres.DataLayer do {_, results} = with_savepoint(repo, query, fn -> repo.update_all( - query, + Map.delete(query, :__ash_bindings__), [], repo_opts ) From afa872b660fcac55dcb50900c19ca21cface7d8f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 3 Jun 2025 22:49:31 -0400 Subject: [PATCH 547/690] chore: cleanup community files --- .github/CODE_OF_CONDUCT.md | 76 ----------------------- .github/CONTRIBUTING.md | 2 - .github/ISSUE_TEMPLATE/bug_report.md | 27 -------- .github/ISSUE_TEMPLATE/feature_request.md | 35 ----------- .github/PULL_REQUEST_TEMPLATE.md | 4 -- 5 files changed, 144 deletions(-) delete mode 100644 .github/CODE_OF_CONDUCT.md delete mode 100644 .github/CONTRIBUTING.md delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index 7aa6f743..00000000 --- a/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,76 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at zach@zachdaniel.dev. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index f537454f..00000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,2 +0,0 @@ -# Contributing Guidelines -Contributing guidelines can be found in the core project, [ash](https://github.com/ash-project/ash/blob/main/.github/CONTRIBUTING.md) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 1f47341d..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug, needs review -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. If you are not sure if the bug is related to `ash` or an extension, log it with [ash](https://github.com/ash-project/ash/issues/new) and we will move it. - -**To Reproduce** -A minimal set of resource definitions and calls that can reproduce the bug. - -**Expected behavior** -A clear and concise description of what you expected to happen. - -** Runtime - - Elixir version - - Erlang version - - OS - - Ash version - - any related extension versions - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index a6442e0d..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Proposal -about: Suggest an idea for this project -title: "" -labels: enhancement, needs review -assignees: "" ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Express the feature either with a change to resource syntax, or with a change to the resource interface** - -For example - -```elixir - attributes do - attribute :foo, :integer, bar: 10 # <- Adding `bar` here would cause - end -``` - -Or - -```elixir - Ash.read(Resource, bar: 10) # <- Adding `bar` here would cause -``` - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 8c13744f..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,4 +0,0 @@ -### Contributor checklist - -- [ ] Bug fixes include regression tests -- [ ] Features include unit/acceptance tests From 3e24e7c8970547b710020fec62918bd3bbfedb5e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Jun 2025 09:49:24 -0400 Subject: [PATCH 548/690] fix: don't use `:"timestamptz(6)"` in ecto storage type --- lib/migration_generator/migration_generator.ex | 7 ++++++- lib/type.ex | 5 ++++- lib/types/timestamptz.ex | 4 ---- lib/types/timestamptz_usec.ex | 6 ++++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 58a0ad71..1699141d 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3364,8 +3364,13 @@ defmodule AshPostgres.MigrationGenerator do defp migration_type(other, constraints) do type = Ash.Type.get_type(other) + Code.ensure_loaded(type) - migration_type_from_storage_type(Ash.Type.storage_type(type, constraints)) + if function_exported?(type, :migration_type, 1) do + type.migration_type(constraints) + else + migration_type_from_storage_type(Ash.Type.storage_type(type, constraints)) + end end defp migration_type_from_storage_type(:string), do: :text diff --git a/lib/type.ex b/lib/type.ex index a437057e..22a3ec07 100644 --- a/lib/type.ex +++ b/lib/type.ex @@ -11,8 +11,11 @@ defmodule AshPostgres.Type do @callback postgres_reference_expr(Ash.Type.t(), Ash.Type.constraints(), term) :: {:ok, term} | :error + @callback migration_type(Ash.Type.constraints()) :: term() + @optional_callbacks value_to_postgres_default: 3, - postgres_reference_expr: 3 + postgres_reference_expr: 3, + migration_type: 1 defmacro __using__(_) do quote do diff --git a/lib/types/timestamptz.ex b/lib/types/timestamptz.ex index dfac2d4f..11b007a3 100644 --- a/lib/types/timestamptz.ex +++ b/lib/types/timestamptz.ex @@ -28,10 +28,6 @@ defmodule AshPostgres.Timestamptz do attribute :timestamp, :timestamptz timestamps type: :timestamptz ``` - - - - """ use Ash.Type.NewType, subtype_of: :datetime, constraints: [precision: :second] diff --git a/lib/types/timestamptz_usec.ex b/lib/types/timestamptz_usec.ex index 513d455d..d723a2dd 100644 --- a/lib/types/timestamptz_usec.ex +++ b/lib/types/timestamptz_usec.ex @@ -21,14 +21,16 @@ defmodule AshPostgres.TimestamptzUsec do timestamps type: :timestamptz_usec ``` - - Please see `AshPostgres.Timestamptz` for details about the usecase for this type. """ use Ash.Type.NewType, subtype_of: :datetime, constraints: [precision: :microsecond] @impl true def storage_type(_constraints) do + :timestamptz + end + + def migration_type(_constraints) do :"timestamptz(6)" end end From 9c6e40426eab9f93a4688fc0b9af4f2d3336e990 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Jun 2025 11:05:13 -0400 Subject: [PATCH 549/690] chore: release version v2.6.2 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f627e950..7280df90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.2](https://github.com/ash-project/ash_postgres/compare/v2.6.1...v2.6.2) (2025-06-04) + + + + +### Bug Fixes: + +* don't use `:"timestamptz(6)"` in ecto storage type + ## [v2.6.1](https://github.com/ash-project/ash_postgres/compare/v2.6.0...v2.6.1) (2025-05-30) diff --git a/mix.exs b/mix.exs index 036bf575..e260f2fd 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.1" + @version "2.6.2" def project do [ From 3995ba30cf8eda1faf748785280f4d12dd194cd9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Jun 2025 13:16:57 -0400 Subject: [PATCH 550/690] fix: undo change for timestamptz usec, retaining precision --- lib/types/timestamptz_usec.ex | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/types/timestamptz_usec.ex b/lib/types/timestamptz_usec.ex index d723a2dd..f1dae8fd 100644 --- a/lib/types/timestamptz_usec.ex +++ b/lib/types/timestamptz_usec.ex @@ -27,10 +27,6 @@ defmodule AshPostgres.TimestamptzUsec do @impl true def storage_type(_constraints) do - :timestamptz - end - - def migration_type(_constraints) do :"timestamptz(6)" end end From 1492fc5596b0e6aaf019294f835db72141633dad Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Jun 2025 13:39:41 -0400 Subject: [PATCH 551/690] chore: stabilize migration tests --- test/dev_migrations_test.exs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/dev_migrations_test.exs b/test/dev_migrations_test.exs index 0f7b93c0..400bca14 100644 --- a/test/dev_migrations_test.exs +++ b/test/dev_migrations_test.exs @@ -94,7 +94,7 @@ defmodule AshPostgres.DevMigrationsTest do do: File.ls!(tenant_migrations_dev_path), else: [] - on_exit(fn -> + clean = fn -> if File.exists?(resource_dev_path) do current_resource_files = File.ls!(resource_dev_path) new_resource_files = current_resource_files -- initial_resource_files @@ -120,7 +120,11 @@ defmodule AshPostgres.DevMigrationsTest do end AshPostgres.DevTestRepo.query!("DROP TABLE IF EXISTS posts") - end) + end + + clean.() + + on_exit(clean) end describe "--dev option" do From 6238948e5cfbe54bdc47b13959c10d7a30765eb7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 4 Jun 2025 13:40:16 -0400 Subject: [PATCH 552/690] chore: release version v2.6.3 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7280df90..b5f5faed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.3](https://github.com/ash-project/ash_postgres/compare/v2.6.2...v2.6.3) (2025-06-04) + + + + +### Bug Fixes: + +* undo change for timestamptz usec, retaining precision + ## [v2.6.2](https://github.com/ash-project/ash_postgres/compare/v2.6.1...v2.6.2) (2025-06-04) diff --git a/mix.exs b/mix.exs index e260f2fd..e13172bb 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.2" + @version "2.6.3" def project do [ From 2b5011369595a5a64d85bd99d7de7209fd0aa0fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Jun 2025 08:01:53 -0400 Subject: [PATCH 553/690] chore(deps): bump the production-dependencies group with 3 updates (#562) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.5.13 to 3.5.15 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.5.13...v3.5.15) Updates `ash_sql` from 0.2.76 to 0.2.77 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.76...v0.2.77) Updates `igniter` from 0.6.4 to 0.6.5 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.6.4...v0.6.5) --- updated-dependencies: - dependency-name: ash dependency-version: 3.5.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-version: 0.2.77 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-version: 0.6.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 1f3910ec..751ea5f0 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.13", "1e2d15188dcf01a00f7c91180f6a0fb990c427828fdf9f014b8a6dde951f46a0", [: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.6", [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.61 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", "bdd52d10f95af357f37b61b74636226bf7c1082c4b815df94443d2aa2607c961"}, - "ash_sql": {:hex, :ash_sql, "0.2.76", "4afac3284194f3d7820b7edc1263ac1eb232a25734406ad7b2284683b9384205", [:mix], [{:ash, "~> 3.5", [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", "f6bc02d8c4cba3f8f9a532e6ff73eaf8a4f7685257646a58fe7a320cfaf10c39"}, + "ash": {:hex, :ash, "3.5.15", "418055e74c4d85d1f397577407aa71c29d44ef0b729be144e23e64630ad2eedc", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.61 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", "8ee885ccc6be65d1023cccbdfda6a534497cf5170d53b67c0b29db72c0c30b9b"}, + "ash_sql": {:hex, :ash_sql, "0.2.77", "731c87a624ffe2bed61de8fed4d11aacc5057ceedbe1df076979e9b6bc3fd499", [:mix], [{:ash, "~> 3.5", [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", "a94f9be7e6583f193dbb1705192c3ddee6a49ff5a870ddeb6cd3a9a947add0db"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.4", "81b7442be9ae0b9107b715144f3633f72788644d13ffded612cb508861b2c726", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "e999fc4b883e5eacc07ca2823273880ab30108c7e6a0d1542a3c8e00605aef46"}, + "igniter": {:hex, :igniter, "0.6.5", "0b16a37e1aaaefc39777c6250980a314df8ba02a8ae81063d786a7bddb40dbf0", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "21dec3066f372f49f391d00a2067769eb20f7a2213513e022593e4b51bad93e2"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -45,7 +45,7 @@ "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, "spark": {:hex, :spark, "2.2.62", "610502559834465edce437de712bf7e6d59713ad48050789dbef69a798e71a3c", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "726df72e1b9c17401584b4657e75e08a27a1cf6a6effa2486bf1c074da6176a7"}, - "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, + "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "stream_data": {:hex, :stream_data, "1.2.0", "58dd3f9e88afe27dc38bef26fce0c84a9e7a96772b2925c7b32cd2435697a52b", [:mix], [], "hexpm", "eb5c546ee3466920314643edf68943a5b14b32d1da9fe01698dc92b73f89a9ed"}, From 7c8b89a6eeb28ddd69535b553b91b0a143a6ed81 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Jun 2025 13:38:51 -0400 Subject: [PATCH 554/690] chore: add test --- test/calculation_test.exs | 16 +++++++++++++++- test/support/resources/record.ex | 14 +++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 017ca25a..a8c1703f 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1,6 +1,6 @@ defmodule AshPostgres.CalculationTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Account, Author, Comedian, Comment, Post, User} + alias AshPostgres.Test.{Account, Author, Comedian, Comment, Post, Record, TempEntity, User} require Ash.Query import Ash.Expr @@ -1016,4 +1016,18 @@ defmodule AshPostgres.CalculationTest do def fred do "fred" end + + test "calculation references use the appropriate schema" do + record = Record |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() + + TempEntity |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() + + full_name = + Record + |> Ash.Query.load(:temp_entity_full_name) + |> Ash.read_first!() + |> Map.get(:temp_entity_full_name) + + assert full_name == "name" + end end diff --git a/test/support/resources/record.ex b/test/support/resources/record.ex index b98ef59e..db820fca 100644 --- a/test/support/resources/record.ex +++ b/test/support/resources/record.ex @@ -14,9 +14,7 @@ defmodule AshPostgres.Test.Record do end relationships do - alias AshPostgres.Test.Entity - - has_one :entity, Entity do + has_one :entity, AshPostgres.Test.Entity do public?(true) no_attributes?(true) @@ -24,6 +22,12 @@ defmodule AshPostgres.Test.Record do filter(expr(full_name == parent(full_name))) end + + has_one :temp_entity, AshPostgres.Test.TempEntity do + public?(true) + source_attribute(:full_name) + destination_attribute(:full_name) + end end postgres do @@ -31,6 +35,10 @@ defmodule AshPostgres.Test.Record do repo AshPostgres.TestRepo end + calculations do + calculate(:temp_entity_full_name, :string, expr(temp_entity.full_name)) + end + actions do default_accept(:*) From 5e21f8946ed7fa01c4e541fedf52fc0dd6120720 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 5 Jun 2025 14:51:58 -0400 Subject: [PATCH 555/690] test: add test for ash_sql datetime time zone issues --- test/calculation_test.exs | 2 +- test/complex_calculations_test.exs | 27 +++++++++++++++++++ .../resources/documentation.ex | 11 ++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index a8c1703f..4b6fff35 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1018,7 +1018,7 @@ defmodule AshPostgres.CalculationTest do end test "calculation references use the appropriate schema" do - record = Record |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() + Record |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() TempEntity |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index 73fd689d..83cb39cf 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -346,4 +346,31 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do |> Ash.Query.for_read(:failing_many_reference) |> Ash.read!(page: [count: true]) end + + test "lazy datetime with timezone is respected in calculations" do + documentation_before = + AshPostgres.Test.ComplexCalculations.Documentation + |> Ash.Changeset.for_create(:create, %{ + status: :demonstrated, + # 2 hours before Seoul time in UTC + inserted_at: ~U[2024-05-01 10:00:00Z] + }) + |> Ash.create!() + + documentation_after = + AshPostgres.Test.ComplexCalculations.Documentation + |> Ash.Changeset.for_create(:create, %{ + status: :demonstrated, + # 2 hours after Seoul time in UTC + inserted_at: ~U[2024-05-01 14:00:00Z] + }) + |> Ash.create!() + + [doc_before, doc_after] = + [documentation_before, documentation_after] + |> Ash.load!([:is_active_with_timezone]) + + assert doc_before.is_active_with_timezone == false + assert doc_after.is_active_with_timezone == true + end end diff --git a/test/support/complex_calculations/resources/documentation.ex b/test/support/complex_calculations/resources/documentation.ex index ad961895..df6c5415 100644 --- a/test/support/complex_calculations/resources/documentation.ex +++ b/test/support/complex_calculations/resources/documentation.ex @@ -42,6 +42,10 @@ defmodule AshPostgres.Test.ComplexCalculations.Documentation do end ) ) + + calculate :is_active_with_timezone, :boolean do + calculation(expr(inserted_at > lazy({AshPostgres.Test.TimezoneHelper, :seoul_time, []}))) + end end postgres do @@ -55,3 +59,10 @@ defmodule AshPostgres.Test.ComplexCalculations.Documentation do end end end + +defmodule AshPostgres.Test.TimezoneHelper do + def seoul_time do + # Fixed datetime for testing - equivalent to 2024-05-01 21:00:00 in Seoul (UTC+9) + ~U[2024-05-01 12:00:00Z] |> DateTime.shift_zone!("Asia/Seoul") + end +end From 5b8f46ffb52378a818dee7278d9ab9702dc12121 Mon Sep 17 00:00:00 2001 From: kernel-io Date: Fri, 6 Jun 2025 12:39:56 +1200 Subject: [PATCH 556/690] test: failing test for calculations in different schema (#563) * failing test for calculations in different schema Signed-off-by: kernel-io * fix test to not require grouping Signed-off-by: kernel-io --------- Signed-off-by: kernel-io --- .../records_temp_entities/20250605230457.json | 93 +++++++++++++++++++ ...0457_create_record_temp_entities_table.exs | 43 +++++++++ test/calculation_test.exs | 8 +- test/support/domain.ex | 1 + test/support/resources/record.ex | 12 ++- test/support/resources/record_temp_entity.ex | 25 +++++ 6 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json create mode 100644 priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs create mode 100644 test/support/resources/record_temp_entity.ex diff --git a/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json b/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json new file mode 100644 index 00000000..af6e3c23 --- /dev/null +++ b/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json @@ -0,0 +1,93 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "records_temp_entities_record_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "records" + }, + "scale": null, + "size": null, + "source": "record_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "records_temp_entities_temp_entity_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "temp", + "table": "temp_entities" + }, + "scale": null, + "size": null, + "source": "temp_entity_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "1F00231E86F4E276096E683FD2836B40F36C6AD617A777D947E908FD52D09FDB", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "records_temp_entities" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs b/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs new file mode 100644 index 00000000..fe910c8c --- /dev/null +++ b/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs @@ -0,0 +1,43 @@ +defmodule AshPostgres.TestRepo.Migrations.CreateRecordTempEntitiesTable do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:records_temp_entities, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + + add( + :record_id, + references(:records, + column: :id, + name: "records_temp_entities_record_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + + add( + :temp_entity_id, + references(:temp_entities, + column: :id, + name: "records_temp_entities_temp_entity_id_fkey", + type: :uuid, + prefix: "temp" + ) + ) + end + end + + def down do + drop(constraint(:records_temp_entities, "records_temp_entities_record_id_fkey")) + + drop(constraint(:records_temp_entities, "records_temp_entities_temp_entity_id_fkey")) + + drop(table(:records_temp_entities)) + end +end diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 4b6fff35..6aa911fe 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1,4 +1,5 @@ defmodule AshPostgres.CalculationTest do + alias AshPostgres.Test.RecordTempEntity use AshPostgres.RepoCase, async: false alias AshPostgres.Test.{Account, Author, Comedian, Comment, Post, Record, TempEntity, User} @@ -1018,9 +1019,12 @@ defmodule AshPostgres.CalculationTest do end test "calculation references use the appropriate schema" do - Record |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() + record = Record |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() - TempEntity |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() + temp_entity = + TempEntity |> Ash.Changeset.for_create(:create, %{full_name: "name"}) |> Ash.create!() + + Ash.Seed.seed!(RecordTempEntity, %{record_id: record.id, temp_entity_id: temp_entity.id}) full_name = Record diff --git a/test/support/domain.ex b/test/support/domain.ex index 25616374..c8c596d5 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -31,6 +31,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Entity) resource(AshPostgres.Test.ContentVisibilityGroup) resource(AshPostgres.Test.TempEntity) + resource(AshPostgres.Test.RecordTempEntity) resource(AshPostgres.Test.Permalink) resource(AshPostgres.Test.Record) resource(AshPostgres.Test.PostFollower) diff --git a/test/support/resources/record.ex b/test/support/resources/record.ex index db820fca..804c981a 100644 --- a/test/support/resources/record.ex +++ b/test/support/resources/record.ex @@ -28,6 +28,12 @@ defmodule AshPostgres.Test.Record do source_attribute(:full_name) destination_attribute(:full_name) end + + many_to_many :temp_entities, AshPostgres.Test.TempEntity do + public?(true) + + through(AshPostgres.Test.RecordTempEntity) + end end postgres do @@ -36,7 +42,11 @@ defmodule AshPostgres.Test.Record do end calculations do - calculate(:temp_entity_full_name, :string, expr(temp_entity.full_name)) + calculate( + :temp_entity_full_name, + :string, + expr(fragment("coalesce(?, '')", temp_entities.full_name)) + ) end actions do diff --git a/test/support/resources/record_temp_entity.ex b/test/support/resources/record_temp_entity.ex new file mode 100644 index 00000000..7750a1df --- /dev/null +++ b/test/support/resources/record_temp_entity.ex @@ -0,0 +1,25 @@ +defmodule AshPostgres.Test.RecordTempEntity do + @moduledoc false + + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "records_temp_entities" + repo AshPostgres.TestRepo + end + + attributes do + uuid_primary_key(:id) + end + + relationships do + belongs_to(:record, AshPostgres.Test.Record, public?: true) + belongs_to(:temp_entity, AshPostgres.Test.TempEntity, public?: true) + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end +end From db011c06900cd24f320dfe5b938a685730497eb0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 7 Jun 2025 15:05:26 -0400 Subject: [PATCH 557/690] fix: use better wrappers around string/ci_string --- lib/types/ci_string_wrapper.ex | 9 +-------- lib/types/string_wrapper.ex | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/types/ci_string_wrapper.ex b/lib/types/ci_string_wrapper.ex index 20a9b12e..74e47347 100644 --- a/lib/types/ci_string_wrapper.ex +++ b/lib/types/ci_string_wrapper.ex @@ -1,14 +1,7 @@ defmodule AshPostgres.Type.CiStringWrapper do @moduledoc false - use Ash.Type + use Ash.Type.NewType, subtype_of: :ci_string, constraints: [allow_empty?: true, trim?: false] @impl true def storage_type(_), do: :citext - - @impl true - defdelegate cast_input(value, constraints), to: Ash.Type.CiString - @impl true - defdelegate cast_stored(value, constraints), to: Ash.Type.CiString - @impl true - defdelegate dump_to_native(value, constraints), to: Ash.Type.CiString end diff --git a/lib/types/string_wrapper.ex b/lib/types/string_wrapper.ex index e6101c52..84b5cd2c 100644 --- a/lib/types/string_wrapper.ex +++ b/lib/types/string_wrapper.ex @@ -1,14 +1,7 @@ defmodule AshPostgres.Type.StringWrapper do @moduledoc false - use Ash.Type + use Ash.Type.NewType, subtype_of: :string, constraints: [allow_empty?: true, trim?: false] @impl true def storage_type(_), do: :text - - @impl true - defdelegate cast_input(value, constraints), to: Ash.Type.String - @impl true - defdelegate cast_stored(value, constraints), to: Ash.Type.String - @impl true - defdelegate dump_to_native(value, constraints), to: Ash.Type.String end From 12579ad3e79418a996dbddf7462b4e3d4e67e158 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 8 Jun 2025 01:02:44 -0400 Subject: [PATCH 558/690] chore: remove deprecated syntax --- lib/sql_implementation.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 6648a7e4..a91b8786 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -188,7 +188,7 @@ defmodule AshPostgres.SqlImplementation do type ) do if function_exported?(attr_type, :postgres_reference_expr, 3) do - non_bare_ref = %Ash.Query.Ref{ref | bare?: nil} + non_bare_ref = %{ref | bare?: nil} {expr, acc} = AshSql.Expr.dynamic_expr(query, non_bare_ref, bindings, embedded?, type, acc) case attr_type.postgres_reference_expr(attr_type, constraints, expr) do From 5c15c7e70e15f34f8fa81816ba2711519cb335c2 Mon Sep 17 00:00:00 2001 From: "Stephan Hug (FlyingNoodle)" <88476449+StephanH90@users.noreply.github.com> Date: Sun, 8 Jun 2025 07:04:06 +0200 Subject: [PATCH 559/690] fix: casting integers to string in expressions works as intended (#564) This commit currently only adds a failing test. --- test/support/resources/post.ex | 6 ++++++ test/type_test.exs | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 4b893048..369283bc 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -154,6 +154,12 @@ defmodule AshPostgres.Test.Post do defaults([:read, :destroy]) + read :with_version_check do + argument(:version, :integer) + + filter(expr(type(^arg(:version), :string) in ["1", "2"])) + end + read :first_and_last_post do prepare(fn query, _ -> Ash.Query.combination_of(query, [ diff --git a/test/type_test.exs b/test/type_test.exs index 428fcab1..4c3731e7 100644 --- a/test/type_test.exs +++ b/test/type_test.exs @@ -100,4 +100,11 @@ defmodule AshPostgres.Test.TypeTest do assert %{x: 2.0, y: 3.0, z: 4.0} = p.db_string_point_id assert %{x: 2.0, y: 3.0, z: 4.0} = p.db_string_point.id end + + test "casting integer to string works" do + Post |> Ash.Changeset.for_create(:create) |> Ash.create!() + + post = Ash.Query.for_read(Post, :with_version_check, version: 1) |> Ash.read!() + refute is_nil(post) + end end From cf3da36618ca27c069386bb35b61d4337752a433 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 8 Jun 2025 01:08:28 -0400 Subject: [PATCH 560/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 751ea5f0..0fd35a2e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.15", "418055e74c4d85d1f397577407aa71c29d44ef0b729be144e23e64630ad2eedc", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.61 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", "8ee885ccc6be65d1023cccbdfda6a534497cf5170d53b67c0b29db72c0c30b9b"}, - "ash_sql": {:hex, :ash_sql, "0.2.77", "731c87a624ffe2bed61de8fed4d11aacc5057ceedbe1df076979e9b6bc3fd499", [:mix], [{:ash, "~> 3.5", [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", "a94f9be7e6583f193dbb1705192c3ddee6a49ff5a870ddeb6cd3a9a947add0db"}, + "ash_sql": {:hex, :ash_sql, "0.2.78", "130d54ca85b8fbd1e65f038beafb905ade1941d1f5e3aef1fec7f8bba7414fc2", [:mix], [{:ash, "~> 3.5", [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", "a640ec0ef176f3a0e95f88d8639d9d23479ca8a5f5e7e177af351f18cddf4f30"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.5", "0b16a37e1aaaefc39777c6250980a314df8ba02a8ae81063d786a7bddb40dbf0", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "21dec3066f372f49f391d00a2067769eb20f7a2213513e022593e4b51bad93e2"}, + "igniter": {:hex, :igniter, "0.6.6", "82d707a2419a95e6ea115949c68a9113dfc0b4802d3d8386aa351feb0ead71ee", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "a85832987fc78f5fdc38f628a62acfd50b4e441166496fea15c7b05218fa84f5"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -44,7 +44,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.62", "610502559834465edce437de712bf7e6d59713ad48050789dbef69a798e71a3c", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "726df72e1b9c17401584b4657e75e08a27a1cf6a6effa2486bf1c074da6176a7"}, + "spark": {:hex, :spark, "2.2.63", "bc771c3c1028136559507e235e721e730118ca316e22e75da347ae1c195b94a1", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "42708ab2884af6abc1aa33aa981a4f51f65146d7879651d1e6c11948a4d8fcfe"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 2c6466d7d0576815bfe01e5d2231b3a6c8440a22 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 9 Jun 2025 10:59:29 -0400 Subject: [PATCH 561/690] improvement: add `c:AshPostgres.Repo.create_schemas_in_migrations?` callback --- lib/migration_generator/migration_generator.ex | 11 +++++++++-- lib/migration_generator/operation.ex | 2 +- lib/migration_generator/phase.ex | 12 +++++++++--- lib/repo.ex | 5 +++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 1699141d..129a7ddd 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -1361,14 +1361,20 @@ defmodule AshPostgres.MigrationGenerator do defp group_into_phases( [ - %Operation.CreateTable{table: table, schema: schema, multitenancy: multitenancy} | rest + %Operation.CreateTable{ + table: table, + schema: schema, + multitenancy: multitenancy, + repo: repo + } + | rest ], nil, acc ) do group_into_phases( rest, - %Phase.Create{table: table, schema: schema, multitenancy: multitenancy}, + %Phase.Create{table: table, schema: schema, multitenancy: multitenancy, repo: repo}, acc ) end @@ -2010,6 +2016,7 @@ defmodule AshPostgres.MigrationGenerator do %Operation.CreateTable{ table: snapshot.table, schema: snapshot.schema, + repo: snapshot.repo, multitenancy: snapshot.multitenancy, old_multitenancy: empty_snapshot.multitenancy } diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 242a5db1..5c8bfbc0 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -145,7 +145,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do defmodule CreateTable do @moduledoc false - defstruct [:table, :schema, :multitenancy, :old_multitenancy] + defstruct [:table, :schema, :multitenancy, :old_multitenancy, :repo] end defmodule AddAttribute do diff --git a/lib/migration_generator/phase.ex b/lib/migration_generator/phase.ex index d743810d..6be7dd81 100644 --- a/lib/migration_generator/phase.ex +++ b/lib/migration_generator/phase.ex @@ -3,18 +3,24 @@ defmodule AshPostgres.MigrationGenerator.Phase do defmodule Create do @moduledoc false - defstruct [:table, :schema, :multitenancy, operations: [], commented?: false] + defstruct [:table, :schema, :multitenancy, :repo, operations: [], commented?: false] import AshPostgres.MigrationGenerator.Operation.Helper, only: [as_atom: 1] - def up(%{schema: schema, table: table, operations: operations, multitenancy: multitenancy}) do + def up(%{ + schema: schema, + table: table, + operations: operations, + multitenancy: multitenancy, + repo: repo + }) do if multitenancy.strategy == :context do "create table(:#{as_atom(table)}, primary_key: false, prefix: prefix()) do\n" <> Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <> "\nend" else {pre_create, opts} = - if schema do + if schema && repo.create_schemas_in_migrations?() do {"execute(\"CREATE SCHEMA IF NOT EXISTS #{schema}\")" <> "\n\n", ", prefix: \"#{schema}\""} else diff --git a/lib/repo.ex b/lib/repo.ex index eb1beebf..fb7cb7eb 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -78,6 +78,9 @@ defmodule AshPostgres.Repo do @doc "The default prefix(postgres schema) to use when building queries" @callback default_prefix() :: String.t() + @doc "Whether or not to create schemas for tables when generating migrations" + @callback create_schemas_in_migrations?() :: boolean() + @doc "Whether or not to explicitly start and close a transaction for each action, even if there are no transaction hooks. Defaults to `true`." @callback prefer_transaction?() :: boolean @@ -135,6 +138,7 @@ defmodule AshPostgres.Repo do def installed_extensions, do: [] def tenant_migrations_path, do: nil def migrations_path, do: nil + def create_schemas_in_migrations?, do: true def default_prefix, do: "public" def override_migration_type(type), do: type def create?, do: true @@ -304,6 +308,7 @@ defmodule AshPostgres.Repo do prefer_transaction?: 0, prefer_transaction_for_atomic_updates?: 0, tenant_migrations_path: 0, + create_schemas_in_migrations?: 0, migrations_path: 0, default_prefix: 0, override_migration_type: 1, From 1c29ac9e3484863e649cd475e6967a0b082f6289 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 9 Jun 2025 12:17:17 -0400 Subject: [PATCH 562/690] fix: use `force: true`, not `force?: true` calling mix.generator --- lib/migration_generator/migration_generator.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 129a7ddd..e00cd4f6 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -86,7 +86,7 @@ defmodule AshPostgres.MigrationGenerator do true -> Enum.each(files, fn {file, contents} -> - Mix.Generator.create_file(file, contents, force?: true) + Mix.Generator.create_file(file, contents, force: true) end) end end From f3465d2308d224f7d1b937c3298f12f43d576d0f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 9 Jun 2025 12:27:15 -0400 Subject: [PATCH 563/690] fix: reenable migrate task --- lib/data_layer.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 8196cbe7..10d1a17b 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -419,6 +419,7 @@ defmodule AshPostgres.DataLayer do ] def migrate(args) do + Mix.Task.reenable("ash_postgres.migrate") Mix.Task.run("ash_postgres.migrate", args) end From dc81e68f5fc03fb99f90f0c95d952fdcf8272090 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 9 Jun 2025 12:31:02 -0400 Subject: [PATCH 564/690] chore: release version v2.6.4 --- CHANGELOG.md | 19 +++++++++++++++++++ mix.exs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5f5faed..4b094699 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.4](https://github.com/ash-project/ash_postgres/compare/v2.6.3...v2.6.4) (2025-06-09) + + + + +### Bug Fixes: + +* reenable migrate task + +* use `force: true`, not `force?: true` calling mix.generator + +* casting integers to string in expressions works as intended (#564) + +* use better wrappers around string/ci_string + +### Improvements: + +* add `c:AshPostgres.Repo.create_schemas_in_migrations?` callback + ## [v2.6.3](https://github.com/ash-project/ash_postgres/compare/v2.6.2...v2.6.3) (2025-06-04) diff --git a/mix.exs b/mix.exs index e13172bb..ee671a1f 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.3" + @version "2.6.4" def project do [ From 2afe9640c289a78024a6948c0274a9d5fd95c2ec Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Jun 2025 09:18:04 -0400 Subject: [PATCH 565/690] fix: properly detect nested array decimals --- lib/migration_generator/migration_generator.ex | 4 ++-- test/migration_generator_test.exs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index e00cd4f6..ba9990ca 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3593,8 +3593,8 @@ defmodule AshPostgres.MigrationGenerator do ["decimal", precision, scale] end - defp sanitize_type(type, size, precision, decimal) when is_atom(type) and is_integer(size) do - [sanitize_type(type, nil, precision, decimal), size] + defp sanitize_type(type, size, precision, decimal) when is_tuple(type) do + sanitize_type(elem(type, 0), size, precision, decimal) end defp sanitize_type(type, _, _, _) do diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index afbd4ed8..bd8f2c92 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -2511,6 +2511,11 @@ defmodule AshPostgres.MigrationGeneratorTest do public?: true ) + attribute(:decimal_list, {:array, :decimal}, + default: [Decimal.new("123.4567890987654321987")], + public?: true + ) + attribute(:name, :string, default: "Fred", public?: true) attribute(:tag, :atom, default: :value, public?: true) attribute(:enabled, :boolean, default: false, public?: true) From e2c0621f2d06d4a63835935a9cedf35b7cfe424a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Jun 2025 11:20:28 -0400 Subject: [PATCH 566/690] fix: remove spurios debug logging --- lib/multitenancy.ex | 4 ---- test/dev_migrations_test.exs | 2 -- 2 files changed, 6 deletions(-) diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 30abecbd..6d70aa49 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -22,7 +22,6 @@ defmodule AshPostgres.MultiTenancy do repo.config(), prefix: tenant_name ) - |> tap(fn v -> Logger.warning(inspect(v, label: "ensure migraitons result")) end) [tenant_migrations_path, "**", "*.exs"] |> Path.join() @@ -42,7 +41,6 @@ defmodule AshPostgres.MultiTenancy do |> Enum.map(&extract_migration_info/1) |> Enum.filter(& &1) |> Enum.map(&load_migration!/1) - |> tap(fn v -> Logger.warning(inspect(v, label: "migrations")) end) |> Enum.each(fn {version, mod} -> Ecto.Migration.Runner.run( repo, @@ -55,10 +53,8 @@ defmodule AshPostgres.MultiTenancy do all: true, prefix: tenant_name ) - |> tap(fn v -> Logger.warning(inspect(v, label: "run result")) end) Ecto.Migration.SchemaMigration.up(repo, repo.config(), version, prefix: tenant_name) - |> tap(fn v -> Logger.warning(inspect(v, label: "schema run result")) end) end) end diff --git a/test/dev_migrations_test.exs b/test/dev_migrations_test.exs index 400bca14..fdaeeff9 100644 --- a/test/dev_migrations_test.exs +++ b/test/dev_migrations_test.exs @@ -224,7 +224,6 @@ defmodule AshPostgres.DevMigrationsTest do "priv/dev_test_repo/migrations", after_file ) - |> tap(fn v -> Logger.warning(inspect(v, label: "result")) end) end defp tenant_migrate do @@ -234,7 +233,6 @@ defmodule AshPostgres.DevMigrationsTest do AshPostgres.DevTestRepo, "priv/dev_test_repo/tenant_migrations" ) - |> tap(fn v -> Logger.warning(inspect(v, label: "result")) end) end end end From 17c66b9402a14e588eddd6ed3a8a72d7ab33fb90 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Jun 2025 11:20:38 -0400 Subject: [PATCH 567/690] chore: release version v2.6.5 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b094699..1d810f81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.5](https://github.com/ash-project/ash_postgres/compare/v2.6.4...v2.6.5) (2025-06-10) + + + + +### Bug Fixes: + +* remove spurios debug logging + +* properly detect nested array decimals + ## [v2.6.4](https://github.com/ash-project/ash_postgres/compare/v2.6.3...v2.6.4) (2025-06-09) diff --git a/mix.exs b/mix.exs index ee671a1f..d1548b95 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.4" + @version "2.6.5" def project do [ From 8d99e9aca932e4dd2cd6428f50d8a0063256ecab Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Jun 2025 19:22:16 -0400 Subject: [PATCH 568/690] fix: simply storage of size/scale/precision information --- .../migration_generator.ex | 109 +++++------------- 1 file changed, 31 insertions(+), 78 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index ba9990ca..a5984a67 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3199,25 +3199,7 @@ defmodule AshPostgres.MigrationGenerator do end {type, size, precision, scale} = - case type do - {:varchar, size} -> - {:varchar, size, nil, nil} - - {:binary, size} -> - {:binary, size, nil, nil} - - {:decimal, precision, scale} -> - {:decimal, nil, precision, scale} - - {:decimal, precision} -> - {:decimal, nil, precision, nil} - - {other, size} when is_atom(other) and is_integer(size) -> - {other, size, nil, nil} - - other -> - {other, nil, nil, nil} - end + migration_type_to_type(type) attribute |> Map.put(:default, default) @@ -3247,6 +3229,32 @@ defmodule AshPostgres.MigrationGenerator do end) end + defp migration_type_to_type(type) do + case type do + {:varchar, size} -> + {:varchar, size, nil, nil} + + {:binary, size} -> + {:binary, size, nil, nil} + + {:decimal, precision, scale} -> + {:decimal, nil, precision, scale} + + {:decimal, precision} -> + {:decimal, nil, precision, nil} + + {other, size} when is_atom(other) and is_integer(size) -> + {other, size, nil, nil} + + {:array, other} -> + {nested, size, precision, scale} = migration_type_to_type(other) + {{:array, nested}, size, precision, scale} + + other -> + {other, nil, nil, nil} + end + end + defp find_reference(resource, table, attribute) do resource |> Ash.Resource.Info.relationships() @@ -3581,22 +3589,6 @@ defmodule AshPostgres.MigrationGenerator do ["array", sanitize_type(type, size, scale, precision)] end - defp sanitize_type(:varchar, size, _scale, _precision) when not is_nil(size) do - ["varchar", size] - end - - defp sanitize_type(:binary, size, _scale, _precision) when not is_nil(size) do - ["binary", size] - end - - defp sanitize_type(:decimal, _size, scale, precision) do - ["decimal", precision, scale] - end - - defp sanitize_type(type, size, precision, decimal) when is_tuple(type) do - sanitize_type(elem(type, 0), size, precision, decimal) - end - defp sanitize_type(type, _, _, _) do type end @@ -3686,27 +3678,6 @@ defmodule AshPostgres.MigrationGenerator do defp load_attribute(attribute, table) do type = load_type(attribute.type) - {type, size, scale, precision} = - case type do - {:varchar, size} -> - {:varchar, size, nil, nil} - - {:binary, size} -> - {:binary, size, nil, nil} - - {other, size} when is_atom(other) and is_integer(size) -> - {other, size, nil, nil} - - {:decimal, precision} -> - {:decimal, nil, nil, precision} - - {:decimal, precision, scale} -> - {:decimal, nil, precision, scale} - - other -> - {other, nil, nil, nil} - end - attribute = if Map.has_key?(attribute, :name) do Map.put(attribute, :source, maybe_to_atom(attribute.name)) @@ -3716,9 +3687,9 @@ defmodule AshPostgres.MigrationGenerator do attribute |> Map.put(:type, type) - |> Map.put(:size, size) - |> Map.put(:precision, precision) - |> Map.put(:scale, scale) + |> Map.put_new(:size, nil) + |> Map.put_new(:precision, nil) + |> Map.put_new(:scale, nil) |> Map.put_new(:default, "nil") |> Map.update!(:default, &(&1 || "nil")) |> Map.update!(:references, fn @@ -3797,25 +3768,7 @@ defmodule AshPostgres.MigrationGenerator do {:array, load_type(type)} end - defp load_type(["varchar", size]) do - {:varchar, size} - end - - defp load_type(["binary", size]) do - {:binary, size} - end - - defp load_type(["decimal", precision]) do - {:decimal, precision} - end - - defp load_type(["decimal", precision, scale]) do - {:decimal, precision, scale} - end - - defp load_type([string, size]) when is_binary(string) and is_integer(size) do - {String.to_existing_atom(string), size} - end + defp load_type([type | _]), do: String.to_existing_atom(type) defp load_type(type) do maybe_to_atom(type) From c653161950948a7a39be8e699f72efefc99fdea9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 10 Jun 2025 19:22:22 -0400 Subject: [PATCH 569/690] chore: release version v2.6.6 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d810f81..cfda92aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.6](https://github.com/ash-project/ash_postgres/compare/v2.6.5...v2.6.6) (2025-06-10) + + + + +### Bug Fixes: + +* simply storage of size/scale/precision information + ## [v2.6.5](https://github.com/ash-project/ash_postgres/compare/v2.6.4...v2.6.5) (2025-06-10) diff --git a/mix.exs b/mix.exs index d1548b95..cf243ab3 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.5" + @version "2.6.6" def project do [ From a5b590b59d43be5cfc4394c9ad4349064792bbf6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:26:49 -0400 Subject: [PATCH 570/690] chore(deps): bump the production-dependencies group with 4 updates (#566) Bumps the production-dependencies group with 4 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql), [ecto](https://github.com/elixir-ecto/ecto) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.5.15 to 3.5.18 - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.5.15...v3.5.18) Updates `ash_sql` from 0.2.78 to 0.2.79 - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.78...v0.2.79) Updates `ecto` from 3.12.5 to 3.12.6 - [Release notes](https://github.com/elixir-ecto/ecto/releases) - [Changelog](https://github.com/elixir-ecto/ecto/blob/master/CHANGELOG.md) - [Commits](https://github.com/elixir-ecto/ecto/compare/v3.12.5...v3.12.6) Updates `igniter` from 0.6.6 to 0.6.7 - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.6.6...v0.6.7) --- updated-dependencies: - dependency-name: ash dependency-version: 3.5.18 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-version: 0.2.79 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ecto dependency-version: 3.12.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-version: 0.6.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 0fd35a2e..24d983d4 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.15", "418055e74c4d85d1f397577407aa71c29d44ef0b729be144e23e64630ad2eedc", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.61 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", "8ee885ccc6be65d1023cccbdfda6a534497cf5170d53b67c0b29db72c0c30b9b"}, - "ash_sql": {:hex, :ash_sql, "0.2.78", "130d54ca85b8fbd1e65f038beafb905ade1941d1f5e3aef1fec7f8bba7414fc2", [:mix], [{:ash, "~> 3.5", [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", "a640ec0ef176f3a0e95f88d8639d9d23479ca8a5f5e7e177af351f18cddf4f30"}, + "ash": {:hex, :ash, "3.5.18", "3fafe7b0c67fb863409ea06fd9ca0f1cb681b4e798973989aabedc42a82e8f2a", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "52e3156f832026aeef0ca4a705741d29d5a94a7a393ab280b694a2d3d43bcf12"}, + "ash_sql": {:hex, :ash_sql, "0.2.79", "1378bb33a7469f50e2854b7490add380ad2cbf73dda9d5b373194097ad03d3eb", [:mix], [{:ash, "~> 3.5", [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", "7ef10d909f238912b4be7aeb587ae32cce7e42d136bf94da07bc7e54a475cdde"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -9,7 +9,7 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, - "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, + "ecto": {:hex, :ecto, "3.12.6", "8bf762dc5b87d85b7aca7ad5fe31ef8142a84cea473a3381eb933bd925751300", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c0cba01795463eebbcd9e4b5ef53c1ee8e68b9c482baef2a80de5a61e7a57fe"}, "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.7.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.6", "82d707a2419a95e6ea115949c68a9113dfc0b4802d3d8386aa351feb0ead71ee", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "a85832987fc78f5fdc38f628a62acfd50b4e441166496fea15c7b05218fa84f5"}, + "igniter": {:hex, :igniter, "0.6.7", "4e183afc59d89289e223c4282fd3e9bb39b82e28d0aa6d3369f70fbd3e21a243", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "43b0a584dc84fd1320772c87047355b604ed2bcdd25392b17f7da8bdd09b61ac"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -44,7 +44,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.63", "bc771c3c1028136559507e235e721e730118ca316e22e75da347ae1c195b94a1", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "42708ab2884af6abc1aa33aa981a4f51f65146d7879651d1e6c11948a4d8fcfe"}, + "spark": {:hex, :spark, "2.2.65", "4c10d109c108417ce394158f330be09ef184878bde45de6462397fbda68cec29", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d66d5070a77f4c69cb4f007e941ac17d5d751ce71190fcd6e6e5fb42ba86f101"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 4a94b817ffc850421d485ff0e41b37b98e43abeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:27:03 -0400 Subject: [PATCH 571/690] chore(deps-dev): bump the dev-dependencies group with 2 updates (#567) Bumps the dev-dependencies group with 2 updates: [git_ops](https://github.com/zachdaniel/git_ops) and [mix_audit](https://github.com/mirego/mix_audit). Updates `git_ops` from 2.7.3 to 2.8.0 - [Changelog](https://github.com/zachdaniel/git_ops/blob/master/CHANGELOG.md) - [Commits](https://github.com/zachdaniel/git_ops/compare/v2.7.3...v2.8.0) Updates `mix_audit` from 2.1.4 to 2.1.5 - [Changelog](https://github.com/mirego/mix_audit/blob/main/CHANGELOG.md) - [Commits](https://github.com/mirego/mix_audit/compare/v2.1.4...v2.1.5) --- updated-dependencies: - dependency-name: git_ops dependency-version: 2.8.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: mix_audit dependency-version: 2.1.5 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 24d983d4..d7a02173 100644 --- a/mix.lock +++ b/mix.lock @@ -20,7 +20,7 @@ "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "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.3", "c993aedb11005752e321d482de6f2a46d0b5d5f09ce69961f31a856e76bf4f12", [: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", "c54ee65e12778be1f4dd6a0921e57ab2bddd35bd6130cbe274dcb1f0a21ca59d"}, + "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "igniter": {:hex, :igniter, "0.6.7", "4e183afc59d89289e223c4282fd3e9bb39b82e28d0aa6d3369f70fbd3e21a243", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "43b0a584dc84fd1320772c87047355b604ed2bcdd25392b17f7da8bdd09b61ac"}, @@ -32,7 +32,7 @@ "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, - "mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, + "mix_audit": {:hex, :mix_audit, "2.1.5", "c0f77cee6b4ef9d97e37772359a187a166c7a1e0e08b50edf5bf6959dfe5a016", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "87f9298e21da32f697af535475860dc1d3617a010e0b418d2ec6142bc8b42d69"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, From 61a075f46a96ddbf9d94137bbd20ffd5db7e6d11 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 12 Jun 2025 08:47:43 -0400 Subject: [PATCH 572/690] test: update tests --- .../test_repo/posts/20250612113920.json | 678 ++++++++++++++++++ .../20250612113920_migrate_resources55.exs | 21 + test/filter_test.exs | 15 + test/support/resources/post.ex | 1 - 4 files changed, 714 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/posts/20250612113920.json create mode 100644 priv/test_repo/migrations/20250612113920_migrate_resources55.exs diff --git a/priv/resource_snapshots/test_repo/posts/20250612113920.json b/priv/resource_snapshots/test_repo/posts/20250612113920.json new file mode 100644 index 00000000..4d585717 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250612113920.json @@ -0,0 +1,678 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "limited_score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "metadata", + "type": "map" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "string_point", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "person_detail", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "model", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "scale": null, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "scale": null, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "scale": null, + "size": null, + "source": "author_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "points" + }, + "scale": null, + "size": null, + "source": "db_point_id", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_string_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "string_points" + }, + "scale": null, + "size": null, + "source": "db_string_point_id", + "type": "text" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "90D4DD5BCCA4A66F2979715F980190DBC33A0A71C697943F2756B87302E0FE5A", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250612113920_migrate_resources55.exs b/priv/test_repo/migrations/20250612113920_migrate_resources55.exs new file mode 100644 index 00000000..082dad95 --- /dev/null +++ b/priv/test_repo/migrations/20250612113920_migrate_resources55.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources55 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + modify(:model, :map, null: true) + end + end + + def down do + alter table(:posts) do + modify(:model, :map, null: false) + end + end +end diff --git a/test/filter_test.exs b/test/filter_test.exs index 83bcbba0..261dd0bf 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -21,6 +21,21 @@ defmodule AshPostgres.FilterTest do end end + describe "type casting" do + test "it does not do unnecessary type casting" do + {query, vars} = + Post + |> Ash.Query.filter(version == ^10) + |> Ash.data_layer_query!() + |> Map.get(:query) + |> then(&AshPostgres.TestRepo.to_sql(:all, &1)) + + assert vars == ["sponsored", 10] + + assert String.contains?(query, "(p0.\"version\"::bigint = $2::bigint)") + end + end + describe "ci_string argument casting" do test "it properly casts" do Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 369283bc..a2c3ceea 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -551,7 +551,6 @@ defmodule AshPostgres.Test.Post do ] ) - allow_nil?(false) default(fn -> {3.0, 3.0, 1.0} end) end From fd2b80d3173e338662b3a2bfed91c3fb60a290ca Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 12 Jun 2025 08:47:54 -0400 Subject: [PATCH 573/690] chore: update bench --- benchmarks/bulk_create.exs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benchmarks/bulk_create.exs b/benchmarks/bulk_create.exs index 5d9ee395..99f235a1 100644 --- a/benchmarks/bulk_create.exs +++ b/benchmarks/bulk_create.exs @@ -1,5 +1,7 @@ alias AshPostgres.Test.{Domain, Post} +AshPostgres.TestRepo.start_link() + ten_rows = 1..10 |> Enum.map(fn i -> From aff1c410f51a12a5ea6e50a7be0e33dbc3658e89 Mon Sep 17 00:00:00 2001 From: Christian Alexander Date: Thu, 12 Jun 2025 08:09:14 -0700 Subject: [PATCH 574/690] docs: Fix mix task documentation typos (#568) --- lib/mix/tasks/ash_postgres.drop.ex | 2 +- lib/mix/tasks/ash_postgres.gen.resources.ex | 4 ++-- lib/mix/tasks/ash_postgres.generate_migrations.ex | 2 +- lib/mix/tasks/ash_postgres.migrate.ex | 4 ++-- lib/mix/tasks/ash_postgres.rollback.ex | 2 +- lib/mix/tasks/ash_postgres.squash_snapshots.ex | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.drop.ex b/lib/mix/tasks/ash_postgres.drop.ex index 43028c38..e54ffddb 100644 --- a/lib/mix/tasks/ash_postgres.drop.ex +++ b/lib/mix/tasks/ash_postgres.drop.ex @@ -39,7 +39,7 @@ defmodule Mix.Tasks.AshPostgres.Drop do * `--force-drop` - force the database to be dropped even if it has connections to it (requires PostgreSQL 13+) * `--no-compile` - do not compile before dropping - * `--no-deps-check` - do not compile before dropping + * `--no-deps-check` - do not check dependencies before dropping """ @doc false diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index 2196c2f0..a187f8d9 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -2,7 +2,7 @@ if Code.ensure_loaded?(Igniter) do defmodule Mix.Tasks.AshPostgres.Gen.Resources do use Igniter.Mix.Task - @example "mix ash_postgres.gen.resource MyApp.MyDomain" + @example "mix ash_postgres.gen.resources MyApp.MyDomain" @shortdoc "Generates resources based on a database schema" @@ -23,7 +23,7 @@ if Code.ensure_loaded?(Igniter) do - `repo`, `r` - The repo or repos to generate resources for, comma separated. Can be specified multiple times. Defaults to all repos. - `tables`, `t` - Defaults to `public.*`. The tables to generate resources for, comma separated. Can be specified multiple times. See the section on tables for more. - `skip-tables`, `s` - The tables to skip generating resources for, comma separated. Can be specified multiple times. See the section on tables for more. `schema_migrations` is always skipped. - - `snapshots-only` - Only generate snapshots for the generated resources, and not migraitons. + - `snapshots-only` - Only generate snapshots for the generated resources, and not migrations. - `extend`, `e` - Extension or extensions to apply to the generated resources. See `mix ash.patch.extend` for more. - `yes`, `y` - Answer yes (or skip) to all questions. - `default-actions` - Add default actions for each resource. Defaults to `true`. diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index 8431572c..028ac8bb 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -37,7 +37,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do Generally speaking, it is bad practice to drop columns when you deploy a change that would remove an attribute. The main reasons for this are backwards compatibility and rolling restarts. - If you deploy an attribute removal, and run migrations. Regardless of your deployment sstrategy, you + If you deploy an attribute removal, and run migrations. Regardless of your deployment strategy, you won't be able to roll back, because the data has been deleted. In a rolling restart situation, some of the machines/pods/whatever may still be running after the column has been deleted, causing errors. With this in mind, its best not to delete those columns until later, after the data has been confirmed unnecessary. diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index f8ab1d20..7da14a78 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -4,7 +4,7 @@ defmodule Mix.Tasks.AshPostgres.Migrate do import AshPostgres.Mix.Helpers, only: [migrations_path: 2, tenant_migrations_path: 2, tenants: 2] - @shortdoc "Runs the repository migrations for all repositories in the provided (or congigured) domains" + @shortdoc "Runs the repository migrations for all repositories in the provided (or configured) domains" @aliases [ n: :step, @@ -95,7 +95,7 @@ defmodule Mix.Tasks.AshPostgres.Migrate do * `--no-compile` - does not compile applications before migrating - * `--no-deps-check` - does not check depedendencies before migrating + * `--no-deps-check` - does not check dependencies before migrating * `--migrations-path` - the path to load the migrations from, defaults to `"priv/repo/migrations"`. This option may be given multiple times in which case the migrations diff --git a/lib/mix/tasks/ash_postgres.rollback.ex b/lib/mix/tasks/ash_postgres.rollback.ex index add81d59..d59fc1bf 100644 --- a/lib/mix/tasks/ash_postgres.rollback.ex +++ b/lib/mix/tasks/ash_postgres.rollback.ex @@ -30,7 +30,7 @@ defmodule Mix.Tasks.AshPostgres.Rollback do mix ash_postgres.rollback --to 20080906120000 ## Command line options - * `--domains` - the domains who's repos should be rolledback + * `--domains` - the domains whose repos should be rolled back * `--all` - revert all applied migrations * `--repo`, `-r` - the repo to rollback * `--step` / `-n` - revert n number of applied migrations diff --git a/lib/mix/tasks/ash_postgres.squash_snapshots.ex b/lib/mix/tasks/ash_postgres.squash_snapshots.ex index 1cf1fd68..84032c9b 100644 --- a/lib/mix/tasks/ash_postgres.squash_snapshots.ex +++ b/lib/mix/tasks/ash_postgres.squash_snapshots.ex @@ -28,7 +28,7 @@ defmodule Mix.Tasks.AshPostgres.SquashSnapshots do a remaining snapshot. `last` keeps the name of the last snapshot, `first` renames it to the previously first, `zero` sets name with fourteen zeros. * `--snapshot-path` - a custom path to stored snapshots. The default is "priv/resource_snapshots". - * `--quiet` - no messages will not be printed. + * `--quiet` - no messages will be printed. * `--dry-run` - no files are touched, instead prints folders that have snapshots to squash. * `--check` - no files are touched, instead returns an exit(1) code if there are snapshots to squash. """ From 25c924d43893c6a4ff78ed11dd281cc7054cb4b1 Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Fri, 13 Jun 2025 02:32:24 +0200 Subject: [PATCH 575/690] fix: double select error (#569) --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 10d1a17b..ffa72385 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3423,7 +3423,7 @@ defmodule AshPostgres.DataLayer do ) query_with_select = - from(sub in query, + from(sub in Ecto.Query.exclude(query, :select), join: row in ^query.__ash_bindings__.resource, # why doesn't `.root_binding` work the way I expect it to here? on: ^dynamic, From c3304a13f42a072e3afc126ada37c03009409f2c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 12 Jun 2025 20:33:06 -0400 Subject: [PATCH 576/690] chore: credo --- test/support/complex_calculations/resources/documentation.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/test/support/complex_calculations/resources/documentation.ex b/test/support/complex_calculations/resources/documentation.ex index df6c5415..405c9dae 100644 --- a/test/support/complex_calculations/resources/documentation.ex +++ b/test/support/complex_calculations/resources/documentation.ex @@ -61,6 +61,7 @@ defmodule AshPostgres.Test.ComplexCalculations.Documentation do end defmodule AshPostgres.Test.TimezoneHelper do + @moduledoc false def seoul_time do # Fixed datetime for testing - equivalent to 2024-05-01 21:00:00 in Seoul (UTC+9) ~U[2024-05-01 12:00:00Z] |> DateTime.shift_zone!("Asia/Seoul") From d2f5d17db06091e04980def178a55c75f53c4893 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 12 Jun 2025 20:34:02 -0400 Subject: [PATCH 577/690] chore: release version v2.6.7 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfda92aa..c9ac6016 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.7](https://github.com/ash-project/ash_postgres/compare/v2.6.6...v2.6.7) (2025-06-13) + + + + +### Bug Fixes: + +* double select error (#569) by Barnabas Jovanovics + ## [v2.6.6](https://github.com/ash-project/ash_postgres/compare/v2.6.5...v2.6.6) (2025-06-10) diff --git a/mix.exs b/mix.exs index cf243ab3..6f5a16cf 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.6" + @version "2.6.7" def project do [ From cb93a8f95be1bbf21b8fc23c5d44552b3521936f Mon Sep 17 00:00:00 2001 From: Rebecca Le <543859+sevenseacat@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:06:45 +0800 Subject: [PATCH 578/690] docs: Add minimum supported PostgreSQL version to README (#570) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 51f74e61..1bef9edc 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ Welcome! `AshPostgres` is the PostgreSQL data layer for [Ash Framework](https://hexdocs.pm/ash). +Minimum required PostgreSQL version: `13.0` + ## Tutorials - [Get Started](documentation/tutorials/get-started-with-ash-postgres.md) From f9d13294c29f786c95e7f55cfb627bad13deae3d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 17 Jun 2025 14:51:49 -0400 Subject: [PATCH 579/690] fix: ensure prefix is set even with create_schemas_in_migrations? false --- lib/migration_generator/phase.ex | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/migration_generator/phase.ex b/lib/migration_generator/phase.ex index 6be7dd81..a4e5861b 100644 --- a/lib/migration_generator/phase.ex +++ b/lib/migration_generator/phase.ex @@ -19,12 +19,18 @@ defmodule AshPostgres.MigrationGenerator.Phase do Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <> "\nend" else - {pre_create, opts} = + pre_create = if schema && repo.create_schemas_in_migrations?() do - {"execute(\"CREATE SCHEMA IF NOT EXISTS #{schema}\")" <> "\n\n", - ", prefix: \"#{schema}\""} + "execute(\"CREATE SCHEMA IF NOT EXISTS #{schema}\")" <> "\n\n" else - {"", ""} + "" + end + + opts = + if schema do + ", prefix: \"#{schema}\"" + else + "" end pre_create <> From 46f325e6e2902fcb3a7737f79d16568aaacba2e5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 17 Jun 2025 15:02:32 -0400 Subject: [PATCH 580/690] chore: update deps --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index d7a02173..69d19586 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.18", "3fafe7b0c67fb863409ea06fd9ca0f1cb681b4e798973989aabedc42a82e8f2a", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "52e3156f832026aeef0ca4a705741d29d5a94a7a393ab280b694a2d3d43bcf12"}, - "ash_sql": {:hex, :ash_sql, "0.2.79", "1378bb33a7469f50e2854b7490add380ad2cbf73dda9d5b373194097ad03d3eb", [:mix], [{:ash, "~> 3.5", [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", "7ef10d909f238912b4be7aeb587ae32cce7e42d136bf94da07bc7e54a475cdde"}, + "ash": {:hex, :ash, "3.5.21", "389303c193962d67fd59da18a3557f5015fdfdaeddaa77150db539bc7203d1a1", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "cb90005d1972e22d0d2ae514394e43e0d67cce18c4485595aa3d3e4bbf25260f"}, + "ash_sql": {:hex, :ash_sql, "0.2.81", "cdc7767400425bb11928ba76e0cdc66a82ff9eabea59af21eb474a60732815ce", [:mix], [{:ash, "~> 3.5", [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", "c2ccef696620852c93cc3fb3bc564200b910a3487266f54b51c444a7e5dfa3d0"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From db2d60d8c2196545680724d5190d6ff587d7f68a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 17 Jun 2025 21:34:41 -0400 Subject: [PATCH 581/690] test: add tests for new boolean expressions --- .../test_repo/posts/20250618011917.json | 690 ++++++++++++++++++ .../20250618011917_migrate_resources56.exs | 21 + test/filter_test.exs | 33 + test/support/resources/post.ex | 1 + 4 files changed, 745 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/posts/20250618011917.json create mode 100644 priv/test_repo/migrations/20250618011917_migrate_resources56.exs diff --git a/priv/resource_snapshots/test_repo/posts/20250618011917.json b/priv/resource_snapshots/test_repo/posts/20250618011917.json new file mode 100644 index 00000000..5031b3cf --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250618011917.json @@ -0,0 +1,690 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "1", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "version", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "title_column", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "not_selected_by_default", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "datetime", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "limited_score", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "public", + "type": "boolean" + }, + { + "allow_nil?": false, + "default": "true", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "is_special", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "category", + "type": "citext" + }, + { + "allow_nil?": true, + "default": "\"sponsored\"", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "price", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "\"0\"", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "decimal", + "type": "decimal" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "status", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "status_enum", + "type": "status" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "metadata", + "type": "map" + }, + { + "allow_nil?": false, + "default": "2", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "constrained_int", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "point", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "composite_point", + "type": "custom_point" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "string_point", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "person_detail", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "stuff", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "list_of_stuff", + "type": [ + "array", + "map" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_custom_one", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_custom_two", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_on_upper", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uniq_if_contains_foo", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "model", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "list_containing_nils", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "ltree_unescaped", + "type": "ltree" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "ltree_escaped", + "type": "ltree" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "created_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "updated_at", + "type": "timestamptz(6)" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_organization_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "orgs" + }, + "scale": null, + "size": null, + "source": "organization_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_parent_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "scale": null, + "size": null, + "source": "parent_post_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_author_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "authors" + }, + "scale": null, + "size": null, + "source": "author_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "points" + }, + "scale": null, + "size": null, + "source": "db_point_id", + "type": [ + "array", + "float" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "posts_db_string_point_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "string_points" + }, + "scale": null, + "size": null, + "source": "db_string_point_id", + "type": "text" + } + ], + "base_filter": "type = 'sponsored'", + "check_constraints": [ + { + "attribute": [ + "price" + ], + "base_filter": "type = 'sponsored'", + "check": "price > 0", + "name": "price_must_be_positive" + } + ], + "custom_indexes": [ + { + "all_tenants?": false, + "concurrently": true, + "error_fields": [ + "uniq_custom_one", + "uniq_custom_two" + ], + "fields": [ + { + "type": "atom", + "value": "uniq_custom_one" + }, + { + "type": "atom", + "value": "uniq_custom_two" + } + ], + "include": null, + "message": "dude what the heck", + "name": null, + "nulls_distinct": true, + "prefix": null, + "table": null, + "unique": true, + "using": null, + "where": null + } + ], + "custom_statements": [], + "has_create_action": true, + "hash": "28B63D8AA18EE499B2A10DFF793995FF00B811F6CB45E01EBFEF15516D305DF8", + "identities": [ + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_if_contains_foo_index", + "keys": [ + { + "type": "atom", + "value": "uniq_if_contains_foo" + } + ], + "name": "uniq_if_contains_foo", + "nils_distinct?": true, + "where": "(uniq_if_contains_foo LIKE '%foo%')" + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_on_upper_index", + "keys": [ + { + "type": "string", + "value": "(UPPER(uniq_on_upper))" + } + ], + "name": "uniq_on_upper", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": "type = 'sponsored'", + "index_name": "posts_uniq_one_and_two_index", + "keys": [ + { + "type": "atom", + "value": "uniq_one" + }, + { + "type": "atom", + "value": "uniq_two" + } + ], + "name": "uniq_one_and_two", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "posts" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250618011917_migrate_resources56.exs b/priv/test_repo/migrations/20250618011917_migrate_resources56.exs new file mode 100644 index 00000000..641aa008 --- /dev/null +++ b/priv/test_repo/migrations/20250618011917_migrate_resources56.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources56 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:posts) do + add(:is_special, :boolean, null: false, default: true) + end + end + + def down do + alter table(:posts) do + remove(:is_special) + end + end +end diff --git a/test/filter_test.exs b/test/filter_test.exs index 261dd0bf..d0332301 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -34,6 +34,39 @@ defmodule AshPostgres.FilterTest do assert String.contains?(query, "(p0.\"version\"::bigint = $2::bigint)") end + + test "it uses coalesce to optimize the || operator for non-booleans" do + {query, _vars} = + Post + |> Ash.Query.filter((version || 10) == 20) + |> Ash.data_layer_query!() + |> Map.get(:query) + |> then(&AshPostgres.TestRepo.to_sql(:all, &1)) + + assert String.contains?(query, "(coalesce(p0.\"version\"::bigint, $2::bigint)") + end + + test "it uses OR to optimize the || operator for booleans" do + {query, _vars} = + Post + |> Ash.Query.filter(is_special || true) + |> Ash.data_layer_query!() + |> Map.get(:query) + |> then(&AshPostgres.TestRepo.to_sql(:all, &1)) + + assert String.contains?(query, "(p0.\"is_special\"::boolean OR $2::boolean)") + end + + test "it uses AND to optimize the && operator for booleans" do + {query, _vars} = + Post + |> Ash.Query.filter(is_special && public) + |> Ash.data_layer_query!() + |> Map.get(:query) + |> then(&AshPostgres.TestRepo.to_sql(:all, &1)) + + assert String.contains?(query, "(p0.\"is_special\"::boolean AND p0.\"public\"::boolean)") + end end describe "ci_string argument casting" do diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index a2c3ceea..f22d3fef 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -509,6 +509,7 @@ defmodule AshPostgres.Test.Post do attribute(:limited_score, :integer, public?: true, constraints: [min: 0, max: 100]) attribute(:public, :boolean, public?: true) + attribute(:is_special, :boolean, public?: true, allow_nil?: false, default: true) attribute(:category, CiCategory, public?: true) attribute(:type, :atom, default: :sponsored, writable?: false, public?: false) attribute(:price, :integer, public?: true) From 0994310ef1c608d9609509e9d36948ca801ddc56 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 18 Jun 2025 14:32:29 -0400 Subject: [PATCH 582/690] chore: more literal -> identifier --- documentation/topics/advanced/manual-relationships.md | 2 +- lib/data_layer.ex | 6 +++--- lib/sql_implementation.ex | 2 +- mix.exs | 4 ++-- mix.lock | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/documentation/topics/advanced/manual-relationships.md b/documentation/topics/advanced/manual-relationships.md index 2da54328..a7adaac3 100644 --- a/documentation/topics/advanced/manual-relationships.md +++ b/documentation/topics/advanced/manual-relationships.md @@ -240,7 +240,7 @@ defmodule MyApp.Employee.ManagedEmployees do employee_keys = Employee.__schema__(:fields) cte_name_ref = - from(cte in fragment("?", literal(^cte_name)), select: map(cte, ^employee_keys)) + from(cte in fragment("?", identifier(^cte_name)), select: map(cte, ^employee_keys)) recursion_query = query diff --git a/lib/data_layer.ex b/lib/data_layer.ex index ffa72385..ddfdc060 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2109,7 +2109,7 @@ defmodule AshPostgres.DataLayer do |> Enum.map(fn upsert_field -> # for safety, we check once more at the end that all values in # upsert_fields are names of attributes. This is because - # below we use `literal/1` to bring them into the query + # below we use `identifier/1` to bring them into the query if is_nil(resource.__schema__(:type, upsert_field)) do raise "Only attribute names can be used in upsert_fields" end @@ -2122,7 +2122,7 @@ defmodule AshPostgres.DataLayer do [], fragment( "COALESCE(EXCLUDED.?, ?)", - literal(^to_string(get_source_for_upsert_field(upsert_field, resource))), + identifier(^to_string(get_source_for_upsert_field(upsert_field, resource))), ^default ) )} @@ -2136,7 +2136,7 @@ defmodule AshPostgres.DataLayer do [], fragment( "EXCLUDED.?", - literal(^to_string(get_source_for_upsert_field(upsert_field, resource))) + identifier(^to_string(get_source_for_upsert_field(upsert_field, resource))) ) )} end diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index a91b8786..99d80f8f 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -56,7 +56,7 @@ defmodule AshPostgres.SqlImplementation do [], fragment( "EXCLUDED.?", - literal( + identifier( ^to_string( AshPostgres.DataLayer.get_source_for_upsert_field( attribute, diff --git a/mix.exs b/mix.exs index 6f5a16cf..a4db2bc6 100644 --- a/mix.exs +++ b/mix.exs @@ -169,8 +169,8 @@ defmodule AshPostgres.MixProject do {:ash, ash_version("~> 3.5 and >= 3.5.13")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, {:igniter, "~> 0.6", optional: true}, - {:ecto_sql, "~> 3.12"}, - {:ecto, "~> 3.12 and >= 3.12.1"}, + {:ecto_sql, "~> 3.13"}, + {:ecto, "~> 3.13"}, {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, # dev/test dependencies diff --git a/mix.lock b/mix.lock index 69d19586..693c305b 100644 --- a/mix.lock +++ b/mix.lock @@ -9,9 +9,9 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, - "ecto": {:hex, :ecto, "3.12.6", "8bf762dc5b87d85b7aca7ad5fe31ef8142a84cea473a3381eb933bd925751300", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c0cba01795463eebbcd9e4b5ef53c1ee8e68b9c482baef2a80de5a61e7a57fe"}, + "ecto": {:hex, :ecto, "3.13.0", "7528ef4f3a4cdcfebeb7eb6545806c8109529b385a69f701fc3d77b5b8bde6e7", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "061f095f1cc097f71f743b500affc792d6869df22b1946a73ab5495eb9b4a280"}, "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, - "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, + "ecto_sql": {:hex, :ecto_sql, "3.13.0", "a732428f38ce86612a2c34a1ea5d0a9642a5a71f044052007fd2f2e815707990", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5ce13085122a0871d93ea9ba1a886447d89c07f3b563e19e0b3dcdf201ed9fe9"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, From ebc3101400e764f1b83c0020c9615a0264de365c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 18 Jun 2025 19:49:53 -0400 Subject: [PATCH 583/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 693c305b..6b5900db 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.21", "389303c193962d67fd59da18a3557f5015fdfdaeddaa77150db539bc7203d1a1", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "cb90005d1972e22d0d2ae514394e43e0d67cce18c4485595aa3d3e4bbf25260f"}, - "ash_sql": {:hex, :ash_sql, "0.2.81", "cdc7767400425bb11928ba76e0cdc66a82ff9eabea59af21eb474a60732815ce", [:mix], [{:ash, "~> 3.5", [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", "c2ccef696620852c93cc3fb3bc564200b910a3487266f54b51c444a7e5dfa3d0"}, + "ash_sql": {:hex, :ash_sql, "0.2.82", "a4fe01ccd2c29ce43af50233e63cd1298735b68ee2c22a1cbb0baa5f31f78ab5", [:mix], [{:ash, "~> 3.5", [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", "a31f1065b72387b7a19d4e357f06904910b4c4fc8986209975786015f40cf795"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -38,13 +38,13 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.15.4", "ef0c56a901c132529a14ab59fed0ccb4fcecb24308fb189a94c908255d4fdafc", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "783bf62fd0c72ded033afabdb8b6190b7048769771a2a97256e6f0bf4fb0a891"}, + "reactor": {:hex, :reactor, "0.15.5", "341d9ee664d6141df6639f227692ee6adc8a493d04232dee79e8a4a88e6cef8a", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "f9f440ecbdb0c41a832902a692608bd24be621fa7a602819d0dd12971d69f9aa"}, "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.65", "4c10d109c108417ce394158f330be09ef184878bde45de6462397fbda68cec29", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d66d5070a77f4c69cb4f007e941ac17d5d751ce71190fcd6e6e5fb42ba86f101"}, + "spark": {:hex, :spark, "2.2.66", "b7b47e76961c747f6128ad092c2109dbf742342dec533d3002c35207cb5f6b8e", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "8f0b79839033ab816c2ae37aea29ded83e245a74240e2c931e2396531a9760d6"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From abaa6e71ef364e7562e8460ca929d3618a7887ac Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 18 Jun 2025 19:50:31 -0400 Subject: [PATCH 584/690] chore: release version v2.6.8 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9ac6016..4600e4e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.8](https://github.com/ash-project/ash_postgres/compare/v2.6.7...v2.6.8) (2025-06-18) + + + + +### Bug Fixes: + +* ensure prefix is set even with create_schemas_in_migrations? false by Zach Daniel + ## [v2.6.7](https://github.com/ash-project/ash_postgres/compare/v2.6.6...v2.6.7) (2025-06-13) diff --git a/mix.exs b/mix.exs index a4db2bc6..af70fd8a 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.7" + @version "2.6.8" def project do [ From adf7a0420d7aef3fb60bc46dfe8955eec20d969a Mon Sep 17 00:00:00 2001 From: Oliver Severin Mulelid-Tynes Date: Thu, 19 Jun 2025 18:42:59 +0200 Subject: [PATCH 585/690] fix: Fix foreign key constraint on specially named references (#572) --- lib/data_layer.ex | 9 ++++++++- test/references_test.exs | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index ddfdc060..22efd25e 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2682,8 +2682,15 @@ defmodule AshPostgres.DataLayer do resource |> Ash.Resource.Info.relationships() |> Enum.reduce(changeset, fn relationship, changeset -> + # Check if there's a custom reference name defined in the DSL name = - "#{AshPostgres.DataLayer.Info.table(resource)}_#{relationship.source_attribute}_fkey" + case AshPostgres.DataLayer.Info.reference(resource, relationship.name) do + %{name: custom_name} when not is_nil(custom_name) -> + custom_name + + _ -> + "#{AshPostgres.DataLayer.Info.table(resource)}_#{relationship.source_attribute}_fkey" + end case repo.default_constraint_match_type(:foreign, name) do {:regex, regex} -> diff --git a/test/references_test.exs b/test/references_test.exs index afb89acd..626a2d97 100644 --- a/test/references_test.exs +++ b/test/references_test.exs @@ -105,4 +105,27 @@ defmodule AshPostgres.ReferencesTest do end end end + + test "named reference results in properly applied foreign_key_constraint/3 on the underlying changeset" do + # Create a comment with an invalid post_id + assert {:error, %Ash.Error.Invalid{errors: errors}} = + AshPostgres.Test.Comment + |> Ash.Changeset.for_create(:create, %{ + title: "Test Comment", + # This post doesn't exist + post_id: Ash.UUID.generate() + }) + |> Ash.create() + + assert [ + %Ash.Error.Changes.InvalidAttribute{ + field: :post_id, + message: "does not exist", + private_vars: private_vars + } + ] = errors + + assert Keyword.get(private_vars, :constraint) == "special_name_fkey" + assert Keyword.get(private_vars, :constraint_type) == :foreign_key + end end From 919b9dfbbdfc0b89b776a527af986a9d604622cd Mon Sep 17 00:00:00 2001 From: Marc Planelles Date: Sat, 21 Jun 2025 23:42:24 +0200 Subject: [PATCH 586/690] fix: smallserial not mapping to proper type (#574) --- lib/resource_generator/spec.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 38eebac5..ff942f16 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -958,7 +958,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do defp type("numeric"), do: {:ok, :decimal} defp type("decimal"), do: {:ok, :decimal} defp type("smallint"), do: {:ok, :integer} - defp type("smallserial"), do: {:ok, :ineger} + defp type("smallserial"), do: {:ok, :integer} defp type("serial"), do: {:ok, :integer} defp type("text"), do: {:ok, :string} defp type("time"), do: {:ok, :time} From d6c35209fb124d4b5c605135262780acd7dd9eb6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 22 Jun 2025 16:44:38 -0400 Subject: [PATCH 587/690] test: add tests for calculation typing --- test/calculation_test.exs | 11 +++++++++++ test/support/resources/post.ex | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 6aa911fe..287ccf9a 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1034,4 +1034,15 @@ defmodule AshPostgres.CalculationTest do assert full_name == "name" end + + test "calculation with fragment and cond returning integer doesn't cause Postgrex encoding error" do + Post + |> Ash.Changeset.for_create(:create, %{title: "hello ash lovers"}) + |> Ash.create!() + + assert [%Post{}] = + Post + |> Ash.Query.sort("posts_with_matching_title.relevance_score") + |> Ash.read!() + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index f22d3fef..85cd60bb 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -788,6 +788,24 @@ defmodule AshPostgres.Test.Post do end calculations do + calculate :relevance_score, + :integer, + expr( + cond do + fragment( + "ts_rank_cd(to_tsvector(?), ?, 32)::float", + ^ref(:title), + fragment("to_tsquery(?)", ^arg(:query)) + ) > 0.6 -> + 1 + + true -> + 2 + end + ) do + argument(:query, :string) + end + calculate(:upper_thing, :string, expr(fragment("UPPER(?)", uniq_on_upper))) calculate(:upper_title, :string, expr(fragment("UPPER(?)", title))) From 2ff3cb2f44486b07a12ca28bbbe76a1542cc30d6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 24 Jun 2025 23:54:12 -0400 Subject: [PATCH 588/690] chore: credo --- mix.lock | 12 ++++++------ test/support/resources/post.ex | 18 ++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/mix.lock b/mix.lock index 6b5900db..601ad73d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,17 +1,17 @@ %{ - "ash": {:hex, :ash, "3.5.21", "389303c193962d67fd59da18a3557f5015fdfdaeddaa77150db539bc7203d1a1", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "cb90005d1972e22d0d2ae514394e43e0d67cce18c4485595aa3d3e4bbf25260f"}, + "ash": {:hex, :ash, "3.5.23", "e3c4e508569850fc276780f4ac94bee4c5f2d8e259ec2157c71e8e286db1c3ce", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "dd491cae52fa73b150e2c3b095ec3ae3aef681666503c300cee60c886d94ebfd"}, "ash_sql": {:hex, :ash_sql, "0.2.82", "a4fe01ccd2c29ce43af50233e63cd1298735b68ee2c22a1cbb0baa5f31f78ab5", [:mix], [{:ash, "~> 3.5", [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", "a31f1065b72387b7a19d4e357f06904910b4c4fc8986209975786015f40cf795"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, - "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, + "db_connection": {:hex, :db_connection, "2.8.0", "64fd82cfa6d8e25ec6660cea73e92a4cbc6a18b31343910427b702838c4b33b2", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "008399dae5eee1bf5caa6e86d204dcb44242c82b1ed5e22c881f2c34da201b15"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, - "ecto": {:hex, :ecto, "3.13.0", "7528ef4f3a4cdcfebeb7eb6545806c8109529b385a69f701fc3d77b5b8bde6e7", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "061f095f1cc097f71f743b500affc792d6869df22b1946a73ab5495eb9b4a280"}, + "ecto": {:hex, :ecto, "3.13.2", "7d0c0863f3fc8d71d17fc3ad3b9424beae13f02712ad84191a826c7169484f01", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "669d9291370513ff56e7b7e7081b7af3283d02e046cf3d403053c557894a0b3e"}, "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, - "ecto_sql": {:hex, :ecto_sql, "3.13.0", "a732428f38ce86612a2c34a1ea5d0a9642a5a71f044052007fd2f2e815707990", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5ce13085122a0871d93ea9ba1a886447d89c07f3b563e19e0b3dcdf201ed9fe9"}, + "ecto_sql": {:hex, :ecto_sql, "3.13.2", "a07d2461d84107b3d037097c822ffdd36ed69d1cf7c0f70e12a3d1decf04e2e1", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "539274ab0ecf1a0078a6a72ef3465629e4d6018a3028095dc90f60a19c371717"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.7", "4e183afc59d89289e223c4282fd3e9bb39b82e28d0aa6d3369f70fbd3e21a243", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "43b0a584dc84fd1320772c87047355b604ed2bcdd25392b17f7da8bdd09b61ac"}, + "igniter": {:hex, :igniter, "0.6.8", "f058e7e5e3e69af9c795cc3022a92f802c8e2e1fd366579f6b60af328f69e2bb", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "b0d9cf65a64ec984417c2eec1fcbbb059faba6eb64fcce3abdae00e0f6d36a33"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -39,7 +39,7 @@ "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, "reactor": {:hex, :reactor, "0.15.5", "341d9ee664d6141df6639f227692ee6adc8a493d04232dee79e8a4a88e6cef8a", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "f9f440ecbdb0c41a832902a692608bd24be621fa7a602819d0dd12971d69f9aa"}, - "req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"}, + "req": {:hex, :req, "0.5.12", "7ce85835867a114c28b6cfc2d8a412f86660290907315ceb173a00e587b853d2", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d65f3d0e7032eb245706554cb5240dbe7a07493154e2dd34e7bb65001aa6ef32"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 85cd60bb..5ff80458 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -791,16 +791,14 @@ defmodule AshPostgres.Test.Post do calculate :relevance_score, :integer, expr( - cond do - fragment( - "ts_rank_cd(to_tsvector(?), ?, 32)::float", - ^ref(:title), - fragment("to_tsquery(?)", ^arg(:query)) - ) > 0.6 -> - 1 - - true -> - 2 + if fragment( + "ts_rank_cd(to_tsvector(?), ?, 32)::float", + ^ref(:title), + fragment("to_tsquery(?)", ^arg(:query)) + ) > 0.6 do + 1 + else + 2 end ) do argument(:query, :string) From 50fc2ba3ed340f072364078f930358a99beca61a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 24 Jun 2025 23:57:05 -0400 Subject: [PATCH 589/690] chore: update deps --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 601ad73d..b802109e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.23", "e3c4e508569850fc276780f4ac94bee4c5f2d8e259ec2157c71e8e286db1c3ce", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "dd491cae52fa73b150e2c3b095ec3ae3aef681666503c300cee60c886d94ebfd"}, - "ash_sql": {:hex, :ash_sql, "0.2.82", "a4fe01ccd2c29ce43af50233e63cd1298735b68ee2c22a1cbb0baa5f31f78ab5", [:mix], [{:ash, "~> 3.5", [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", "a31f1065b72387b7a19d4e357f06904910b4c4fc8986209975786015f40cf795"}, + "ash": {:hex, :ash, "3.5.24", "47bffb562c39482315d245ce22a381768b1bc16628ba974195630f3ca87d6218", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "881e0decc5e75a0109ca545472b5c6ecb3b28893fec9eaf1866b8c35ddf78c16"}, + "ash_sql": {:hex, :ash_sql, "0.2.83", "de8a9776186d1d1df54e265c1cf0c4e61c1d72be1297c9538f1a32eb9b84de55", [:mix], [{:ash, "~> 3.5", [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", "5c99192814177d589d2ba518968b97d1ec7af12446631e3e5538f7a617d7d289"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.8", "f058e7e5e3e69af9c795cc3022a92f802c8e2e1fd366579f6b60af328f69e2bb", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "b0d9cf65a64ec984417c2eec1fcbbb059faba6eb64fcce3abdae00e0f6d36a33"}, + "igniter": {:hex, :igniter, "0.6.9", "99dd9ea7bcf2fe829617dac660069b3461183e4efbf303dd120fdef96923287d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "5fe407e10bc9416f7cd6af90d0409c8226ff2acacb9a7e7b9a097a66c8b5caef"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -44,7 +44,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.66", "b7b47e76961c747f6128ad092c2109dbf742342dec533d3002c35207cb5f6b8e", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "8f0b79839033ab816c2ae37aea29ded83e245a74240e2c931e2396531a9760d6"}, + "spark": {:hex, :spark, "2.2.67", "67626cb9f59ea4b1c5aa85d4afdd025e0740cbd49ed82665d0a40ff007d7fd4b", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "c8575402e3afc66871362e821bece890536d16319cdb758c5fb2d1250182e46f"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, From 844f7ba6a40f9c3b52b93c8168b14eca95817559 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 24 Jun 2025 23:58:07 -0400 Subject: [PATCH 590/690] chore: release version v2.6.9 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4600e4e0..5cf99e8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.9](https://github.com/ash-project/ash_postgres/compare/v2.6.8...v2.6.9) (2025-06-25) + + + + +### Bug Fixes: + +* smallserial not mapping to proper type (#574) by Marc Planelles + +* Fix foreign key constraint on specially named references (#572) by olivermt + ## [v2.6.8](https://github.com/ash-project/ash_postgres/compare/v2.6.7...v2.6.8) (2025-06-18) diff --git a/mix.exs b/mix.exs index af70fd8a..4c59bea1 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.8" + @version "2.6.9" def project do [ From 83abe4fcdabf451a36db09d6ca26820996075536 Mon Sep 17 00:00:00 2001 From: Frank Dugan III Date: Sun, 29 Jun 2025 14:33:06 -0500 Subject: [PATCH 591/690] refactor: use multiline string templates to preserve escapes in checks (#578) --- lib/migration_generator/operation.ex | 28 ++++++++++++++++++++---- test/migration_generator_test.exs | 32 ++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 5c8bfbc0..3b266494 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1351,10 +1351,20 @@ defmodule AshPostgres.MigrationGenerator.Operation do }, table: table }) do + prefix = if schema, do: ", " <> option(:prefix, schema), else: "" + if base_filter do - "create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"(#{check}) OR NOT (#{base_filter})\")", option(:prefix, schema)])}" + ~s''' + create constraint(:#{as_atom(table)}, :#{as_atom(name)}, check: """ + (#{check}) OR NOT (#{base_filter}) + """#{prefix}) + ''' else - "create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{check}\")", option(:prefix, schema)])}" + ~s''' + create constraint(:#{as_atom(table)}, :#{as_atom(name)}, check: """ + #{check} + """#{prefix}) + ''' end end @@ -1386,10 +1396,20 @@ defmodule AshPostgres.MigrationGenerator.Operation do schema: schema, table: table }) do + prefix = if schema, do: ", " <> option(:prefix, schema), else: "" + if base_filter do - "create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{base_filter} AND #{check}\")", option(:prefix, schema)])}" + ~s''' + create constraint(:#{as_atom(table)}, :#{as_atom(name)}, check: """ + #{base_filter} AND #{check} + """#{prefix}) + ''' else - "create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{check}\")", option(:prefix, schema)])}" + ~s''' + create constraint(:#{as_atom(table)}, :#{as_atom(name)}, check: """ + #{check} + """#{prefix}) + ''' end end end diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index bd8f2c92..e284e847 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -2240,11 +2240,16 @@ defmodule AshPostgres.MigrationGeneratorTest do attributes do uuid_primary_key(:id) attribute(:price, :integer, public?: true) + attribute(:title, :string, public?: true) end postgres do check_constraints do - check_constraint(:price, "price_must_be_positive", check: "price > 0") + check_constraint(:price, "price_must_be_positive", check: ~S["price" > 0]) + + check_constraint(:title, "title_must_conform_to_format", + check: ~S[title ~= '("\"\\"\\\"\\\\"\\\\\")'] + ) end end end @@ -2268,7 +2273,18 @@ defmodule AshPostgres.MigrationGeneratorTest do |> File.read!() assert file =~ - ~S[create constraint(:posts, :price_must_be_positive, check: "price > 0")] + ~S''' + create constraint(:posts, :price_must_be_positive, check: """ + "price" > 0 + """) + ''' + + assert file =~ + ~S''' + create constraint(:posts, :title_must_conform_to_format, check: """ + title ~= '("\"\\"\\\"\\\\"\\\\\")' + """) + ''' defposts do attributes do @@ -2307,7 +2323,11 @@ defmodule AshPostgres.MigrationGeneratorTest do String.split(down, "drop_if_exists constraint(:posts, :price_must_be_positive)") assert remaining =~ - ~S[create constraint(:posts, :price_must_be_positive, check: "price > 0")] + ~S''' + create constraint(:posts, :price_must_be_positive, check: """ + "price" > 0 + """) + ''' end test "base filters are taken into account, negated" do @@ -2349,7 +2369,11 @@ defmodule AshPostgres.MigrationGeneratorTest do |> File.read!() assert file =~ - ~S[create constraint(:posts, :price_must_be_positive, check: "(price > 0) OR NOT (price > -10)")] + ~S''' + create constraint(:posts, :price_must_be_positive, check: """ + (price > 0) OR NOT (price > -10) + """) + ''' end test "when removed, the constraint is dropped before modification" do From 70189697ee962bb1e366a14a4c0bb665e4ae5f6f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 2 Jul 2025 10:12:51 -0400 Subject: [PATCH 592/690] test: fix test case to be transactional --- test/references_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/references_test.exs b/test/references_test.exs index 626a2d97..a8be1d07 100644 --- a/test/references_test.exs +++ b/test/references_test.exs @@ -1,5 +1,5 @@ defmodule AshPostgres.ReferencesTest do - use ExUnit.Case + use AshPostgres.RepoCase test "can't use match_type != :full when referencing an non-primary key index" do Code.compiler_options(ignore_module_conflict: true) From b175eb4785ee65978a22afe72cbe10a623cd971b Mon Sep 17 00:00:00 2001 From: kernel-io Date: Thu, 3 Jul 2025 23:42:55 +1200 Subject: [PATCH 593/690] test: failing test for parent ref / policy thing (#580) * failing test Signed-off-by: kernel-io * cleaned up and added another failing test Signed-off-by: kernel-io * updated tests Signed-off-by: kernel-io --------- Signed-off-by: kernel-io --- mix.lock | 10 ++++---- test/parent_filter_test.exs | 47 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 15 +++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 test/parent_filter_test.exs diff --git a/mix.lock b/mix.lock index b802109e..7f05569e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.24", "47bffb562c39482315d245ce22a381768b1bc16628ba974195630f3ca87d6218", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "881e0decc5e75a0109ca545472b5c6ecb3b28893fec9eaf1866b8c35ddf78c16"}, - "ash_sql": {:hex, :ash_sql, "0.2.83", "de8a9776186d1d1df54e265c1cf0c4e61c1d72be1297c9538f1a32eb9b84de55", [:mix], [{:ash, "~> 3.5", [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", "5c99192814177d589d2ba518968b97d1ec7af12446631e3e5538f7a617d7d289"}, + "ash": {:hex, :ash, "3.5.25", "99f7139e98b745a64312ae80e2420589205b2fec1799f00fc58da771d2c63373", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "d45844ea30062b796d4adcad75b8d91e21081ac0f1bb6627d1a2663ca5ecf258"}, + "ash_sql": {:hex, :ash_sql, "0.2.84", "1187555609f4773aacb5cccdca82a78c2b3f7390e78b400a8f03c91b2e7cd82f", [:mix], [{:ash, ">= 3.5.25 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", "5e6a4d3070e60a0653c572527276a8c034b9458e37b1aca8868b17fcf0a1d1c0"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.9", "99dd9ea7bcf2fe829617dac660069b3461183e4efbf303dd120fdef96923287d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "5fe407e10bc9416f7cd6af90d0409c8226ff2acacb9a7e7b9a097a66c8b5caef"}, + "igniter": {:hex, :igniter, "0.6.10", "896d75fc48ed493ff22accd111fe2e34747163d26c5f374267bad1ef4a6c5076", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "9a3abc56e94f362730a3023dfe0ac2ced1186f95fa1ccf4cc30df0c8ce0fc276"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -38,8 +38,8 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, - "reactor": {:hex, :reactor, "0.15.5", "341d9ee664d6141df6639f227692ee6adc8a493d04232dee79e8a4a88e6cef8a", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "f9f440ecbdb0c41a832902a692608bd24be621fa7a602819d0dd12971d69f9aa"}, - "req": {:hex, :req, "0.5.12", "7ce85835867a114c28b6cfc2d8a412f86660290907315ceb173a00e587b853d2", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d65f3d0e7032eb245706554cb5240dbe7a07493154e2dd34e7bb65001aa6ef32"}, + "reactor": {:hex, :reactor, "0.15.6", "d717f9add549b25a089a94c90197718d2d838e35d81dd776b1d81587d4cf2aaa", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "74db98165e3644d86e0f723672d91ceca4339eaa935bcad7e78bf146a46d77b9"}, + "req": {:hex, :req, "0.5.14", "521b449fa0bf275e6d034c05f29bec21789a0d6cd6f7a1c326c7bee642bf6e07", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "b7b15692071d556c73432c7797aa7e96b51d1a2db76f746b976edef95c930021"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, diff --git a/test/parent_filter_test.exs b/test/parent_filter_test.exs new file mode 100644 index 00000000..fefbde24 --- /dev/null +++ b/test/parent_filter_test.exs @@ -0,0 +1,47 @@ +defmodule AshPostgres.Test.ParentFilterTest do + use AshPostgres.RepoCase, async: false + + alias AshPostgres.Test.{Organization, Post, User} + + require Ash.Query + + test "when the first relationship in an `exists` path has parent references in its filter, we don't get error" do + organization = + Organization + |> Ash.Changeset.for_create(:create, %{name: "test_org"}) + |> Ash.create!() + + not_my_organization = + Organization + |> Ash.Changeset.for_create(:create, %{name: "test_org_2"}) + |> Ash.create!() + + user = + User + |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, name: "foo bar"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{organization_id: not_my_organization.id}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, title: "test_org"}) + |> Ash.create!() + + assert {:ok, [%Post{title: "test_org"}]} = + Post + |> Ash.Query.for_read(:read_with_policy_with_parent) + |> Ash.read( + authorize?: true, + actor: user + ) + + assert {:ok, _} = + Post + |> Ash.Query.filter( + organization.posts.posts_with_my_organization_name_as_a_title.title == "tuna" + ) + |> Ash.read(authorize?: false) + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 5ff80458..5da68941 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -92,6 +92,12 @@ defmodule AshPostgres.Test.Post do authorize_if(relates_to_actor_via([:organization, :users])) end + policy action(:read_with_policy_with_parent) do + authorize_if( + relates_to_actor_via([:posts_with_my_organization_name_as_a_title, :organization, :users]) + ) + end + policy action(:allow_any) do authorize_if(always()) end @@ -360,6 +366,9 @@ defmodule AshPostgres.Test.Post do filter(expr(title == "foo")) end + read :read_with_policy_with_parent do + end + read :category_matches do argument(:category, CiCategory) filter(expr(category == ^arg(:category))) @@ -599,6 +608,12 @@ defmodule AshPostgres.Test.Post do filter(expr(^actor(:id) == id)) end + has_many(:posts_with_my_organization_name_as_a_title, __MODULE__) do + public?(true) + no_attributes?(true) + filter(expr(fragment("? = ?", title, parent(organization.name)))) + end + belongs_to :parent_post, __MODULE__ do public?(true) end From 5522c5cae178996285e826eaf3458e45d9d6441a Mon Sep 17 00:00:00 2001 From: Robert Ellen Date: Tue, 8 Jul 2025 11:06:08 +1000 Subject: [PATCH 594/690] test: Add tests for combination queries and loading calculations (#586) These tests show that loading calculations in queries that have combinations works. --- test/combination_nullable_calc_test.exs | 197 ++++++++++++++++++++++++ test/support/resources/author.ex | 2 + test/support/resources/post.ex | 2 + 3 files changed, 201 insertions(+) create mode 100644 test/combination_nullable_calc_test.exs diff --git a/test/combination_nullable_calc_test.exs b/test/combination_nullable_calc_test.exs new file mode 100644 index 00000000..1618f1c8 --- /dev/null +++ b/test/combination_nullable_calc_test.exs @@ -0,0 +1,197 @@ +defmodule AshPostgres.CombinationNullableCalcTest do + @moduledoc false + use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Author + alias AshPostgres.Test.Post + + require Ash.Query + import Ash.Expr + + describe "combination_of with nullable calculations" do + test "combination query with allow_nil? calculation loses ORDER BY" do + Post + |> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20}) + |> Ash.create!() + + query = + Post + |> Ash.Query.sort([{:title, :asc}]) + |> Ash.Query.load([:latest_comment_title]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(score < 15), + calculations: %{ + sort_order: calc(score * 20, type: :integer) + }, + sort: [{calc(score * 20, type: :integer), :desc}] + ), + Ash.Query.Combination.union( + filter: expr(score >= 15), + calculations: %{ + sort_order: calc(score * 5, type: :integer) + }, + sort: [{calc(score * 5, type: :integer), :desc}] + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + titles = Enum.map(result, & &1.title) + # Expected order: sort_order DESC, then title ASC + # Dog(200), Apple(125), Cat(100), Zebra(100) + expected_title_order = ["Dog", "Apple", "Cat", "Zebra"] + assert titles == expected_title_order + end + + test "combination query without nullable calc works" do + Post + |> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20}) + |> Ash.create!() + + query = + Post + |> Ash.Query.sort([{:title, :asc}]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(score < 15), + calculations: %{ + sort_order: calc(score * 20, type: :integer) + }, + sort: [{calc(score * 20, type: :integer), :desc}] + ), + Ash.Query.Combination.union( + filter: expr(score >= 15), + calculations: %{ + sort_order: calc(score * 5, type: :integer) + }, + sort: [{calc(score * 5, type: :integer), :desc}] + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + titles = Enum.map(result, & &1.title) + # Expected order: sort_order DESC, then title ASC + # Dog(200), Apple(125), Cat(100), Zebra(100) + expected_title_order = ["Dog", "Apple", "Cat", "Zebra"] + assert titles == expected_title_order + end + end + + describe "Author combination_of with nullable calculations" do + test "Author combination query with allow_nil? calculation loses ORDER BY" do + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"}) + |> Ash.create!() + + query = + Author + |> Ash.Query.sort([{:first_name, :asc}]) + |> Ash.Query.load([:profile_description_calc]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(first_name in ["Zebra", "Dog"]), + calculations: %{ + sort_order: calc(1000, type: :integer) + }, + sort: [{calc(1000, type: :integer), :desc}] + ), + Ash.Query.Combination.union( + filter: expr(first_name in ["Apple", "Cat"]), + calculations: %{ + sort_order: calc(500, type: :integer) + }, + sort: [{calc(500, type: :integer), :desc}] + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + first_names = Enum.map(result, & &1.first_name) + # Expected order: sort_order DESC, then first_name ASC + # [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat + expected_name_order = ["Dog", "Zebra", "Apple", "Cat"] + assert first_names == expected_name_order + end + + test "Author combination query without nullable calc works" do + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"}) + |> Ash.create!() + + query = + Author + |> Ash.Query.sort([{:first_name, :asc}]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(first_name in ["Zebra", "Dog"]), + calculations: %{ + sort_order: calc(1000, type: :integer) + } + ), + Ash.Query.Combination.union( + filter: expr(first_name in ["Apple", "Cat"]), + calculations: %{ + sort_order: calc(500, type: :integer) + } + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + first_names = Enum.map(result, & &1.first_name) + # Expected order: sort_order DESC, then first_name ASC + # [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat + expected_name_order = ["Dog", "Zebra", "Apple", "Cat"] + assert first_names == expected_name_order + end + end +end diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index acf9310a..54568518 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -175,6 +175,8 @@ defmodule AshPostgres.Test.Author do calculate(:has_posts, :boolean, expr(exists(posts, true == true))) calculate(:has_no_posts, :boolean, expr(has_posts == false)) + + calculate(:profile_description_calc, :string, expr(profile.description), allow_nil?: true) end aggregates do diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 5da68941..94ab170e 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -1006,6 +1006,8 @@ defmodule AshPostgres.Test.Post do calculate(:author_first_name_ref_agg_calc, :string, expr(author_first_name)) calculate(:author_profile_description_from_agg, :string, expr(author_profile_description)) + + calculate(:latest_comment_title, :string, expr(latest_comment.title), allow_nil?: true) end aggregates do From 8f5097f779a36dcbde791ff91d9e67d470f2b962 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 7 Jul 2025 21:11:40 -0400 Subject: [PATCH 595/690] fix: retain sort when upgrading to a subquery --- lib/data_layer.ex | 1 + test/combination_nullable_calc_test.exs | 197 ------------------------ test/combination_test.exs | 191 +++++++++++++++++++++++ 3 files changed, 192 insertions(+), 197 deletions(-) delete mode 100644 test/combination_nullable_calc_test.exs diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 22efd25e..0a8b4644 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3445,6 +3445,7 @@ defmodule AshPostgres.DataLayer do &Map.merge(&1, %{ already_selected: fieldset, subquery_upgrade?: true, + sort: query.__ash_bindings__[:sort], context: query.__ash_bindings__.context }) ) diff --git a/test/combination_nullable_calc_test.exs b/test/combination_nullable_calc_test.exs deleted file mode 100644 index 1618f1c8..00000000 --- a/test/combination_nullable_calc_test.exs +++ /dev/null @@ -1,197 +0,0 @@ -defmodule AshPostgres.CombinationNullableCalcTest do - @moduledoc false - use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.Author - alias AshPostgres.Test.Post - - require Ash.Query - import Ash.Expr - - describe "combination_of with nullable calculations" do - test "combination query with allow_nil? calculation loses ORDER BY" do - Post - |> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5}) - |> Ash.create!() - - Post - |> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25}) - |> Ash.create!() - - Post - |> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10}) - |> Ash.create!() - - Post - |> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20}) - |> Ash.create!() - - query = - Post - |> Ash.Query.sort([{:title, :asc}]) - |> Ash.Query.load([:latest_comment_title]) - |> Ash.Query.combination_of([ - Ash.Query.Combination.base( - filter: expr(score < 15), - calculations: %{ - sort_order: calc(score * 20, type: :integer) - }, - sort: [{calc(score * 20, type: :integer), :desc}] - ), - Ash.Query.Combination.union( - filter: expr(score >= 15), - calculations: %{ - sort_order: calc(score * 5, type: :integer) - }, - sort: [{calc(score * 5, type: :integer), :desc}] - ) - ]) - |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) - - result = Ash.read!(query) - titles = Enum.map(result, & &1.title) - # Expected order: sort_order DESC, then title ASC - # Dog(200), Apple(125), Cat(100), Zebra(100) - expected_title_order = ["Dog", "Apple", "Cat", "Zebra"] - assert titles == expected_title_order - end - - test "combination query without nullable calc works" do - Post - |> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5}) - |> Ash.create!() - - Post - |> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25}) - |> Ash.create!() - - Post - |> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10}) - |> Ash.create!() - - Post - |> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20}) - |> Ash.create!() - - query = - Post - |> Ash.Query.sort([{:title, :asc}]) - |> Ash.Query.combination_of([ - Ash.Query.Combination.base( - filter: expr(score < 15), - calculations: %{ - sort_order: calc(score * 20, type: :integer) - }, - sort: [{calc(score * 20, type: :integer), :desc}] - ), - Ash.Query.Combination.union( - filter: expr(score >= 15), - calculations: %{ - sort_order: calc(score * 5, type: :integer) - }, - sort: [{calc(score * 5, type: :integer), :desc}] - ) - ]) - |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) - - result = Ash.read!(query) - titles = Enum.map(result, & &1.title) - # Expected order: sort_order DESC, then title ASC - # Dog(200), Apple(125), Cat(100), Zebra(100) - expected_title_order = ["Dog", "Apple", "Cat", "Zebra"] - assert titles == expected_title_order - end - end - - describe "Author combination_of with nullable calculations" do - test "Author combination query with allow_nil? calculation loses ORDER BY" do - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"}) - |> Ash.create!() - - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"}) - |> Ash.create!() - - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"}) - |> Ash.create!() - - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"}) - |> Ash.create!() - - query = - Author - |> Ash.Query.sort([{:first_name, :asc}]) - |> Ash.Query.load([:profile_description_calc]) - |> Ash.Query.combination_of([ - Ash.Query.Combination.base( - filter: expr(first_name in ["Zebra", "Dog"]), - calculations: %{ - sort_order: calc(1000, type: :integer) - }, - sort: [{calc(1000, type: :integer), :desc}] - ), - Ash.Query.Combination.union( - filter: expr(first_name in ["Apple", "Cat"]), - calculations: %{ - sort_order: calc(500, type: :integer) - }, - sort: [{calc(500, type: :integer), :desc}] - ) - ]) - |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) - - result = Ash.read!(query) - first_names = Enum.map(result, & &1.first_name) - # Expected order: sort_order DESC, then first_name ASC - # [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat - expected_name_order = ["Dog", "Zebra", "Apple", "Cat"] - assert first_names == expected_name_order - end - - test "Author combination query without nullable calc works" do - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"}) - |> Ash.create!() - - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"}) - |> Ash.create!() - - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"}) - |> Ash.create!() - - Author - |> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"}) - |> Ash.create!() - - query = - Author - |> Ash.Query.sort([{:first_name, :asc}]) - |> Ash.Query.combination_of([ - Ash.Query.Combination.base( - filter: expr(first_name in ["Zebra", "Dog"]), - calculations: %{ - sort_order: calc(1000, type: :integer) - } - ), - Ash.Query.Combination.union( - filter: expr(first_name in ["Apple", "Cat"]), - calculations: %{ - sort_order: calc(500, type: :integer) - } - ) - ]) - |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) - - result = Ash.read!(query) - first_names = Enum.map(result, & &1.first_name) - # Expected order: sort_order DESC, then first_name ASC - # [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat - expected_name_order = ["Dog", "Zebra", "Apple", "Cat"] - assert first_names == expected_name_order - end - end -end diff --git a/test/combination_test.exs b/test/combination_test.exs index 086ae91d..5faaa020 100644 --- a/test/combination_test.exs +++ b/test/combination_test.exs @@ -5,6 +5,9 @@ defmodule AshPostgres.CombinationTest do require Ash.Query import Ash.Expr + alias AshPostgres.Test.Author + alias AshPostgres.Test.Post + describe "combinations in actions" do test "with no data" do Post @@ -427,4 +430,192 @@ defmodule AshPostgres.CombinationTest do |> Enum.map(&to_string(&1.category)) end end + + describe "combination_of with nullable calculations" do + test "combination query with allow_nil? calculation loses ORDER BY" do + Post + |> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20}) + |> Ash.create!() + + query = + Post + |> Ash.Query.sort([{:title, :asc}]) + |> Ash.Query.load([:latest_comment_title]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(score < 15), + calculations: %{ + sort_order: calc(score * 20, type: :integer) + }, + sort: [{calc(score * 20, type: :integer), :desc}] + ), + Ash.Query.Combination.union( + filter: expr(score >= 15), + calculations: %{ + sort_order: calc(score * 5, type: :integer) + }, + sort: [{calc(score * 5, type: :integer), :desc}] + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + titles = Enum.map(result, & &1.title) + # Expected order: sort_order DESC, then title ASC + # Dog(200), Apple(125), Cat(100), Zebra(100) + expected_title_order = ["Dog", "Apple", "Cat", "Zebra"] + assert titles == expected_title_order + end + + test "combination query without nullable calc works" do + Post + |> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20}) + |> Ash.create!() + + query = + Post + |> Ash.Query.sort([{:title, :asc}]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(score < 15), + calculations: %{ + sort_order: calc(score * 20, type: :integer) + }, + sort: [{calc(score * 20, type: :integer), :desc}] + ), + Ash.Query.Combination.union( + filter: expr(score >= 15), + calculations: %{ + sort_order: calc(score * 5, type: :integer) + }, + sort: [{calc(score * 5, type: :integer), :desc}] + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + titles = Enum.map(result, & &1.title) + # Expected order: sort_order DESC, then title ASC + # Dog(200), Apple(125), Cat(100), Zebra(100) + expected_title_order = ["Dog", "Apple", "Cat", "Zebra"] + assert titles == expected_title_order + end + end + + describe "Author combination_of with nullable calculations" do + test "Author combination query with allow_nil? calculation loses ORDER BY" do + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"}) + |> Ash.create!() + + query = + Author + |> Ash.Query.sort([{:first_name, :asc}]) + |> Ash.Query.load([:profile_description_calc]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(first_name in ["Zebra", "Dog"]), + calculations: %{ + sort_order: calc(1000, type: :integer) + }, + sort: [{calc(1000, type: :integer), :desc}] + ), + Ash.Query.Combination.union( + filter: expr(first_name in ["Apple", "Cat"]), + calculations: %{ + sort_order: calc(500, type: :integer) + }, + sort: [{calc(500, type: :integer), :desc}] + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + first_names = Enum.map(result, & &1.first_name) + # Expected order: sort_order DESC, then first_name ASC + # [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat + expected_name_order = ["Dog", "Zebra", "Apple", "Cat"] + assert first_names == expected_name_order + end + + test "Author combination query without nullable calc works" do + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"}) + |> Ash.create!() + + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"}) + |> Ash.create!() + + query = + Author + |> Ash.Query.sort([{:first_name, :asc}]) + |> Ash.Query.combination_of([ + Ash.Query.Combination.base( + filter: expr(first_name in ["Zebra", "Dog"]), + calculations: %{ + sort_order: calc(1000, type: :integer) + } + ), + Ash.Query.Combination.union( + filter: expr(first_name in ["Apple", "Cat"]), + calculations: %{ + sort_order: calc(500, type: :integer) + } + ) + ]) + |> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true) + + result = Ash.read!(query) + first_names = Enum.map(result, & &1.first_name) + # Expected order: sort_order DESC, then first_name ASC + # [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat + expected_name_order = ["Dog", "Zebra", "Apple", "Cat"] + assert first_names == expected_name_order + end + end end From 986c4c724ea098c4679be271869f1d598ad287e6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 7 Jul 2025 21:25:02 -0400 Subject: [PATCH 596/690] fix: properly return the type when configured closes #588 --- lib/resource_generator/spec.ex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index ff942f16..8b6d4ae6 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -908,7 +908,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do - MyApp.Types.CustomType - {:array, :string} - Use `skip` to skip ignore this attribute. + Use `skip` to ignore this attribute. """) end @@ -921,13 +921,12 @@ defmodule AshPostgres.ResourceGenerator.Spec do ":" <> type -> new_type = String.to_atom(type) Process.put({:type_cache, attribute.type}, new_type) - {:ok, %{attribute | attr_type: new_type}} + {:ok, new_type} type -> try do - Code.eval_string(type) Process.put({:type_cache, attribute.type}, new_type) - {:ok, %{attribute | attr_type: new_type}} + {:ok, type} rescue _e -> get_type(attribute, opts) From 50d9d0f02c0f5747b30d74012f40a649c265ca76 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 8 Jul 2025 23:10:22 -0400 Subject: [PATCH 597/690] chore: update deps --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index 7f05569e..297b4075 100644 --- a/mix.lock +++ b/mix.lock @@ -18,12 +18,12 @@ "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, "ex_doc": {:hex, :ex_doc, "0.38.2", "504d25eef296b4dec3b8e33e810bc8b5344d565998cd83914ffe1b8503737c02", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "732f2d972e42c116a70802f9898c51b54916e542cc50968ac6980512ec90f42b"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, - "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"}, + "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [: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", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.10", "896d75fc48ed493ff22accd111fe2e34747163d26c5f374267bad1ef4a6c5076", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "9a3abc56e94f362730a3023dfe0ac2ced1186f95fa1ccf4cc30df0c8ce0fc276"}, + "igniter": {:hex, :igniter, "0.6.12", "a8e20a67c2729dd0e03ccb06799efb23017fbdbed939ac6a88d8ddcc1a005bf7", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "4ba183c8fa299ac1207c078c3d055c635b418d6573006a2e92c131dfd1879a92"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -47,7 +47,7 @@ "spark": {:hex, :spark, "2.2.67", "67626cb9f59ea4b1c5aa85d4afdd025e0740cbd49ed82665d0a40ff007d7fd4b", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "c8575402e3afc66871362e821bece890536d16319cdb758c5fb2d1250182e46f"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, - "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, + "statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"}, "stream_data": {:hex, :stream_data, "1.2.0", "58dd3f9e88afe27dc38bef26fce0c84a9e7a96772b2925c7b32cd2435697a52b", [:mix], [], "hexpm", "eb5c546ee3466920314643edf68943a5b14b32d1da9fe01698dc92b73f89a9ed"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, From a0314239db57fff2046b80cc70e482fced54d99a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 8 Jul 2025 23:11:22 -0400 Subject: [PATCH 598/690] chore: release version v2.6.10 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cf99e8d..b5d718f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.10](https://github.com/ash-project/ash_postgres/compare/v2.6.9...v2.6.10) (2025-07-09) + + + + +### Bug Fixes: + +* properly return the type when configured by Zach Daniel + +* retain sort when upgrading to a subquery by Zach Daniel + ## [v2.6.9](https://github.com/ash-project/ash_postgres/compare/v2.6.8...v2.6.9) (2025-06-25) diff --git a/mix.exs b/mix.exs index 4c59bea1..c954d13a 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.9" + @version "2.6.10" def project do [ From 106a532e95ffe393f387ca518e84b5b38a6b5303 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 8 Jul 2025 23:11:46 -0400 Subject: [PATCH 599/690] chore: update more deps --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 297b4075..a09948cd 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.25", "99f7139e98b745a64312ae80e2420589205b2fec1799f00fc58da771d2c63373", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "d45844ea30062b796d4adcad75b8d91e21081ac0f1bb6627d1a2663ca5ecf258"}, - "ash_sql": {:hex, :ash_sql, "0.2.84", "1187555609f4773aacb5cccdca82a78c2b3f7390e78b400a8f03c91b2e7cd82f", [:mix], [{:ash, ">= 3.5.25 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", "5e6a4d3070e60a0653c572527276a8c034b9458e37b1aca8868b17fcf0a1d1c0"}, + "ash": {:hex, :ash, "3.5.26", "f2e884623bfc39e0228a4fee0c41fbdb90195c6b1e1618a0a97f03f2dfbb1c4f", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "a9f5edbb7d838e2053e84f62c428650dadbff3ea4ec40ef68f167483eb7e9012"}, + "ash_sql": {:hex, :ash_sql, "0.2.85", "96a35d197f5ff846c17aca9225d4baafa0fda6c804f1e46a79345d237b5e5c5f", [:mix], [{:ash, ">= 3.5.25 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", "62e7f8b79bcb04d82654ba519008b80bd21bd177ec646e9fffb87ec34285722b"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From fdb077e7b52b1ecf50352ff18446a960480d14e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Wed, 9 Jul 2025 22:02:33 +0200 Subject: [PATCH 600/690] fix: Reverse migrations order when reverting dev migrations (#590) --- lib/migration_generator/migration_generator.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index a5984a67..84630f7d 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -556,6 +556,7 @@ defmodule AshPostgres.MigrationGenerator do |> Enum.filter(& &1) |> Enum.map(&load_migration!/1) |> Enum.sort() + |> Enum.reverse() |> Enum.filter(fn {version, _} -> version in versions end) @@ -589,6 +590,7 @@ defmodule AshPostgres.MigrationGenerator do |> Enum.filter(& &1) |> Enum.map(&load_migration!/1) |> Enum.sort() + |> Enum.reverse() |> Enum.filter(fn {version, _} -> version in versions end) From d174139867ace7027b6a97fcd557ff1d0a31592d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 9 Jul 2025 17:34:56 -0400 Subject: [PATCH 601/690] chore: update installer for latest igniter changes --- lib/mix/tasks/ash_postgres.install.ex | 11 +++++++++-- mix.exs | 2 +- mix.lock | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 73f50db0..a984f2d8 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -200,12 +200,12 @@ if Code.ensure_loaded?(Igniter) do ) do {:ok, _zipper} -> zipper - |> Igniter.Project.Config.modify_configuration_code( + |> modify_configuration_code( [repo, :url], otp_app, {:database_url, [], nil} ) - |> Igniter.Project.Config.modify_configuration_code( + |> modify_configuration_code( [repo, :pool_size], otp_app, Sourceror.parse_string!(""" @@ -252,6 +252,13 @@ if Code.ensure_loaded?(Igniter) do end end + defp modify_configuration_code(zipper, path, otp_app, code) do + case Igniter.Project.Config.modify_config_code(zipper, path, otp_app, code) do + {:ok, zipper} -> zipper + _ -> zipper + end + end + defp configure_dev(igniter, otp_app, repo) do if Igniter.Project.Config.configures_key?(igniter, "dev.exs", otp_app, [repo]) do igniter diff --git a/mix.exs b/mix.exs index c954d13a..4aa37c8e 100644 --- a/mix.exs +++ b/mix.exs @@ -168,7 +168,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.5 and >= 3.5.13")}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, - {:igniter, "~> 0.6", optional: true}, + {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, {:jason, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index a09948cd..e27a5efc 100644 --- a/mix.lock +++ b/mix.lock @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.12", "a8e20a67c2729dd0e03ccb06799efb23017fbdbed939ac6a88d8ddcc1a005bf7", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "4ba183c8fa299ac1207c078c3d055c635b418d6573006a2e92c131dfd1879a92"}, + "igniter": {:hex, :igniter, "0.6.14", "c7d1aa437bd87389a724ab8971ed4f4b645d844f55cb9dfa2d3933a8350f5d68", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "2d566654e3ee33351307053869235c51bed25fb2c0af491896fd91c3315ecb8c"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From de90abdd71c10d26bdb7907856511d414b68e7ca Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 13 Jul 2025 22:01:25 -0400 Subject: [PATCH 602/690] improvement: make rollbacks safer by using `--to` instead of `-n` --- lib/data_layer.ex | 60 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 0a8b4644..b0000ee2 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -459,10 +459,14 @@ defmodule AshPostgres.DataLayer do end) |> Enum.take(20) |> Enum.map(&String.trim_leading(&1, migrations_path)) + |> Enum.map(&String.trim_leading(&1, "/")) + + indexed = + files |> Enum.with_index() |> Enum.map(fn {file, index} -> "#{index + 1}: #{file}" end) - n = + to = Mix.shell().prompt( """ How many migrations should be rolled back#{for_repo}? (default: 0) @@ -470,7 +474,7 @@ defmodule AshPostgres.DataLayer do Last 20 migration names, with the input you must provide to rollback up to *and including* that migration: - #{Enum.join(files, "\n")} + #{Enum.join(indexed, "\n")} Rollback to: """ |> String.trim_trailing() @@ -478,19 +482,32 @@ defmodule AshPostgres.DataLayer do |> String.trim() |> case do "" -> - 0 + nil + + "0" -> + nil n -> try do - String.to_integer(n) + files + |> Enum.at(String.to_integer(n) - 1) rescue _ -> reraise "Required an integer value, got: #{n}", __STACKTRACE__ end + |> String.split("_", parts: 2) + |> Enum.at(0) + |> String.to_integer() end - Mix.Task.run("ash_postgres.rollback", args ++ ["-r", inspect(repo), "-n", to_string(n)]) - Mix.Task.reenable("ash_postgres.rollback") + if to do + Mix.Task.run( + "ash_postgres.rollback", + args ++ ["-r", inspect(repo), "--to", to_string(to)] + ) + + Mix.Task.reenable("ash_postgres.rollback") + end tenant_files = tenant_migrations_path @@ -520,10 +537,14 @@ defmodule AshPostgres.DataLayer do end) |> Enum.take(20) |> Enum.map(&String.trim_leading(&1, tenant_migrations_path)) + |> Enum.map(&String.trim_leading(&1, "/")) + + indexed = + tenant_files |> Enum.with_index() |> Enum.map(fn {file, index} -> "#{index + 1}: #{file}" end) - n = + to = Mix.shell().prompt( """ @@ -536,7 +557,7 @@ defmodule AshPostgres.DataLayer do Last 20 migration names, with the input you must provide to rollback up to *and including* that migration: - #{Enum.join(tenant_files, "\n")} + #{Enum.join(indexed, "\n")} Rollback to: """ @@ -545,23 +566,32 @@ defmodule AshPostgres.DataLayer do |> String.trim() |> case do "" -> - 0 + nil + + "0" -> + nil n -> try do - String.to_integer(n) + tenant_files + |> Enum.at(String.to_integer(n) - 1) rescue _ -> reraise "Required an integer value, got: #{n}", __STACKTRACE__ end + |> String.split("_", parts: 2) + |> Enum.at(0) + |> String.to_integer() end - Mix.Task.run( - "ash_postgres.rollback", - args ++ ["--tenants", "-r", inspect(repo), "-n", to_string(n)] - ) + if to do + Mix.Task.run( + "ash_postgres.rollback", + args ++ ["--tenants", "-r", inspect(repo), "--to", to] + ) - Mix.Task.reenable("ash_postgres.rollback") + Mix.Task.reenable("ash_postgres.rollback") + end end end end) From 1f064f52b51e7661aee0fde95a9c719a0f1ad70e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 14 Jul 2025 13:48:00 -0400 Subject: [PATCH 603/690] fix: clean args and properly scope rollback task closes #592 --- lib/data_layer.ex | 10 +++++++++- lib/mix/helpers.ex | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index b0000ee2..d527bce6 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -424,7 +424,15 @@ defmodule AshPostgres.DataLayer do end def rollback(args) do - repos = AshPostgres.Mix.Helpers.repos!([], args) + {opts, _, _} = + OptionParser.parse(args, + switches: [ + repo: :string + ], + aliases: [r: :repo] + ) + + repos = AshPostgres.Mix.Helpers.repos!(opts, args) show_for_repo? = Enum.count_until(repos, 2) == 2 diff --git a/lib/mix/helpers.ex b/lib/mix/helpers.ex index 2eb2d40b..316778fd 100644 --- a/lib/mix/helpers.ex +++ b/lib/mix/helpers.ex @@ -119,7 +119,7 @@ defmodule AshPostgres.Mix.Helpers do def delete_flag(args, arg) do case Enum.split_while(args, &(&1 != arg)) do {left, [_ | rest]} -> - left ++ rest + delete_flag(left ++ rest, arg) _ -> args @@ -129,7 +129,7 @@ defmodule AshPostgres.Mix.Helpers do def delete_arg(args, arg) do case Enum.split_while(args, &(&1 != arg)) do {left, [_, _ | rest]} -> - left ++ rest + delete_arg(left ++ rest, arg) _ -> args From 8787615f38e276c8b37d405f010b1c044d0ed834 Mon Sep 17 00:00:00 2001 From: Jesse Williams Date: Tue, 15 Jul 2025 16:26:43 -0700 Subject: [PATCH 604/690] test: reproduce a bug with a complex calculation (#593) * reproduce a bug with a complex calculation * no unused vars --- .../20250714225304.json | 86 +++++++++++++++++++ .../20250714225304.json | 55 ++++++++++++ ..._complex_calculations_folder_and_items.exs | 61 +++++++++++++ test/complex_calculations_test.exs | 30 +++++++ test/support/complex_calculations/domain.ex | 2 + .../complex_calculations/resources/folder.ex | 75 ++++++++++++++++ .../resources/folder_item.ex | 38 ++++++++ 7 files changed, 347 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json create mode 100644 priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs create mode 100644 test/support/complex_calculations/resources/folder.ex create mode 100644 test/support/complex_calculations/resources/folder_item.ex diff --git a/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json b/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json new file mode 100644 index 00000000..f217c546 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json @@ -0,0 +1,86 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "level", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "complex_calculations_folder_items_folder_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "complex_calculations_folders" + }, + "scale": null, + "size": null, + "source": "folder_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "C7BC97676F202A744482B4095560986B265E6BCB74F6E69C1330034FBC4981E5", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "complex_calculations_folder_items" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json b/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json new file mode 100644 index 00000000..8d499706 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json @@ -0,0 +1,55 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "some_integer_setting", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "level", + "type": "ltree" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": false, + "hash": "1982E0DAF0B5B22502A5747ED8533C6F1D58E882E1132FAB0939EC13F2CFC5AF", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "complex_calculations_folders" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs b/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs new file mode 100644 index 00000000..88d73d15 --- /dev/null +++ b/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs @@ -0,0 +1,61 @@ +defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationsFolderAndItems do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:complex_calculations_folder_items, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:name, :text) + add(:level, :bigint) + add(:folder_id, :uuid) + end + + create table(:complex_calculations_folders, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + end + + alter table(:complex_calculations_folder_items) do + modify( + :folder_id, + references(:complex_calculations_folders, + column: :id, + name: "complex_calculations_folder_items_folder_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + + alter table(:complex_calculations_folders) do + add(:some_integer_setting, :bigint) + add(:level, :ltree) + end + end + + def down do + alter table(:complex_calculations_folders) do + remove(:level) + remove(:some_integer_setting) + end + + drop( + constraint( + :complex_calculations_folder_items, + "complex_calculations_folder_items_folder_id_fkey" + ) + ) + + alter table(:complex_calculations_folder_items) do + modify(:folder_id, :uuid) + end + + drop(table(:complex_calculations_folders)) + + drop(table(:complex_calculations_folder_items)) + end +end diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index 83cb39cf..5617a6d1 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -373,4 +373,34 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do assert doc_before.is_active_with_timezone == false assert doc_after.is_active_with_timezone == true end + + test "gnarly parent bug with some weird ltree setup" do + _folder_a = + Ash.Seed.seed!( + AshPostgres.Test.Support.ComplexCalculations.Folder, + %{some_integer_setting: 1, level: "a"} + ) + + _folder_b = + Ash.Seed.seed!( + AshPostgres.Test.Support.ComplexCalculations.Folder, + %{some_integer_setting: nil, level: "a.b"} + ) + + folder_c = + Ash.Seed.seed!( + AshPostgres.Test.Support.ComplexCalculations.Folder, + %{some_integer_setting: nil, level: "a.b.c"} + ) + + folder_c_item = + Ash.Seed.seed!( + AshPostgres.Test.Support.ComplexCalculations.FolderItem, + %{name: "Item in C", level: 1, folder_id: folder_c.id} + ) + + # reproduction: this raises Unknown Error + # * ** (Postgrex.Error) ERROR 42846 (cannot_coerce) cannot cast type bigint to ltree + assert Ash.calculate!(folder_c_item, :folder_setting) == 1 + end end diff --git a/test/support/complex_calculations/domain.ex b/test/support/complex_calculations/domain.ex index 76d066c2..15a306ef 100644 --- a/test/support/complex_calculations/domain.ex +++ b/test/support/complex_calculations/domain.ex @@ -9,6 +9,8 @@ defmodule AshPostgres.Test.ComplexCalculations.Domain do resource(AshPostgres.Test.ComplexCalculations.Channel) resource(AshPostgres.Test.ComplexCalculations.DMChannel) resource(AshPostgres.Test.ComplexCalculations.ChannelMember) + resource(AshPostgres.Test.Support.ComplexCalculations.Folder) + resource(AshPostgres.Test.Support.ComplexCalculations.FolderItem) end authorization do diff --git a/test/support/complex_calculations/resources/folder.ex b/test/support/complex_calculations/resources/folder.ex new file mode 100644 index 00000000..d4b31e38 --- /dev/null +++ b/test/support/complex_calculations/resources/folder.ex @@ -0,0 +1,75 @@ +defmodule AshPostgres.Test.Support.ComplexCalculations.Folder do + @moduledoc """ + A tree structure using the ltree type. + """ + + alias AshPostgres.Test.Support.ComplexCalculations.Folder + + use Ash.Resource, + domain: AshPostgres.Test.ComplexCalculations.Domain, + data_layer: AshPostgres.DataLayer + + @default_integer_setting 5 + + postgres do + table "complex_calculations_folders" + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + + attribute(:some_integer_setting, :integer, + public?: true, + description: "Some setting that can be inherited. No real semantic meaning, just for demo" + ) + + attribute(:level, AshPostgres.Ltree, public?: true) + end + + actions do + defaults([:read]) + end + + relationships do + has_many :ancestors, Folder do + public?(true) + no_attributes?(true) + + # use ltree @> operator to get all ancestors + filter(expr(fragment("? @> ? AND ? < ?", level, parent(level), nlevel, parent(nlevel)))) + end + + has_many :items, AshPostgres.Test.Support.ComplexCalculations.FolderItem do + public?(true) + end + end + + calculations do + calculate(:nlevel, :integer, expr(fragment("nlevel(?)", level))) + + calculate( + :effective_integer_setting, + :integer, + expr( + if is_nil(some_integer_setting) do + # closest ancestor with a non-nil setting, or the default + first( + ancestors, + query: [ + sort: [nlevel: :desc], + filter: expr(not is_nil(some_integer_setting)) + ], + field: :some_integer_setting + ) || @default_integer_setting + else + some_integer_setting + end + ), + description: """ + The effective integer setting, inheriting from ancestors if not explicitly set, + or defaulting to #{@default_integer_setting} if none are set. No real semantic meaning, just for demo + """ + ) + end +end diff --git a/test/support/complex_calculations/resources/folder_item.ex b/test/support/complex_calculations/resources/folder_item.ex new file mode 100644 index 00000000..ac115aef --- /dev/null +++ b/test/support/complex_calculations/resources/folder_item.ex @@ -0,0 +1,38 @@ +defmodule AshPostgres.Test.Support.ComplexCalculations.FolderItem do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.ComplexCalculations.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "complex_calculations_folder_items" + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + + attribute(:level, :integer, + public?: true, + description: """ + No real semantic meaning here, just for demo, this *deliberately* is named the same as the ltree level column in Folder, + but is NOT related to it in any way + """ + ) + end + + actions do + defaults([:read]) + end + + calculations do + calculate(:folder_setting, :integer, expr(folder.effective_integer_setting)) + end + + relationships do + belongs_to(:folder, AshPostgres.Test.Support.ComplexCalculations.Folder) do + public?(true) + end + end +end From ce21b9239aeb85240082fe5f2657894e2a078031 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 17 Jul 2025 10:48:53 -0400 Subject: [PATCH 605/690] chore: release version v2.6.11 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d718f2..996183c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.11](https://github.com/ash-project/ash_postgres/compare/v2.6.10...v2.6.11) (2025-07-17) + + + + +### Bug Fixes: + +* clean args and properly scope rollback task by Zach Daniel + +* Reverse migrations order when reverting dev migrations (#590) by Kenneth Kostrešević + +### Improvements: + +* make rollbacks safer by using `--to` instead of `-n` by Zach Daniel + ## [v2.6.10](https://github.com/ash-project/ash_postgres/compare/v2.6.9...v2.6.10) (2025-07-09) diff --git a/mix.exs b/mix.exs index 4aa37c8e..68afd199 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.10" + @version "2.6.11" def project do [ From db24c4e4a55355c410173456b7be7eebc3187004 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 17 Jul 2025 10:49:25 -0400 Subject: [PATCH 606/690] chore: update deps --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index e27a5efc..b0c5a864 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.26", "f2e884623bfc39e0228a4fee0c41fbdb90195c6b1e1618a0a97f03f2dfbb1c4f", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "a9f5edbb7d838e2053e84f62c428650dadbff3ea4ec40ef68f167483eb7e9012"}, - "ash_sql": {:hex, :ash_sql, "0.2.85", "96a35d197f5ff846c17aca9225d4baafa0fda6c804f1e46a79345d237b5e5c5f", [:mix], [{:ash, ">= 3.5.25 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", "62e7f8b79bcb04d82654ba519008b80bd21bd177ec646e9fffb87ec34285722b"}, + "ash": {:hex, :ash, "3.5.27", "bfa227b75da2b447d1b98e16a19b2fa957fe32bef33dfe33aa93b861a532c641", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "f75694b0012e4e56293e1beef1d6c20a52f2f2c9baebfa5c8f2426d25d43608e"}, + "ash_sql": {:hex, :ash_sql, "0.2.86", "9b4013010981352e295eed22dc6b09998e23a724baca07f1ff617b6bec4ba8d4", [:mix], [{:ash, ">= 3.5.25 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", "97fa13e87d55194f7746c5a9fa97a9693bc26cdf7825d1c6d7cdfe5f166285a4"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.14", "c7d1aa437bd87389a724ab8971ed4f4b645d844f55cb9dfa2d3933a8350f5d68", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "2d566654e3ee33351307053869235c51bed25fb2c0af491896fd91c3315ecb8c"}, + "igniter": {:hex, :igniter, "0.6.19", "d87703b36890bc4278341d966a7ed8e10604a18610a4331ac10c75d1af48fff4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "c2070b3fdbd238fc0a0bfbc1f125b5c0f79a1fe2f5b3c7b43cd33de696783663"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -39,7 +39,7 @@ "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, "reactor": {:hex, :reactor, "0.15.6", "d717f9add549b25a089a94c90197718d2d838e35d81dd776b1d81587d4cf2aaa", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "74db98165e3644d86e0f723672d91ceca4339eaa935bcad7e78bf146a46d77b9"}, - "req": {:hex, :req, "0.5.14", "521b449fa0bf275e6d034c05f29bec21789a0d6cd6f7a1c326c7bee642bf6e07", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "b7b15692071d556c73432c7797aa7e96b51d1a2db76f746b976edef95c930021"}, + "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, @@ -54,5 +54,5 @@ "tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, - "ymlr": {:hex, :ymlr, "5.1.3", "a8061add5a378e20272a31905be70209a5680fdbe0ad51f40cb1af4bdd0a010b", [:mix], [], "hexpm", "8663444fa85101a117887c170204d4c5a2182567e5f84767f0071cf15f2efb1e"}, + "ymlr": {:hex, :ymlr, "5.1.4", "b924d61e1fc1ec371cde6ab3ccd9311110b1e052fc5c2460fb322e8380e7712a", [:mix], [], "hexpm", "75f16cf0709fbd911b30311a0359a7aa4b5476346c01882addefd5f2b1cfaa51"}, } From 5428e89671872cf585e07d71ae6090bc9c2e111e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 20 Jul 2025 23:14:40 -0400 Subject: [PATCH 607/690] chore: tests for aggregate error w/ modify_query --- test/aggregate_test.exs | 11 +++++++++++ test/support/resources/comment.ex | 15 +++++++++++++++ test/support/resources/post.ex | 4 ++++ 3 files changed, 30 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 167a00c9..d17b753b 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1667,4 +1667,15 @@ defmodule AshSql.AggregateTest do Ash.Query.filter_input(AshPostgres.Test.StandupClub, filter) |> Ash.read!(load: [:punchline_count]) end + + @tag :regression + test "aggregates with modify_query raise an appropriate error" do + assert_raise Ash.Error.Unknown, ~r/does not currently support aggregates/, fn -> + Post + |> Ash.Query.load([ + :count_comments_with_modify_query + ]) + |> Ash.read_one!() + end + end end diff --git a/test/support/resources/comment.ex b/test/support/resources/comment.ex index fe4a818e..517c42af 100644 --- a/test/support/resources/comment.ex +++ b/test/support/resources/comment.ex @@ -33,6 +33,10 @@ defmodule AshPostgres.Test.Comment do change(manage_relationship(:rating, :ratings, on_missing: :ignore, on_match: :create)) end + + read :with_modify_query do + modify_query({AshPostgres.Test.Comment.ModifyQuery, :modify, []}) + end end attributes do @@ -104,3 +108,14 @@ defmodule AshPostgres.Test.Comment do ) end end + +defmodule AshPostgres.Test.Comment.ModifyQuery do + @moduledoc """ + Raises when modifying query so we can assert + this code path is called. + """ + + def modify(_ash_query, _ecto_query) do + raise "modifying query!" + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 94ab170e..79eddd34 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -1164,6 +1164,10 @@ defmodule AshPostgres.Test.Post do end first(:author_profile_description, :author, :description) + + count :count_comments_with_modify_query, :comments do + read_action(:with_modify_query) + end end end From b24b845ae35b7654fc613d60d02c3a3aaf86ceef Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 22 Jul 2025 15:09:00 -0400 Subject: [PATCH 608/690] Update dependabot schedule to monthly --- .github/dependabot.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a3168e45..597c8ec7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,13 +1,14 @@ -version: 2 +--- updates: - - package-ecosystem: mix - directory: "/" - versioning-strategy: lockfile-only - schedule: - interval: weekly - day: thursday + - directory: / groups: - production-dependencies: - dependency-type: production dev-dependencies: dependency-type: development + production-dependencies: + dependency-type: production + package-ecosystem: mix + schedule: + day: thursday + interval: monthly + versioning-strategy: lockfile-only +version: 2 From 5bbc43fa64b69b4dfd18957f0be151fb6e37cceb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 15:20:32 -0400 Subject: [PATCH 609/690] chore(deps): bump the production-dependencies group with 3 updates (#598) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql) and [igniter](https://github.com/ash-project/igniter). Updates `ash` from 3.5.27 to 3.5.31 - [Release notes](https://github.com/ash-project/ash/releases) - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.5.27...v3.5.31) Updates `ash_sql` from 0.2.86 to 0.2.87 - [Release notes](https://github.com/ash-project/ash_sql/releases) - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.86...v0.2.87) Updates `igniter` from 0.6.19 to 0.6.22 - [Release notes](https://github.com/ash-project/igniter/releases) - [Changelog](https://github.com/ash-project/igniter/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/igniter/compare/v0.6.19...v0.6.22) --- updated-dependencies: - dependency-name: ash dependency-version: 3.5.31 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-version: 0.2.87 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: igniter dependency-version: 0.6.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.lock b/mix.lock index b0c5a864..7706f2a1 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.27", "bfa227b75da2b447d1b98e16a19b2fa957fe32bef33dfe33aa93b861a532c641", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "f75694b0012e4e56293e1beef1d6c20a52f2f2c9baebfa5c8f2426d25d43608e"}, - "ash_sql": {:hex, :ash_sql, "0.2.86", "9b4013010981352e295eed22dc6b09998e23a724baca07f1ff617b6bec4ba8d4", [:mix], [{:ash, ">= 3.5.25 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", "97fa13e87d55194f7746c5a9fa97a9693bc26cdf7825d1c6d7cdfe5f166285a4"}, + "ash": {:hex, :ash, "3.5.31", "fea1abcbb58d00d1edf65ac5bccba5d679ca80754aaac6af7877cbf9056d4462", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "a7e07c8ae297dd764d92dd3c478e8bbb825fc0dd14a5cce83b85d19235510a74"}, + "ash_sql": {:hex, :ash_sql, "0.2.87", "17197c643918cdaee657946a1998860402dcf53a980f7665bb81d1fa53c224e7", [:mix], [{:ash, ">= 3.5.25 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", "f82d6bf78f08bd9040af3adc28676965421598c88866074d8b1ccca65978d774"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.19", "d87703b36890bc4278341d966a7ed8e10604a18610a4331ac10c75d1af48fff4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "c2070b3fdbd238fc0a0bfbc1f125b5c0f79a1fe2f5b3c7b43cd33de696783663"}, + "igniter": {:hex, :igniter, "0.6.22", "b170fc64ae0cae54a7713cf3f96e7c96183f81d75f31746de080b27518b0f96e", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "d753129f693a214da32f39ba5b335f7ea6e1e87833e647b280f395b3c3742acf"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From 7f441488f0205ba82deb21a91b083168a219c280 Mon Sep 17 00:00:00 2001 From: "Pois.Nada" <46747395+horberlan@users.noreply.github.com> Date: Fri, 25 Jul 2025 13:03:22 -0300 Subject: [PATCH 610/690] improvement: do not create snapshots for resources that have no attributes #571 (#599) --- .../migration_generator.ex | 68 ++++++++++------- test/migration_generator_test.exs | 73 +++++++++++++++++++ 2 files changed, 116 insertions(+), 25 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 84630f7d..7222c7f4 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -1983,6 +1983,17 @@ defmodule AshPostgres.MigrationGenerator do end) end + defp resource_has_meaningful_content?(snapshot) do + [ + snapshot.attributes, + snapshot.identities, + snapshot.custom_indexes, + snapshot.custom_statements, + snapshot.check_constraints + ] + |> Enum.any?(&Enum.any?/1) + end + defp do_fetch_operations(snapshot, existing_snapshot, opts, acc \\ []) defp do_fetch_operations( @@ -1996,34 +2007,41 @@ defmodule AshPostgres.MigrationGenerator do end defp do_fetch_operations(snapshot, nil, opts, acc) do - empty_snapshot = %{ - attributes: [], - identities: [], - schema: nil, - custom_indexes: [], - custom_statements: [], - check_constraints: [], - table: snapshot.table, - repo: snapshot.repo, - base_filter: nil, - empty?: true, - multitenancy: %{ - attribute: nil, - strategy: nil, - global: nil - } - } - - do_fetch_operations(snapshot, empty_snapshot, opts, [ - %Operation.CreateTable{ + if resource_has_meaningful_content?(snapshot) do + empty_snapshot = %{ + attributes: [], + identities: [], + schema: nil, + custom_indexes: [], + custom_statements: [], + check_constraints: [], table: snapshot.table, - schema: snapshot.schema, repo: snapshot.repo, - multitenancy: snapshot.multitenancy, - old_multitenancy: empty_snapshot.multitenancy + base_filter: nil, + empty?: true, + multitenancy: %{ + attribute: nil, + strategy: nil, + global: nil + } } - | acc - ]) + + do_fetch_operations(snapshot, empty_snapshot, opts, [ + %Operation.CreateTable{ + table: snapshot.table, + schema: snapshot.schema, + repo: snapshot.repo, + multitenancy: snapshot.multitenancy, + old_multitenancy: empty_snapshot.multitenancy + } + | acc + ]) + else + unless opts.quiet do + Logger.info("Skipping migration for empty resource: #{snapshot.table} (no attributes, identities, indexes, statements, or constraints)") + end + acc + end end defp do_fetch_operations(snapshot, old_snapshot, opts, acc) do diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index e284e847..18577e13 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -111,6 +111,79 @@ defmodule AshPostgres.MigrationGeneratorTest do end end + describe "empty resources" do + setup do + on_exit(fn -> + File.rm_rf!("test_snapshots_path") + File.rm_rf!("test_migration_path") + end) + end + + test "empty resource does not generate migration files" do + defresource EmptyPost, "empty_posts" do + resource do + require_primary_key?(false) + end + + actions do + defaults([:read, :create]) + end + end + + defdomain([EmptyPost]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: false, + format: false, + auto_name: true + ) + + migration_files = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert migration_files == [] + + snapshot_files = + Path.wildcard("test_snapshots_path/**/*.json") + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert snapshot_files == [] + end + + test "resource with only primary key generates migration" do + defresource PostWithId, "posts_with_id" do + attributes do + uuid_primary_key(:id) + end + end + + defdomain([PostWithId]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: false, + format: false, + auto_name: true + ) + + migration_files = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert length(migration_files) == 1 + + snapshot_files = + Path.wildcard("test_snapshots_path/**/*.json") + |> Enum.reject(&String.contains?(&1, "extensions")) + + assert length(snapshot_files) == 1 + end + end + describe "creating initial snapshots" do setup do on_exit(fn -> From 60ab568d6747a98ad6db9ceae86c663397e54bac Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 25 Jul 2025 12:11:17 -0400 Subject: [PATCH 611/690] fix: ensure tenant is set on query for updates --- lib/data_layer.ex | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index d527bce6..e407eaff 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3139,6 +3139,14 @@ defmodule AshPostgres.DataLayer do changeset.context ) |> pkey_filter(changeset.data) + |> then(fn query -> + if changeset.tenant do + set_tenant(resource, query, changeset.tenant) + |> elem(1) + else + query + end + end) |> then(fn query -> Map.put( query, From 10b2162dfb5d20aea0375b370c22ddfb7761cfa1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 25 Jul 2025 12:12:42 -0400 Subject: [PATCH 612/690] chore: mix.lock --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 7706f2a1..ba960c35 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.31", "fea1abcbb58d00d1edf65ac5bccba5d679ca80754aaac6af7877cbf9056d4462", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "a7e07c8ae297dd764d92dd3c478e8bbb825fc0dd14a5cce83b85d19235510a74"}, + "ash": {:hex, :ash, "3.5.32", "ee717c49744374be7abe8997011115a4997917535e02d36146937fb6f89c19fe", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "4704f536682538ee3ae0e8f99ff3cef6af53df09ef3e7e550e202da9d5ce685c"}, "ash_sql": {:hex, :ash_sql, "0.2.87", "17197c643918cdaee657946a1998860402dcf53a980f7665bb81d1fa53c224e7", [:mix], [{:ash, ">= 3.5.25 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", "f82d6bf78f08bd9040af3adc28676965421598c88866074d8b1ccca65978d774"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.22", "b170fc64ae0cae54a7713cf3f96e7c96183f81d75f31746de080b27518b0f96e", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "d753129f693a214da32f39ba5b335f7ea6e1e87833e647b280f395b3c3742acf"}, + "igniter": {:hex, :igniter, "0.6.25", "e2774a4605c2bc9fc38f689232604aea0fc925c7966ae8e928fd9ea2fa9d300c", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "b1916e1e45796d5c371c7671305e81277231617eb58b1c120915aba237fbce6a"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, From 7b6bf1d595e31b29ad75cfcccc9e365146f5bb45 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 25 Jul 2025 12:13:17 -0400 Subject: [PATCH 613/690] chore: release version v2.6.12 --- CHANGELOG.md | 13 +++++++++++++ mix.exs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 996183c1..8b1f381a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.12](https://github.com/ash-project/ash_postgres/compare/v2.6.11...v2.6.12) (2025-07-25) + + + + +### Bug Fixes: + +* ensure tenant is set on query for updates by Zach Daniel + +### Improvements: + +* do not create snapshots for resources that have no attributes #571 (#599) by horberlan + ## [v2.6.11](https://github.com/ash-project/ash_postgres/compare/v2.6.10...v2.6.11) (2025-07-17) diff --git a/mix.exs b/mix.exs index 68afd199..da422e01 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.11" + @version "2.6.12" def project do [ From 2655ddcf6edf947ac77fb9b7b206271e386a5345 Mon Sep 17 00:00:00 2001 From: Emad Shaaban Date: Sun, 27 Jul 2025 08:26:58 +0300 Subject: [PATCH 614/690] fix: ensure tenant prefix is set only for resources with context multitenancy (#600) This fixes attribute multitenancy which is currently broken by this commit https://github.com/ash-project/ash_postgres/commit/60ab568d6747a98ad6db9ceae86c663397e54bac I thought updating set_tenant is the proper way to do it since it currently just adds the prefix to the query which only makes sense in context multitenancy Maybe attribute multitenancy can be handled there too? .. by adding a filter or something, but it currently seems to be handled somewhere else (not sure where) but I see the multitennacy attribute filter is added to my update queries. * chore: format --- lib/data_layer.ex | 8 ++++++-- lib/migration_generator/migration_generator.ex | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index e407eaff..506e0baf 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -893,8 +893,12 @@ defmodule AshPostgres.DataLayer do end @impl true - def set_tenant(_resource, query, tenant) do - {:ok, Map.put(Ecto.Query.put_query_prefix(query, to_string(tenant)), :__tenant__, tenant)} + def set_tenant(resource, query, tenant) do + if Ash.Resource.Info.multitenancy_strategy(resource) == :context do + {:ok, Map.put(Ecto.Query.put_query_prefix(query, to_string(tenant)), :__tenant__, tenant)} + else + {:ok, query} + end end @impl true diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 7222c7f4..74e0611d 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -2037,9 +2037,12 @@ defmodule AshPostgres.MigrationGenerator do | acc ]) else - unless opts.quiet do - Logger.info("Skipping migration for empty resource: #{snapshot.table} (no attributes, identities, indexes, statements, or constraints)") + if !opts.quiet do + Logger.info( + "Skipping migration for empty resource: #{snapshot.table} (no attributes, identities, indexes, statements, or constraints)" + ) end + acc end end From 424c536aa5371f6db668f885d3e5ae6a01a0f2ce Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 27 Jul 2025 01:27:09 -0400 Subject: [PATCH 615/690] chore: release version v2.6.13 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b1f381a..b214923a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.13](https://github.com/ash-project/ash_postgres/compare/v2.6.12...v2.6.13) (2025-07-27) + + + + +### Bug Fixes: + +* ensure tenant prefix is set only for resources with context multitenancy (#600) by Emad Shaaban + ## [v2.6.12](https://github.com/ash-project/ash_postgres/compare/v2.6.11...v2.6.12) (2025-07-25) diff --git a/mix.exs b/mix.exs index da422e01..8f83ed84 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.12" + @version "2.6.13" def project do [ From 1e271ca54ddb7968d3f889486bfd1e8be9e5efd3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 28 Jul 2025 11:28:48 -0400 Subject: [PATCH 616/690] fix: deduplicate identity keys fixes #602 --- lib/migration_generator/operation.ex | 2 +- mix.lock | 2 +- test/migration_generator_test.exs | 62 ++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 3b266494..13127d2a 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -130,7 +130,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do def index_keys(keys, all_tenants?, multitenancy) do if multitenancy.strategy == :attribute and not all_tenants? do - [multitenancy.attribute | keys] + Enum.uniq([multitenancy.attribute | keys]) else keys end diff --git a/mix.lock b/mix.lock index ba960c35..bc1b7e3e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.32", "ee717c49744374be7abe8997011115a4997917535e02d36146937fb6f89c19fe", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "4704f536682538ee3ae0e8f99ff3cef6af53df09ef3e7e550e202da9d5ce685c"}, - "ash_sql": {:hex, :ash_sql, "0.2.87", "17197c643918cdaee657946a1998860402dcf53a980f7665bb81d1fa53c224e7", [:mix], [{:ash, ">= 3.5.25 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", "f82d6bf78f08bd9040af3adc28676965421598c88866074d8b1ccca65978d774"}, + "ash_sql": {:hex, :ash_sql, "0.2.89", "ad4ad497263b586a7f3949ceea5d44620a36cb99a1ef0ff5f58f13a77d9b99ef", [:mix], [{:ash, ">= 3.5.25 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", "bd957aee95bbdf6326fc7a9212f9a2ab87329b99ee3646c373a87bb3c9968566"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 18577e13..1e666f72 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -2793,6 +2793,68 @@ defmodule AshPostgres.MigrationGeneratorTest do end end + describe "multitenancy identity with tenant attribute" do + setup do + on_exit(fn -> + File.rm_rf!("test_snapshots_path") + File.rm_rf!("test_migration_path") + end) + end + + test "identity including tenant attribute does not duplicate columns in index" do + defresource Channel, "channels" do + postgres do + table "channels" + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + + multitenancy do + strategy(:attribute) + attribute(:project_id) + end + + identities do + identity(:unique_type_per_project, [:project_id, :type]) + end + + attributes do + uuid_primary_key(:id) + attribute(:project_id, :uuid, allow_nil?: false, public?: true) + attribute(:type, :string, allow_nil?: false, public?: true) + attribute(:name, :string, public?: true) + end + end + + defdomain([Channel]) + + AshPostgres.MigrationGenerator.generate(Domain, + snapshot_path: "test_snapshots_path", + migration_path: "test_migration_path", + quiet: true, + format: false, + auto_name: true + ) + + assert [file] = + Path.wildcard("test_migration_path/**/*_migrate_resources*.exs") + |> Enum.reject(&String.contains?(&1, "extensions")) + + file_content = File.read!(file) + + # The index should only have project_id and type, not project_id twice + assert file_content =~ + ~S{create unique_index(:channels, [:project_id, :type], name: "channels_unique_type_per_project_index")} + + # Make sure it doesn't have duplicate columns + refute file_content =~ + ~S{create unique_index(:channels, [:project_id, :project_id, :type]} + end + end + describe "decimal precision and scale" do setup do on_exit(fn -> From 1b20a9bc9939d2a39067377027e32e855785ec64 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 29 Jul 2025 17:23:58 -0400 Subject: [PATCH 617/690] chore: release version v2.6.14 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b214923a..a51285bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.14](https://github.com/ash-project/ash_postgres/compare/v2.6.13...v2.6.14) (2025-07-29) + + + + +### Bug Fixes: + +* deduplicate identity keys by Zach Daniel + ## [v2.6.13](https://github.com/ash-project/ash_postgres/compare/v2.6.12...v2.6.13) (2025-07-27) diff --git a/mix.exs b/mix.exs index 8f83ed84..143f43ce 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.13" + @version "2.6.14" def project do [ From 996327077edefb5b67db96f8765168acc90bb2d6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 30 Jul 2025 10:44:12 -0400 Subject: [PATCH 618/690] fix: always set disable_async, and remove log level config --- lib/mix/tasks/ash_postgres.install.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index a984f2d8..5bfa39f4 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -341,9 +341,8 @@ if Code.ensure_loaded?(Igniter) do Ecto.Adapters.SQL.Sandbox ) |> Igniter.Project.Config.configure_new("test.exs", otp_app, [repo, :pool_size], 10) - |> Igniter.Project.Config.configure_new("test.exs", :ash, [:disable_async?], true) - |> Igniter.Project.Config.configure_new("test.exs", :logger, [:level], :warning) end + |> Igniter.Project.Config.configure_new("test.exs", :ash, [:disable_async?], true) end defp setup_data_case(igniter) do From baf4e3247e28346dc61d682756fd55948e4e4b61 Mon Sep 17 00:00:00 2001 From: Anatolij Werle Date: Sun, 3 Aug 2025 19:17:22 +0200 Subject: [PATCH 619/690] fix: Use new attribute source in down migration (#604) closes: #582 When an attribute is renamed, alongside other changes to it (like changing default or not null constraint), the generated up migration first renames the column, then modifies it. For the generated down migration, the order of operations is reversed, so we need to use the new column name when modifying the column, before renaming it back. --- lib/migration_generator/operation.ex | 2 +- test/migration_generator_test.exs | 37 ++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 13127d2a..88525c11 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -752,7 +752,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do up(%{ op | old_attribute: op.new_attribute, - new_attribute: op.old_attribute, + new_attribute: Map.put(op.old_attribute, :source, op.new_attribute.source), old_multitenancy: op.multitenancy, multitenancy: op.old_multitenancy }) diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 1e666f72..a12a09a0 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -825,8 +825,41 @@ defmodule AshPostgres.MigrationGeneratorTest do Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")) |> Enum.reject(&String.contains?(&1, "extensions")) - assert File.read!(file2) =~ ~S[rename table(:posts, prefix: "example"), :title, to: :name] - assert File.read!(file2) =~ ~S[modify :title, :text, null: true, default: nil] + contents = File.read!(file2) + + [up_side, down_side] = String.split(contents, "def down", parts: 2) + + up_side_parts = + String.split(up_side, "\n", trim: true) + |> Enum.map(&String.trim/1) + + up_rename_index = + Enum.find_index(up_side_parts, fn x -> + x == ~S[rename table(:posts, prefix: "example"), :title, to: :name] + end) + + up_modify_index = + Enum.find_index(up_side_parts, fn x -> + x == ~S[modify :name, :text, null: false, default: "fred"] + end) + + assert up_rename_index < up_modify_index + + down_side_parts = + String.split(down_side, "\n", trim: true) + |> Enum.map(&String.trim/1) + + down_modify_index = + Enum.find_index(down_side_parts, fn x -> + x == ~S[modify :name, :text, null: true, default: nil] + end) + + down_rename_index = + Enum.find_index(down_side_parts, fn x -> + x == ~S[rename table(:posts, prefix: "example"), :name, to: :title] + end) + + assert down_modify_index < down_rename_index end end From e19918967b7ea33f31d5a07a8a78f87c0ca5a772 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 6 Aug 2025 22:23:30 -0400 Subject: [PATCH 620/690] chore: release version v2.6.15 --- CHANGELOG.md | 11 +++++++++++ mix.exs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a51285bc..a9610b52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.15](https://github.com/ash-project/ash_postgres/compare/v2.6.14...v2.6.15) (2025-08-07) + + + + +### Bug Fixes: + +* Use new attribute source in down migration (#604) by Anatolij Werle + +* always set disable_async, and remove log level config by Zach Daniel + ## [v2.6.14](https://github.com/ash-project/ash_postgres/compare/v2.6.13...v2.6.14) (2025-07-29) diff --git a/mix.exs b/mix.exs index 143f43ce..549fbcd9 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.14" + @version "2.6.15" def project do [ From 7cd3019b543b528aa75a07d718cdd36f668f0bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Kostre=C5=A1evi=C4=87?= Date: Mon, 11 Aug 2025 15:53:36 +0200 Subject: [PATCH 621/690] test: Add distinct sort tests (#605) * Add support for sorting with filtered relationship tests * Add filter relationship tests --- .../test_repo/post_tags/20250810102512.json | 100 ++++++++++++++++++ .../test_repo/tags/20250810102512.json | 43 ++++++++ .../20250810102512_migrate_resources57.exs | 58 ++++++++++ test/calculation_test.exs | 33 +++++- test/sort_test.exs | 24 ++++- test/support/domain.ex | 2 + test/support/resources/post.ex | 6 ++ test/support/resources/post_tag.ex | 37 +++++++ test/support/resources/tag.ex | 47 ++++++++ 9 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/post_tags/20250810102512.json create mode 100644 priv/resource_snapshots/test_repo/tags/20250810102512.json create mode 100644 priv/test_repo/migrations/20250810102512_migrate_resources57.exs create mode 100644 test/support/resources/post_tag.ex create mode 100644 test/support/resources/tag.ex diff --git a/priv/resource_snapshots/test_repo/post_tags/20250810102512.json b/priv/resource_snapshots/test_repo/post_tags/20250810102512.json new file mode 100644 index 00000000..31adb69f --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_tags/20250810102512.json @@ -0,0 +1,100 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "post_tags_post_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "scale": null, + "size": null, + "source": "post_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "post_tags_tag_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "tags" + }, + "scale": null, + "size": null, + "source": "tag_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "BC5024D4E17EDD4ABDD0EF3D81EE5932FB63DF036E1BA81989D21A12496FE4A9", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "post_tags_unique_post_tag_index", + "keys": [ + { + "type": "atom", + "value": "post_id" + }, + { + "type": "atom", + "value": "tag_id" + } + ], + "name": "unique_post_tag", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "post_tags" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/tags/20250810102512.json b/priv/resource_snapshots/test_repo/tags/20250810102512.json new file mode 100644 index 00000000..4ca1e30a --- /dev/null +++ b/priv/resource_snapshots/test_repo/tags/20250810102512.json @@ -0,0 +1,43 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "0", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "importance", + "type": "bigint" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "9770C678D127B7ECA9FEAF174305101CC111417744E5D5712CD7F0A865D9877A", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "tags" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250810102512_migrate_resources57.exs b/priv/test_repo/migrations/20250810102512_migrate_resources57.exs new file mode 100644 index 00000000..1eb6911a --- /dev/null +++ b/priv/test_repo/migrations/20250810102512_migrate_resources57.exs @@ -0,0 +1,58 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources57 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:tags, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:importance, :bigint, null: false, default: 0) + end + + create table(:post_tags, primary_key: false) do + add( + :post_id, + references(:posts, + column: :id, + name: "post_tags_post_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + + add( + :tag_id, + references(:tags, + column: :id, + name: "post_tags_tag_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + ) + end + + create(unique_index(:post_tags, [:post_id, :tag_id], name: "post_tags_unique_post_tag_index")) + end + + def down do + drop_if_exists( + unique_index(:post_tags, [:post_id, :tag_id], name: "post_tags_unique_post_tag_index") + ) + + drop(constraint(:post_tags, "post_tags_post_id_fkey")) + + drop(constraint(:post_tags, "post_tags_tag_id_fkey")) + + drop(table(:post_tags)) + + drop(table(:tags)) + end +end diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 287ccf9a..68c975d9 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1,7 +1,19 @@ defmodule AshPostgres.CalculationTest do alias AshPostgres.Test.RecordTempEntity use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Account, Author, Comedian, Comment, Post, Record, TempEntity, User} + + alias AshPostgres.Test.{ + Account, + Author, + Comedian, + Comment, + Post, + PostTag, + Record, + Tag, + TempEntity, + User + } require Ash.Query import Ash.Expr @@ -1045,4 +1057,23 @@ defmodule AshPostgres.CalculationTest do |> Ash.Query.sort("posts_with_matching_title.relevance_score") |> Ash.read!() end + + test "sorting with filtered relationship by calculated field" do + tag = Ash.Changeset.for_create(Tag, :create) |> Ash.create!() + scores = [0, 3, 111, 22, 9, 4, 2, 33, 10] + + scores + |> Enum.each(fn score -> + post = + Ash.Changeset.for_create(Post, :create, %{score: score}) + |> Ash.create!() + + Ash.Changeset.for_create(PostTag, :create, post_id: post.id, tag_id: tag.id) + |> Ash.create!() + end) + + post_with_highest_score = Ash.load!(tag, :post_with_highest_score).post_with_highest_score + highest_score = hd(Enum.sort(scores, :desc)) + assert post_with_highest_score.score == highest_score + end end diff --git a/test/sort_test.exs b/test/sort_test.exs index 5ca9c922..cd5deddb 100644 --- a/test/sort_test.exs +++ b/test/sort_test.exs @@ -1,7 +1,7 @@ defmodule AshPostgres.SortTest do @moduledoc false use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Comment, Post, PostLink, PostView} + alias AshPostgres.Test.{Comment, Post, PostLink, PostTag, PostView, Tag} require Ash.Query require Ash.Sort @@ -267,4 +267,26 @@ defmodule AshPostgres.SortTest do |> Ash.Query.sort({Ash.Sort.expr_sort(views.time, :datetime), :desc}, title: :asc) ) end + + test "sorting with filtered relationship" do + tag = Ash.Changeset.for_create(Tag, :create) |> Ash.create!() + dates = [~D[2025-01-03], ~D[2025-01-05], ~D[2025-01-01], ~D[2025-01-10], ~D[2025-01-02]] + + dates + |> Enum.each(fn date -> + {:ok, datetime} = DateTime.new(date, ~T[00:00:00]) + + post = + Ash.Changeset.for_create(Post, :create, %{created_at: datetime}) + |> Ash.create!() + + Ash.Changeset.for_create(PostTag, :create, post_id: post.id, tag_id: tag.id) + |> Ash.create!() + end) + + latest_post = Ash.load!(tag, :latest_post).latest_post + expected_date = hd(Enum.sort(dates, :desc)) + + assert DateTime.to_date(latest_post.created_at) == expected_date + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index c8c596d5..58074271 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -42,6 +42,8 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.CSV) resource(AshPostgres.Test.StandupClub) resource(AshPostgres.Test.Punchline) + resource(AshPostgres.Test.Tag) + resource(AshPostgres.Test.PostTag) end authorization do diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 79eddd34..1f90535c 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -777,6 +777,12 @@ defmodule AshPostgres.Test.Post do sort: [Ash.Sort.expr_sort(parent(post_followers.order), :integer)] ) + many_to_many :tags, AshPostgres.Test.Tag do + public?(true) + through(AshPostgres.Test.PostTag) + sort(importance: :desc) + end + has_many(:views, AshPostgres.Test.PostView) do public?(true) end diff --git a/test/support/resources/post_tag.ex b/test/support/resources/post_tag.ex new file mode 100644 index 00000000..c1cb13e8 --- /dev/null +++ b/test/support/resources/post_tag.ex @@ -0,0 +1,37 @@ +defmodule AshPostgres.Test.PostTag do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + require Ash.Sort + + postgres do + table "post_tags" + repo AshPostgres.TestRepo + end + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + end + + identities do + identity(:unique_post_tag, [:post_id, :tag_id]) + end + + relationships do + belongs_to :post, AshPostgres.Test.Post do + primary_key?(true) + public?(true) + allow_nil?(false) + end + + belongs_to :tag, AshPostgres.Test.Tag do + primary_key?(true) + public?(true) + allow_nil?(false) + end + end +end diff --git a/test/support/resources/tag.ex b/test/support/resources/tag.ex new file mode 100644 index 00000000..20d8d5a8 --- /dev/null +++ b/test/support/resources/tag.ex @@ -0,0 +1,47 @@ +defmodule AshPostgres.Test.Tag do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + require Ash.Sort + + postgres do + table "tags" + repo AshPostgres.TestRepo + end + + actions do + defaults([:read]) + + create :create do + accept(:*) + end + end + + attributes do + uuid_primary_key(:id) + attribute(:importance, :integer, allow_nil?: false, default: 0, public?: true) + end + + relationships do + many_to_many :posts, AshPostgres.Test.Post do + through(AshPostgres.Test.PostTag) + public?(true) + end + + has_one :latest_post, AshPostgres.Test.Post do + public?(true) + no_attributes?(true) + filter(expr(tags.id == parent(id))) + sort(created_at: :desc) + end + + has_one :post_with_highest_score, AshPostgres.Test.Post do + public?(true) + no_attributes?(true) + filter(expr(tags.id == parent(id))) + sort(score_after_winning: :desc) + end + end +end From d1236799194d4d2d4f1f5f655cc173f2c5a21d27 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 11 Aug 2025 17:39:35 -0400 Subject: [PATCH 622/690] improvement: Unrelated aggregates (#606) --- lib/data_layer.ex | 1 + mix.exs | 4 +- mix.lock | 8 +- .../unrelated_profiles/20250731124648.json | 91 ++++ .../unrelated_reports/20250731124648.json | 79 +++ .../20250731124648.json | 91 ++++ .../unrelated_users/20250731124648.json | 79 +++ .../20250731124648_migrate_resources57.exs | 59 ++ test/support/domain.ex | 4 + test/support/unrelated_aggregates/profile.ex | 36 ++ test/support/unrelated_aggregates/report.ex | 33 ++ .../unrelated_aggregates/secure_profile.ex | 38 ++ test/support/unrelated_aggregates/user.ex | 154 ++++++ test/unrelated_aggregates_test.exs | 507 ++++++++++++++++++ 14 files changed, 1178 insertions(+), 6 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json create mode 100644 priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json create mode 100644 priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json create mode 100644 priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json create mode 100644 priv/test_repo/migrations/20250731124648_migrate_resources57.exs create mode 100644 test/support/unrelated_aggregates/profile.ex create mode 100644 test/support/unrelated_aggregates/report.ex create mode 100644 test/support/unrelated_aggregates/secure_profile.ex create mode 100644 test/support/unrelated_aggregates/user.ex create mode 100644 test/unrelated_aggregates_test.exs diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 506e0baf..3fa1aa30 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -721,6 +721,7 @@ defmodule AshPostgres.DataLayer do when type in [:count, :sum, :first, :list, :avg, :max, :min, :exists, :custom], do: true + def can?(_, {:aggregate, :unrelated}), do: true def can?(_, :aggregate_filter), do: true def can?(_, :aggregate_sort), do: true def can?(_, :calculate), do: true diff --git a/mix.exs b/mix.exs index 549fbcd9..0ff8df8e 100644 --- a/mix.exs +++ b/mix.exs @@ -166,8 +166,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.5 and >= 3.5.13")}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")}, + {:ash, ash_version(github: "ash-project/ash", branch: "main")}, + {:ash_sql, ash_sql_version(github: "ash-project/ash_sql", branch: "main")}, {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, diff --git a/mix.lock b/mix.lock index bc1b7e3e..3c6f7826 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.32", "ee717c49744374be7abe8997011115a4997917535e02d36146937fb6f89c19fe", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.65 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", "4704f536682538ee3ae0e8f99ff3cef6af53df09ef3e7e550e202da9d5ce685c"}, - "ash_sql": {:hex, :ash_sql, "0.2.89", "ad4ad497263b586a7f3949ceea5d44620a36cb99a1ef0ff5f58f13a77d9b99ef", [:mix], [{:ash, ">= 3.5.25 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", "bd957aee95bbdf6326fc7a9212f9a2ab87329b99ee3646c373a87bb3c9968566"}, + "ash": {:git, "https://github.com/ash-project/ash.git", "471274d2f75a4bda6405c5630b72f9323d572260", [branch: "main"]}, + "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "40c9bcb905603dbcee2bc064f37c6f5ce30da7c7", [branch: "main"]}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.25", "e2774a4605c2bc9fc38f689232604aea0fc925c7966ae8e928fd9ea2fa9d300c", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "b1916e1e45796d5c371c7671305e81277231617eb58b1c120915aba237fbce6a"}, + "igniter": {:hex, :igniter, "0.6.26", "a6b4f6680a7e158bd13cd3b2be047102e42c046b3b240578d68d89d1a39a83fa", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "a4f8c404fc4cbc05a1b536c8125ae64909e3a02d5f972ffe6a3a2ebd75530f3c"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -37,7 +37,7 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, - "postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"}, + "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, "reactor": {:hex, :reactor, "0.15.6", "d717f9add549b25a089a94c90197718d2d838e35d81dd776b1d81587d4cf2aaa", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "74db98165e3644d86e0f723672d91ceca4339eaa935bcad7e78bf146a46d77b9"}, "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, diff --git a/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json b/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json new file mode 100644 index 00000000..a3c884ee --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json @@ -0,0 +1,91 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "age", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "bio", + "type": "text" + }, + { + "allow_nil?": true, + "default": "true", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "active", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "owner_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "B32650B5196D79814F5D5EF0481C757CDE5F7545E787EA911A13B9B9CBD38E7E", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "unrelated_profiles" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json b/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json new file mode 100644 index 00000000..327cce49 --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json @@ -0,0 +1,79 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "title", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "author_name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "score", + "type": "bigint" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "728B41F3FC4BC58102261057925992766C0A3D9ED3AD7D16B887CCF8EF6B6E19", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "unrelated_reports" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json b/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json new file mode 100644 index 00000000..9df541b0 --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json @@ -0,0 +1,91 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "age", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "true", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "active", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "owner_id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "department", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "56BB9374A010E8E23144743DEDD10B6557BCD002338D1B06A35431AB0320F88B", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "unrelated_secure_profiles" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json b/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json new file mode 100644 index 00000000..4d83b926 --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json @@ -0,0 +1,79 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "age", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "email", + "type": "text" + }, + { + "allow_nil?": true, + "default": "\"user\"", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "role", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "E56D245A9DA955A309FDF1BD11C215F3056FF9BA7A4D4D3A3D5E285F0D183AC2", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "unrelated_users" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250731124648_migrate_resources57.exs b/priv/test_repo/migrations/20250731124648_migrate_resources57.exs new file mode 100644 index 00000000..3493fd6b --- /dev/null +++ b/priv/test_repo/migrations/20250731124648_migrate_resources57.exs @@ -0,0 +1,59 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources57 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:unrelated_reports, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:title, :text) + add(:author_name, :text) + add(:score, :bigint) + + add(:inserted_at, :utc_datetime, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + ) + end + + create table(:unrelated_users, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:name, :text) + add(:age, :bigint) + add(:email, :text) + add(:role, :text, default: "user") + end + + create table(:unrelated_profiles, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:name, :text) + add(:age, :bigint) + add(:bio, :text) + add(:active, :boolean, default: true) + add(:owner_id, :uuid) + end + + create table(:unrelated_secure_profiles, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:name, :text) + add(:age, :bigint) + add(:active, :boolean, default: true) + add(:owner_id, :uuid) + add(:department, :text) + end + end + + def down do + drop(table(:unrelated_secure_profiles)) + + drop(table(:unrelated_profiles)) + + drop(table(:unrelated_users)) + + drop(table(:unrelated_reports)) + end +end diff --git a/test/support/domain.ex b/test/support/domain.ex index 58074271..58802a18 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -44,6 +44,10 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Punchline) resource(AshPostgres.Test.Tag) resource(AshPostgres.Test.PostTag) + resource(AshPostgres.Test.UnrelatedAggregatesTest.Profile) + resource(AshPostgres.Test.UnrelatedAggregatesTest.SecureProfile) + resource(AshPostgres.Test.UnrelatedAggregatesTest.Report) + resource(AshPostgres.Test.UnrelatedAggregatesTest.User) end authorization do diff --git a/test/support/unrelated_aggregates/profile.ex b/test/support/unrelated_aggregates/profile.ex new file mode 100644 index 00000000..87a9fa9f --- /dev/null +++ b/test/support/unrelated_aggregates/profile.ex @@ -0,0 +1,36 @@ +defmodule AshPostgres.Test.UnrelatedAggregatesTest.Profile do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + postgres do + table("unrelated_profiles") + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + attribute(:age, :integer, public?: true) + attribute(:bio, :string, public?: true) + attribute(:active, :boolean, default: true, public?: true) + attribute(:owner_id, :uuid, public?: true) + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + policies do + # Allow unrestricted access for most tests, but we'll create a SecureProfile for auth tests + policy action_type([:create, :update, :destroy]) do + authorize_if(always()) + end + + policy action_type(:read) do + authorize_if(always()) + end + end +end diff --git a/test/support/unrelated_aggregates/report.ex b/test/support/unrelated_aggregates/report.ex new file mode 100644 index 00000000..652df03c --- /dev/null +++ b/test/support/unrelated_aggregates/report.ex @@ -0,0 +1,33 @@ +defmodule AshPostgres.Test.UnrelatedAggregatesTest.Report do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("unrelated_reports") + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + attribute(:title, :string, public?: true) + attribute(:author_name, :string, public?: true) + attribute(:score, :integer, public?: true) + + attribute(:inserted_at, :utc_datetime, + public?: true, + default: &DateTime.utc_now/0, + allow_nil?: false + ) + end + + actions do + defaults([:read, :destroy, update: :*]) + + create :create do + primary?(true) + accept([:title, :author_name, :score, :inserted_at]) + end + end +end diff --git a/test/support/unrelated_aggregates/secure_profile.ex b/test/support/unrelated_aggregates/secure_profile.ex new file mode 100644 index 00000000..3f50bf73 --- /dev/null +++ b/test/support/unrelated_aggregates/secure_profile.ex @@ -0,0 +1,38 @@ +defmodule AshPostgres.Test.UnrelatedAggregatesTest.SecureProfile do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + postgres do + table("unrelated_secure_profiles") + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + attribute(:age, :integer, public?: true) + attribute(:active, :boolean, default: true, public?: true) + attribute(:owner_id, :uuid, public?: true) + attribute(:department, :string, public?: true) + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + policies do + # Allow creation/updates for testing setup + policy action_type([:create, :update, :destroy]) do + authorize_if(always()) + end + + # Only allow users to see their own profiles, or admins to see all + policy action_type(:read) do + authorize_if(actor_attribute_equals(:role, :admin)) + authorize_if(expr(owner_id == ^actor(:id))) + end + end +end diff --git a/test/support/unrelated_aggregates/user.ex b/test/support/unrelated_aggregates/user.ex new file mode 100644 index 00000000..ce143489 --- /dev/null +++ b/test/support/unrelated_aggregates/user.ex @@ -0,0 +1,154 @@ +defmodule AshPostgres.Test.UnrelatedAggregatesTest.User do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + alias AshPostgres.Test.UnrelatedAggregatesTest.{Profile, Report, SecureProfile} + + postgres do + table("unrelated_users") + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, public?: true) + attribute(:age, :integer, public?: true) + attribute(:email, :string, public?: true) + attribute(:role, :atom, public?: true, default: :user) + end + + # Test basic unrelated aggregates + aggregates do + # Count of profiles with matching name + count :matching_name_profiles_count, Profile do + filter(expr(name == parent(name))) + public?(true) + end + + # Count of all active profiles (no parent filter) + count :total_active_profiles, Profile do + filter(expr(active == true)) + public?(true) + end + + # First report with matching author name + first :latest_authored_report, Report, :title do + filter(expr(author_name == parent(name))) + sort(inserted_at: :desc) + public?(true) + end + + # Sum of report scores for matching author + sum :total_report_score, Report, :score do + filter(expr(author_name == parent(name))) + public?(true) + end + + # Exists check for profiles with same name + exists :has_matching_name_profile, Profile do + filter(expr(name == parent(name))) + public?(true) + end + + # List of all profile names with same name (should be just one usually) + list :matching_profile_names, Profile, :name do + filter(expr(name == parent(name))) + public?(true) + end + + # Max age of profiles with same name + max :max_age_same_name, Profile, :age do + filter(expr(name == parent(name))) + public?(true) + end + + # Min age of profiles with same name + min :min_age_same_name, Profile, :age do + filter(expr(name == parent(name))) + public?(true) + end + + # Average age of profiles with same name + avg :avg_age_same_name, Profile, :age do + filter(expr(name == parent(name))) + public?(true) + end + + # Secure aggregate - should respect authorization policies + count :secure_profile_count, SecureProfile do + filter(expr(name == parent(name))) + public?(true) + end + end + + # Test unrelated aggregates in calculations + calculations do + calculate :matching_profiles_summary, + :string, + expr("Found " <> type(matching_name_profiles_count, :string) <> " profiles") do + public?(true) + end + + calculate :inline_profile_count, + :integer, + expr(count(Profile, filter: expr(name == parent(name)))) do + public?(true) + end + + calculate :inline_latest_report_title, + :string, + expr( + first(Report, + field: :title, + query: [ + filter: expr(author_name == parent(name)), + sort: [inserted_at: :desc] + ] + ) + ) do + public?(true) + end + + calculate :inline_total_score, + :integer, + expr( + sum(Report, + field: :score, + query: [ + filter: expr(author_name == parent(name)) + ] + ) + ) do + public?(true) + end + + calculate :complex_calculation, + :map, + expr(%{ + profile_count: count(Profile, filter: expr(name == parent(name))), + latest_report: + first(Report, + field: :title, + query: [ + filter: expr(author_name == parent(name)), + sort: [inserted_at: :desc] + ] + ), + total_score: + sum(Report, + field: :score, + query: [ + filter: expr(author_name == parent(name)) + ] + ) + }) do + public?(true) + end + end + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end +end diff --git a/test/unrelated_aggregates_test.exs b/test/unrelated_aggregates_test.exs new file mode 100644 index 00000000..09a15740 --- /dev/null +++ b/test/unrelated_aggregates_test.exs @@ -0,0 +1,507 @@ +defmodule AshPostgres.Test.UnrelatedAggregatesTest do + @moduledoc false + use AshPostgres.RepoCase, async: false + + require Ash.Query + import Ash.Expr + + alias AshPostgres.Test.UnrelatedAggregatesTest.{Profile, Report, SecureProfile, User} + + describe "basic unrelated aggregate definitions" do + test "aggregates are properly defined with related?: false" do + aggregates = Ash.Resource.Info.aggregates(User) + + count_agg = Enum.find(aggregates, &(&1.name == :matching_name_profiles_count)) + assert count_agg + assert count_agg.related? == false + assert count_agg.resource == Profile + assert count_agg.kind == :count + assert count_agg.relationship_path == [] + + first_agg = Enum.find(aggregates, &(&1.name == :latest_authored_report)) + assert first_agg + assert first_agg.related? == false + assert first_agg.resource == Report + assert first_agg.kind == :first + assert first_agg.field == :title + + sum_agg = Enum.find(aggregates, &(&1.name == :total_report_score)) + assert sum_agg + assert sum_agg.related? == false + assert sum_agg.resource == Report + assert sum_agg.kind == :sum + assert sum_agg.field == :score + end + + test "unrelated aggregates support all aggregate kinds" do + aggregates = Ash.Resource.Info.aggregates(User) + aggregate_names = Enum.map(aggregates, & &1.name) + + # Verify all kinds are supported + # count + assert :matching_name_profiles_count in aggregate_names + # first + assert :latest_authored_report in aggregate_names + # sum + assert :total_report_score in aggregate_names + # exists + assert :has_matching_name_profile in aggregate_names + # list + assert :matching_profile_names in aggregate_names + # max + assert :max_age_same_name in aggregate_names + # min + assert :min_age_same_name in aggregate_names + # avg + assert :avg_age_same_name in aggregate_names + end + + test "can define aggregates without parent filters" do + aggregates = Ash.Resource.Info.aggregates(User) + total_active_agg = Enum.find(aggregates, &(&1.name == :total_active_profiles)) + + assert total_active_agg + assert total_active_agg.related? == false + assert total_active_agg.resource == Profile + # Should have filter but no parent() reference + end + end + + describe "loading unrelated aggregates" do + setup do + # Create test data + {:ok, user1} = Ash.create(User, %{name: "John", email: "john@example.com"}) + {:ok, user2} = Ash.create(User, %{name: "Jane", email: "jane@example.com"}) + + {:ok, _profile1} = Ash.create(Profile, %{name: "John", age: 25, active: true}) + {:ok, _profile2} = Ash.create(Profile, %{name: "John", age: 30, active: true}) + {:ok, _profile3} = Ash.create(Profile, %{name: "Jane", age: 28, active: true}) + {:ok, _profile4} = Ash.create(Profile, %{name: "Bob", age: 35, active: false}) + + base_time = ~U[2024-01-01 12:00:00Z] + + {:ok, _report1} = + Ash.create(Report, %{ + title: "John's First Report", + author_name: "John", + score: 85, + inserted_at: base_time + }) + + {:ok, _report2} = + Ash.create(Report, %{ + title: "John's Latest Report", + author_name: "John", + score: 92, + inserted_at: DateTime.add(base_time, 3600, :second) + }) + + {:ok, _report3} = + Ash.create(Report, %{ + title: "Jane's Report", + author_name: "Jane", + score: 78 + }) + + %{user1: user1, user2: user2} + end + + test "can load count unrelated aggregates", %{user1: user1, user2: user2} do + # Load users with aggregates + users = + User + |> Ash.Query.load([:matching_name_profiles_count, :total_active_profiles]) + |> Ash.read!() + + john = Enum.find(users, &(&1.id == user1.id)) + jane = Enum.find(users, &(&1.id == user2.id)) + + # John should have 2 matching profiles + assert john.matching_name_profiles_count == 2 + # Both should see 3 total active profiles (John x2, Jane x1) + assert john.total_active_profiles == 3 + + # Jane should have 1 matching profile + assert jane.matching_name_profiles_count == 1 + assert jane.total_active_profiles == 3 + end + + test "can load first unrelated aggregates", %{user1: user1} do + user = + User + |> Ash.Query.filter(id == ^user1.id) + |> Ash.Query.load(:latest_authored_report) + |> Ash.read_one!() + + # Should get the latest report title + assert user.latest_authored_report == "John's Latest Report" + end + + test "can load sum unrelated aggregates", %{user1: user1, user2: user2} do + users = + User + |> Ash.Query.load(:total_report_score) + |> Ash.read!() + + john = Enum.find(users, &(&1.id == user1.id)) + jane = Enum.find(users, &(&1.id == user2.id)) + + # John's total score: 85 + 92 = 177 + assert john.total_report_score == 177 + # Jane's total score: 78 + assert jane.total_report_score == 78 + end + + test "can load exists unrelated aggregates", %{user1: user1} do + user = + User + |> Ash.Query.filter(id == ^user1.id) + |> Ash.Query.load(:has_matching_name_profile) + |> Ash.read_one!() + + assert user.has_matching_name_profile == true + end + + test "can load list unrelated aggregates", %{user1: user1} do + user = + User + |> Ash.Query.filter(id == ^user1.id) + |> Ash.Query.load(:matching_profile_names) + |> Ash.read_one!() + + # Should have two "John" entries + assert length(user.matching_profile_names) == 2 + assert Enum.all?(user.matching_profile_names, &(&1 == "John")) + end + + test "can load min/max/avg unrelated aggregates", %{user1: user1} do + user = + User + |> Ash.Query.filter(id == ^user1.id) + |> Ash.Query.load([:min_age_same_name, :max_age_same_name, :avg_age_same_name]) + |> Ash.read_one!() + + # John profiles have ages 25 and 30 + assert user.min_age_same_name == 25 + assert user.max_age_same_name == 30 + assert user.avg_age_same_name == 27.5 + end + end + + describe "unrelated aggregates in calculations" do + setup do + {:ok, user} = Ash.create(User, %{name: "Alice", email: "alice@example.com"}) + {:ok, _profile} = Ash.create(Profile, %{name: "Alice", age: 25, active: true}) + + {:ok, _report} = + Ash.create(Report, %{ + title: "Alice's Research", + author_name: "Alice", + score: 95, + inserted_at: ~U[2024-01-01 12:00:00Z] + }) + + %{user: user} + end + + test "calculations using named unrelated aggregates work", %{user: user} do + user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.load(:matching_profiles_summary) + |> Ash.read_one!() + + assert user.matching_profiles_summary == "Found 1 profiles" + end + + test "inline unrelated aggregates in calculations work", %{user: user} do + user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.load([ + :inline_profile_count, + :inline_latest_report_title, + :inline_total_score + ]) + |> Ash.read_one!() + + assert user.inline_profile_count == 1 + assert user.inline_latest_report_title == "Alice's Research" + assert user.inline_total_score == 95 + end + + test "complex calculations with multiple inline unrelated aggregates work", %{user: user} do + user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.load(:complex_calculation) + |> Ash.read_one!() + + assert user.complex_calculation == %{ + profile_count: 1, + latest_report: "Alice's Research", + total_score: 95 + } + end + end + + describe "data layer capability checking" do + test "Postgres data layer should support unrelated aggregates" do + # This will fail until we implement the capability + assert AshPostgres.DataLayer.can?(nil, {:aggregate, :unrelated}) == true + end + + test "error when data layer doesn't support unrelated aggregates" do + # Test with a mock data layer that doesn't support unrelated aggregates + # This will be relevant when we add the capability checking + end + end + + describe "authorization with unrelated aggregates" do + # These tests verify that authorization works properly for unrelated aggregates + # The main concern is that unrelated aggregates don't have relationship paths, + # so the authorization logic must handle this correctly + + test "unrelated aggregates work without relationship path authorization errors" do + # This test verifies that unrelated aggregates don't trigger the + # :lists.droplast([]) error that was happening before the fix + {:ok, user} = Ash.create(User, %{name: "AuthTest", email: "auth@example.com"}) + {:ok, _profile} = Ash.create(Profile, %{name: "AuthTest", age: 25, active: true}) + + # This should not raise authorization errors + user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.load(:matching_name_profiles_count) + |> Ash.read_one!() + + assert user.matching_name_profiles_count == 1 + end + + test "unrelated aggregates in calculations don't cause authorization errors" do + # Test that the authorization logic correctly handles unrelated aggregates + # when they're referenced in calculations + {:ok, user} = Ash.create(User, %{name: "CalcAuth", email: "calcauth@example.com"}) + {:ok, _profile} = Ash.create(Profile, %{name: "CalcAuth", age: 30, active: true}) + + # This should not raise authorization errors + user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.load(:matching_profiles_summary) + |> Ash.read_one!() + + assert user.matching_profiles_summary == "Found 1 profiles" + end + + test "multiple unrelated aggregates can be loaded together without authorization issues" do + # Test loading multiple unrelated aggregates simultaneously + {:ok, user} = Ash.create(User, %{name: "MultiAuth", email: "multi@example.com"}) + {:ok, _profile} = Ash.create(Profile, %{name: "MultiAuth", age: 28, active: true}) + + {:ok, _report} = + Ash.create(Report, %{ + title: "MultiAuth Report", + author_name: "MultiAuth", + score: 88, + inserted_at: ~U[2024-01-01 15:00:00Z] + }) + + # Loading multiple unrelated aggregates should work + user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.load([ + :matching_name_profiles_count, + :total_active_profiles, + :latest_authored_report, + :total_report_score + ]) + |> Ash.read_one!() + + assert user.matching_name_profiles_count == 1 + # Could include profiles from other tests + assert user.total_active_profiles >= 1 + assert user.latest_authored_report == "MultiAuth Report" + assert user.total_report_score == 88 + end + + test "unrelated aggregates respect target resource authorization policies" do + admin_user = Ash.create!(User, %{name: "Admin", email: "admin@test.com", role: :admin}) + regular_user1 = Ash.create!(User, %{name: "User1", email: "user1@test.com", role: :user}) + regular_user2 = Ash.create!(User, %{name: "User1", email: "user2@test.com", role: :user}) + + Ash.create!(SecureProfile, %{ + name: "User1", + age: 25, + active: true, + owner_id: regular_user1.id, + department: "Engineering" + }) + + Ash.create!(SecureProfile, %{ + name: "User1", + age: 30, + active: true, + owner_id: regular_user2.id, + department: "Marketing" + }) + + Ash.create!(SecureProfile, %{ + name: "Admin", + age: 35, + active: true, + owner_id: admin_user.id, + department: "Management" + }) + + user1_result = + User + |> Ash.Query.filter(id == ^regular_user1.id) + |> Ash.Query.load(:secure_profile_count) + |> Ash.read_one!(actor: regular_user1, authorize?: true) + + assert user1_result.secure_profile_count == 1 + + user2_result = + User + |> Ash.Query.filter(id == ^regular_user2.id) + |> Ash.Query.load(:secure_profile_count) + |> Ash.read_one!(actor: regular_user2, authorize?: true) + + assert user2_result.secure_profile_count == 1 + + admin_as_user1 = + User + |> Ash.Query.filter(id == ^regular_user1.id) + |> Ash.Query.load(:secure_profile_count) + |> Ash.read_one!(actor: admin_user, authorize?: true) + + assert admin_as_user1.secure_profile_count == 2 + + admin_result = + User + |> Ash.Query.filter(id == ^admin_user.id) + |> Ash.Query.load(:secure_profile_count) + |> Ash.read_one!(actor: admin_user, authorize?: true) + + assert admin_result.secure_profile_count == 1 + end + end + + describe "edge cases" do + test "unrelated aggregates work with empty result sets" do + users = + User + |> Ash.Query.filter(name == "NonExistent") + |> Ash.Query.load(:matching_name_profiles_count) + |> Ash.read!() + + # Should be empty, but aggregate should still work + assert users == [] + end + + test "unrelated aggregates work with filters that return no results" do + {:ok, user} = Ash.create(User, %{name: "Unique", email: "unique@example.com"}) + + # No profiles with name "Unique" exist + loaded_user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.load(:matching_name_profiles_count) + |> Ash.read_one!() + + assert loaded_user.matching_name_profiles_count == 0 + end + + test "unrelated aggregates work with complex filter expressions" do + {:ok, user} = + Ash.create(User, %{name: "ComplexTest", age: 25, email: "complex@example.com"}) + + # Create profiles with various attributes + {:ok, _profile1} = + Ash.create(Profile, %{name: "ComplexTest", age: 25, bio: "Bio contains ComplexTest"}) + + {:ok, _profile2} = + Ash.create(Profile, %{name: "ComplexTest", age: 30, bio: "Different bio"}) + + {:ok, _profile3} = + Ash.create(Profile, %{name: "Other", age: 25, bio: "ComplexTest mentioned"}) + + # Test parent() with boolean AND + loaded_user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.aggregate(:same_name_and_age, :count, Profile, + query: [filter: expr(name == parent(name) and age == parent(age))] + ) + |> Ash.read_one!() + + assert loaded_user.aggregates.same_name_and_age == 1 + + # Test parent() with OR conditions + loaded_user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.aggregate(:name_or_bio_match, :count, Profile, + query: [filter: expr(name == parent(name) or contains(bio, parent(name)))] + ) + |> Ash.read_one!() + + assert loaded_user.aggregates.name_or_bio_match == 3 + + # Test parent() with comparison operators + loaded_user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.aggregate(:older_profiles, :count, Profile, + query: [filter: expr(name == parent(name) and age > parent(age))] + ) + |> Ash.read_one!() + + assert loaded_user.aggregates.older_profiles == 1 + end + + test "parent() works with nested conditional expressions" do + {:ok, user} = Ash.create(User, %{name: "NestedTest", age: 30, email: "nested@example.com"}) + + {:ok, _profile1} = Ash.create(Profile, %{name: "NestedTest", age: 25, bio: "Young"}) + {:ok, _profile2} = Ash.create(Profile, %{name: "NestedTest", age: 35, bio: "Old"}) + {:ok, _profile3} = Ash.create(Profile, %{name: "Other", age: 30, bio: "Same age"}) + + # Test nested parentheses with parent() + loaded_user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.aggregate(:complex_condition, :count, Profile, + query: [filter: expr(name == parent(name) and (age < parent(age) or age > parent(age)))] + ) + |> Ash.read_one!() + + assert loaded_user.aggregates.complex_condition == 2 + end + + test "parent() works with string functions" do + {:ok, user} = Ash.create(User, %{name: "StringTest", email: "string@example.com"}) + + {:ok, _profile1} = + Ash.create(Profile, %{name: "StringTest", bio: "StringTest is mentioned here"}) + + {:ok, _profile2} = + Ash.create(Profile, %{name: "DifferentName", bio: "StringTest appears in bio"}) + + {:ok, _profile3} = Ash.create(Profile, %{name: "StringTest", bio: "No mention"}) + + # Test parent() with string contains function + loaded_user = + User + |> Ash.Query.filter(id == ^user.id) + |> Ash.Query.aggregate(:bio_mentions_name, :count, Profile, + query: [filter: expr(contains(bio, parent(name)))] + ) + |> Ash.read_one!() + + assert loaded_user.aggregates.bio_mentions_name == 2 + end + end +end From d83157df2ee0a27e5d7fe4450ca44a43a0d9454b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 21 Aug 2025 18:33:40 -0400 Subject: [PATCH 623/690] chore: update ash/ash_sql --- mix.exs | 4 ++-- mix.lock | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mix.exs b/mix.exs index 0ff8df8e..e9bd0ed8 100644 --- a/mix.exs +++ b/mix.exs @@ -166,8 +166,8 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version(github: "ash-project/ash", branch: "main")}, - {:ash_sql, ash_sql_version(github: "ash-project/ash_sql", branch: "main")}, + {:ash, ash_version("~> 3.5 and >= 3.5.35")}, + {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.90")}, {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, diff --git a/mix.lock b/mix.lock index 3c6f7826..a6ba65e8 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:git, "https://github.com/ash-project/ash.git", "471274d2f75a4bda6405c5630b72f9323d572260", [branch: "main"]}, - "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "40c9bcb905603dbcee2bc064f37c6f5ce30da7c7", [branch: "main"]}, + "ash": {:hex, :ash, "3.5.35", "ff63b9d3670a05ad036ecc8732c0143770aff4e23f07662931a9ebd1f4aba3c4", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.68 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", "b6ff48f80efabcc1867af9847c8656fa376d9b800e8988b82ec0a42bee4f6b58"}, + "ash_sql": {:hex, :ash_sql, "0.2.90", "6b533e963e4b7c0855654597d8eb7bb87c30db0be7328628cb9bb63e2e547a54", [:mix], [{:ash, ">= 3.5.35 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", "57a7235f22f01381b1a2d63364c353fe6fa31278f3bbd402aacab6dba78a7e6b"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.26", "a6b4f6680a7e158bd13cd3b2be047102e42c046b3b240578d68d89d1a39a83fa", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "a4f8c404fc4cbc05a1b536c8125ae64909e3a02d5f972ffe6a3a2ebd75530f3c"}, + "igniter": {:hex, :igniter, "0.6.28", "9db10192f19f10b924f14c805f5b2ad992617fccaff9cf9582b7f065d562d4d8", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "ad9369d626aeca21079ef17661a2672fb32598610c5e5bccae2537efd36b27d4"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -44,7 +44,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.67", "67626cb9f59ea4b1c5aa85d4afdd025e0740cbd49ed82665d0a40ff007d7fd4b", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "c8575402e3afc66871362e821bece890536d16319cdb758c5fb2d1250182e46f"}, + "spark": {:hex, :spark, "2.2.68", "4c4547c88d73311e3157bc402ab27f3a7bbd5e55a2ee92bcf7cd3a0a475d201e", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "2fa4dd89801415a098a421589633f0e3df7ed9ff4046e80a65d35a413bc0d194"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"}, From 3d1fe5e744c3815b5f644cece4d68c087c8346e6 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 21 Aug 2025 18:49:18 -0400 Subject: [PATCH 624/690] chore: release version v2.6.16 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9610b52..7df2c49a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.16](https://github.com/ash-project/ash_postgres/compare/v2.6.15...v2.6.16) (2025-08-21) + + + + +### Improvements: + +* Unrelated aggregates (#606) by Zach Daniel + ## [v2.6.15](https://github.com/ash-project/ash_postgres/compare/v2.6.14...v2.6.15) (2025-08-07) diff --git a/mix.exs b/mix.exs index e9bd0ed8..2d3f04b1 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.15" + @version "2.6.16" def project do [ From ed22f3e699e30069a3048f5f2566d1bd45055805 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 23 Aug 2025 10:37:21 -0400 Subject: [PATCH 625/690] chore: rename migration file --- ...e_resources57.exs => 20250810102512_migrate_resources58.exs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename priv/test_repo/migrations/{20250810102512_migrate_resources57.exs => 20250810102512_migrate_resources58.exs} (95%) diff --git a/priv/test_repo/migrations/20250810102512_migrate_resources57.exs b/priv/test_repo/migrations/20250810102512_migrate_resources58.exs similarity index 95% rename from priv/test_repo/migrations/20250810102512_migrate_resources57.exs rename to priv/test_repo/migrations/20250810102512_migrate_resources58.exs index 1eb6911a..484e4dc0 100644 --- a/priv/test_repo/migrations/20250810102512_migrate_resources57.exs +++ b/priv/test_repo/migrations/20250810102512_migrate_resources58.exs @@ -1,4 +1,4 @@ -defmodule AshPostgres.TestRepo.Migrations.MigrateResources57 do +defmodule AshPostgres.TestRepo.Migrations.MigrateResources58 do @moduledoc """ Updates resources based on their most recent snapshots. From ad0fd663a9e3de091ef1622907c9ae1e7c557014 Mon Sep 17 00:00:00 2001 From: Sheharyar Naseer Date: Mon, 25 Aug 2025 07:06:05 -0600 Subject: [PATCH 626/690] fix: resolve a typo in pending dev migration error message (#608) --- lib/migration_generator/migration_generator.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 74e0611d..86920ed4 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -460,8 +460,8 @@ defmodule AshPostgres.MigrationGenerator do You have migrations remaining that were generated with the --dev flag. - Run `mix ash.codegen ` to remove the dev migraitons and replace them - with production ready migrations. + Run `mix ash.codegen ` to remove the dev migrations and replace them + with production-ready migrations. """) exit({:shutdown, 1}) From 22ab05e0b2d56600dbe72dda12a2f1402d48b9a4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 31 Aug 2025 11:48:45 -0400 Subject: [PATCH 627/690] chore: release version v2.6.17 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7df2c49a..08169773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.17](https://github.com/ash-project/ash_postgres/compare/v2.6.16...v2.6.17) (2025-08-31) + + + + +### Bug Fixes: + +* resolve a typo in pending dev migration error message (#608) by Sheharyar Naseer + ## [v2.6.16](https://github.com/ash-project/ash_postgres/compare/v2.6.15...v2.6.16) (2025-08-21) diff --git a/mix.exs b/mix.exs index 2d3f04b1..3e8719c1 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.16" + @version "2.6.17" def project do [ From ff3402e759faae5364e37ad855a0f06a1778c304 Mon Sep 17 00:00:00 2001 From: Rodolfo Torres Date: Sun, 31 Aug 2025 16:46:44 -0400 Subject: [PATCH 628/690] test: test for default sort referencing parent field in many_to_many relationship with no_attributes? true (#607) --- test/parent_sort_test.ex | 32 ++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 6 ++++++ 2 files changed, 38 insertions(+) create mode 100644 test/parent_sort_test.ex diff --git a/test/parent_sort_test.ex b/test/parent_sort_test.ex new file mode 100644 index 00000000..e4647672 --- /dev/null +++ b/test/parent_sort_test.ex @@ -0,0 +1,32 @@ +defmodule AshPostgres.Test.ParentSortTest do + use AshPostgres.RepoCase, async: false + + alias AshPostgres.Test.{Organization, Post, User} + + require Ash.Query + + test "can reference parent field when declaring default sort in has_many no_attributes? relationship" do + organization = + Organization + |> Ash.Changeset.for_create(:create, %{name: "test_org"}) + |> Ash.create!() + + user = + User + |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, name: "foo bar"}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{organization_id: organization.id}) + |> Ash.create!() + + Post + |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, title: "test_org"}) + |> Ash.create!() + + assert {:ok, _} = + Post + |> Ash.Query.load(:recommendations) + |> Ash.read(authorize?: false) + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 1f90535c..0441dda9 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -614,6 +614,12 @@ defmodule AshPostgres.Test.Post do filter(expr(fragment("? = ?", title, parent(organization.name)))) end + has_many(:recommendations, __MODULE__) do + public?(true) + no_attributes?(true) + sort([calc(fragment("abs(extract epoch from ?))", parent(datetime) - datetime))]) + end + belongs_to :parent_post, __MODULE__ do public?(true) end From 7d53f476b9af782bd88cedf76b74cc7cb5d50ca9 Mon Sep 17 00:00:00 2001 From: Rodolfo Torres Date: Mon, 1 Sep 2025 08:07:07 -0400 Subject: [PATCH 629/690] rename test file so it matches pattern (#609) --- test/{parent_sort_test.ex => parent_sort_test.exs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{parent_sort_test.ex => parent_sort_test.exs} (100%) diff --git a/test/parent_sort_test.ex b/test/parent_sort_test.exs similarity index 100% rename from test/parent_sort_test.ex rename to test/parent_sort_test.exs From 1948f80b2a982f19981c599a953d311d8a483e4d Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 4 Sep 2025 21:46:51 -0400 Subject: [PATCH 630/690] fix: annotate unrelated exists expressions as supported --- lib/data_layer.ex | 1 + test/unrelated_aggregates_test.exs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 3fa1aa30..27b88dd1 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -722,6 +722,7 @@ defmodule AshPostgres.DataLayer do do: true def can?(_, {:aggregate, :unrelated}), do: true + def can?(_, {:exists, :unrelated}), do: true def can?(_, :aggregate_filter), do: true def can?(_, :aggregate_sort), do: true def can?(_, :calculate), do: true diff --git a/test/unrelated_aggregates_test.exs b/test/unrelated_aggregates_test.exs index 09a15740..0ec55535 100644 --- a/test/unrelated_aggregates_test.exs +++ b/test/unrelated_aggregates_test.exs @@ -503,5 +503,22 @@ defmodule AshPostgres.Test.UnrelatedAggregatesTest do assert loaded_user.aggregates.bio_mentions_name == 2 end + + test "unrelated exists expressions work with parent() reference" do + {:ok, user1} = Ash.create(User, %{name: "ExistsTest", email: "exists@example.com"}) + {:ok, user2} = Ash.create(User, %{name: "NoMatch", email: "nomatch@example.com"}) + + {:ok, _profile} = Ash.create(Profile, %{name: "ExistsTest", age: 25, active: true}) + + # Check if any profile exists with the same name using unrelated exists + users_with_matching_profiles = + User + |> Ash.Query.filter(exists(Profile, name == parent(name))) + |> Ash.read!() + + user_ids = Enum.map(users_with_matching_profiles, & &1.id) + assert user1.id in user_ids + refute user2.id in user_ids + end end end From 36213e4e00631a5911b9bfcd6acfd558d0fc5cbf Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 7 Sep 2025 01:15:27 +0200 Subject: [PATCH 631/690] fix: properly handle sorts w/ parent refs on lateral joins --- lib/data_layer.ex | 11 +++++++---- test/parent_sort_test.exs | 15 +++++++-------- test/support/resources/post.ex | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 27b88dd1..e4cde133 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1185,7 +1185,7 @@ defmodule AshPostgres.DataLayer do if query.__ash_bindings__[:__order__?] do {:ok, from(source in data_layer_query, - inner_lateral_join: destination in ^subquery, + inner_lateral_join: destination in subquery(get_subquery(subquery)), on: true, order_by: destination.__order__, select: merge(destination, %{__lateral_join_source__: map(source, ^source_pkey)}), @@ -1194,7 +1194,7 @@ defmodule AshPostgres.DataLayer do else {:ok, from(source in data_layer_query, - inner_lateral_join: destination in ^subquery, + inner_lateral_join: destination in subquery(get_subquery(subquery)), on: true, select: merge(destination, %{__lateral_join_source__: map(source, ^source_pkey)}), distinct: true @@ -1286,7 +1286,7 @@ defmodule AshPostgres.DataLayer do {:ok, from(source in data_layer_query, where: field(source, ^source_attribute) in ^source_values, - inner_lateral_join: destination in ^subquery, + inner_lateral_join: destination in subquery(get_subquery(subquery)), on: true, select: destination, select_merge: %{__lateral_join_source__: map(source, ^source_pkey)}, @@ -1321,7 +1321,7 @@ defmodule AshPostgres.DataLayer do {:ok, from(source in data_layer_query, where: field(source, ^source_attribute) in ^source_values, - inner_lateral_join: destination in ^subquery, + inner_lateral_join: destination in subquery(get_subquery(subquery)), on: true, select: destination, select_merge: %{__lateral_join_source__: map(source, ^source_pkey)}, @@ -1434,6 +1434,9 @@ defmodule AshPostgres.DataLayer do Ash.Query.do_filter(query, expr) end + defp get_subquery(%Ecto.Query{} = query), do: query + defp get_subquery(%Ecto.SubQuery{query: query}), do: query + @doc false def set_subquery_prefix(data_layer_query, source_query, resource) do repo = AshPostgres.DataLayer.Info.repo(resource, :mutate) diff --git a/test/parent_sort_test.exs b/test/parent_sort_test.exs index e4647672..423d6634 100644 --- a/test/parent_sort_test.exs +++ b/test/parent_sort_test.exs @@ -11,10 +11,9 @@ defmodule AshPostgres.Test.ParentSortTest do |> Ash.Changeset.for_create(:create, %{name: "test_org"}) |> Ash.create!() - user = - User - |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, name: "foo bar"}) - |> Ash.create!() + User + |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, name: "foo bar"}) + |> Ash.create!() Post |> Ash.Changeset.for_create(:create, %{organization_id: organization.id}) @@ -24,9 +23,9 @@ defmodule AshPostgres.Test.ParentSortTest do |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, title: "test_org"}) |> Ash.create!() - assert {:ok, _} = - Post - |> Ash.Query.load(:recommendations) - |> Ash.read(authorize?: false) + # just asserting it doesn't errror + Post + |> Ash.Query.load(:recommendations) + |> Ash.read!(authorize?: false) end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 0441dda9..dfba5a06 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -617,7 +617,7 @@ defmodule AshPostgres.Test.Post do has_many(:recommendations, __MODULE__) do public?(true) no_attributes?(true) - sort([calc(fragment("abs(extract epoch from ?))", parent(datetime) - datetime))]) + sort([calc(parent(datetime) > now())]) end belongs_to :parent_post, __MODULE__ do From 6f97884ec6930c79441f05afb4fa3a18959402d7 Mon Sep 17 00:00:00 2001 From: kernel-io Date: Mon, 8 Sep 2025 21:42:13 +1200 Subject: [PATCH 632/690] test: add failing tests for loads not getting added automatically in certain situations (#612) --- test/parent_filter_test.exs | 29 ++++++++++++++++++++++++++++- test/support/resources/post.ex | 10 ++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/test/parent_filter_test.exs b/test/parent_filter_test.exs index fefbde24..78d295fe 100644 --- a/test/parent_filter_test.exs +++ b/test/parent_filter_test.exs @@ -1,7 +1,7 @@ defmodule AshPostgres.Test.ParentFilterTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Organization, Post, User} + alias AshPostgres.Test.{Organization, Post, User, Comment} require Ash.Query @@ -44,4 +44,31 @@ defmodule AshPostgres.Test.ParentFilterTest do ) |> Ash.read(authorize?: false) end + + test "something else" do + organization = + Organization + |> Ash.Changeset.for_create(:create, %{name: "test_org"}) + |> Ash.create!() + + post_in_my_org = + Post + |> Ash.Changeset.for_create(:create, %{organization_id: organization.id, title: "test_org"}) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "test_org"}) + |> Ash.Changeset.manage_relationship(:post, post_in_my_org, type: :append_and_remove) + |> Ash.create!() + + assert {:ok, _} = + Post + |> Ash.Query.for_read(:read) + |> Ash.Query.filter( + organizations_with_posts_that_have_the_post_title_somewhere_in_their_comments.name in [ + ^organization.name + ] + ) + |> Ash.read(authorize?: false) + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index dfba5a06..e6009d57 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -614,6 +614,14 @@ defmodule AshPostgres.Test.Post do filter(expr(fragment("? = ?", title, parent(organization.name)))) end + has_many( + :organizations_with_posts_that_have_the_post_title_somewhere_in_their_comments, + AshPostgres.Test.Organization + ) do + no_attributes?(true) + filter(expr(fragment("POSITION(? IN ?) > 0", posts.title, parent(concated_comment_titles)))) + end + has_many(:recommendations, __MODULE__) do public?(true) no_attributes?(true) @@ -1020,6 +1028,8 @@ defmodule AshPostgres.Test.Post do calculate(:author_profile_description_from_agg, :string, expr(author_profile_description)) calculate(:latest_comment_title, :string, expr(latest_comment.title), allow_nil?: true) + + calculate(:concated_comment_titles, :string, expr(fragment("concat(?)", comment_titles))) end aggregates do From 89622eb6fef805278eb76724531fceea0dbe90e3 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 8 Sep 2025 11:43:37 +0200 Subject: [PATCH 633/690] test: add tests of distinct/sort issues --- .../test_repo/chats/20250908093505.json | 43 ++++++++ .../test_repo/customers/20250908073737.json | 43 ++++++++ .../test_repo/messages/20250908093505.json | 98 +++++++++++++++++++ .../test_repo/orders/20250908073737.json | 93 ++++++++++++++++++ .../test_repo/products/20250908073737.json | 43 ++++++++ .../20250908073737_migrate_resources59.exs | 73 ++++++++++++++ .../20250908093505_migrate_resources60.exs | 55 +++++++++++ test/distinct_test.exs | 28 +++++- test/sort_test.exs | 54 +++++++++- test/support/domain.ex | 5 + test/support/resources/chat.ex | 40 ++++++++ test/support/resources/customer.ex | 35 +++++++ test/support/resources/message.ex | 30 ++++++ test/support/resources/order.ex | 32 ++++++ test/support/resources/product.ex | 33 +++++++ 15 files changed, 703 insertions(+), 2 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/chats/20250908093505.json create mode 100644 priv/resource_snapshots/test_repo/customers/20250908073737.json create mode 100644 priv/resource_snapshots/test_repo/messages/20250908093505.json create mode 100644 priv/resource_snapshots/test_repo/orders/20250908073737.json create mode 100644 priv/resource_snapshots/test_repo/products/20250908073737.json create mode 100644 priv/test_repo/migrations/20250908073737_migrate_resources59.exs create mode 100644 priv/test_repo/migrations/20250908093505_migrate_resources60.exs create mode 100644 test/support/resources/chat.ex create mode 100644 test/support/resources/customer.ex create mode 100644 test/support/resources/message.ex create mode 100644 test/support/resources/order.ex create mode 100644 test/support/resources/product.ex diff --git a/priv/resource_snapshots/test_repo/chats/20250908093505.json b/priv/resource_snapshots/test_repo/chats/20250908093505.json new file mode 100644 index 00000000..aa5ea757 --- /dev/null +++ b/priv/resource_snapshots/test_repo/chats/20250908093505.json @@ -0,0 +1,43 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "E200EA8628A3CC9B29EF3921CA5E72F3819E7E4CBA4B64E2E0684A2F45F9E873", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "chats" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/customers/20250908073737.json b/priv/resource_snapshots/test_repo/customers/20250908073737.json new file mode 100644 index 00000000..28f93ea2 --- /dev/null +++ b/priv/resource_snapshots/test_repo/customers/20250908073737.json @@ -0,0 +1,43 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "93AF0132FAB23B3B438FD526411F0C9E504C80F803322B5ABCDFFA8B3103B762", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "customers" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/messages/20250908093505.json b/priv/resource_snapshots/test_repo/messages/20250908093505.json new file mode 100644 index 00000000..abe62ca8 --- /dev/null +++ b/priv/resource_snapshots/test_repo/messages/20250908093505.json @@ -0,0 +1,98 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "content", + "type": "text" + }, + { + "allow_nil?": true, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "sent_at", + "type": "utc_datetime" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "read_at", + "type": "utc_datetime" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "messages_chat_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "chats" + }, + "scale": null, + "size": null, + "source": "chat_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "97C85779868973EAB5363B16FCE9562DBAD347062547341855A08557B127FD7E", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "messages" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/orders/20250908073737.json b/priv/resource_snapshots/test_repo/orders/20250908073737.json new file mode 100644 index 00000000..104128a4 --- /dev/null +++ b/priv/resource_snapshots/test_repo/orders/20250908073737.json @@ -0,0 +1,93 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "orders_customer_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "customers" + }, + "scale": null, + "size": null, + "source": "customer_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "orders_product_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "products" + }, + "scale": null, + "size": null, + "source": "product_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "BDB105B45D28F7BB79E6AC102805F748C15EB6B19B7FFC6D166E71CD40F60B15", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "orders" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/products/20250908073737.json b/priv/resource_snapshots/test_repo/products/20250908073737.json new file mode 100644 index 00000000..1b787e4f --- /dev/null +++ b/priv/resource_snapshots/test_repo/products/20250908073737.json @@ -0,0 +1,43 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "name", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "F8C4228D8DCC1DADD126675744C0BEE52107FADA5135A2E603A26F5F115709DC", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "products" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250908073737_migrate_resources59.exs b/priv/test_repo/migrations/20250908073737_migrate_resources59.exs new file mode 100644 index 00000000..a4acd79a --- /dev/null +++ b/priv/test_repo/migrations/20250908073737_migrate_resources59.exs @@ -0,0 +1,73 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources59 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:products, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:name, :text) + end + + create table(:orders, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:customer_id, :uuid, null: false) + add(:product_id, :uuid, null: false) + end + + create table(:customers, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + end + + alter table(:orders) do + modify( + :customer_id, + references(:customers, + column: :id, + name: "orders_customer_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + + modify( + :product_id, + references(:products, + column: :id, + name: "orders_product_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + + alter table(:customers) do + add(:name, :text) + end + end + + def down do + alter table(:customers) do + remove(:name) + end + + drop(constraint(:orders, "orders_customer_id_fkey")) + + drop(constraint(:orders, "orders_product_id_fkey")) + + alter table(:orders) do + modify(:product_id, :uuid) + modify(:customer_id, :uuid) + end + + drop(table(:customers)) + + drop(table(:orders)) + + drop(table(:products)) + end +end diff --git a/priv/test_repo/migrations/20250908093505_migrate_resources60.exs b/priv/test_repo/migrations/20250908093505_migrate_resources60.exs new file mode 100644 index 00000000..404906e5 --- /dev/null +++ b/priv/test_repo/migrations/20250908093505_migrate_resources60.exs @@ -0,0 +1,55 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources60 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:messages, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:content, :text) + add(:sent_at, :utc_datetime, default: fragment("(now() AT TIME ZONE 'utc')")) + add(:read_at, :utc_datetime) + add(:chat_id, :uuid, null: false) + end + + create table(:chats, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + end + + alter table(:messages) do + modify( + :chat_id, + references(:chats, + column: :id, + name: "messages_chat_id_fkey", + type: :uuid, + prefix: "public" + ) + ) + end + + alter table(:chats) do + add(:name, :text) + end + end + + def down do + alter table(:chats) do + remove(:name) + end + + drop(constraint(:messages, "messages_chat_id_fkey")) + + alter table(:messages) do + modify(:chat_id, :uuid) + end + + drop(table(:chats)) + + drop(table(:messages)) + end +end diff --git a/test/distinct_test.exs b/test/distinct_test.exs index bbc9a1c6..452f0068 100644 --- a/test/distinct_test.exs +++ b/test/distinct_test.exs @@ -1,7 +1,7 @@ defmodule AshPostgres.DistinctTest do @moduledoc false use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.Post + alias AshPostgres.Test.{Customer, Post, Product, Order} require Ash.Query @@ -177,4 +177,30 @@ defmodule AshPostgres.DistinctTest do assert [_, _] = results end + + test "distinct breaks with prepare build(sort: [:id]) - original issue reproduction" do + + customer = + Customer + |> Ash.Changeset.for_create(:create, %{name: "Test Customer"}) + |> Ash.create!() + + product = + Product + |> Ash.Changeset.for_create(:create, %{name: "Test Product"}) + |> Ash.create!() + + Order + |> Ash.Changeset.for_create(:create, %{customer_id: customer.id, product_id: product.id}) + |> Ash.create!() + + Order + |> Ash.Changeset.for_create(:create, %{customer_id: customer.id, product_id: product.id}) + |> Ash.create!() + + customer_with_products = Ash.load!(customer, :purchased_products) + purchased_products = customer_with_products.purchased_products + + assert length(purchased_products) == 1, "Expected 1 unique product, got #{length(purchased_products)} products. This indicates the distinct + sort preparation bug." + end end diff --git a/test/sort_test.exs b/test/sort_test.exs index cd5deddb..6be3113d 100644 --- a/test/sort_test.exs +++ b/test/sort_test.exs @@ -1,10 +1,11 @@ defmodule AshPostgres.SortTest do @moduledoc false use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Comment, Post, PostLink, PostTag, PostView, Tag} + alias AshPostgres.Test.{Chat, Comment, Message, Post, PostLink, PostTag, PostView, Tag} require Ash.Query require Ash.Sort + import Ash.Expr test "multi-column sorts work" do Post @@ -289,4 +290,55 @@ defmodule AshPostgres.SortTest do assert DateTime.to_date(latest_post.created_at) == expected_date end + + describe "sorting by multiple has_one relationships" do + test "sorting by single calculated field through has_one relationship works" do + chat = Ash.create!(Chat, %{name: "Test Chat"}) + + # Create some messages + Ash.create!(Message, %{chat_id: chat.id, content: "First", sent_at: ~U[2025-01-01 10:00:00Z]}) + Ash.create!(Message, %{chat_id: chat.id, content: "Second", sent_at: ~U[2025-01-02 10:00:00Z], read_at: ~U[2025-01-02 11:00:00Z]}) + Ash.create!(Message, %{chat_id: chat.id, content: "Third", sent_at: ~U[2025-01-03 10:00:00Z]}) + + # This should work - sorting by single has_one relationship calculation + result = + Chat + |> Ash.Query.sort([{Ash.Sort.expr_sort(expr(last_unread_message.sent_at)), :desc}]) + |> Ash.read!() + + assert [%Chat{}] = result + end + + test "sorting by different single calculated field through has_one relationship works" do + chat = Ash.create!(Chat, %{name: "Test Chat"}) + + # Create some messages + Ash.create!(Message, %{chat_id: chat.id, content: "First", sent_at: ~U[2025-01-01 10:00:00Z]}) + Ash.create!(Message, %{chat_id: chat.id, content: "Second", sent_at: ~U[2025-01-02 10:00:00Z], read_at: ~U[2025-01-02 11:00:00Z]}) + + # This should work - sorting by different single has_one relationship calculation + result = + Chat + |> Ash.Query.sort([{Ash.Sort.expr_sort(expr(last_message.read_at)), :desc}]) + |> Ash.read!() + + assert [%Chat{}] = result + end + + test "sorting by multiple calculated fields through different has_one relationships fails" do + chat = Ash.create!(Chat, %{name: "Test Chat"}) + + # Create some messages + Ash.create!(Message, %{chat_id: chat.id, content: "First", sent_at: ~U[2025-01-01 10:00:00Z]}) + Ash.create!(Message, %{chat_id: chat.id, content: "Second", sent_at: ~U[2025-01-02 10:00:00Z], read_at: ~U[2025-01-02 11:00:00Z]}) + Ash.create!(Message, %{chat_id: chat.id, content: "Third", sent_at: ~U[2025-01-03 10:00:00Z]}) + + Chat + |> Ash.Query.sort([ + {Ash.Sort.expr_sort(expr(last_unread_message.sent_at)), :desc}, + {Ash.Sort.expr_sort(expr(last_message.read_at)), :desc} + ]) + |> Ash.read!() + end + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index 58802a18..2bf55a0b 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -48,6 +48,11 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.UnrelatedAggregatesTest.SecureProfile) resource(AshPostgres.Test.UnrelatedAggregatesTest.Report) resource(AshPostgres.Test.UnrelatedAggregatesTest.User) + resource(AshPostgres.Test.Customer) + resource(AshPostgres.Test.Product) + resource(AshPostgres.Test.Order) + resource(AshPostgres.Test.Chat) + resource(AshPostgres.Test.Message) end authorization do diff --git a/test/support/resources/chat.ex b/test/support/resources/chat.ex new file mode 100644 index 00000000..853c3c17 --- /dev/null +++ b/test/support/resources/chat.ex @@ -0,0 +1,40 @@ +defmodule AshPostgres.Test.Chat do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("chats") + repo(AshPostgres.TestRepo) + end + + actions do + default_accept(:*) + defaults([:create, :read, :destroy, :update]) + end + + attributes do + uuid_primary_key(:id, writable?: true) + attribute(:name, :string, public?: true) + end + + relationships do + has_many :messages, AshPostgres.Test.Message do + public?(true) + end + + has_one :last_message, AshPostgres.Test.Message do + public?(true) + from_many?(true) + sort(sent_at: :desc) + end + + has_one :last_unread_message, AshPostgres.Test.Message do + public?(true) + from_many?(true) + filter(expr(is_nil(read_at))) + sort(sent_at: :desc) + end + end +end \ No newline at end of file diff --git a/test/support/resources/customer.ex b/test/support/resources/customer.ex new file mode 100644 index 00000000..2bd94105 --- /dev/null +++ b/test/support/resources/customer.ex @@ -0,0 +1,35 @@ +defmodule AshPostgres.Test.Customer do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("customers") + repo(AshPostgres.TestRepo) + end + + actions do + default_accept(:*) + defaults([:create, :read, :destroy, :update]) + end + + attributes do + uuid_primary_key(:id, writable?: true) + attribute(:name, :string, public?: true) + end + + relationships do + has_many :orders, AshPostgres.Test.Order do + public?(true) + end + + # This relationship reproduces the bug described in: + # https://github.com/ash-project/ash_sql/issues/172#issuecomment-3264660128 + has_many :purchased_products, AshPostgres.Test.Product do + public?(true) + no_attributes?(true) + filter(expr(orders.customer_id == parent(id))) + end + end +end \ No newline at end of file diff --git a/test/support/resources/message.ex b/test/support/resources/message.ex new file mode 100644 index 00000000..6e0a2ded --- /dev/null +++ b/test/support/resources/message.ex @@ -0,0 +1,30 @@ +defmodule AshPostgres.Test.Message do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("messages") + repo(AshPostgres.TestRepo) + end + + actions do + default_accept(:*) + defaults([:create, :read, :destroy, :update]) + end + + attributes do + uuid_primary_key(:id, writable?: true) + attribute(:content, :string, public?: true) + attribute(:sent_at, :utc_datetime, default: &DateTime.utc_now/0, public?: true) + attribute(:read_at, :utc_datetime, public?: true) + end + + relationships do + belongs_to :chat, AshPostgres.Test.Chat do + public?(true) + allow_nil?(false) + end + end +end \ No newline at end of file diff --git a/test/support/resources/order.ex b/test/support/resources/order.ex new file mode 100644 index 00000000..83c6751a --- /dev/null +++ b/test/support/resources/order.ex @@ -0,0 +1,32 @@ +defmodule AshPostgres.Test.Order do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("orders") + repo(AshPostgres.TestRepo) + end + + actions do + default_accept(:*) + defaults([:create, :read, :destroy, :update]) + end + + attributes do + uuid_primary_key(:id, writable?: true) + end + + relationships do + belongs_to :customer, AshPostgres.Test.Customer do + public?(true) + allow_nil?(false) + end + + belongs_to :product, AshPostgres.Test.Product do + public?(true) + allow_nil?(false) + end + end +end \ No newline at end of file diff --git a/test/support/resources/product.ex b/test/support/resources/product.ex new file mode 100644 index 00000000..0ddb9169 --- /dev/null +++ b/test/support/resources/product.ex @@ -0,0 +1,33 @@ +defmodule AshPostgres.Test.Product do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table("products") + repo(AshPostgres.TestRepo) + end + + actions do + default_accept(:*) + defaults([:create, :read, :destroy, :update]) + end + + # This preparation reproduces the bug described in: + # https://github.com/ash-project/ash_sql/issues/172#issuecomment-3264660128 + preparations do + prepare build(sort: [:id]) + end + + attributes do + uuid_primary_key(:id, writable?: true) + attribute(:name, :string, public?: true) + end + + relationships do + has_many :orders, AshPostgres.Test.Order do + public?(true) + end + end +end \ No newline at end of file From 108dd845a49297b00dfd39c3260554ab565aafe5 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 8 Sep 2025 11:44:52 +0200 Subject: [PATCH 634/690] chore: format/credo --- test/distinct_test.exs | 6 ++-- test/parent_filter_test.exs | 2 +- test/sort_test.exs | 56 +++++++++++++++++++++++++----- test/support/resources/chat.ex | 2 +- test/support/resources/customer.ex | 2 +- test/support/resources/message.ex | 2 +- test/support/resources/order.ex | 2 +- test/support/resources/product.ex | 4 +-- 8 files changed, 58 insertions(+), 18 deletions(-) diff --git a/test/distinct_test.exs b/test/distinct_test.exs index 452f0068..284ed5b5 100644 --- a/test/distinct_test.exs +++ b/test/distinct_test.exs @@ -1,7 +1,7 @@ defmodule AshPostgres.DistinctTest do @moduledoc false use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Customer, Post, Product, Order} + alias AshPostgres.Test.{Customer, Order, Post, Product} require Ash.Query @@ -179,7 +179,6 @@ defmodule AshPostgres.DistinctTest do end test "distinct breaks with prepare build(sort: [:id]) - original issue reproduction" do - customer = Customer |> Ash.Changeset.for_create(:create, %{name: "Test Customer"}) @@ -201,6 +200,7 @@ defmodule AshPostgres.DistinctTest do customer_with_products = Ash.load!(customer, :purchased_products) purchased_products = customer_with_products.purchased_products - assert length(purchased_products) == 1, "Expected 1 unique product, got #{length(purchased_products)} products. This indicates the distinct + sort preparation bug." + assert length(purchased_products) == 1, + "Expected 1 unique product, got #{length(purchased_products)} products. This indicates the distinct + sort preparation bug." end end diff --git a/test/parent_filter_test.exs b/test/parent_filter_test.exs index 78d295fe..aa2e7af3 100644 --- a/test/parent_filter_test.exs +++ b/test/parent_filter_test.exs @@ -1,7 +1,7 @@ defmodule AshPostgres.Test.ParentFilterTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Organization, Post, User, Comment} + alias AshPostgres.Test.{Comment, Organization, Post, User} require Ash.Query diff --git a/test/sort_test.exs b/test/sort_test.exs index 6be3113d..e7d949da 100644 --- a/test/sort_test.exs +++ b/test/sort_test.exs @@ -296,9 +296,24 @@ defmodule AshPostgres.SortTest do chat = Ash.create!(Chat, %{name: "Test Chat"}) # Create some messages - Ash.create!(Message, %{chat_id: chat.id, content: "First", sent_at: ~U[2025-01-01 10:00:00Z]}) - Ash.create!(Message, %{chat_id: chat.id, content: "Second", sent_at: ~U[2025-01-02 10:00:00Z], read_at: ~U[2025-01-02 11:00:00Z]}) - Ash.create!(Message, %{chat_id: chat.id, content: "Third", sent_at: ~U[2025-01-03 10:00:00Z]}) + Ash.create!(Message, %{ + chat_id: chat.id, + content: "First", + sent_at: ~U[2025-01-01 10:00:00Z] + }) + + Ash.create!(Message, %{ + chat_id: chat.id, + content: "Second", + sent_at: ~U[2025-01-02 10:00:00Z], + read_at: ~U[2025-01-02 11:00:00Z] + }) + + Ash.create!(Message, %{ + chat_id: chat.id, + content: "Third", + sent_at: ~U[2025-01-03 10:00:00Z] + }) # This should work - sorting by single has_one relationship calculation result = @@ -313,8 +328,18 @@ defmodule AshPostgres.SortTest do chat = Ash.create!(Chat, %{name: "Test Chat"}) # Create some messages - Ash.create!(Message, %{chat_id: chat.id, content: "First", sent_at: ~U[2025-01-01 10:00:00Z]}) - Ash.create!(Message, %{chat_id: chat.id, content: "Second", sent_at: ~U[2025-01-02 10:00:00Z], read_at: ~U[2025-01-02 11:00:00Z]}) + Ash.create!(Message, %{ + chat_id: chat.id, + content: "First", + sent_at: ~U[2025-01-01 10:00:00Z] + }) + + Ash.create!(Message, %{ + chat_id: chat.id, + content: "Second", + sent_at: ~U[2025-01-02 10:00:00Z], + read_at: ~U[2025-01-02 11:00:00Z] + }) # This should work - sorting by different single has_one relationship calculation result = @@ -329,9 +354,24 @@ defmodule AshPostgres.SortTest do chat = Ash.create!(Chat, %{name: "Test Chat"}) # Create some messages - Ash.create!(Message, %{chat_id: chat.id, content: "First", sent_at: ~U[2025-01-01 10:00:00Z]}) - Ash.create!(Message, %{chat_id: chat.id, content: "Second", sent_at: ~U[2025-01-02 10:00:00Z], read_at: ~U[2025-01-02 11:00:00Z]}) - Ash.create!(Message, %{chat_id: chat.id, content: "Third", sent_at: ~U[2025-01-03 10:00:00Z]}) + Ash.create!(Message, %{ + chat_id: chat.id, + content: "First", + sent_at: ~U[2025-01-01 10:00:00Z] + }) + + Ash.create!(Message, %{ + chat_id: chat.id, + content: "Second", + sent_at: ~U[2025-01-02 10:00:00Z], + read_at: ~U[2025-01-02 11:00:00Z] + }) + + Ash.create!(Message, %{ + chat_id: chat.id, + content: "Third", + sent_at: ~U[2025-01-03 10:00:00Z] + }) Chat |> Ash.Query.sort([ diff --git a/test/support/resources/chat.ex b/test/support/resources/chat.ex index 853c3c17..9a035f4c 100644 --- a/test/support/resources/chat.ex +++ b/test/support/resources/chat.ex @@ -37,4 +37,4 @@ defmodule AshPostgres.Test.Chat do sort(sent_at: :desc) end end -end \ No newline at end of file +end diff --git a/test/support/resources/customer.ex b/test/support/resources/customer.ex index 2bd94105..d5cff43e 100644 --- a/test/support/resources/customer.ex +++ b/test/support/resources/customer.ex @@ -32,4 +32,4 @@ defmodule AshPostgres.Test.Customer do filter(expr(orders.customer_id == parent(id))) end end -end \ No newline at end of file +end diff --git a/test/support/resources/message.ex b/test/support/resources/message.ex index 6e0a2ded..25896e04 100644 --- a/test/support/resources/message.ex +++ b/test/support/resources/message.ex @@ -27,4 +27,4 @@ defmodule AshPostgres.Test.Message do allow_nil?(false) end end -end \ No newline at end of file +end diff --git a/test/support/resources/order.ex b/test/support/resources/order.ex index 83c6751a..27566cb4 100644 --- a/test/support/resources/order.ex +++ b/test/support/resources/order.ex @@ -29,4 +29,4 @@ defmodule AshPostgres.Test.Order do allow_nil?(false) end end -end \ No newline at end of file +end diff --git a/test/support/resources/product.ex b/test/support/resources/product.ex index 0ddb9169..199bbff8 100644 --- a/test/support/resources/product.ex +++ b/test/support/resources/product.ex @@ -17,7 +17,7 @@ defmodule AshPostgres.Test.Product do # This preparation reproduces the bug described in: # https://github.com/ash-project/ash_sql/issues/172#issuecomment-3264660128 preparations do - prepare build(sort: [:id]) + prepare(build(sort: [:id])) end attributes do @@ -30,4 +30,4 @@ defmodule AshPostgres.Test.Product do public?(true) end end -end \ No newline at end of file +end From 2c4e6fdd19ce9217e08c85e00f67b44873bd58f4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 8 Sep 2025 16:08:06 +0200 Subject: [PATCH 635/690] chore: update test name --- test/parent_filter_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parent_filter_test.exs b/test/parent_filter_test.exs index aa2e7af3..b7f8f8dc 100644 --- a/test/parent_filter_test.exs +++ b/test/parent_filter_test.exs @@ -45,7 +45,7 @@ defmodule AshPostgres.Test.ParentFilterTest do |> Ash.read(authorize?: false) end - test "something else" do + test "aggregates from related filters are properly added to the query" do organization = Organization |> Ash.Changeset.for_create(:create, %{name: "test_org"}) From 14ec89d20b9af74adb27849106ce922d884f0b77 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 13 Sep 2025 17:32:02 +0200 Subject: [PATCH 636/690] test: tests and reproductions for get_path composition --- mix.lock | 8 +- .../test_repo/authors/20250908212414.json | 106 ++++++++++++++++++ .../20250908212414_migrate_resources61.exs | 21 ++++ test/storage_types_test.exs | 46 ++++++++ test/support/resources/author.ex | 5 +- 5 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/authors/20250908212414.json create mode 100644 priv/test_repo/migrations/20250908212414_migrate_resources61.exs diff --git a/mix.lock b/mix.lock index a6ba65e8..90a49a91 100644 --- a/mix.lock +++ b/mix.lock @@ -1,10 +1,10 @@ %{ - "ash": {:hex, :ash, "3.5.35", "ff63b9d3670a05ad036ecc8732c0143770aff4e23f07662931a9ebd1f4aba3c4", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.68 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", "b6ff48f80efabcc1867af9847c8656fa376d9b800e8988b82ec0a42bee4f6b58"}, - "ash_sql": {:hex, :ash_sql, "0.2.90", "6b533e963e4b7c0855654597d8eb7bb87c30db0be7328628cb9bb63e2e547a54", [:mix], [{:ash, ">= 3.5.35 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", "57a7235f22f01381b1a2d63364c353fe6fa31278f3bbd402aacab6dba78a7e6b"}, + "ash": {:hex, :ash, "3.5.40", "19b82796359f32520acd83581c5edfefd06e177fb3c15875f52d5f437f90d902", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.68 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", "278959afb7e54fd3e7184650bfd4ee6a45979aa3d37913d9e19a7400097eae2d"}, + "ash_sql": {:hex, :ash_sql, "0.2.92", "7ef55c307944e68bfd9de07a186fda4bc3b6b7b401f5c5a5cdd0fafafe75d7d2", [:mix], [{:ash, ">= 3.5.35 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", "445fea8343a17d3842ad48007ef07b09ffa28209b3e03ea8772062c42fc50df1"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, - "db_connection": {:hex, :db_connection, "2.8.0", "64fd82cfa6d8e25ec6660cea73e92a4cbc6a18b31343910427b702838c4b33b2", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "008399dae5eee1bf5caa6e86d204dcb44242c82b1ed5e22c881f2c34da201b15"}, + "db_connection": {:hex, :db_connection, "2.8.1", "9abdc1e68c34c6163f6fb96a96532272d13ad7ca45262156ae8b7ec6d9dc4bec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61a3d489b239d76f326e03b98794fb8e45168396c925ef25feb405ed09da8fd"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, @@ -36,7 +36,7 @@ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, - "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, + "owl": {:hex, :owl, "0.13.0", "26010e066d5992774268f3163506972ddac0a7e77bfe57fa42a250f24d6b876e", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "59bf9d11ce37a4db98f57cb68fbfd61593bf419ec4ed302852b6683d3d2f7475"}, "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, "reactor": {:hex, :reactor, "0.15.6", "d717f9add549b25a089a94c90197718d2d838e35d81dd776b1d81587d4cf2aaa", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "74db98165e3644d86e0f723672d91ceca4339eaa935bcad7e78bf146a46d77b9"}, "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, diff --git a/priv/resource_snapshots/test_repo/authors/20250908212414.json b/priv/resource_snapshots/test_repo/authors/20250908212414.json new file mode 100644 index 00000000..b271e003 --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20250908212414.json @@ -0,0 +1,106 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "first_name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "last_name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "bio", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "bios", + "type": "jsonb" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "badges", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "settings", + "type": "jsonb" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "DD102A40219E8086BECBF5306AAA1196B59CC38B6FAA0BCEECFD24E82FF24DCD", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "authors" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20250908212414_migrate_resources61.exs b/priv/test_repo/migrations/20250908212414_migrate_resources61.exs new file mode 100644 index 00000000..303a4e53 --- /dev/null +++ b/priv/test_repo/migrations/20250908212414_migrate_resources61.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources61 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:authors) do + add(:settings, :jsonb) + end + end + + def down do + alter table(:authors) do + remove(:settings) + end + end +end diff --git a/test/storage_types_test.exs b/test/storage_types_test.exs index dde647b3..88783e54 100644 --- a/test/storage_types_test.exs +++ b/test/storage_types_test.exs @@ -42,4 +42,50 @@ defmodule AshPostgres.StorageTypesTest do assert author.bios == [%{"a" => 1}] end + + test "`in` operator works on get_path results" do + %{id: id} = + Author + |> Ash.Changeset.for_create( + :create, + %{ + first_name: "Test", + last_name: "User", + settings: %{ + "dues_reminders" => ["email", "sms"], + "newsletter" => ["email"], + "optional_field" => nil + } + } + ) + |> Ash.create!() + + assert [%Author{id: ^id}] = + Author + |> Ash.Query.filter("email" in settings["dues_reminders"]) + |> Ash.read!() + end + + test "`is_nil` operator works on get_path results" do + %{id: id} = + Author + |> Ash.Changeset.for_create( + :create, + %{ + first_name: "Test", + last_name: "User", + settings: %{ + "dues_reminders" => ["email", "sms"], + "newsletter" => ["email"], + "optional_field" => nil + } + } + ) + |> Ash.create!() + + assert [%Author{id: ^id}] = + Author + |> Ash.Query.filter(is_nil(settings["optional_field"])) + |> Ash.read!() + end end diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index 54568518..77ad0d15 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -19,8 +19,8 @@ defmodule AshPostgres.Test.Author do table("authors") repo(AshPostgres.TestRepo) - migration_types bios: :jsonb - storage_types(bios: :jsonb) + migration_types bios: :jsonb, settings: :jsonb + storage_types(bios: :jsonb, settings: :jsonb) end attributes do @@ -30,6 +30,7 @@ defmodule AshPostgres.Test.Author do attribute(:bio, AshPostgres.Test.Bio, public?: true) attribute(:bios, {:array, :map}, public?: true) attribute(:badges, {:array, :atom}, public?: true) + attribute(:settings, :map, public?: true) end actions do From 19ed5ef68c6ab3d09e3e30169d838b17dbc30f21 Mon Sep 17 00:00:00 2001 From: Trond A Ekseth Date: Sat, 13 Sep 2025 17:57:54 +0200 Subject: [PATCH 637/690] docs: Fix duplicate `public` option in ash_postgres.gen.resources (#613) --- lib/mix/tasks/ash_postgres.gen.resources.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index a187f8d9..babac4f1 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -30,7 +30,6 @@ if Code.ensure_loaded?(Igniter) do - `public` - Mark all attributes and relationships as `public? true`. Defaults to `true`. - `no-migrations` - Do not generate snapshots & migrations for the resources. Defaults to `false`. - `skip-unknown` - Skip any attributes with types that we don't have a corresponding Elixir type for, and relationships that we can't assume the name of. - - `public` - Mark all attributes and relationships as `public? true`. Defaults to `true`. ## Tables From b2f98cf6de47daa094942be0f31f9f9fccfebb2c Mon Sep 17 00:00:00 2001 From: Trond A Ekseth Date: Mon, 15 Sep 2025 21:12:29 +0200 Subject: [PATCH 638/690] fix: Handle optional/empty input in relationship name guesser (#616) --- lib/resource_generator/spec.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 8b6d4ae6..f2da7ec5 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -781,7 +781,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do end Owl.IO.input(label: label, optional: true) - |> String.trim() + |> Kernel.||("") # common typo |> String.trim_leading(":") |> case do From f33cfbecd86870715de3532d69d23d66f7424a4d Mon Sep 17 00:00:00 2001 From: Moxley Stratton Date: Thu, 18 Sep 2025 04:12:32 -0700 Subject: [PATCH 639/690] test: Demonstrate failed query for is_nil on array within jsonb (#615) --- test/storage_types_test.exs | 3 ++- test/support/resources/author.ex | 2 +- test/support/resources/settings.ex | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 test/support/resources/settings.ex diff --git a/test/storage_types_test.exs b/test/storage_types_test.exs index 88783e54..6b5a44cd 100644 --- a/test/storage_types_test.exs +++ b/test/storage_types_test.exs @@ -66,6 +66,7 @@ defmodule AshPostgres.StorageTypesTest do |> Ash.read!() end + @tag capture_log: false test "`is_nil` operator works on get_path results" do %{id: id} = Author @@ -85,7 +86,7 @@ defmodule AshPostgres.StorageTypesTest do assert [%Author{id: ^id}] = Author - |> Ash.Query.filter(is_nil(settings["optional_field"])) + |> Ash.Query.filter(is_nil(settings["dues_reminders"])) |> Ash.read!() end end diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index 77ad0d15..e30f7592 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -30,7 +30,7 @@ defmodule AshPostgres.Test.Author do attribute(:bio, AshPostgres.Test.Bio, public?: true) attribute(:bios, {:array, :map}, public?: true) attribute(:badges, {:array, :atom}, public?: true) - attribute(:settings, :map, public?: true) + attribute(:settings, AshPostgres.Test.Settings, public?: true) end actions do diff --git a/test/support/resources/settings.ex b/test/support/resources/settings.ex new file mode 100644 index 00000000..681584db --- /dev/null +++ b/test/support/resources/settings.ex @@ -0,0 +1,10 @@ +defmodule AshPostgres.Test.Settings do + @moduledoc false + use Ash.Resource, data_layer: :embedded + + attributes do + attribute :dues_reminders, {:array, :string}, public?: true + attribute :newsletter, {:array, :string}, public?: true + attribute :optional_field, :string, public?: true + end +end From 850f7d267c8e2ffd6d558323327d01d74cff71b7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 18 Sep 2025 10:09:41 -0400 Subject: [PATCH 640/690] chore: update test to pass against ash_sql main --- test/storage_types_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/storage_types_test.exs b/test/storage_types_test.exs index 6b5a44cd..ca433860 100644 --- a/test/storage_types_test.exs +++ b/test/storage_types_test.exs @@ -86,7 +86,7 @@ defmodule AshPostgres.StorageTypesTest do assert [%Author{id: ^id}] = Author - |> Ash.Query.filter(is_nil(settings["dues_reminders"])) + |> Ash.Query.filter(not is_nil(settings["dues_reminders"])) |> Ash.read!() end end From 58c9543f2c8ce7ad8243a8296cf924c828c4e540 Mon Sep 17 00:00:00 2001 From: Robert Ellen Date: Fri, 19 Sep 2025 04:35:54 +1000 Subject: [PATCH 641/690] test: Add a test for an expr calc using an aggregation in a sort (#617) This replicates an issue seen. We have an expression calculation using a aggregation from a transitive relationship. If that calculation is used in a sort, the text of the expression is passed as the aggregate name, instead of a variable name such as "aggregate0" etc. E.g. ``` * ** (RuntimeError) Unbound aggregate field: "first(comments[field: :created_at, query: [filter: author_id == \"54c6b3da-d3a5-41f6-8409-780fed9fe184\"]])" ``` --- test/calculation_test.exs | 41 ++++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 28 +++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 68c975d9..cf539f18 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1076,4 +1076,45 @@ defmodule AshPostgres.CalculationTest do highest_score = hd(Enum.sort(scores, :desc)) assert post_with_highest_score.score == highest_score end + + test "an expression calculation can use an aggregate" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "my post"}) + |> Ash.create!() + + author = + Author + |> Ash.Changeset.for_create(:create, %{ + first_name: "ashley" + }) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "first comment"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + first_comment_by_author = + Comment + |> Ash.Changeset.for_create(:create, %{title: "first comment by Ashley"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + post = + Post + |> Ash.Query.for_read(:read_by_comment_author, %{ + author_id: author.id + }) + |> Ash.Query.sort_input([ + {"datetime_of_first_comment_by_author", {%{author_id: author.id}, :desc}} + ]) + |> Ash.read_one!() + + assert DateTime.compare( + post.datetime_of_first_comment_by_author, + first_comment_by_author.created_at + ) + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index e6009d57..817e0ff9 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -488,6 +488,20 @@ defmodule AshPostgres.Test.Post do pagination(keyset?: true, default_limit: 25) filter(expr(count_nils(latest_comment.linked_comment_post_ids) == 0)) end + + read :read_by_comment_author do + argument(:author_id, :uuid, allow_nil?: false) + + filter(expr(comments.author_id == ^arg(:author_id))) + + prepare( + build( + load: [ + datetime_of_first_comment_by_author: %{author_id: arg(:author_id)} + ] + ) + ) + end end identities do @@ -1030,6 +1044,20 @@ defmodule AshPostgres.Test.Post do calculate(:latest_comment_title, :string, expr(latest_comment.title), allow_nil?: true) calculate(:concated_comment_titles, :string, expr(fragment("concat(?)", comment_titles))) + + calculate :datetime_of_first_comment_by_author, + :utc_datetime_usec, + expr( + first(comments, + field: :created_at, + query: [ + filter: author_id == ^arg(:author_id) + ] + ) + ) do + public?(true) + argument(:author_id, :uuid, allow_nil?: false) + end end aggregates do From 1e09ef3e8031fea0f7fb62880468aa6c9b44279b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Sep 2025 07:37:03 -0400 Subject: [PATCH 642/690] chore: update ash_sql --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 90a49a91..602a8e67 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.40", "19b82796359f32520acd83581c5edfefd06e177fb3c15875f52d5f437f90d902", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.68 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", "278959afb7e54fd3e7184650bfd4ee6a45979aa3d37913d9e19a7400097eae2d"}, - "ash_sql": {:hex, :ash_sql, "0.2.92", "7ef55c307944e68bfd9de07a186fda4bc3b6b7b401f5c5a5cdd0fafafe75d7d2", [:mix], [{:ash, ">= 3.5.35 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", "445fea8343a17d3842ad48007ef07b09ffa28209b3e03ea8772062c42fc50df1"}, + "ash_sql": {:hex, :ash_sql, "0.2.93", "d2e50a718f18e67bffa8fd9c7bea39d260ca746ca4df357bd9726a3ad4a39294", [:mix], [{:ash, ">= 3.5.35 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", "492d811a636c19dad990c4f1af83761c0006ec5650970252f78cf4bd2b50b500"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From 798f37d0250e7298fd3b1fb60f197b19ddca2596 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Fri, 19 Sep 2025 07:37:24 -0400 Subject: [PATCH 643/690] chore: release version v2.6.18 --- CHANGELOG.md | 13 +++++++++++++ mix.exs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08169773..09e31680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.18](https://github.com/ash-project/ash_postgres/compare/v2.6.17...v2.6.18) (2025-09-19) + + + + +### Bug Fixes: + +* Handle optional/empty input in relationship name guesser (#616) by Trond A Ekseth + +* properly handle sorts w/ parent refs on lateral joins by Zach Daniel + +* annotate unrelated exists expressions as supported by Zach Daniel + ## [v2.6.17](https://github.com/ash-project/ash_postgres/compare/v2.6.16...v2.6.17) (2025-08-31) diff --git a/mix.exs b/mix.exs index 3e8719c1..ebb4daba 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.17" + @version "2.6.18" def project do [ From cd34939b5b4f9359d1d8b1c6056359fbfeb05795 Mon Sep 17 00:00:00 2001 From: Kantum <43590963+kantum@users.noreply.github.com> Date: Sat, 20 Sep 2025 21:05:06 +0200 Subject: [PATCH 644/690] docs: list_tenants -> all_tenants (#619) --- documentation/topics/development/migrations-and-tasks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/topics/development/migrations-and-tasks.md b/documentation/topics/development/migrations-and-tasks.md index 04fefc93..5fd26271 100644 --- a/documentation/topics/development/migrations-and-tasks.md +++ b/documentation/topics/development/migrations-and-tasks.md @@ -19,9 +19,9 @@ dev migrations and run them. For more information on generating migrations, run `mix help ash_postgres.generate_migrations` (the underlying task that is called by `mix ash.migrate`) -> ### list_tenants/0 {: .info} +> ### all_tenants/0 {: .info} > -> If you have are using schema-based multitenancy, you will also need to define a `list_tenants/0` function in your repo module. See `AshPostgres.Repo` for more. +> If you have are using schema-based multitenancy, you will also need to define a `all_tenants/0` function in your repo module. See `AshPostgres.Repo` for more. ### Regenerating Migrations From 98ea317e02dfe6034603f1be60ba2a895cadd2d0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 20 Sep 2025 17:43:17 -0400 Subject: [PATCH 645/690] fix: fix conditional on installing ash in installer --- lib/mix/tasks/ash_postgres.install.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 5bfa39f4..6808cbfb 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -39,6 +39,8 @@ if Code.ensure_loaded?(Igniter) do igniter = if Igniter.Project.Deps.has_dep?(igniter, :ash) do igniter + else + igniter |> Igniter.Project.Deps.add_dep({:ash, "~> 3.0"}, yes: opts[:yes]) |> then(fn %{assigns: %{test_mode?: true}} = igniter -> @@ -52,8 +54,6 @@ if Code.ensure_loaded?(Igniter) do ) end) |> Igniter.compose_task("ash.install", argv) - else - igniter end igniter From dce5c4b3e29546fff543df12b26d8adf8fa586f9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 20 Sep 2025 17:43:42 -0400 Subject: [PATCH 646/690] chore: release version v2.6.19 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e31680..4b9eaa03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.19](https://github.com/ash-project/ash_postgres/compare/v2.6.18...v2.6.19) (2025-09-20) + + + + +### Bug Fixes: + +* fix conditional on installing ash in installer by Zach Daniel + ## [v2.6.18](https://github.com/ash-project/ash_postgres/compare/v2.6.17...v2.6.18) (2025-09-19) diff --git a/mix.exs b/mix.exs index ebb4daba..22d502f0 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.18" + @version "2.6.19" def project do [ From 53d2a9525eb726a45f81bbaba59f3e93efcd4065 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 20 Sep 2025 23:03:39 -0400 Subject: [PATCH 647/690] fix: use `:mutate` repo for on_transaction_begin callback --- lib/data_layer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index e4cde133..43b8f5a1 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3561,7 +3561,7 @@ defmodule AshPostgres.DataLayer do repo _ -> - AshPostgres.DataLayer.Info.repo(resource, :read) + AshPostgres.DataLayer.Info.repo(resource, :mutate) end func = fn -> From ee2d2f5f9dea646c4a3bccd7a2f6f19b22f878b9 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 21 Sep 2025 09:47:46 -0400 Subject: [PATCH 648/690] chore: remove ash installation step in ash_postgres --- lib/mix/tasks/ash_postgres.install.ex | 21 --------------------- mix.lock | 8 ++++---- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 6808cbfb..4935fdf1 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -22,7 +22,6 @@ if Code.ensure_loaded?(Igniter) do @impl true def igniter(igniter) do - argv = igniter.args.argv opts = igniter.args.options repo = @@ -36,26 +35,6 @@ if Code.ensure_loaded?(Igniter) do otp_app = Igniter.Project.Application.app_name(igniter) - igniter = - if Igniter.Project.Deps.has_dep?(igniter, :ash) do - igniter - else - igniter - |> Igniter.Project.Deps.add_dep({:ash, "~> 3.0"}, yes: opts[:yes]) - |> then(fn - %{assigns: %{test_mode?: true}} = igniter -> - igniter - - igniter -> - Igniter.apply_and_fetch_dependencies(igniter, - error_on_abort?: true, - yes: opts[:yes], - yes_to_deps: true - ) - end) - |> Igniter.compose_task("ash.install", argv) - end - igniter |> Igniter.Project.Formatter.import_dep(:ash_postgres) |> setup_aliases() diff --git a/mix.lock b/mix.lock index 602a8e67..78a54f83 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.40", "19b82796359f32520acd83581c5edfefd06e177fb3c15875f52d5f437f90d902", [: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.6.4 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.68 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", "278959afb7e54fd3e7184650bfd4ee6a45979aa3d37913d9e19a7400097eae2d"}, + "ash": {:hex, :ash, "3.5.42", "bdd84c468c05e497a8b1ee579901274125c540b66df82ed67c35f889a529ee70", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.68 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", "dc0988e171630401e8eab65c95ac33c04b8fe47084fc038e80f4d713cb2d44ba"}, "ash_sql": {:hex, :ash_sql, "0.2.93", "d2e50a718f18e67bffa8fd9c7bea39d260ca746ca4df357bd9726a3ad4a39294", [:mix], [{:ash, ">= 3.5.35 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", "492d811a636c19dad990c4f1af83761c0006ec5650970252f78cf4bd2b50b500"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -9,7 +9,7 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, - "ecto": {:hex, :ecto, "3.13.2", "7d0c0863f3fc8d71d17fc3ad3b9424beae13f02712ad84191a826c7169484f01", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "669d9291370513ff56e7b7e7081b7af3283d02e046cf3d403053c557894a0b3e"}, + "ecto": {:hex, :ecto, "3.13.3", "6a983f0917f8bdc7a89e96f2bf013f220503a0da5d8623224ba987515b3f0d80", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1927db768f53a88843ff25b6ba7946599a8ca8a055f69ad8058a1432a399af94"}, "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, "ecto_sql": {:hex, :ecto_sql, "3.13.2", "a07d2461d84107b3d037097c822ffdd36ed69d1cf7c0f70e12a3d1decf04e2e1", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "539274ab0ecf1a0078a6a72ef3465629e4d6018a3028095dc90f60a19c371717"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.28", "9db10192f19f10b924f14c805f5b2ad992617fccaff9cf9582b7f065d562d4d8", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "ad9369d626aeca21079ef17661a2672fb32598610c5e5bccae2537efd36b27d4"}, + "igniter": {:hex, :igniter, "0.6.29", "58ec46e601445df5ff3d98e65dce1305b10f23391d8f43558bc22bcbb3e1a7f0", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "b45a5c70dcee77afd81a71c707fda7d0a8637061c60cdee639dc38d049443e02"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -38,7 +38,7 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.13.0", "26010e066d5992774268f3163506972ddac0a7e77bfe57fa42a250f24d6b876e", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "59bf9d11ce37a4db98f57cb68fbfd61593bf419ec4ed302852b6683d3d2f7475"}, "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, - "reactor": {:hex, :reactor, "0.15.6", "d717f9add549b25a089a94c90197718d2d838e35d81dd776b1d81587d4cf2aaa", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "74db98165e3644d86e0f723672d91ceca4339eaa935bcad7e78bf146a46d77b9"}, + "reactor": {:hex, :reactor, "0.16.0", "394087fe0f01b09e5cbcbf6525d9a54cd484582214e0e9e59f69ebc8d79eb70c", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "9ac43e70a9a36c5a016b02b6c068933dfd36edc0e3abd9cd6325a30194900c66"}, "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, From fefb612c3c873b65638e68df45f12edc41dcbd81 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 21 Sep 2025 22:02:04 -0400 Subject: [PATCH 649/690] chore: format --- test/support/resources/settings.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/support/resources/settings.ex b/test/support/resources/settings.ex index 681584db..b24b3afc 100644 --- a/test/support/resources/settings.ex +++ b/test/support/resources/settings.ex @@ -3,8 +3,8 @@ defmodule AshPostgres.Test.Settings do use Ash.Resource, data_layer: :embedded attributes do - attribute :dues_reminders, {:array, :string}, public?: true - attribute :newsletter, {:array, :string}, public?: true - attribute :optional_field, :string, public?: true + attribute(:dues_reminders, {:array, :string}, public?: true) + attribute(:newsletter, {:array, :string}, public?: true) + attribute(:optional_field, :string, public?: true) end end From 36ccc75f52fcc545a6bccf45d0531e277bc38fde Mon Sep 17 00:00:00 2001 From: siassaj Date: Sat, 27 Sep 2025 11:59:43 +0300 Subject: [PATCH 650/690] improvement: use default constraint of 'now()' for AshPostgres.Timestamptz (#621) AshPostgres.Timestamptz creates a pg column of type 'timestamptz', however the existing default behaviour was to implement the default constraint as a 'timestamp' type. Effectively 'now()::timestamptz' was converted to 'timestamp' then back to 'timestamptz'. This has been changed to 'now()'. --- lib/migration_generator/migration_generator.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 86920ed4..1a3a396d 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3489,7 +3489,7 @@ defmodule AshPostgres.MigrationGenerator do @uuid_functions [&Ash.UUID.generate/0, &Ecto.UUID.generate/0] - defp default(%{name: name, default: default}, resource, _repo) when is_function(default) do + defp default(%{name: name, default: default, type: type}, resource, _repo) when is_function(default) do configured_default(resource, name) || cond do default in @uuid_functions -> @@ -3498,6 +3498,9 @@ defmodule AshPostgres.MigrationGenerator do default == (&Ash.UUIDv7.generate/0) -> ~S[fragment("uuid_generate_v7()")] + default == (&DateTime.utc_now/0) && type == AshPostgres.Timestamptz -> + ~S[fragment("now()")] + default == (&DateTime.utc_now/0) -> ~S[fragment("(now() AT TIME ZONE 'utc')")] From 4021b73e2609439c0cf853c7837b118bebfa1fc0 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Sep 2025 05:26:12 -0400 Subject: [PATCH 651/690] chore: update spark & fix warnings --- lib/check_constraint.ex | 2 +- lib/custom_index.ex | 3 ++- lib/reference.ex | 1 + lib/statement.ex | 3 ++- mix.exs | 1 + mix.lock | 4 ++-- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/check_constraint.ex b/lib/check_constraint.ex index 3cfeecd7..a16e7346 100644 --- a/lib/check_constraint.ex +++ b/lib/check_constraint.ex @@ -1,7 +1,7 @@ defmodule AshPostgres.CheckConstraint do @moduledoc "Represents a configured check constraint on the table backing a resource" - defstruct [:attribute, :name, :message, :check] + defstruct [:attribute, :name, :message, :check, :__spark_metadata__] def schema do [ diff --git a/lib/custom_index.ex b/lib/custom_index.ex index 9d037331..9972e4da 100644 --- a/lib/custom_index.ex +++ b/lib/custom_index.ex @@ -13,7 +13,8 @@ defmodule AshPostgres.CustomIndex do :include, :nulls_distinct, :message, - :all_tenants? + :all_tenants?, + :__spark_metadata__ ] defstruct @fields diff --git a/lib/reference.ex b/lib/reference.ex index 724251e0..e724a0b6 100644 --- a/lib/reference.ex +++ b/lib/reference.ex @@ -9,6 +9,7 @@ defmodule AshPostgres.Reference do :match_type, :deferrable, :index?, + :__spark_metadata__, ignore?: false ] diff --git a/lib/statement.ex b/lib/statement.ex index ae04496e..ba51622d 100644 --- a/lib/statement.ex +++ b/lib/statement.ex @@ -5,7 +5,8 @@ defmodule AshPostgres.Statement do :name, :up, :down, - :code? + :code?, + :__spark_metadata__ ] defstruct @fields diff --git a/mix.exs b/mix.exs index 22d502f0..6c02fab0 100644 --- a/mix.exs +++ b/mix.exs @@ -167,6 +167,7 @@ defmodule AshPostgres.MixProject do defp deps do [ {:ash, ash_version("~> 3.5 and >= 3.5.35")}, + {:spark, "~> 2.3 and >= 2.3.4"}, {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.90")}, {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, diff --git a/mix.lock b/mix.lock index 78a54f83..90c38313 100644 --- a/mix.lock +++ b/mix.lock @@ -23,7 +23,7 @@ "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.29", "58ec46e601445df5ff3d98e65dce1305b10f23391d8f43558bc22bcbb3e1a7f0", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "b45a5c70dcee77afd81a71c707fda7d0a8637061c60cdee639dc38d049443e02"}, + "igniter": {:hex, :igniter, "0.6.30", "83a466369ebb8fe009e0823c7bf04314dc545122c2d48f896172fc79df33e99d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "76a14d5b7f850bb03b5243088c3649d54a2e52e34a2aa1104dee23cf50a8bae0"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, @@ -44,7 +44,7 @@ "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.2.68", "4c4547c88d73311e3157bc402ab27f3a7bbd5e55a2ee92bcf7cd3a0a475d201e", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "2fa4dd89801415a098a421589633f0e3df7ed9ff4046e80a65d35a413bc0d194"}, + "spark": {:hex, :spark, "2.3.4", "3fe37fdfa01e3f7c9f4ced16b7b9950d5bfbb7fab024148e1968b0460ce1336b", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "c0293d41461f1c1f1774379c668a240b008f4f8dcd550ea82b06163a55dcd53b"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"}, From 702ce5e56052a8ffd5399a9b52f7f9b2df94bf84 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Sep 2025 05:58:47 -0400 Subject: [PATCH 652/690] chore: update tests to account for warnings --- test/aggregate_test.exs | 55 ++++++++++++++++++--------------- test/references_test.exs | 66 +++++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index d17b753b..e26ca964 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1,5 +1,6 @@ defmodule AshSql.AggregateTest do use AshPostgres.RepoCase, async: false + import ExUnit.CaptureIO alias AshPostgres.Test.{Author, Comment, Organization, Post, Rating, User} require Ash.Query @@ -970,37 +971,41 @@ defmodule AshSql.AggregateTest do end test "can't define multidimensional array aggregate types" do - assert_raise Spark.Error.DslError, ~r/Aggregate not supported/, fn -> - defmodule Foo do - @moduledoc false - use Ash.Resource, - domain: nil, - data_layer: AshPostgres.DataLayer - - postgres do - table("profile") - repo(AshPostgres.TestRepo) - end + # This used to raise an error, but now should only emit a warning and allow the module to compile + {_, io} = + with_io(:stderr, fn -> + defmodule Foo do + @moduledoc false + use Ash.Resource, + domain: nil, + data_layer: AshPostgres.DataLayer + + postgres do + table("profile") + repo(AshPostgres.TestRepo) + end - attributes do - uuid_primary_key(:id, writable?: true) - end + attributes do + uuid_primary_key(:id, writable?: true) + end - actions do - defaults([:create, :read, :update, :destroy]) - end + actions do + defaults([:create, :read, :update, :destroy]) + end - relationships do - belongs_to(:author, AshPostgres.Test.Author) do - public?(true) + relationships do + belongs_to(:author, AshPostgres.Test.Author) do + public?(true) + end end - end - aggregates do - first(:author_badges, :author, :badges) + aggregates do + first(:author_badges, :author, :badges) + end end - end - end + end) + + assert io =~ "Aggregate not supported" end test "related aggregates can be filtered on" do diff --git a/test/references_test.exs b/test/references_test.exs index a8be1d07..7632c9f8 100644 --- a/test/references_test.exs +++ b/test/references_test.exs @@ -1,5 +1,6 @@ defmodule AshPostgres.ReferencesTest do use AshPostgres.RepoCase + import ExUnit.CaptureIO test "can't use match_type != :full when referencing an non-primary key index" do Code.compiler_options(ignore_module_conflict: true) @@ -66,44 +67,47 @@ defmodule AshPostgres.ReferencesTest do end end - assert_raise Spark.Error.DslError, ~r/Unsupported match_type./, fn -> - defmodule UserThing do - @moduledoc false - use Ash.Resource, - domain: nil, - data_layer: AshPostgres.DataLayer - - attributes do - attribute(:id, :string, primary_key?: true, allow_nil?: false, public?: true) - attribute(:name, :string, public?: true) - attribute(:org_id, :uuid, public?: true) - attribute(:foo_id, :uuid, public?: true) - end + {_, io} = + with_io(:stderr, fn -> + defmodule UserThing do + @moduledoc false + use Ash.Resource, + domain: nil, + data_layer: AshPostgres.DataLayer + + attributes do + attribute(:id, :string, primary_key?: true, allow_nil?: false, public?: true) + attribute(:name, :string, public?: true) + attribute(:org_id, :uuid, public?: true) + attribute(:foo_id, :uuid, public?: true) + end - multitenancy do - strategy(:attribute) - attribute(:org_id) - end + multitenancy do + strategy(:attribute) + attribute(:org_id) + end - relationships do - belongs_to(:org, Org) - belongs_to(:user, User, destination_attribute: :secondary_id) - end + relationships do + belongs_to(:org, Org) + belongs_to(:user, User, destination_attribute: :secondary_id) + end - postgres do - table("user_things") - repo(AshPostgres.TestRepo) + postgres do + table("user_things") + repo(AshPostgres.TestRepo) - references do - reference :user, match_with: [foo_id: :foo_id], match_type: :simple + references do + reference :user, match_with: [foo_id: :foo_id], match_type: :simple + end end - end - actions do - defaults([:create, :read, :update, :destroy]) + actions do + defaults([:create, :read, :update, :destroy]) + end end - end - end + end) + + assert io =~ "Unsupported match_type" end test "named reference results in properly applied foreign_key_constraint/3 on the underlying changeset" do From a35894b08caf915e3b205cd19f6b3735b30cc2aa Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Sep 2025 06:18:14 -0400 Subject: [PATCH 653/690] improvement: location in spark errors and migration generator fixes --- lib/custom_index.ex | 5 ++--- lib/migration_generator/migration_generator.ex | 8 ++++++-- lib/statement.ex | 5 ++--- lib/verifiers/ensure_table_or_polymorphic.ex | 3 ++- ...ent_attribute_multitenancy_and_non_full_match_type.ex | 3 ++- .../prevent_multidimensional_array_aggregates.ex | 3 ++- lib/verifiers/validate_identity_index_names.ex | 9 ++++++--- lib/verifiers/validate_references.ex | 3 ++- 8 files changed, 24 insertions(+), 15 deletions(-) diff --git a/lib/custom_index.ex b/lib/custom_index.ex index 9972e4da..29496ceb 100644 --- a/lib/custom_index.ex +++ b/lib/custom_index.ex @@ -13,11 +13,10 @@ defmodule AshPostgres.CustomIndex do :include, :nulls_distinct, :message, - :all_tenants?, - :__spark_metadata__ + :all_tenants? ] - defstruct @fields + defstruct @fields ++ [:__spark_metadata__] def fields, do: @fields diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 1a3a396d..c0a1abac 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3044,6 +3044,7 @@ defmodule AshPostgres.MigrationGenerator do identity_index_names[identity.name] || "#{relationship.context[:data_layer][:table]}_#{identity.name}_index" ) + |> Map.delete(:__spark_metadata__) end) end) |> Map.update!(:attributes, fn attributes -> @@ -3057,7 +3058,9 @@ defmodule AshPostgres.MigrationGenerator do source_attribute = Ash.Resource.Info.attribute(relationship.source, relationship.source_attribute) - Map.put(attribute, :references, %{ + attribute + |> Map.delete(:__spark_metadata__) + |> Map.put(:references, %{ destination_attribute: source_attribute.source, destination_attribute_default: default( @@ -3489,7 +3492,8 @@ defmodule AshPostgres.MigrationGenerator do @uuid_functions [&Ash.UUID.generate/0, &Ecto.UUID.generate/0] - defp default(%{name: name, default: default, type: type}, resource, _repo) when is_function(default) do + defp default(%{name: name, default: default, type: type}, resource, _repo) + when is_function(default) do configured_default(resource, name) || cond do default in @uuid_functions -> diff --git a/lib/statement.ex b/lib/statement.ex index ba51622d..dfc49322 100644 --- a/lib/statement.ex +++ b/lib/statement.ex @@ -5,11 +5,10 @@ defmodule AshPostgres.Statement do :name, :up, :down, - :code?, - :__spark_metadata__ + :code? ] - defstruct @fields + defstruct @fields ++ [:__spark_metadata__] def fields, do: @fields diff --git a/lib/verifiers/ensure_table_or_polymorphic.ex b/lib/verifiers/ensure_table_or_polymorphic.ex index 1f60b8ed..c2e612ca 100644 --- a/lib/verifiers/ensure_table_or_polymorphic.ex +++ b/lib/verifiers/ensure_table_or_polymorphic.ex @@ -24,7 +24,8 @@ defmodule AshPostgres.Verifiers.EnsureTableOrPolymorphic do end ``` """, - path: [:postgres, :table] + path: [:postgres, :table], + location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres]) end end end diff --git a/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex b/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex index 0d9e71c8..5e0a25cc 100644 --- a/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex +++ b/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex @@ -23,7 +23,8 @@ defmodule AshPostgres.Verifiers.PreventAttributeMultitenancyAndNonFullMatchType The reference #{inspect(resource)}.#{reference.relationship} can't have `match_type: :#{reference.match_type}` because it's referencing another multitenant resource with attribute strategy using a non-primary key index, which requires using `match_type: :full`. """, - path: [:postgres, :references, reference.relationship] + path: [:postgres, :references, reference.relationship], + location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :references]) else :ok end diff --git a/lib/verifiers/prevent_multidimensional_array_aggregates.ex b/lib/verifiers/prevent_multidimensional_array_aggregates.ex index cdb688b4..5bea26eb 100644 --- a/lib/verifiers/prevent_multidimensional_array_aggregates.ex +++ b/lib/verifiers/prevent_multidimensional_array_aggregates.ex @@ -35,7 +35,8 @@ defmodule AshPostgres.Verifiers.PreventMultidimensionalArrayAggregates do Postgres does not support multidimensional arrays with differing lengths internally. In the future we may be able to remove this restriction for the `:first` type aggregate, but likely never for `:list`. In the meantime, you will have to use a custom calculation to get this data. - """ + """, + location: Ash.Resource.Info.aggregate(resource, aggregate.name) |> Spark.Dsl.Entity.anno() _ -> :ok diff --git a/lib/verifiers/validate_identity_index_names.ex b/lib/verifiers/validate_identity_index_names.ex index 269e881e..91ef203c 100644 --- a/lib/verifiers/validate_identity_index_names.ex +++ b/lib/verifiers/validate_identity_index_names.ex @@ -14,7 +14,8 @@ defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do module: Verifier.get_persisted(dsl, :module), message: """ Identity #{identity} has a name that is too long. Names must be 63 characters or less. - """ + """, + location: Spark.Dsl.Transformer.get_opt_anno(dsl, [:postgres, :identity_index_names], identity) end end) @@ -36,7 +37,8 @@ defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do Multiple identities would result in the same index name: #{name} Identities: #{inspect(Enum.map(identities, & &1.name))} - """ + """, + location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :identity_index_names]) {name, [identity]} -> if String.length(name) > 63 do @@ -51,7 +53,8 @@ defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do postgres do identity_index_names #{identity.name}: "a_shorter_name" end - """ + """, + location: Spark.Dsl.Entity.anno(identity) end end) end diff --git a/lib/verifiers/validate_references.ex b/lib/verifiers/validate_references.ex index 3f2c90aa..40c47a8e 100644 --- a/lib/verifiers/validate_references.ex +++ b/lib/verifiers/validate_references.ex @@ -12,7 +12,8 @@ defmodule AshPostgres.Verifiers.ValidateReferences do path: [:postgres, :references, reference.relationship], module: Verifier.get_persisted(dsl, :module), message: - "Found reference configuration for relationship `#{reference.relationship}`, but no such relationship exists" + "Found reference configuration for relationship `#{reference.relationship}`, but no such relationship exists", + location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :references]) end end) From 03d26cbbb4fdda321834267a10ef72e119180763 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Sep 2025 06:29:51 -0400 Subject: [PATCH 654/690] chore: more fixes around spark_metadata --- lib/migration_generator/migration_generator.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index c0a1abac..fcb44c95 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3580,6 +3580,7 @@ defmodule AshPostgres.MigrationGenerator do end) %{index | fields: fields} + |> Map.delete(:__spark_metadata__) end) end) |> Map.update!(:identities, fn identities -> @@ -3591,6 +3592,7 @@ defmodule AshPostgres.MigrationGenerator do end) %{identity | keys: keys} + |> Map.delete(:__spark_metadata__) end) end) |> to_ordered_object() @@ -3610,6 +3612,7 @@ defmodule AshPostgres.MigrationGenerator do |> Map.update!(:type, fn type -> sanitize_type(type, attribute[:size], attribute[:precision], attribute[:scale]) end) + |> Map.delete(:__spark_metadata__) end defp references_on_delete_to_binary(value) when is_atom(value), do: value From 7be8af41ffdd4650c2e70d380b2b44b20d2faf6e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Sep 2025 06:31:44 -0400 Subject: [PATCH 655/690] chore: format --- lib/verifiers/prevent_multidimensional_array_aggregates.ex | 3 ++- lib/verifiers/validate_identity_index_names.ex | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/verifiers/prevent_multidimensional_array_aggregates.ex b/lib/verifiers/prevent_multidimensional_array_aggregates.ex index 5bea26eb..82a38202 100644 --- a/lib/verifiers/prevent_multidimensional_array_aggregates.ex +++ b/lib/verifiers/prevent_multidimensional_array_aggregates.ex @@ -36,7 +36,8 @@ defmodule AshPostgres.Verifiers.PreventMultidimensionalArrayAggregates do Postgres does not support multidimensional arrays with differing lengths internally. In the future we may be able to remove this restriction for the `:first` type aggregate, but likely never for `:list`. In the meantime, you will have to use a custom calculation to get this data. """, - location: Ash.Resource.Info.aggregate(resource, aggregate.name) |> Spark.Dsl.Entity.anno() + location: + Ash.Resource.Info.aggregate(resource, aggregate.name) |> Spark.Dsl.Entity.anno() _ -> :ok diff --git a/lib/verifiers/validate_identity_index_names.ex b/lib/verifiers/validate_identity_index_names.ex index 91ef203c..82457eb2 100644 --- a/lib/verifiers/validate_identity_index_names.ex +++ b/lib/verifiers/validate_identity_index_names.ex @@ -15,7 +15,8 @@ defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do message: """ Identity #{identity} has a name that is too long. Names must be 63 characters or less. """, - location: Spark.Dsl.Transformer.get_opt_anno(dsl, [:postgres, :identity_index_names], identity) + location: + Spark.Dsl.Transformer.get_opt_anno(dsl, [:postgres, :identity_index_names], identity) end end) @@ -38,7 +39,8 @@ defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do Identities: #{inspect(Enum.map(identities, & &1.name))} """, - location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :identity_index_names]) + location: + Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :identity_index_names]) {name, [identity]} -> if String.length(name) > 63 do From ed3ff07c8c1287b36f2ad4925c79c5590bc38e6c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Sep 2025 06:31:55 -0400 Subject: [PATCH 656/690] chore: release version v2.6.20 --- CHANGELOG.md | 15 +++++++++++++++ mix.exs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b9eaa03..f6546f3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.20](https://github.com/ash-project/ash_postgres/compare/v2.6.19...v2.6.20) (2025-09-27) + + + + +### Bug Fixes: + +* use `:mutate` repo for on_transaction_begin callback by Zach Daniel + +### Improvements: + +* location in spark errors and migration generator fixes by Zach Daniel + +* use default constraint of 'now()' for AshPostgres.Timestamptz (#621) by siassaj + ## [v2.6.19](https://github.com/ash-project/ash_postgres/compare/v2.6.18...v2.6.19) (2025-09-20) diff --git a/mix.exs b/mix.exs index 6c02fab0..00778fec 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.19" + @version "2.6.20" def project do [ From 1130a0235da46e82d452ea9ca08b415cebf8678a Mon Sep 17 00:00:00 2001 From: Chris O'Donnell Date: Sun, 28 Sep 2025 21:11:05 -0400 Subject: [PATCH 657/690] test: write failing test to illustrate regression (#622) --- test/aggregate_test.exs | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index e26ca964..4803ec5c 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1683,4 +1683,51 @@ defmodule AshSql.AggregateTest do |> Ash.read_one!() end end + + @tag :regression + test "count is accurate" do + org = + AshPostgres.Test.Organization + |> Ash.Changeset.for_create(:create, %{name: "Test Org"}) + |> Ash.create!() + + user = + AshPostgres.Test.User + |> Ash.Changeset.for_create(:create, %{name: "test_user", organization_id: org.id}) + |> Ash.create!() + + AshPostgres.Test.User + |> Ash.Changeset.for_create(:create, %{name: "another_user", organization_id: org.id}) + |> Ash.create!() + + author = + AshPostgres.Test.Author + |> Ash.Changeset.for_create(:create, %{first_name: "Test", last_name: "Author"}) + |> Ash.create!() + + post = + AshPostgres.Test.Post + |> Ash.Changeset.for_create(:create, %{ + title: "Test Post", + organization_id: org.id, + author_id: author.id + }) + |> Ash.create!() + + AshPostgres.Test.Comment + |> Ash.Changeset.for_create(:create, %{ + title: "First comment", + post_id: post.id, + author_id: author.id + }) + |> Ash.create!() + + loaded_post = + AshPostgres.Test.Post + |> Ash.Query.filter(id == ^post.id) + |> Ash.Query.load(:count_of_comments) + |> Ash.read_one!(actor: user) + + assert loaded_post.count_of_comments == 1 + end end From 28862b1c78ebb1277f7571824e39b7f8ec689a12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 23:19:13 -0400 Subject: [PATCH 658/690] chore(deps): bump the production-dependencies group with 3 updates (#625) Bumps the production-dependencies group with 3 updates: [ash](https://github.com/ash-project/ash), [ash_sql](https://github.com/ash-project/ash_sql) and [spark](https://github.com/ash-project/spark). Updates `ash` from 3.5.42 to 3.5.43 - [Release notes](https://github.com/ash-project/ash/releases) - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.5.42...v3.5.43) Updates `ash_sql` from 0.2.93 to 0.3.0 - [Release notes](https://github.com/ash-project/ash_sql/releases) - [Changelog](https://github.com/ash-project/ash_sql/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash_sql/compare/v0.2.93...v0.3.0) Updates `spark` from 2.3.4 to 2.3.5 - [Release notes](https://github.com/ash-project/spark/releases) - [Changelog](https://github.com/ash-project/spark/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/spark/compare/v2.3.4...v2.3.5) --- updated-dependencies: - dependency-name: ash dependency-version: 3.5.43 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: ash_sql dependency-version: 0.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies - dependency-name: spark dependency-version: 2.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mix.lock b/mix.lock index 90c38313..726124db 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ - "ash": {:hex, :ash, "3.5.42", "bdd84c468c05e497a8b1ee579901274125c540b66df82ed67c35f889a529ee70", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.68 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", "dc0988e171630401e8eab65c95ac33c04b8fe47084fc038e80f4d713cb2d44ba"}, - "ash_sql": {:hex, :ash_sql, "0.2.93", "d2e50a718f18e67bffa8fd9c7bea39d260ca746ca4df357bd9726a3ad4a39294", [:mix], [{:ash, ">= 3.5.35 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", "492d811a636c19dad990c4f1af83761c0006ec5650970252f78cf4bd2b50b500"}, + "ash": {:hex, :ash, "3.5.43", "222f9a8ac26ad3b029f8e69306cc83091c992d858b4538af12e33a148f301cab", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "48b2aa274c524f5b968c563dd56aec8f9b278c529c8aa46e6fe0ca564c26cc1c"}, + "ash_sql": {:hex, :ash_sql, "0.3.0", "2c43ddcc8c7fb51dc25ba3bca965d8b68e7aaecb290cabfed3cf213965aca937", [:mix], [{:ash, ">= 3.5.43 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", "ef03759d6a1d4cb189fcadbd183cf047f0565d7d88ea8612d85c9e6e724835e7"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -38,13 +38,13 @@ "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.13.0", "26010e066d5992774268f3163506972ddac0a7e77bfe57fa42a250f24d6b876e", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "59bf9d11ce37a4db98f57cb68fbfd61593bf419ec4ed302852b6683d3d2f7475"}, "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, - "reactor": {:hex, :reactor, "0.16.0", "394087fe0f01b09e5cbcbf6525d9a54cd484582214e0e9e59f69ebc8d79eb70c", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "9ac43e70a9a36c5a016b02b6c068933dfd36edc0e3abd9cd6325a30194900c66"}, + "reactor": {:hex, :reactor, "0.17.0", "eb8bdb530dbae824e2d36a8538f8ec4f3aa7c2d1b61b04959fa787c634f88b49", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, ">= 2.3.3 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "3c3bf71693adbad9117b11ec83cfed7d5851b916ade508ed9718de7ae165bf25"}, "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, - "spark": {:hex, :spark, "2.3.4", "3fe37fdfa01e3f7c9f4ced16b7b9950d5bfbb7fab024148e1968b0460ce1336b", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "c0293d41461f1c1f1774379c668a240b008f4f8dcd550ea82b06163a55dcd53b"}, + "spark": {:hex, :spark, "2.3.5", "f30d30ecc3b4ab9b932d9aada66af7677fc1f297a2c349b0bcec3eafb9f996e8", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "0e9d339704d5d148f77f2b2fef3bcfc873a9e9bb4224fcf289c545d65827202f"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, "splode": {:hex, :splode, "0.2.9", "3a2776e187c82f42f5226b33b1220ccbff74f4bcc523dd4039c804caaa3ffdc7", [:mix], [], "hexpm", "8002b00c6e24f8bd1bcced3fbaa5c33346048047bb7e13d2f3ad428babbd95c3"}, "statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"}, @@ -53,6 +53,6 @@ "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, "tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, - "yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"}, + "yaml_elixir": {:hex, :yaml_elixir, "2.12.0", "30343ff5018637a64b1b7de1ed2a3ca03bc641410c1f311a4dbdc1ffbbf449c7", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "ca6bacae7bac917a7155dca0ab6149088aa7bc800c94d0fe18c5238f53b313c6"}, "ymlr": {:hex, :ymlr, "5.1.4", "b924d61e1fc1ec371cde6ab3ccd9311110b1e052fc5c2460fb322e8380e7712a", [:mix], [], "hexpm", "75f16cf0709fbd911b30311a0359a7aa4b5476346c01882addefd5f2b1cfaa51"}, } From 14581be77761b62f26597f8f0648540523fef96e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 23:19:22 -0400 Subject: [PATCH 659/690] chore(deps-dev): bump the dev-dependencies group with 4 updates (#624) Bumps the dev-dependencies group with 4 updates: [dialyxir](https://github.com/jeremyjh/dialyxir), [ecto_dev_logger](https://github.com/fuelen/ecto_dev_logger), [ex_doc](https://github.com/elixir-lang/ex_doc) and [git_ops](https://github.com/zachdaniel/git_ops). Updates `dialyxir` from 1.4.5 to 1.4.6 - [Release notes](https://github.com/jeremyjh/dialyxir/releases) - [Changelog](https://github.com/jeremyjh/dialyxir/blob/master/CHANGELOG.md) - [Commits](https://github.com/jeremyjh/dialyxir/compare/1.4.5...1.4.6) Updates `ecto_dev_logger` from 0.14.1 to 0.15.0 - [Release notes](https://github.com/fuelen/ecto_dev_logger/releases) - [Commits](https://github.com/fuelen/ecto_dev_logger/compare/v0.14.1...v0.15.0) Updates `ex_doc` from 0.38.2 to 0.38.4 - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.38.2...v0.38.4) Updates `git_ops` from 2.8.0 to 2.9.0 - [Changelog](https://github.com/zachdaniel/git_ops/blob/master/CHANGELOG.md) - [Commits](https://github.com/zachdaniel/git_ops/compare/v2.8.0...v2.9.0) --- updated-dependencies: - dependency-name: dialyxir dependency-version: 1.4.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: ecto_dev_logger dependency-version: 0.15.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: ex_doc dependency-version: 0.38.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: git_ops dependency-version: 2.9.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 726124db..be72f892 100644 --- a/mix.lock +++ b/mix.lock @@ -7,20 +7,20 @@ "db_connection": {:hex, :db_connection, "2.8.1", "9abdc1e68c34c6163f6fb96a96532272d13ad7ca45262156ae8b7ec6d9dc4bec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61a3d489b239d76f326e03b98794fb8e45168396c925ef25feb405ed09da8fd"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, + "dialyxir": {:hex, :dialyxir, "1.4.6", "7cca478334bf8307e968664343cbdb432ee95b4b68a9cba95bdabb0ad5bdfd9a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "8cf5615c5cd4c2da6c501faae642839c8405b49f8aa057ad4ae401cb808ef64d"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "ecto": {:hex, :ecto, "3.13.3", "6a983f0917f8bdc7a89e96f2bf013f220503a0da5d8623224ba987515b3f0d80", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1927db768f53a88843ff25b6ba7946599a8ca8a055f69ad8058a1432a399af94"}, - "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.14.1", "af385ce1af1c4210ad67a4c46b985c370713446a179144a1da2885138c9fb242", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "14a64ebae728b3c45db6ba8bb185979c8e01fc1b0d3d1d9c01c7a2b798e8c698"}, + "ecto_dev_logger": {:hex, :ecto_dev_logger, "0.15.0", "df5a997ffb17dca9011556857a0f5b7d8cd53ca7c452ef98828664b6e48d4400", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:geo, "~> 3.5 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.17", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "b2c807d7d599a4fcf288139851c09262333b193bdb41f8d65f515853d117e88a"}, "ecto_sql": {:hex, :ecto_sql, "3.13.2", "a07d2461d84107b3d037097c822ffdd36ed69d1cf7c0f70e12a3d1decf04e2e1", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "539274ab0ecf1a0078a6a72ef3465629e4d6018a3028095dc90f60a19c371717"}, "eflame": {:hex, :eflame, "1.0.1", "0664d287e39eef3c413749254b3af5f4f8b00be71c1af67d325331c4890be0fc", [:mix], [], "hexpm", "e0b08854a66f9013129de0b008488f3411ae9b69b902187837f994d7a99cf04e"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, - "ex_doc": {:hex, :ex_doc, "0.38.2", "504d25eef296b4dec3b8e33e810bc8b5344d565998cd83914ffe1b8503737c02", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "732f2d972e42c116a70802f9898c51b54916e542cc50968ac6980512ec90f42b"}, + "ex_doc": {:hex, :ex_doc, "0.38.4", "ab48dff7a8af84226bf23baddcdda329f467255d924380a0cf0cee97bb9a9ede", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "f7b62346408a83911c2580154e35613eb314e0278aeea72ed7fedef9c1f165b2"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [: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", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, - "git_ops": {:hex, :git_ops, "2.8.0", "29ac9ab68bf9645973cb2752047b987e75cbd3d9761489c615e3ba80018fa885", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "b535e4ad6b5d13e14c455e76f65825659081b5530b0827eb0232d18719530eec"}, + "git_ops": {:hex, :git_ops, "2.9.0", "b74f6040084f523055b720cc7ef718da47f2cbe726a5f30c2871118635cb91c1", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "7fdf84be3490e5692c5dc1f8a1084eed47a221c1063e41938c73312f0bfea259"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "igniter": {:hex, :igniter, "0.6.30", "83a466369ebb8fe009e0823c7bf04314dc545122c2d48f896172fc79df33e99d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, 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", "76a14d5b7f850bb03b5243088c3649d54a2e52e34a2aa1104dee23cf50a8bae0"}, From 5c4a429b0f404bd8ef5d803b80ff462c129cf807 Mon Sep 17 00:00:00 2001 From: Steve Brambilla Date: Thu, 2 Oct 2025 23:09:32 -0400 Subject: [PATCH 660/690] improvement: Add immutable version of `ash_raise_error` function to support extensions like Citus (#620) --- lib/extensions/immutable_raise_error.ex | 74 +++++++++++++++++++++++++ lib/repo.ex | 11 +++- lib/sql_implementation.ex | 5 ++ mix.exs | 4 +- mix.lock | 2 +- 5 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 lib/extensions/immutable_raise_error.ex diff --git a/lib/extensions/immutable_raise_error.ex b/lib/extensions/immutable_raise_error.ex new file mode 100644 index 00000000..7cda113d --- /dev/null +++ b/lib/extensions/immutable_raise_error.ex @@ -0,0 +1,74 @@ +defmodule AshPostgres.Extensions.ImmutableRaiseError do + @moduledoc """ + An extension that installs an immutable version of ash_raise_error. + + This can be used to improve compatibility with Postgres sharding extensions like Citus, + which requires functions used in CASE or COALESCE expressions to be immutable. + + The new `ash_raise_error_immutable` functions add an additional row-dependent argument to ensure + the planner doesn't constant-fold error expressions. + + To install, add this module to your repo's `installed_extensions` list: + + ```elixir + def installed_extensions do + ["ash-functions", AshPostgres.Extensions.ImmutableRaiseError] + end + ``` + + And run `mix ash_postgres.generate_migrations` to generate the migrations. + + Once installed, you can control whether the immutable function is used by adding this to your + repo: + + ```elixir + def immutable_expr_error?, do: true + ``` + """ + + use AshPostgres.CustomExtension, name: "immutable_raise_error", latest_version: 1 + + @impl true + def install(0) do + ash_raise_error_immutable() + end + + @impl true + def uninstall(_version) do + "execute(\"DROP FUNCTION IF EXISTS ash_raise_error_immutable(jsonb, ANYCOMPATIBLE), ash_raise_error_immutable(jsonb, ANYELEMENT, ANYCOMPATIBLE)\")" + end + + defp ash_raise_error_immutable do + """ + execute(\"\"\" + CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, token ANYCOMPATIBLE) + RETURNS BOOLEAN AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + -- 'token' is intentionally ignored; its presence makes the call non-constant at the call site. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql + IMMUTABLE + SET search_path = ''; + \"\"\") + + execute(\"\"\" + CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, type_signal ANYELEMENT, token ANYCOMPATIBLE) + RETURNS ANYELEMENT AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + -- 'token' is intentionally ignored; its presence makes the call non-constant at the call site. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql + IMMUTABLE + SET search_path = ''; + \"\"\") + """ + end +end diff --git a/lib/repo.ex b/lib/repo.ex index fb7cb7eb..e1b0726d 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -113,6 +113,13 @@ defmodule AshPostgres.Repo do @doc "Disable expression errors for this repo" @callback disable_expr_error?() :: boolean + @doc """ + Opt-in to using immutable versions of the expression error functions. + + Requires the `AshPostgres.Extensions.ImmutableRaiseError` extension. + """ + @callback immutable_expr_error?() :: boolean + defmacro __using__(opts) do quote bind_quoted: [opts: opts] do if Keyword.get(opts, :define_ecto_repo?, true) do @@ -145,6 +152,7 @@ defmodule AshPostgres.Repo do def drop?, do: true def disable_atomic_actions?, do: false def disable_expr_error?, do: false + def immutable_expr_error?, do: false # default to false in 4.0 def prefer_transaction?, do: true @@ -315,7 +323,8 @@ defmodule AshPostgres.Repo do create?: 0, drop?: 0, disable_atomic_actions?: 0, - disable_expr_error?: 0 + disable_expr_error?: 0, + immutable_expr_error?: 0 # We do this switch because `!@warn_on_missing_ash_functions` in the function body triggers # a dialyzer error diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 99d80f8f..fefdf876 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -334,4 +334,9 @@ defmodule AshPostgres.SqlImplementation do {types, new_returns || returns} end + + @impl true + def immutable_errors?(repo) do + repo.immutable_expr_error?() + end end diff --git a/mix.exs b/mix.exs index 00778fec..c06ca801 100644 --- a/mix.exs +++ b/mix.exs @@ -168,7 +168,9 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.5 and >= 3.5.35")}, {:spark, "~> 2.3 and >= 2.3.4"}, - {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.90")}, + # TODO: bump to next ash_sql release + # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.90")}, + {:ash_sql, git: "https://github.com/ash-project/ash_sql.git"}, {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, diff --git a/mix.lock b/mix.lock index be72f892..7cd067b4 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.43", "222f9a8ac26ad3b029f8e69306cc83091c992d858b4538af12e33a148f301cab", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "48b2aa274c524f5b968c563dd56aec8f9b278c529c8aa46e6fe0ca564c26cc1c"}, - "ash_sql": {:hex, :ash_sql, "0.3.0", "2c43ddcc8c7fb51dc25ba3bca965d8b68e7aaecb290cabfed3cf213965aca937", [:mix], [{:ash, ">= 3.5.43 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", "ef03759d6a1d4cb189fcadbd183cf047f0565d7d88ea8612d85c9e6e724835e7"}, + "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "65854408e7ce129f78fabafb0a4393f0142da6a6", []}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From 6a2675cd8865cb5d3b38dc052e98b944a7355282 Mon Sep 17 00:00:00 2001 From: Steve Brambilla Date: Fri, 3 Oct 2025 09:52:31 -0400 Subject: [PATCH 661/690] test: add repro for ash_sql issue (#629) --- .../test_repo/rsvps/20251002180954.json | 43 +++++++++++ .../20251002180954_migrate_resources62.exs | 20 +++++ test/support/domain.ex | 1 + test/support/resources/rsvp.ex | 42 +++++++++++ test/support/types/response.ex | 75 +++++++++++++++++++ test/type_test.exs | 9 +++ 6 files changed, 190 insertions(+) create mode 100644 priv/resource_snapshots/test_repo/rsvps/20251002180954.json create mode 100644 priv/test_repo/migrations/20251002180954_migrate_resources62.exs create mode 100644 test/support/resources/rsvp.ex create mode 100644 test/support/types/response.ex diff --git a/priv/resource_snapshots/test_repo/rsvps/20251002180954.json b/priv/resource_snapshots/test_repo/rsvps/20251002180954.json new file mode 100644 index 00000000..31e6d18f --- /dev/null +++ b/priv/resource_snapshots/test_repo/rsvps/20251002180954.json @@ -0,0 +1,43 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "0", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "response", + "type": "integer" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "8ADC3A631361A18B1B9A2070D5E8477428EDE39DE3B43FA5FF8E50CE7710B9E5", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "rsvps" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20251002180954_migrate_resources62.exs b/priv/test_repo/migrations/20251002180954_migrate_resources62.exs new file mode 100644 index 00000000..fe90b42c --- /dev/null +++ b/priv/test_repo/migrations/20251002180954_migrate_resources62.exs @@ -0,0 +1,20 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources62 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:rsvps, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:response, :integer, null: false, default: 0) + end + end + + def down do + drop(table(:rsvps)) + end +end diff --git a/test/support/domain.ex b/test/support/domain.ex index 2bf55a0b..ec992cbe 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -53,6 +53,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Order) resource(AshPostgres.Test.Chat) resource(AshPostgres.Test.Message) + resource(AshPostgres.Test.RSVP) end authorization do diff --git a/test/support/resources/rsvp.ex b/test/support/resources/rsvp.ex new file mode 100644 index 00000000..965f053d --- /dev/null +++ b/test/support/resources/rsvp.ex @@ -0,0 +1,42 @@ +defmodule AshPostgres.Test.RSVP do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "rsvps" + repo AshPostgres.TestRepo + end + + actions do + default_accept(:*) + defaults([:create, :read, :update, :destroy]) + + # Uses an expression with an array of atoms for a custom type backed by integers. + update :clear_response do + change( + atomic_update( + :response, + expr( + if response in [:accepted, :declined] do + :awaiting + else + response + end + ) + ) + ) + end + end + + attributes do + uuid_primary_key(:id) + + attribute(:response, AshPostgres.Test.Types.Response, + allow_nil?: false, + public?: true, + default: 0 + ) + end +end diff --git a/test/support/types/response.ex b/test/support/types/response.ex new file mode 100644 index 00000000..51f475e0 --- /dev/null +++ b/test/support/types/response.ex @@ -0,0 +1,75 @@ +defmodule AshPostgres.Test.Types.Response do + @moduledoc false + use Ash.Type + use AshPostgres.Type + require Ash.Expr + + @atoms_to_ints %{accepted: 1, declined: 2, awaiting: 0} + @ints_to_atoms Map.new(@atoms_to_ints, fn {k, v} -> {v, k} end) + @atom_values Map.keys(@atoms_to_ints) + @string_values Enum.map(@atom_values, &to_string/1) + + @impl Ash.Type + def storage_type, do: :integer + + @impl Ash.Type + def cast_input(nil, _), do: {:ok, nil} + + def cast_input(value, _) when value in @atom_values, do: {:ok, value} + def cast_input(value, _) when value in @string_values, do: {:ok, String.to_existing_atom(value)} + + def cast_input(integer, _) when is_integer(integer), + do: Map.fetch(@ints_to_atoms, integer) + + def cast_input(_, _), do: :error + + @impl Ash.Type + def matches_type?(value, _) when is_atom(value) and value in @atom_values, do: true + def matches_type?(_, _), do: false + + @impl Ash.Type + def cast_stored(nil, _), do: {:ok, nil} + def cast_stored(integer, _) when is_integer(integer), do: Map.fetch(@ints_to_atoms, integer) + def cast_stored(_, _), do: :error + + @impl Ash.Type + def dump_to_native(nil, _), do: {:ok, nil} + def dump_to_native(atom, _) when is_atom(atom), do: Map.fetch(@atoms_to_ints, atom) + def dump_to_native(_, _), do: :error + + @impl Ash.Type + def cast_atomic(new_value, constraints) do + if Ash.Expr.expr?(new_value) do + {:atomic, new_value} + else + case cast_input(new_value, constraints) do + {:ok, value} -> {:atomic, value} + {:error, error} -> {:error, error} + end + end + end + + @impl Ash.Type + def apply_atomic_constraints(new_value, _constraints) do + {:ok, + Ash.Expr.expr( + if ^new_value in ^@atom_values do + ^new_value + else + error( + Ash.Error.Changes.InvalidChanges, + message: "must be one of %{values}", + vars: %{values: ^Enum.join(@atom_values, ", ")} + ) + end + )} + end + + @impl AshPostgres.Type + def value_to_postgres_default(_, _, value) do + case Map.fetch(@atoms_to_ints, value) do + {:ok, integer} -> {:ok, Integer.to_string(integer)} + :error -> :error + end + end +end diff --git a/test/type_test.exs b/test/type_test.exs index 4c3731e7..6355fe92 100644 --- a/test/type_test.exs +++ b/test/type_test.exs @@ -1,6 +1,7 @@ defmodule AshPostgres.Test.TypeTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post + alias AshPostgres.Test.RSVP require Ash.Query @@ -107,4 +108,12 @@ defmodule AshPostgres.Test.TypeTest do post = Ash.Query.for_read(Post, :with_version_check, version: 1) |> Ash.read!() refute is_nil(post) end + + test "array expressions work with custom types that map atoms to integers" do + rsvp = RSVP |> Ash.Changeset.for_create(:create, %{response: :accepted}) |> Ash.create!() + + updated = rsvp |> Ash.Changeset.for_update(:clear_response, %{}) |> Ash.update!() + + assert updated.response == :awaiting + end end From c9a6e3e7b580361274fdd7102b9dbe23bb1223a6 Mon Sep 17 00:00:00 2001 From: Alexandre Moreau Date: Sat, 4 Oct 2025 22:33:37 +0200 Subject: [PATCH 662/690] test:add failing test (#627) --- .../20251001120813.json | 124 ++++++++++++++++++ .../20251001120813_migrate_resources7.exs | 78 +++++++++++ test/multitenancy_test.exs | 20 ++- test/support/multitenancy/domain.ex | 1 + .../non_multitenant_post_multitenant_link.ex | 52 ++++++++ test/support/multitenancy/resources/post.ex | 11 ++ 6 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json create mode 100644 priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs create mode 100644 test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex diff --git a/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json b/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json new file mode 100644 index 00000000..16e8af1a --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json @@ -0,0 +1,124 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "\"active\"", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "state", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": true, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": false, + "strategy": "context" + }, + "name": "non_multitenant_post_multitenant_links_source_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "multitenant_posts" + }, + "scale": null, + "size": null, + "source": "source_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": true, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "non_multitenant_post_multitenant_links_dest_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "scale": null, + "size": null, + "source": "dest_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "F19D22A316D43A64BF2F1E052F545346BD0BCBC660E8EF559D1D4D73D8969A4D", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "non_multitenant_post_multitenant_links_unique_link_index", + "keys": [ + { + "type": "atom", + "value": "source_id" + }, + { + "type": "atom", + "value": "dest_id" + } + ], + "name": "unique_link", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": false, + "strategy": "context" + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "non_multitenant_post_multitenant_links" +} \ No newline at end of file diff --git a/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs b/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs new file mode 100644 index 00000000..42a6f5a3 --- /dev/null +++ b/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs @@ -0,0 +1,78 @@ +defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources7 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:non_multitenant_post_multitenant_links, primary_key: false, prefix: prefix()) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:state, :text, default: "active") + + add( + :source_id, + references(:multitenant_posts, + column: :id, + name: "non_multitenant_post_multitenant_links_source_id_fkey", + type: :uuid, + prefix: prefix(), + on_delete: :delete_all + ), + null: false + ) + + add( + :dest_id, + references(:posts, + column: :id, + name: "non_multitenant_post_multitenant_links_dest_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :delete_all + ), + null: false + ) + end + + create(index(:non_multitenant_post_multitenant_links, [:source_id])) + + create(index(:non_multitenant_post_multitenant_links, [:dest_id])) + + create( + unique_index(:non_multitenant_post_multitenant_links, [:source_id, :dest_id], + name: "non_multitenant_post_multitenant_links_unique_link_index" + ) + ) + end + + def down do + drop_if_exists( + unique_index(:non_multitenant_post_multitenant_links, [:source_id, :dest_id], + name: "non_multitenant_post_multitenant_links_unique_link_index" + ) + ) + + drop_if_exists(index(:non_multitenant_post_multitenant_links, [:dest_id])) + + drop_if_exists(index(:non_multitenant_post_multitenant_links, [:source_id])) + + drop( + constraint( + :non_multitenant_post_multitenant_links, + "non_multitenant_post_multitenant_links_source_id_fkey" + ) + ) + + drop( + constraint( + :non_multitenant_post_multitenant_links, + "non_multitenant_post_multitenant_links_dest_id_fkey" + ) + ) + + drop(table(:non_multitenant_post_multitenant_links, prefix: prefix())) + end +end diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 0dd99520..89034434 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -2,7 +2,7 @@ defmodule AshPostgres.Test.MultitenancyTest do use AshPostgres.RepoCase, async: false require Ash.Query - alias AshPostgres.MultitenancyTest.{CompositeKeyPost, NamedOrg, Org, Post, User} + alias AshPostgres.MultitenancyTest.{CompositeKeyPost, NamedOrg, Org, Post, User, NonMultitenantPostMultitenantLink} alias AshPostgres.Test.Post, as: GlobalPost setup do @@ -226,6 +226,24 @@ defmodule AshPostgres.Test.MultitenancyTest do ) end + test "loading non multitenant resource across a many_to_many works", %{org1: org1} do + post = Post + |> Ash.Changeset.for_create(:create, %{name: "foo"}) + |> Ash.Changeset.set_tenant(org1) + |> Ash.create!() + + GlobalPost + |> Ash.Changeset.for_create(:create, %{title: "fred"}) + |> Ash.create!() + + NonMultitenantPostMultitenantLink + |> Ash.Changeset.for_create(:create, %{source_id: post.id, dest_id: global_post.id}, tenant: org1) + |> Ash.create!() + + post |> Ash.load!([:linked_non_multitenant_posts_through_multitenant_link], tenant: org1) |> IO.inspect() + end + + test "manage_relationship from context multitenant resource to attribute multitenant resource doesn't raise an error" do org = Org |> Ash.Changeset.new() |> Ash.create!() user = User |> Ash.Changeset.new() |> Ash.create!() diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 52ffbc63..6c1db197 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -12,6 +12,7 @@ defmodule AshPostgres.MultitenancyTest.Domain do resource(AshPostgres.MultitenancyTest.NonMultitenantPostLink) resource(AshPostgres.MultitenancyTest.CrossTenantPostLink) resource(AshPostgres.MultitenancyTest.CompositeKeyPost) + resource(AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink) end authorization do diff --git a/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex new file mode 100644 index 00000000..4dff4d41 --- /dev/null +++ b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex @@ -0,0 +1,52 @@ +defmodule AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.MultitenancyTest.Domain, + data_layer: AshPostgres.DataLayer + + postgres do + table "non_multitenant_post_multitenant_links" + repo AshPostgres.TestRepo + + references do + reference :source, on_delete: :delete, index?: true + reference :dest, on_delete: :delete, index?: true + end + end + + multitenancy do + strategy(:context) + end + + actions do + default_accept(:*) + + defaults([:create, :read, :update, :destroy]) + end + + identities do + identity(:unique_link, [:source_id, :dest_id]) + end + + attributes do + uuid_primary_key :id + + attribute :state, :atom do + public?(true) + constraints(one_of: [:active, :archived]) + default(:active) + end + end + + relationships do + belongs_to :source, AshPostgres.MultitenancyTest.Post do + public? true + allow_nil? false + end + + belongs_to :dest, AshPostgres.Test.Post do + public? true + allow_nil? false + end + end +end diff --git a/test/support/multitenancy/resources/post.ex b/test/support/multitenancy/resources/post.ex index e097fffb..b3358361 100644 --- a/test/support/multitenancy/resources/post.ex +++ b/test/support/multitenancy/resources/post.ex @@ -59,12 +59,23 @@ defmodule AshPostgres.MultitenancyTest.Post do # has_many(:non_multitenant_post_links, AshPostgres.MultitenancyTest.NonMultitenantPostLink) + has_many :non_multitenant_post_multitenant_links, AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink do + destination_attribute :source_id + end + many_to_many :linked_non_multitenant_posts, AshPostgres.Test.Post do through(AshPostgres.MultitenancyTest.NonMultitenantPostLink) join_relationship(:non_multitenant_post_links) source_attribute_on_join_resource(:source_id) destination_attribute_on_join_resource(:dest_id) end + + many_to_many :linked_non_multitenant_posts_through_multitenant_link, AshPostgres.Test.Post do + through(AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink) + join_relationship(:non_multitenant_post_links_through_multitenant_link) + source_attribute_on_join_resource(:source_id) + destination_attribute_on_join_resource(:dest_id) + end end calculations do From 7ad0b86d145d4760882248d463222b742a872741 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 4 Oct 2025 16:53:54 -0400 Subject: [PATCH 663/690] fix: ensure that tenant is properly used in many-to-many joins --- lib/data_layer.ex | 6 +++-- mix.exs | 3 +-- test/multitenancy_test.exs | 27 ++++++++++++++----- .../non_multitenant_post_multitenant_link.ex | 10 +++---- test/support/multitenancy/resources/post.ex | 5 ++-- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 43b8f5a1..d9b2f41a 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1247,7 +1247,9 @@ defmodule AshPostgres.DataLayer do through_query = Ecto.Query.exclude(through_query, :select) through_query = - if through_query.joins && through_query.joins != [] do + if (through_query.joins && through_query.joins != []) || + (Ash.Resource.Info.multitenancy_strategy(relationship.through) == :context && + source_query.tenant) do subquery( set_subquery_prefix( through_query, @@ -1256,7 +1258,7 @@ defmodule AshPostgres.DataLayer do ) ) else - through_query + set_subquery_prefix(through_query, source_query, relationship.through) end if query.__ash_bindings__[:__order__?] do diff --git a/mix.exs b/mix.exs index c06ca801..cdc61840 100644 --- a/mix.exs +++ b/mix.exs @@ -169,8 +169,7 @@ defmodule AshPostgres.MixProject do {:ash, ash_version("~> 3.5 and >= 3.5.35")}, {:spark, "~> 2.3 and >= 2.3.4"}, # TODO: bump to next ash_sql release - # {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.90")}, - {:ash_sql, git: "https://github.com/ash-project/ash_sql.git"}, + {:ash_sql, ash_sql_version(git: "https://github.com/ash-project/ash_sql.git")}, {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 89034434..6253e46f 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -2,7 +2,16 @@ defmodule AshPostgres.Test.MultitenancyTest do use AshPostgres.RepoCase, async: false require Ash.Query - alias AshPostgres.MultitenancyTest.{CompositeKeyPost, NamedOrg, Org, Post, User, NonMultitenantPostMultitenantLink} + + alias AshPostgres.MultitenancyTest.{ + CompositeKeyPost, + NamedOrg, + Org, + Post, + User, + NonMultitenantPostMultitenantLink + } + alias AshPostgres.Test.Post, as: GlobalPost setup do @@ -227,23 +236,27 @@ defmodule AshPostgres.Test.MultitenancyTest do end test "loading non multitenant resource across a many_to_many works", %{org1: org1} do - post = Post + post = + Post |> Ash.Changeset.for_create(:create, %{name: "foo"}) |> Ash.Changeset.set_tenant(org1) |> Ash.create!() - GlobalPost + global_post = + GlobalPost |> Ash.Changeset.for_create(:create, %{title: "fred"}) |> Ash.create!() NonMultitenantPostMultitenantLink - |> Ash.Changeset.for_create(:create, %{source_id: post.id, dest_id: global_post.id}, tenant: org1) - |> Ash.create!() + |> Ash.Changeset.for_create(:create, %{source_id: post.id, dest_id: global_post.id}, + tenant: org1 + ) + |> Ash.create!() - post |> Ash.load!([:linked_non_multitenant_posts_through_multitenant_link], tenant: org1) |> IO.inspect() + post + |> Ash.load!([:linked_non_multitenant_posts_through_multitenant_link], tenant: org1) end - test "manage_relationship from context multitenant resource to attribute multitenant resource doesn't raise an error" do org = Org |> Ash.Changeset.new() |> Ash.create!() user = User |> Ash.Changeset.new() |> Ash.create!() diff --git a/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex index 4dff4d41..56dd8d26 100644 --- a/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex +++ b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex @@ -29,7 +29,7 @@ defmodule AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink do end attributes do - uuid_primary_key :id + uuid_primary_key(:id) attribute :state, :atom do public?(true) @@ -40,13 +40,13 @@ defmodule AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink do relationships do belongs_to :source, AshPostgres.MultitenancyTest.Post do - public? true - allow_nil? false + public?(true) + allow_nil?(false) end belongs_to :dest, AshPostgres.Test.Post do - public? true - allow_nil? false + public?(true) + allow_nil?(false) end end end diff --git a/test/support/multitenancy/resources/post.ex b/test/support/multitenancy/resources/post.ex index b3358361..6f9a943a 100644 --- a/test/support/multitenancy/resources/post.ex +++ b/test/support/multitenancy/resources/post.ex @@ -59,8 +59,9 @@ defmodule AshPostgres.MultitenancyTest.Post do # has_many(:non_multitenant_post_links, AshPostgres.MultitenancyTest.NonMultitenantPostLink) - has_many :non_multitenant_post_multitenant_links, AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink do - destination_attribute :source_id + has_many :non_multitenant_post_multitenant_links, + AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink do + destination_attribute(:source_id) end many_to_many :linked_non_multitenant_posts, AshPostgres.Test.Post do From 588b1cbd28a15a3a19fd1cc59a3ff78a65ddd715 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 4 Oct 2025 17:00:47 -0400 Subject: [PATCH 664/690] chore: credo --- test/multitenancy_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 6253e46f..85a97cbe 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -6,10 +6,10 @@ defmodule AshPostgres.Test.MultitenancyTest do alias AshPostgres.MultitenancyTest.{ CompositeKeyPost, NamedOrg, + NonMultitenantPostMultitenantLink, Org, Post, - User, - NonMultitenantPostMultitenantLink + User } alias AshPostgres.Test.Post, as: GlobalPost From 7d4d4a4f879cae82c363635179717367584e8c9b Mon Sep 17 00:00:00 2001 From: Frank Polasek Dugan III Date: Sun, 5 Oct 2025 14:41:42 -0500 Subject: [PATCH 665/690] chore: remove deprecated script documentation; fix mise confusion in .tool-versions (#630) * chore: remove deprecated script * chore: fix mise confusion in .tool-versions --- .tool-versions | 2 +- .../development/migrations-and-tasks.md | 29 ------------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/.tool-versions b/.tool-versions index 32823875..6c947239 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ erlang 27.1.2 -elixir 1.18.4 \ No newline at end of file +elixir 1.18.4-otp-27 diff --git a/documentation/topics/development/migrations-and-tasks.md b/documentation/topics/development/migrations-and-tasks.md index 5fd26271..592bb9a9 100644 --- a/documentation/topics/development/migrations-and-tasks.md +++ b/documentation/topics/development/migrations-and-tasks.md @@ -23,35 +23,6 @@ For more information on generating migrations, run `mix help ash_postgres.genera > > If you have are using schema-based multitenancy, you will also need to define a `all_tenants/0` function in your repo module. See `AshPostgres.Repo` for more. -### Regenerating Migrations - -Often, you will run into a situation where you want to make a slight change to a resource after you've already generated and run migrations. If you are using git and would like to undo those changes, then regenerate the migrations, this script may prove useful: - -```bash -#!/bin/bash - -# Get count of untracked migrations -N_MIGRATIONS=$(git ls-files --others priv/repo/migrations | wc -l) - -# Rollback untracked migrations -mix ash_postgres.rollback -n $N_MIGRATIONS - -# Delete untracked migrations and snapshots -git ls-files --others priv/repo/migrations | xargs rm -git ls-files --others priv/resource_snapshots | xargs rm - -# Regenerate migrations -mix ash.codegen --name $1 - -# Run migrations if flag -if echo $* | grep -e "-m" -q -then - mix ash.migrate -fi -``` - -After saving this file to something like `regen.sh`, make it executable with `chmod +x regen.sh`. Now you can run it with `./regen.sh name_of_operation`. If you would like the migrations to automatically run after regeneration, add the `-m` flag: `./regen.sh name_of_operation -m`. - ## Running Migrations in Production Define a module similar to the following: From c45b3366f95c3419da576eaadc7f37860d5873a9 Mon Sep 17 00:00:00 2001 From: Elliot Bowes Date: Sun, 5 Oct 2025 22:45:54 +0100 Subject: [PATCH 666/690] fix: Support non-public PostgreSQL schemas in resource generator (#631) - Add schema field to generated resources when table is in non-public schema - Fix SQL queries to use schema-qualified table names for foreign keys and constraints - Update index queries to respect actual schema instead of hardcoded 'public' - Add test coverage for tables in custom schemas with foreign keys and indexes * fix: guard against missing snapshot directories in migration generator Fixes crash when generating migrations for resources in non-public schemas where the snapshot directory doesn't exist yet. * chore: run mix format --- .../migration_generator.ex | 19 ++- lib/resource_generator/resource_generator.ex | 7 + lib/resource_generator/spec.ex | 16 ++- test/resource_generator_test.exs | 130 ++++++++++++++++++ 4 files changed, 161 insertions(+), 11 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index fcb44c95..00276e25 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -649,14 +649,19 @@ defmodule AshPostgres.MigrationGenerator do folder = get_snapshot_folder(snapshot, opts) snapshot_path = get_snapshot_path(snapshot, folder) - snapshot_path - |> File.ls!() - |> Enum.filter(&String.contains?(&1, "_dev.json")) - |> Enum.each(fn snapshot_name -> + # Guard against missing directories - can happen for new resources or when + # get_snapshot_path's fallback logic returns a non-existent path for + # resources in non-public schemas + if File.dir?(snapshot_path) do snapshot_path - |> Path.join(snapshot_name) - |> File.rm!() - end) + |> File.ls!() + |> Enum.filter(&String.contains?(&1, "_dev.json")) + |> Enum.each(fn snapshot_name -> + snapshot_path + |> Path.join(snapshot_name) + |> File.rm!() + end) + end end) end diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 99da8386..b3a507b7 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -115,6 +115,7 @@ if Code.ensure_loaded?(Igniter) do postgres do table #{inspect(table_spec.table_name)} repo #{inspect(table_spec.repo)} + #{schema_option(table_spec)} #{no_migrate_flag} #{references(table_spec, opts[:no_migrations])} #{custom_indexes(table_spec, opts[:no_migrations])} @@ -144,6 +145,12 @@ if Code.ensure_loaded?(Igniter) do end) end + defp schema_option(%{schema: schema}) when schema != "public" do + "schema #{inspect(schema)}" + end + + defp schema_option(_), do: "" + defp default_actions(opts) do cond do opts[:default_actions] && opts[:public] -> diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index f2da7ec5..9997bbac 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -122,7 +122,13 @@ defmodule AshPostgres.ResourceGenerator.Spec do result end + defp qualified_table_name(%{schema: schema, table_name: table_name}) do + "#{schema}.#{table_name}" + end + defp add_foreign_keys(spec) do + qualified_table = qualified_table_name(spec) + %Postgrex.Result{rows: fkey_rows} = spec.repo.query!( """ @@ -178,7 +184,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do constraints.update_rule, constraints.delete_rule """, - [spec.table_name, spec.schema], + [qualified_table, spec.schema], log: false ) @@ -218,6 +224,8 @@ defmodule AshPostgres.ResourceGenerator.Spec do end defp add_check_constraints(spec) do + qualified_table = qualified_table_name(spec) + %Postgrex.Result{rows: check_constraint_rows} = spec.repo.query!( """ @@ -230,7 +238,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do contype = 'c' AND conrelid::regclass::text = $1 """, - [spec.table_name], + [qualified_table], log: false ) @@ -278,7 +286,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do LEFT JOIN pg_constraint c ON c.conindid = ix.indexrelid AND c.contype = 'p' JOIN - pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = 'public' -- Adjust schema name if necessary + pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = $2 JOIN information_schema.tables ta ON ta.table_name = t.relname WHERE @@ -312,7 +320,7 @@ defmodule AshPostgres.ResourceGenerator.Spec do LEFT JOIN pg_constraint c ON c.conindid = ix.indexrelid AND c.contype = 'p' JOIN - pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = 'public' -- Adjust schema name if necessary + pg_indexes idx ON idx.indexname = i.relname AND idx.schemaname = $2 JOIN information_schema.tables ta ON ta.table_name = t.relname WHERE diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index c50292aa..4878cf6d 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -62,4 +62,134 @@ defmodule AshPostgres.ResourceGeenratorTests do end """) end + + test "a resource is generated from a table in a non-public schema with foreign keys and indexes" do + AshPostgres.TestRepo.query!("CREATE SCHEMA IF NOT EXISTS inventory") + + AshPostgres.TestRepo.query!("DROP TABLE IF EXISTS inventory.products CASCADE") + AshPostgres.TestRepo.query!("DROP TABLE IF EXISTS inventory.warehouses CASCADE") + + AshPostgres.TestRepo.query!(""" + CREATE TABLE inventory.warehouses ( + id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, + name VARCHAR(255) NOT NULL, + location VARCHAR(255) + ) + """) + + AshPostgres.TestRepo.query!("CREATE INDEX warehouses_name_idx ON inventory.warehouses(name)") + + AshPostgres.TestRepo.query!(""" + CREATE TABLE inventory.products ( + id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, + name VARCHAR(255) NOT NULL, + warehouse_id UUID REFERENCES inventory.warehouses(id) ON DELETE CASCADE, + quantity INTEGER + ) + """) + + AshPostgres.TestRepo.query!( + "CREATE INDEX products_warehouse_id_idx ON inventory.products(warehouse_id)" + ) + + test_project() + |> Igniter.compose_task("ash_postgres.gen.resources", [ + "MyApp.Inventory", + "--tables", + "inventory.warehouses,inventory.products", + "--yes", + "--repo", + "AshPostgres.TestRepo" + ]) + |> assert_creates("lib/my_app/inventory/warehouse.ex", """ + defmodule MyApp.Inventory.Warehouse do + use Ash.Resource, + domain: MyApp.Inventory, + data_layer: AshPostgres.DataLayer + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + postgres do + table("warehouses") + repo(AshPostgres.TestRepo) + schema("inventory") + end + + attributes do + uuid_primary_key :id do + public?(true) + end + + attribute :name, :string do + allow_nil?(false) + public?(true) + end + + attribute :location, :string do + public?(true) + end + end + + relationships do + has_many :products, MyApp.Inventory.Product do + public?(true) + end + end + end + """) + |> assert_creates("lib/my_app/inventory/product.ex", """ + defmodule MyApp.Inventory.Product do + use Ash.Resource, + domain: MyApp.Inventory, + data_layer: AshPostgres.DataLayer + + actions do + defaults([:read, :destroy, create: :*, update: :*]) + end + + postgres do + table("products") + repo(AshPostgres.TestRepo) + schema("inventory") + + references do + reference :warehouse do + on_delete(:delete) + end + end + end + + attributes do + uuid_primary_key :id do + public?(true) + end + + uuid_primary_key :id do + public?(true) + end + + attribute :name, :string do + public?(true) + end + + attribute :name, :string do + allow_nil?(false) + public?(true) + end + + attribute :quantity, :integer do + public?(true) + end + end + + relationships do + belongs_to :warehouse, MyApp.Inventory.Warehouse do + public?(true) + end + end + end + """) + end end From cf0d1df59476c263002aeae37d90a3ea21ae4c87 Mon Sep 17 00:00:00 2001 From: Steve Brambilla Date: Wed, 8 Oct 2025 23:18:05 -0400 Subject: [PATCH 667/690] refactor: move immutable error expr from AshSql into AshPostgres (#633) --- lib/extensions/immutable_raise_error.ex | 155 ++++++++++++++++++++++++ lib/sql_implementation.ex | 30 ++++- mix.exs | 1 - mix.lock | 2 +- 4 files changed, 181 insertions(+), 7 deletions(-) diff --git a/lib/extensions/immutable_raise_error.ex b/lib/extensions/immutable_raise_error.ex index 7cda113d..b7ccf347 100644 --- a/lib/extensions/immutable_raise_error.ex +++ b/lib/extensions/immutable_raise_error.ex @@ -28,6 +28,8 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do use AshPostgres.CustomExtension, name: "immutable_raise_error", latest_version: 1 + require Ecto.Query + @impl true def install(0) do ash_raise_error_immutable() @@ -71,4 +73,157 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do \"\"\") """ end + + @doc false + def immutable_error_expr( + query, + %Ash.Query.Function.Error{arguments: [exception, input]} = value, + bindings, + embedded?, + acc, + type + ) do + acc = %{acc | has_error?: true} + + {encoded, acc} = + if Ash.Expr.expr?(input) do + frag_parts = + Enum.flat_map(input, fn {key, value} -> + if Ash.Expr.expr?(value) do + [ + expr: to_string(key), + raw: "::text, ", + expr: value, + raw: ", " + ] + else + [ + expr: to_string(key), + raw: "::text, ", + expr: value, + raw: "::jsonb, " + ] + end + end) + + frag_parts = + List.update_at(frag_parts, -1, fn {:raw, text} -> + {:raw, String.trim_trailing(text, ", ") <> "))"} + end) + + AshSql.Expr.dynamic_expr( + query, + %Ash.Query.Function.Fragment{ + embedded?: false, + arguments: + [ + raw: "jsonb_build_object('exception', ", + expr: inspect(exception), + raw: "::text, 'input', jsonb_build_object(" + ] ++ + frag_parts + }, + bindings, + embedded?, + nil, + acc + ) + else + {Jason.encode!(%{exception: inspect(exception), input: Map.new(input)}), acc} + end + + dynamic_type = + if type do + # This is a type hint, if we're raising an error, we tell it what the value + # type *would* be in this expression so that we can return a "NULL" of that type + # its weird, but there isn't any other way that I can tell :) + AshSql.Expr.validate_type!(query, type, value) + + type = + AshSql.Expr.parameterized_type( + bindings.sql_behaviour, + type, + [], + :expr + ) + + Ecto.Query.dynamic(type(fragment("NULL"), ^type)) + else + nil + end + + case {dynamic_type, immutable_error_expr_token(query, bindings)} do + {_, nil} -> + :error + + {nil, row_token} -> + {:ok, + Ecto.Query.dynamic( + fragment("ash_raise_error_immutable(?::jsonb, ?)", ^encoded, ^row_token) + ), acc} + + {dynamic_type, row_token} -> + {:ok, + Ecto.Query.dynamic( + fragment( + "ash_raise_error_immutable(?::jsonb, ?, ?)", + ^encoded, + ^dynamic_type, + ^row_token + ) + ), acc} + end + end + + # Returns a row-dependent token to prevent constant-folding for immutable functions. + defp immutable_error_expr_token(query, bindings) do + resource = query.__ash_bindings__.resource + ref_binding = bindings.root_binding + + pk_attr_names = Ash.Resource.Info.primary_key(resource) + + attr_names = + case pk_attr_names do + [] -> + case Ash.Resource.Info.attributes(resource) do + [%{name: name} | _] -> [name] + _ -> [] + end + + pk -> + pk + end + + if ref_binding && attr_names != [] do + value_exprs = + Enum.map(attr_names, fn attr_name -> + if bindings[:parent?] && + ref_binding not in List.wrap(bindings[:lateral_join_bindings]) do + Ecto.Query.dynamic(field(parent_as(^ref_binding), ^attr_name)) + else + Ecto.Query.dynamic(field(as(^ref_binding), ^attr_name)) + end + end) + + row_parts = + value_exprs + |> Enum.map(&{:casted_expr, &1}) + |> Enum.intersperse({:raw, ", "}) + + {%Ecto.Query.DynamicExpr{} = token, _acc} = + AshSql.Expr.dynamic_expr( + query, + %Ash.Query.Function.Fragment{ + embedded?: false, + arguments: [raw: "ROW("] ++ row_parts ++ [raw: ")"] + }, + AshSql.Expr.set_location(bindings, :sub_expr), + false + ) + + token + else + nil + end + end end diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index fefdf876..71b7f03d 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -200,6 +200,31 @@ defmodule AshPostgres.SqlImplementation do end end + def expr( + query, + %Ash.Query.Function.Error{} = value, + bindings, + embedded?, + acc, + type + ) do + resource = query.__ash_bindings__.resource + repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, query) + + if repo.immutable_expr_error?() do + AshPostgres.Extensions.ImmutableRaiseError.immutable_error_expr( + query, + value, + bindings, + embedded?, + acc, + type + ) + else + :error + end + end + def expr( _query, _expr, @@ -334,9 +359,4 @@ defmodule AshPostgres.SqlImplementation do {types, new_returns || returns} end - - @impl true - def immutable_errors?(repo) do - repo.immutable_expr_error?() - end end diff --git a/mix.exs b/mix.exs index cdc61840..79848b88 100644 --- a/mix.exs +++ b/mix.exs @@ -168,7 +168,6 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.5 and >= 3.5.35")}, {:spark, "~> 2.3 and >= 2.3.4"}, - # TODO: bump to next ash_sql release {:ash_sql, ash_sql_version(git: "https://github.com/ash-project/ash_sql.git")}, {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, diff --git a/mix.lock b/mix.lock index 7cd067b4..f5d12abd 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.43", "222f9a8ac26ad3b029f8e69306cc83091c992d858b4538af12e33a148f301cab", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "48b2aa274c524f5b968c563dd56aec8f9b278c529c8aa46e6fe0ca564c26cc1c"}, - "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "65854408e7ce129f78fabafb0a4393f0142da6a6", []}, + "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "3044c0555dbe6733d16868951ee89e6d5ef336fa", []}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From 84e528cbf7d43655dec367350d7b020e88fc38f8 Mon Sep 17 00:00:00 2001 From: Daniel Gollings Date: Thu, 9 Oct 2025 06:01:51 +0200 Subject: [PATCH 668/690] fix: update ash_postgresql to handle the new bulk_create response in Ash v3.5.44 (#632) --- lib/data_layer.ex | 33 ++++++-- test/bulk_create_test.exs | 147 +++++++++++++++++++++++++++++++++ test/support/resources/post.ex | 50 +++++++++++ 3 files changed, 225 insertions(+), 5 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index d9b2f41a..aaa2738f 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2047,11 +2047,18 @@ defmodule AshPostgres.DataLayer do maybe_create_tenant!(resource, result) end - Ash.Resource.put_metadata( - result, - :bulk_create_index, - changeset.context.bulk_create.index - ) + case get_bulk_operation_metadata(changeset, :bulk_create) do + {index, metadata_key} -> + Ash.Resource.put_metadata(result, metadata_key, index) + + nil -> + # Compatibility fallback + Ash.Resource.put_metadata( + result, + :bulk_create_index, + changeset.context[:bulk_create][:index] + ) + end end)} end end @@ -3638,4 +3645,20 @@ defmodule AshPostgres.DataLayer do resource end end + + defp get_bulk_operation_metadata(changeset, bulk_action_type) do + changeset.context + |> Enum.find_value(fn + # New format: {{:bulk_create, ref}, value} -> {index, metadata_key} + {{^bulk_action_type, ref}, value} -> + {value.index, {:"#{bulk_action_type}_index", ref}} + + # Fallback for old format: {:bulk_create, value} -> {index, metadata_key} + {^bulk_action_type, value} when is_map(value) -> + {value.index, :"#{bulk_action_type}_index"} + + _ -> + nil + end) + end end diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index 01769ccb..d6fd8c17 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -2,6 +2,7 @@ defmodule AshPostgres.BulkCreateTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.{Post, Record} + require Ash.Query import Ash.Expr describe "bulk creates" do @@ -355,4 +356,150 @@ defmodule AshPostgres.BulkCreateTest do |> Ash.read!() end end + + describe "nested bulk operations" do + test "supports bulk_create in after_action callbacks" do + result = + Ash.bulk_create!( + [%{title: "trigger_nested"}], + Post, + :create_with_nested_bulk_create, + return_records?: true, + authorize?: false + ) + + # Assert the bulk result contains the expected data + assert %Ash.BulkResult{records: [original_post]} = result + assert original_post.title == "trigger_nested" + + # Verify all posts that should exist after the nested operation + all_posts = + Post + |> Ash.Query.sort(:title) + |> Ash.read!() + + # Should have: 1 original + 2 nested = 3 total posts + assert length(all_posts) == 3 + + # Verify we have the expected posts with correct titles + post_titles = Enum.map(all_posts, & &1.title) |> Enum.sort() + assert post_titles == ["nested_post_1", "nested_post_2", "trigger_nested"] + + # Verify the specific nested posts were created by the after_action callback + nested_posts = + Post + |> Ash.Query.filter(expr(title in ["nested_post_1", "nested_post_2"])) + |> Ash.Query.sort(:title) + |> Ash.read!() + + assert length(nested_posts) == 2 + assert [%{title: "nested_post_1"}, %{title: "nested_post_2"}] = nested_posts + + # Verify that each nested post has proper metadata + Enum.each(nested_posts, fn post -> + assert is_binary(post.id) + assert post.title in ["nested_post_1", "nested_post_2"] + end) + end + + test "supports bulk_update in after_action callbacks" do + # Create the original post - the after_action callback will create and update additional posts + result = + Ash.bulk_create!( + [%{title: "trigger_nested_update"}], + Post, + :create_with_nested_bulk_update, + return_records?: true, + authorize?: false + ) + + # Assert the bulk result contains the expected data + assert %Ash.BulkResult{records: [original_post]} = result + assert original_post.title == "trigger_nested_update" + + # Verify all posts that should exist after the nested operations + # The after_action callback should have created 2 posts and updated them + all_posts = + Post + |> Ash.Query.sort(:title) + |> Ash.read!() + + # Should have: 1 original + 2 created and updated = 3 total posts + assert length(all_posts) == 3 + + # Verify the original post still exists + original_posts = + Post + |> Ash.Query.filter(expr(title == "trigger_nested_update")) + |> Ash.read!() + + assert length(original_posts) == 1 + assert hd(original_posts).title == "trigger_nested_update" + + # Verify the nested posts were created and then updated by the after_action callback + updated_posts = + Post + |> Ash.Query.filter(expr(title == "updated_via_nested_bulk")) + |> Ash.read!() + + assert length(updated_posts) == 2 + + # Verify that the updated posts have proper metadata and were actually updated + Enum.each(updated_posts, fn post -> + assert is_binary(post.id) + assert post.title == "updated_via_nested_bulk" + end) + + # Verify no posts remain with the intermediate titles (they should have been updated) + intermediate_posts = + Post + |> Ash.Query.filter(expr(title in ["post_to_update_1", "post_to_update_2"])) + |> Ash.read!() + + assert intermediate_posts == [], + "Posts should have been updated, not left with intermediate titles" + end + + test "nested bulk operations handle metadata indexing correctly" do + # Create multiple posts in the parent bulk operation to test indexing + # Each parent post's after_action callback will create nested posts + result = + Ash.bulk_create!( + [ + %{title: "trigger_nested"}, + %{title: "trigger_nested_2"} + ], + Post, + :create_with_nested_bulk_create, + return_records?: true, + authorize?: false + ) + + # Assert both parent posts were created + assert %Ash.BulkResult{records: parent_posts} = result + assert length(parent_posts) == 2 + + parent_titles = Enum.map(parent_posts, & &1.title) |> Enum.sort() + assert parent_titles == ["trigger_nested", "trigger_nested_2"] + + # Verify total posts: 2 parent + (2 nested per parent from after_action) = 6 total + all_posts = Post |> Ash.Query.sort(:title) |> Ash.read!() + assert length(all_posts) == 6 + + # Count posts by type + nested_posts = + Post + |> Ash.Query.filter(expr(title in ["nested_post_1", "nested_post_2"])) + |> Ash.read!() + + # Should have 4 nested posts (2 for each parent operation via after_action callbacks) + assert length(nested_posts) == 4 + + # Verify each nested post has proper structure + Enum.each(nested_posts, fn post -> + assert is_binary(post.id) + assert post.title in ["nested_post_1", "nested_post_2"] + end) + end + end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 817e0ff9..69791a38 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -432,6 +432,56 @@ defmodule AshPostgres.Test.Post do upsert_fields([:price]) end + create :create_with_nested_bulk_create do + change( + after_action(fn changeset, result, context -> + Ash.bulk_create!( + [%{title: "nested_post_1"}, %{title: "nested_post_2"}], + __MODULE__, + :create, + authorize?: false, + tenant: changeset.tenant, + return_records?: true + ) + + {:ok, result} + end) + ) + end + + create :create_with_nested_bulk_update do + change( + after_action(fn changeset, result, context -> + created_posts = + Ash.bulk_create!( + [%{title: "post_to_update_1"}, %{title: "post_to_update_2"}], + __MODULE__, + :create, + authorize?: false, + tenant: changeset.tenant, + return_records?: true + ) + + post_ids = Enum.map(created_posts.records, & &1.id) + + Ash.bulk_update!( + __MODULE__, + :set_title, + %{title: "updated_via_nested_bulk"}, + filter: [id: [in: post_ids]], + authorize?: false, + tenant: changeset.tenant + ) + + {:ok, result} + end) + ) + end + + update :set_title do + accept([:title]) + end + update :set_title_from_author do change(atomic_update(:title, expr(author.first_name))) end From a2aac8ae84547f2f828383052abcb4f7e89ad459 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 9 Oct 2025 23:38:09 -0400 Subject: [PATCH 669/690] chore: update ash_sql fix: simplify bulk operation metadata handling --- lib/data_layer.ex | 12 ++++++------ mix.exs | 2 +- mix.lock | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index aaa2738f..6e3354d8 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2047,7 +2047,7 @@ defmodule AshPostgres.DataLayer do maybe_create_tenant!(resource, result) end - case get_bulk_operation_metadata(changeset, :bulk_create) do + case get_bulk_operation_metadata(changeset) do {index, metadata_key} -> Ash.Resource.put_metadata(result, metadata_key, index) @@ -3646,16 +3646,16 @@ defmodule AshPostgres.DataLayer do end end - defp get_bulk_operation_metadata(changeset, bulk_action_type) do + defp get_bulk_operation_metadata(changeset) do changeset.context |> Enum.find_value(fn # New format: {{:bulk_create, ref}, value} -> {index, metadata_key} - {{^bulk_action_type, ref}, value} -> - {value.index, {:"#{bulk_action_type}_index", ref}} + {{:bulk_create, ref}, value} -> + {value.index, {:bulk_create_index, ref}} # Fallback for old format: {:bulk_create, value} -> {index, metadata_key} - {^bulk_action_type, value} when is_map(value) -> - {value.index, :"#{bulk_action_type}_index"} + {:bulk_create, value} when is_map(value) -> + {value.index, :bulk_create_index} _ -> nil diff --git a/mix.exs b/mix.exs index 79848b88..260de0d3 100644 --- a/mix.exs +++ b/mix.exs @@ -168,7 +168,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.5 and >= 3.5.35")}, {:spark, "~> 2.3 and >= 2.3.4"}, - {:ash_sql, ash_sql_version(git: "https://github.com/ash-project/ash_sql.git")}, + {:ash_sql, ash_sql_version("~> 0.3 and >= 0.3.2")}, {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, diff --git a/mix.lock b/mix.lock index f5d12abd..0c876d7c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.43", "222f9a8ac26ad3b029f8e69306cc83091c992d858b4538af12e33a148f301cab", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "48b2aa274c524f5b968c563dd56aec8f9b278c529c8aa46e6fe0ca564c26cc1c"}, - "ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "3044c0555dbe6733d16868951ee89e6d5ef336fa", []}, + "ash_sql": {:hex, :ash_sql, "0.3.1", "10c6b69d5b860d1162733324d249624399ade42ecfaff17573617a00f09eb66a", [:mix], [{:ash, ">= 3.5.43 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", "a6f69c8709afd6581cfebf4713b90be8e63c530bde162b2691da850599da4a2c"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -40,7 +40,7 @@ "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, "reactor": {:hex, :reactor, "0.17.0", "eb8bdb530dbae824e2d36a8538f8ec4f3aa7c2d1b61b04959fa787c634f88b49", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, ">= 2.3.3 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "3c3bf71693adbad9117b11ec83cfed7d5851b916ade508ed9718de7ae165bf25"}, "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, - "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, + "rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, From 9aaebc60f0f8015d8344aa7fc1ab2deaf5900d86 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 9 Oct 2025 23:38:56 -0400 Subject: [PATCH 670/690] chore: update ash_sql --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 0c876d7c..1827dcb4 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.5.43", "222f9a8ac26ad3b029f8e69306cc83091c992d858b4538af12e33a148f301cab", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "48b2aa274c524f5b968c563dd56aec8f9b278c529c8aa46e6fe0ca564c26cc1c"}, - "ash_sql": {:hex, :ash_sql, "0.3.1", "10c6b69d5b860d1162733324d249624399ade42ecfaff17573617a00f09eb66a", [:mix], [{:ash, ">= 3.5.43 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", "a6f69c8709afd6581cfebf4713b90be8e63c530bde162b2691da850599da4a2c"}, + "ash_sql": {:hex, :ash_sql, "0.3.2", "e2d65dac1c813cbd2569a750bf1c063109778e840052e44535ced294d7638a19", [:mix], [{:ash, ">= 3.5.43 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", "1f6e5d827c0eb55fc5a07f58eb97f9bb3e6b290d83df75883f422537b98c9c68"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, From c50052fde2aae223e2eb7949b7c5b869f3eb2da4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 9 Oct 2025 23:39:09 -0400 Subject: [PATCH 671/690] chore: release version v2.6.21 --- CHANGELOG.md | 21 +++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6546f3a..2778d41d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,27 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.21](https://github.com/ash-project/ash_postgres/compare/v2.6.20...v2.6.21) (2025-10-10) + + + + +### Bug Fixes: + +* simplify bulk operation metadata handling by Zach Daniel + +* update ash_postgresql to handle the new bulk_create response in Ash v3.5.44 (#632) by Daniel Gollings + +* Support non-public PostgreSQL schemas in resource generator (#631) by Elliot Bowes + +* guard against missing snapshot directories in migration generator by Elliot Bowes + +* ensure that tenant is properly used in many-to-many joins by Zach Daniel + +### Improvements: + +* Add immutable version of `ash_raise_error` function to support extensions like Citus (#620) by Steve Brambilla + ## [v2.6.20](https://github.com/ash-project/ash_postgres/compare/v2.6.19...v2.6.20) (2025-09-27) diff --git a/mix.exs b/mix.exs index 260de0d3..f1d82380 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.20" + @version "2.6.21" def project do [ From e43b89f4381ac4dcf6e4fbe5cfc5a2a7db270b9d Mon Sep 17 00:00:00 2001 From: James Harton Date: Sat, 11 Oct 2025 12:51:55 +1300 Subject: [PATCH 672/690] chore: REUSE compliance (#635) --- .check.exs | 7 ++++++- .credo.exs | 4 ++++ .formatter.exs | 4 ++++ .github/dependabot.yml | 4 ++++ .github/workflows/elixir.yml | 6 +++++- .gitignore | 4 ++++ .tool-versions | 1 + .tool-versions.license | 3 +++ .vscode/settings.json.license | 3 +++ CHANGELOG.md | 6 ++++++ LICENSE | 21 ------------------- LICENSES/MIT.txt | 18 ++++++++++++++++ README.md | 7 +++++++ SECURITY.md | 6 ++++++ benchmarks/bulk_create.exs | 4 ++++ config/config.exs | 4 ++++ documentation/1.0-CHANGELOG.md | 6 ++++++ .../dsls/DSL-AshPostgres.DataLayer.md.license | 3 +++ .../what-is-ash-postgres.md | 6 ++++++ documentation/topics/advanced/expressions.md | 6 ++++++ .../topics/advanced/manual-relationships.md | 6 ++++++ .../advanced/schema-based-multitenancy.md | 6 ++++++ .../topics/advanced/using-multiple-repos.md | 6 ++++++ .../development/migrations-and-tasks.md | 6 ++++++ documentation/topics/development/testing.md | 6 ++++++ .../topics/development/upgrading-to-2.0.md | 6 ++++++ .../topics/resources/polymorphic-resources.md | 6 ++++++ documentation/topics/resources/references.md | 6 ++++++ .../get-started-with-ash-postgres.md | 6 ++++++ .../set-up-with-existing-database.md | 6 ++++++ lib/ash_postgres.ex | 4 ++++ lib/check_constraint.ex | 4 ++++ lib/custom_aggregate.ex | 4 ++++ lib/custom_extension.ex | 4 ++++ lib/custom_index.ex | 4 ++++ lib/data_layer.ex | 4 ++++ lib/data_layer/info.ex | 4 ++++ lib/ecto_migration_default.ex | 4 ++++ lib/extensions/immutable_raise_error.ex | 4 ++++ lib/extensions/vector.ex | 4 ++++ lib/functions/binding.ex | 4 ++++ lib/functions/ilike.ex | 4 ++++ lib/functions/like.ex | 4 ++++ lib/functions/trigram_similarity.ex | 4 ++++ lib/functions/vector_cosine_distance.ex | 4 ++++ lib/functions/vector_l2_distance.ex | 4 ++++ lib/igniter.ex | 4 ++++ lib/manual_relationship.ex | 4 ++++ lib/migration.ex | 4 ++++ lib/migration_compile_cache.ex | 4 ++++ lib/migration_generator/ash_functions.ex | 4 ++++ .../migration_generator.ex | 4 ++++ lib/migration_generator/operation.ex | 4 ++++ lib/migration_generator/phase.ex | 4 ++++ lib/mix/helpers.ex | 4 ++++ lib/mix/tasks/ash_postgres.create.ex | 4 ++++ lib/mix/tasks/ash_postgres.drop.ex | 4 ++++ lib/mix/tasks/ash_postgres.gen.resources.ex | 4 ++++ .../tasks/ash_postgres.generate_migrations.ex | 4 ++++ lib/mix/tasks/ash_postgres.install.ex | 4 ++++ lib/mix/tasks/ash_postgres.migrate.ex | 4 ++++ lib/mix/tasks/ash_postgres.rollback.ex | 4 ++++ lib/mix/tasks/ash_postgres.setup_vector.ex | 4 ++++ .../tasks/ash_postgres.squash_snapshots.ex | 4 ++++ lib/multitenancy.ex | 4 ++++ lib/reference.ex | 4 ++++ lib/repo.ex | 4 ++++ lib/repo/before_compile.ex | 4 ++++ lib/resource_generator/resource_generator.ex | 4 ++++ lib/resource_generator/sensitive_data.ex | 4 ++++ lib/resource_generator/spec.ex | 4 ++++ lib/sql_implementation.ex | 4 ++++ lib/statement.ex | 4 ++++ lib/type.ex | 4 ++++ lib/types/ci_string_wrapper.ex | 4 ++++ lib/types/ltree.ex | 4 ++++ lib/types/string_wrapper.ex | 4 ++++ lib/types/timestamptz.ex | 4 ++++ lib/types/timestamptz_usec.ex | 4 ++++ lib/types/tsquery.ex | 4 ++++ lib/types/tsvector.ex | 4 ++++ lib/verifiers/ensure_table_or_polymorphic.ex | 4 ++++ ...te_multitenancy_and_non_full_match_type.ex | 4 ++++ ...event_multidimensional_array_aggregates.ex | 4 ++++ .../validate_identity_index_names.ex | 4 ++++ lib/verifiers/validate_references.ex | 4 ++++ lib/version_agent.ex | 3 +++ logos/small-logo.png.license | 3 +++ mix.exs | 17 ++++++++++++--- mix.lock.license | 3 +++ ...6214825_migrate_resources_extensions_1.exs | 4 ++++ .../20250526214827_migrate_resources1.exs | 4 ++++ .../dev_test_repo/extensions.json.license | 3 +++ .../20250526214827.json.license | 3 +++ .../extensions.json.license | 3 +++ .../accounts/20221217123726.json.license | 3 +++ .../accounts/20240327211150.json.license | 3 +++ .../authors/20220805191443.json.license | 3 +++ .../authors/20220914104733.json.license | 3 +++ .../authors/20240327211150.json.license | 3 +++ .../authors/20240705113722.json.license | 3 +++ .../authors/20250908212414.json.license | 3 +++ .../chats/20250908093505.json.license | 3 +++ .../20241208221219.json.license | 3 +++ .../comedians/20241217232254.json.license | 3 +++ .../comedians/20250413141328.json.license | 3 +++ .../comment_links/20250123161002.json.license | 3 +++ .../20220805191443.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../comments/20220805191443.json.license | 3 +++ .../comments/20240327211150.json.license | 3 +++ .../comments/20240327211917.json.license | 3 +++ .../20230816231942.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../20231116013020.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../20240327211917.json.license | 3 +++ .../20231116013020.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../20240327211917.json.license | 3 +++ .../20230816231942.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../20240327211917.json.license | 3 +++ .../20250714225304.json.license | 3 +++ .../20250714225304.json.license | 3 +++ .../20230816231942.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../content/20250123164209.json.license | 3 +++ .../20250123164209.json.license | 3 +++ .../test_repo/csv/20250320225052.json.license | 3 +++ .../customers/20250908073737.json.license | 3 +++ .../entities/20240109160153.json.license | 3 +++ .../entities/20240327211150.json.license | 3 +++ .../entities/20240327211917.json.license | 3 +++ .../test_repo/extensions.json.license | 3 +++ .../integer_posts/20220805191443.json.license | 3 +++ .../items/20240713134055.json.license | 3 +++ .../items/20240717104854.json.license | 3 +++ .../items/20240717153736.json.license | 3 +++ .../jokes/20241217232254.json.license | 3 +++ .../jokes/20250413141328.json.license | 3 +++ .../managers/20230526144249.json.license | 3 +++ .../managers/20240327211150.json.license | 3 +++ .../messages/20250908093505.json.license | 3 +++ .../20250519103535.json.license | 3 +++ .../20220805191443.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../20240627223225.json.license | 3 +++ .../20240702164513.json.license | 3 +++ .../20240703155134.json.license | 3 +++ .../20250122190558.json.license | 3 +++ .../note/20250123164209.json.license | 3 +++ .../orders/20250908073737.json.license | 3 +++ .../orgs/20230129050950.json.license | 3 +++ .../orgs/20240327211150.json.license | 3 +++ .../orgs/20250210191116.json.license | 3 +++ .../other_items/20240713134055.json.license | 3 +++ .../other_items/20240717151815.json.license | 3 +++ .../points/20250313112823.json.license | 3 +++ .../20240227180858.json.license | 3 +++ .../20240227181137.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../20240516205244.json.license | 3 +++ .../20240517223946.json.license | 3 +++ .../post_links/20220805191443.json.license | 3 +++ .../post_links/20221017133955.json.license | 3 +++ .../post_links/20221202194704.json.license | 3 +++ .../post_links/20240610195853.json.license | 3 +++ .../post_links/20240617193218.json.license | 3 +++ .../20240906170759.json.license | 3 +++ .../post_ratings/20220805191443.json.license | 3 +++ .../post_ratings/20240327211150.json.license | 3 +++ .../post_tags/20250810102512.json.license | 3 +++ .../post_views/20230905050351.json.license | 3 +++ .../post_views/20240327211917.json.license | 3 +++ .../posts/20220805191443.json.license | 3 +++ .../posts/20221125171150.json.license | 3 +++ .../posts/20221125171204.json.license | 3 +++ .../posts/20230129050950.json.license | 3 +++ .../posts/20230823161017.json.license | 3 +++ .../posts/20231127215636.json.license | 3 +++ .../posts/20231129141453.json.license | 3 +++ .../posts/20231219132807.json.license | 3 +++ .../posts/20240129221511.json.license | 3 +++ .../posts/20240224001913.json.license | 3 +++ .../posts/20240327211150.json.license | 3 +++ .../posts/20240327211917.json.license | 3 +++ .../posts/20240503012410.json.license | 3 +++ .../posts/20240504185511.json.license | 3 +++ .../posts/20240524031113.json.license | 3 +++ .../posts/20240524041750.json.license | 3 +++ .../posts/20240617193218.json.license | 3 +++ .../posts/20240618102809.json.license | 3 +++ .../posts/20240712232026.json.license | 3 +++ .../posts/20240715135403.json.license | 3 +++ .../posts/20240910180107.json.license | 3 +++ .../posts/20240911225320.json.license | 3 +++ .../posts/20240918104740.json.license | 3 +++ .../posts/20240929121224.json.license | 3 +++ .../posts/20250217054207.json.license | 3 +++ .../posts/20250313112823.json.license | 3 +++ .../posts/20250520130634.json.license | 3 +++ .../posts/20250521105654.json.license | 3 +++ .../posts/20250612113920.json.license | 3 +++ .../posts/20250618011917.json.license | 3 +++ .../products/20250908073737.json.license | 3 +++ .../profile/20220805191443.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../punchlines/20250413141328.json.license | 3 +++ .../records/20240109160153.json.license | 3 +++ .../records/20240327211150.json.license | 3 +++ .../records/20240327211917.json.license | 3 +++ .../20250605230457.json.license | 3 +++ .../20240717153736.json.license | 3 +++ .../rsvps/20251002180954.json.license | 3 +++ .../20240821213522.json.license | 3 +++ .../staff_group/20250123164209.json.license | 3 +++ .../20250123164209.json.license | 3 +++ .../standup_clubs/20250413141328.json.license | 3 +++ .../20240618085942.json.license | 3 +++ .../string_points/20250313112823.json.license | 3 +++ .../sub_items/20240713134055.json.license | 3 +++ .../20240130133933.json.license | 3 +++ .../20240130133933.json.license | 3 +++ .../20240130133933.json.license | 3 +++ .../20240130133933.json.license | 3 +++ .../tags/20250810102512.json.license | 3 +++ .../20240327211150.json.license | 3 +++ .../20240327211917.json.license | 3 +++ .../temp_entities/20240109160153.json.license | 3 +++ .../composite_key/20250220073135.json.license | 3 +++ .../composite_key/20250220073141.json.license | 3 +++ .../20250122203454.json.license | 3 +++ .../friend_links/20240610162043.json.license | 3 +++ .../20220805191441.json.license | 3 +++ .../20240327211149.json.license | 3 +++ .../20251001120813.json.license | 3 +++ .../20250731124648.json.license | 3 +++ .../20250731124648.json.license | 3 +++ .../20250731124648.json.license | 3 +++ .../20250731124648.json.license | 3 +++ .../user_invites/20240727145758.json.license | 3 +++ .../users/20220805191443.json.license | 3 +++ .../users/20221217123726.json.license | 3 +++ .../users/20230129050950.json.license | 3 +++ .../users/20240327211150.json.license | 3 +++ .../users/20240727145758.json.license | 3 +++ .../users/20240929124728.json.license | 3 +++ .../users/20250320225052.json.license | 3 +++ .../users/20250321142835.json.license | 3 +++ .../migrations/.gitkeep.license | 3 +++ .../20240627223224_install_5_extensions.exs | 4 ++++ ...2025_install_ash-functions_extension_4.exs | 4 ++++ ...3205301_migrate_resources_extensions_1.exs | 4 ++++ .../20220805191440_install_4_extensions.exs | 4 ++++ .../20220805191443_migrate_resources1.exs | 4 ++++ .../20220914104733_migrate_resources2.exs | 4 ++++ .../20221017133955_migrate_resources3.exs | 4 ++++ .../20221125171148_migrate_resources4.exs | 4 ++++ .../20221125171150_migrate_resources5.exs | 4 ++++ .../20221202194704_migrate_resources6.exs | 4 ++++ .../20221217123726_migrate_resources7.exs | 4 ++++ .../20230129050950_migrate_resources8.exs | 4 ++++ .../20230526144249_migrate_resources9.exs | 4 ++++ ...182523_install_ash-functions_extension.exs | 4 ++++ ...59_install_demo-functions_v0_extension.exs | 4 ++++ ...18_install_demo-functions_v1_extension.exs | 4 ++++ ...6231942_add_complex_calculation_tables.exs | 4 ++++ .../20230823161017_migrate_resources10.exs | 4 ++++ .../20230905050351_add_post_views.exs | 4 ++++ ...3020_add_complex_calculations_channels.exs | 4 ++++ .../20231127212608_add_composite_type.exs | 4 ++++ .../20231127215636_migrate_resources11.exs | 4 ++++ .../20231129141453_migrate_resources12.exs | 4 ++++ ...0937_install_ash-functions_extension_2.exs | 4 ++++ .../20231219132807_migrate_resources13.exs | 4 ++++ ...1611_install_ash-functions_extension_3.exs | 4 ++++ .../20240109155951_create_temp_schema.exs | 4 ++++ .../20240109160153_migrate_resources14.exs | 4 ++++ .../20240129221511_migrate_resources15.exs | 4 ++++ ...133933_add_resources_for_subquery_test.exs | 4 ++++ .../20240224001913_migrate_resources16.exs | 4 ++++ .../20240227180858_migrate_resources17.exs | 4 ++++ .../20240227181137_migrate_resources18.exs | 4 ++++ .../20240229050455_install_5_extensions.exs | 4 ++++ .../20240327211150_migrate_resources19.exs | 4 ++++ .../20240327211917_migrate_resources20.exs | 4 ++++ .../20240503012410_migrate_resources21.exs | 4 ++++ .../20240504185511_migrate_resources22.exs | 4 ++++ .../20240516205244_migrate_resources23.exs | 4 ++++ .../20240517223946_migrate_resources24.exs | 4 ++++ .../20240524031113_migrate_resources25.exs | 4 ++++ .../20240524041750_migrate_resources26.exs | 4 ++++ .../20240610195853_migrate_resources27.exs | 4 ++++ .../20240617193218_migrate_resources28.exs | 4 ++++ .../20240618085942_migrate_resources29.exs | 4 ++++ .../20240618102809_migrate_resources30.exs | 4 ++++ ...2715_install_ash-functions_extension_4.exs | 4 ++++ .../20240627223225_migrate_resources31.exs | 4 ++++ .../20240703155134_migrate_resources32.exs | 4 ++++ .../20240705113722_migrate_resources33.exs | 4 ++++ .../20240712232026_migrate_resources34.exs | 4 ++++ ...240713134055_multi_domain_calculations.exs | 4 ++++ .../20240715135403_migrate_resources35.exs | 4 ++++ ...7104854_no_attributes_calculation_test.exs | 4 ++++ .../20240717151815_migrate_resources36.exs | 4 ++++ .../20240717153736_migrate_resources37.exs | 4 ++++ .../20240727145758_user_invites.exs | 4 ++++ .../20240906170759_migrate_resources38.exs | 4 ++++ .../20240910180107_migrate_resources39.exs | 4 ++++ .../20240911225319_install_1_extensions.exs | 4 ++++ .../20240911225320_migrate_resources40.exs | 4 ++++ .../20240918104740_migrate_resources41.exs | 4 ++++ .../20240929121224_migrate_resources42.exs | 4 ++++ .../20240929124728_migrate_resources43.exs | 4 ++++ .../20241208221219_migrate_resources44.exs | 4 ++++ .../20241217232254_migrate_resources45.exs | 4 ++++ ...3205259_migrate_resources_extensions_1.exs | 4 ++++ .../20250122190558_migrate_resources46.exs | 4 ++++ .../20250123161002_migrate_resources47.exs | 4 ++++ .../20250123164209_migrate_resources48.exs | 4 ++++ .../20250210191116_migrate_resources49.exs | 4 ++++ .../20250217054207_migrate_resources50.exs | 4 ++++ .../20250313112823_migrate_resources51.exs | 4 ++++ .../20250320225052_add_csv_resource.exs | 4 ++++ .../20250321142835_migrate_resources52.exs | 4 ++++ ...41328_add_punchlines_and_standup_clubs.exs | 4 ++++ .../20250519103535_migrate_resources53.exs | 4 ++++ .../20250520130634_migrate_resources54.exs | 4 ++++ ...20250521105654_add_model_tuple_to_post.exs | 4 ++++ ...0457_create_record_temp_entities_table.exs | 4 ++++ .../20250612113920_migrate_resources55.exs | 4 ++++ .../20250618011917_migrate_resources56.exs | 4 ++++ ..._complex_calculations_folder_and_items.exs | 4 ++++ .../20250731124648_migrate_resources57.exs | 4 ++++ .../20250810102512_migrate_resources58.exs | 4 ++++ .../20250908073737_migrate_resources59.exs | 4 ++++ .../20250908093505_migrate_resources60.exs | 4 ++++ .../20250908212414_migrate_resources61.exs | 4 ++++ .../20251002180954_migrate_resources62.exs | 4 ++++ .../20220805191441_migrate_resources1.exs | 4 ++++ .../20240327211149_migrate_resources2.exs | 4 ++++ .../20240610162043_migrate_resources3.exs | 4 ++++ .../20250122203454_migrate_resources4.exs | 4 ++++ .../20250220073135_migrate_resources5.exs | 4 ++++ .../20250220073141_migrate_resources6.exs | 4 ++++ .../20251001120813_migrate_resources7.exs | 4 ++++ test/aggregate_test.exs | 4 ++++ test/ash_postgres_test.exs | 4 ++++ test/atomics_test.exs | 4 ++++ test/bulk_create_test.exs | 4 ++++ test/bulk_destroy_test.exs | 4 ++++ test/bulk_update_test.exs | 4 ++++ test/calculation_test.exs | 4 ++++ test/cascade_destroy_test.exs | 4 ++++ test/combination_test.exs | 4 ++++ test/complex_calculations_test.exs | 4 ++++ test/composite_type_test.exs | 4 ++++ test/constraint_test.exs | 4 ++++ test/create_test.exs | 4 ++++ test/custom_expression_test.exs | 4 ++++ test/custom_index_test.exs | 4 ++++ ...ic_non_bulk_actions_policy_bypass_test.exs | 4 ++++ test/destroy_test.exs | 4 ++++ test/dev_migrations_test.exs | 4 ++++ test/distinct_test.exs | 4 ++++ test/ecto_compatibility_test.exs | 4 ++++ test/embeddable_resource_test.exs | 4 ++++ test/enum_test.exs | 4 ++++ test/error_expr_test.exs | 4 ++++ ...lationship_by_parent_relationship_test.exs | 4 ++++ test/filter_field_policy_test.exs | 4 ++++ test/filter_test.exs | 4 ++++ test/load_test.exs | 4 ++++ test/lock_test.exs | 4 ++++ test/ltree_test.exs | 4 ++++ test/manual_relationships_test.exs | 4 ++++ test/manual_update_test.exs | 4 ++++ test/many_to_many_expr_test.exs | 4 ++++ test/migration_generator_test.exs | 4 ++++ test/mix/tasks/ash_postgres.install_test.exs | 4 ++++ test/mix_squash_snapshots_test.exs | 4 ++++ test/multi_domain_calculations_test.exs | 4 ++++ test/multitenancy_test.exs | 4 ++++ test/parent_filter_test.exs | 4 ++++ test/parent_sort_test.exs | 4 ++++ test/polymorphism_test.exs | 4 ++++ test/primary_key_test.exs | 4 ++++ test/references_test.exs | 4 ++++ test/rel_with_parent_filter_test.exs | 4 ++++ test/resource_generator_test.exs | 4 ++++ test/schema_test.exs | 4 ++++ test/select_test.exs | 4 ++++ test/sort_test.exs | 4 ++++ test/storage_types_test.exs | 4 ++++ test/subquery_test.exs | 4 ++++ test/support/complex_calculations/domain.ex | 4 ++++ .../resources/certification.ex | 4 ++++ .../complex_calculations/resources/channel.ex | 4 ++++ .../resources/channel_member.ex | 4 ++++ .../resources/dm_channel.ex | 4 ++++ .../resources/documentation.ex | 4 ++++ .../complex_calculations/resources/folder.ex | 4 ++++ .../resources/folder_item.ex | 4 ++++ .../complex_calculations/resources/skill.ex | 4 ++++ test/support/concat.ex | 4 ++++ test/support/dev_test_repo.ex | 4 ++++ test/support/domain.ex | 4 ++++ .../multi_domain_calculations/domain_one.ex | 4 ++++ .../domain_one/item.ex | 4 ++++ .../multi_domain_calculations/domain_three.ex | 4 ++++ .../domain_three/relationship_item.ex | 4 ++++ .../multi_domain_calculations/domain_two.ex | 4 ++++ .../domain_two/other_item.ex | 4 ++++ .../domain_two/sub_item.ex | 4 ++++ test/support/multitenancy/domain.ex | 4 ++++ .../resources/composite_key_post.ex | 4 ++++ .../resources/cross_tenant_post_link.ex | 4 ++++ .../resources/dev_migrations_org.ex | 4 ++++ .../multitenancy/resources/named_org.ex | 4 ++++ .../resources/non_multitenant_post_link.ex | 4 ++++ .../non_multitenant_post_multitenant_link.ex | 4 ++++ test/support/multitenancy/resources/org.ex | 4 ++++ test/support/multitenancy/resources/post.ex | 4 ++++ .../multitenancy/resources/post_link.ex | 4 ++++ test/support/multitenancy/resources/user.ex | 4 ++++ .../comments_containing_title.ex | 4 ++++ test/support/repo_case.ex | 4 ++++ test/support/resources/account.ex | 4 ++++ test/support/resources/author.ex | 4 ++++ test/support/resources/bio.ex | 4 ++++ test/support/resources/chat.ex | 4 ++++ test/support/resources/co_authored_post.ex | 4 ++++ test/support/resources/comedian.ex | 4 ++++ test/support/resources/comment.ex | 4 ++++ test/support/resources/comment_link.ex | 4 ++++ test/support/resources/content.ex | 4 ++++ .../resources/content_visibility_group.ex | 4 ++++ test/support/resources/csv.ex | 4 ++++ test/support/resources/customer.ex | 4 ++++ test/support/resources/db_point.ex | 4 ++++ test/support/resources/db_string_point.ex | 4 ++++ test/support/resources/entity.ex | 4 ++++ test/support/resources/integer_post.ex | 4 ++++ test/support/resources/invite.ex | 4 ++++ test/support/resources/joke.ex | 4 ++++ test/support/resources/manager.ex | 4 ++++ test/support/resources/message.ex | 4 ++++ test/support/resources/note.ex | 4 ++++ test/support/resources/order.ex | 4 ++++ test/support/resources/organization.ex | 4 ++++ test/support/resources/permalink.ex | 4 ++++ test/support/resources/post.ex | 4 ++++ test/support/resources/post_follower.ex | 4 ++++ test/support/resources/post_link.ex | 4 ++++ test/support/resources/post_tag.ex | 4 ++++ test/support/resources/post_views.ex | 4 ++++ .../resources/post_with_empty_update.ex | 4 ++++ test/support/resources/product.ex | 4 ++++ test/support/resources/profile.ex | 4 ++++ test/support/resources/punchline.ex | 4 ++++ test/support/resources/rating.ex | 4 ++++ test/support/resources/record.ex | 4 ++++ test/support/resources/record_temp_entity.ex | 4 ++++ test/support/resources/role.ex | 4 ++++ test/support/resources/rsvp.ex | 4 ++++ test/support/resources/settings.ex | 4 ++++ test/support/resources/staff_group.ex | 4 ++++ test/support/resources/staff_group_member.ex | 4 ++++ test/support/resources/standup_club.ex | 4 ++++ .../resources/stateful_post_follwer.ex | 4 ++++ test/support/resources/subquery/access.ex | 4 ++++ test/support/resources/subquery/child.ex | 4 ++++ .../resources/subquery/child_domain.ex | 4 ++++ test/support/resources/subquery/parent.ex | 4 ++++ .../resources/subquery/parent_domain.ex | 4 ++++ test/support/resources/subquery/through.ex | 4 ++++ test/support/resources/tag.ex | 4 ++++ test/support/resources/temp_entity.ex | 4 ++++ test/support/resources/user.ex | 4 ++++ test/support/string_agg.ex | 4 ++++ test/support/test_app.ex | 4 ++++ test/support/test_custom_extension.ex | 4 ++++ test/support/test_no_sandbox_repo.ex | 4 ++++ test/support/test_repo.ex | 4 ++++ test/support/trigram_word_similarity.ex | 4 ++++ test/support/types/composite_point.ex | 4 ++++ test/support/types/email.ex | 4 ++++ test/support/types/money.ex | 4 ++++ test/support/types/person_detail.ex | 4 ++++ test/support/types/point.ex | 4 ++++ test/support/types/response.ex | 4 ++++ test/support/types/status.ex | 4 ++++ test/support/types/status_enum.ex | 4 ++++ test/support/types/status_enum_no_cast.ex | 4 ++++ test/support/types/string_point.ex | 4 ++++ test/support/unrelated_aggregates/profile.ex | 4 ++++ test/support/unrelated_aggregates/report.ex | 4 ++++ .../unrelated_aggregates/secure_profile.ex | 4 ++++ test/support/unrelated_aggregates/user.ex | 4 ++++ test/test_helper.exs | 4 ++++ test/transaction_test.exs | 4 ++++ test/tuple_test.exs | 4 ++++ test/type_test.exs | 4 ++++ test/unique_identity_test.exs | 4 ++++ test/unrelated_aggregates_test.exs | 4 ++++ test/update_test.exs | 4 ++++ test/upsert_test.exs | 4 ++++ usage-rules.md | 6 ++++++ 509 files changed, 1926 insertions(+), 26 deletions(-) create mode 100644 .tool-versions.license create mode 100644 .vscode/settings.json.license delete mode 100644 LICENSE create mode 100644 LICENSES/MIT.txt create mode 100644 documentation/dsls/DSL-AshPostgres.DataLayer.md.license create mode 100644 logos/small-logo.png.license create mode 100644 mix.lock.license create mode 100644 priv/resource_snapshots/dev_test_repo/extensions.json.license create mode 100644 priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license create mode 100644 priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license create mode 100644 priv/resource_snapshots/test_repo/accounts/20221217123726.json.license create mode 100644 priv/resource_snapshots/test_repo/accounts/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/authors/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/authors/20220914104733.json.license create mode 100644 priv/resource_snapshots/test_repo/authors/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/authors/20240705113722.json.license create mode 100644 priv/resource_snapshots/test_repo/authors/20250908212414.json.license create mode 100644 priv/resource_snapshots/test_repo/chats/20250908093505.json.license create mode 100644 priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license create mode 100644 priv/resource_snapshots/test_repo/comedians/20241217232254.json.license create mode 100644 priv/resource_snapshots/test_repo/comedians/20250413141328.json.license create mode 100644 priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license create mode 100644 priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/comments/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/comments/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/comments/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license create mode 100644 priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/content/20250123164209.json.license create mode 100644 priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license create mode 100644 priv/resource_snapshots/test_repo/csv/20250320225052.json.license create mode 100644 priv/resource_snapshots/test_repo/customers/20250908073737.json.license create mode 100644 priv/resource_snapshots/test_repo/entities/20240109160153.json.license create mode 100644 priv/resource_snapshots/test_repo/entities/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/entities/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/extensions.json.license create mode 100644 priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/items/20240713134055.json.license create mode 100644 priv/resource_snapshots/test_repo/items/20240717104854.json.license create mode 100644 priv/resource_snapshots/test_repo/items/20240717153736.json.license create mode 100644 priv/resource_snapshots/test_repo/jokes/20241217232254.json.license create mode 100644 priv/resource_snapshots/test_repo/jokes/20250413141328.json.license create mode 100644 priv/resource_snapshots/test_repo/managers/20230526144249.json.license create mode 100644 priv/resource_snapshots/test_repo/managers/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/messages/20250908093505.json.license create mode 100644 priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license create mode 100644 priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license create mode 100644 priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license create mode 100644 priv/resource_snapshots/test_repo/note/20250123164209.json.license create mode 100644 priv/resource_snapshots/test_repo/orders/20250908073737.json.license create mode 100644 priv/resource_snapshots/test_repo/orgs/20230129050950.json.license create mode 100644 priv/resource_snapshots/test_repo/orgs/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/orgs/20250210191116.json.license create mode 100644 priv/resource_snapshots/test_repo/other_items/20240713134055.json.license create mode 100644 priv/resource_snapshots/test_repo/other_items/20240717151815.json.license create mode 100644 priv/resource_snapshots/test_repo/points/20250313112823.json.license create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license create mode 100644 priv/resource_snapshots/test_repo/post_links/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/post_links/20221017133955.json.license create mode 100644 priv/resource_snapshots/test_repo/post_links/20221202194704.json.license create mode 100644 priv/resource_snapshots/test_repo/post_links/20240610195853.json.license create mode 100644 priv/resource_snapshots/test_repo/post_links/20240617193218.json.license create mode 100644 priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license create mode 100644 priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license create mode 100644 priv/resource_snapshots/test_repo/post_views/20230905050351.json.license create mode 100644 priv/resource_snapshots/test_repo/post_views/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20221125171150.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20221125171204.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20230129050950.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20230823161017.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20231127215636.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20231129141453.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20231219132807.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240129221511.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240224001913.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240503012410.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240504185511.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240524031113.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240524041750.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240617193218.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240618102809.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240712232026.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240715135403.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240910180107.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240911225320.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240918104740.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20240929121224.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20250217054207.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20250313112823.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20250520130634.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20250521105654.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20250612113920.json.license create mode 100644 priv/resource_snapshots/test_repo/posts/20250618011917.json.license create mode 100644 priv/resource_snapshots/test_repo/products/20250908073737.json.license create mode 100644 priv/resource_snapshots/test_repo/profile/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license create mode 100644 priv/resource_snapshots/test_repo/records/20240109160153.json.license create mode 100644 priv/resource_snapshots/test_repo/records/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/records/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license create mode 100644 priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license create mode 100644 priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license create mode 100644 priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license create mode 100644 priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license create mode 100644 priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license create mode 100644 priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license create mode 100644 priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license create mode 100644 priv/resource_snapshots/test_repo/string_points/20250313112823.json.license create mode 100644 priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license create mode 100644 priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license create mode 100644 priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license create mode 100644 priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license create mode 100644 priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license create mode 100644 priv/resource_snapshots/test_repo/tags/20250810102512.json.license create mode 100644 priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license create mode 100644 priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license create mode 100644 priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license create mode 100644 priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license create mode 100644 priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license create mode 100644 priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license create mode 100644 priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license create mode 100644 priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license create mode 100644 priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license create mode 100644 priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license create mode 100644 priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license create mode 100644 priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license create mode 100644 priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license create mode 100644 priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20220805191443.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20221217123726.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20230129050950.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20240327211150.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20240727145758.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20240929124728.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20250320225052.json.license create mode 100644 priv/resource_snapshots/test_repo/users/20250321142835.json.license create mode 100644 priv/test_no_sandbox_repo/migrations/.gitkeep.license diff --git a/.check.exs b/.check.exs index 91e14cb1..cecfbc08 100644 --- a/.check.exs +++ b/.check.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + [ ## all available options with default values (see `mix check` docs for description) # parallel: true, @@ -12,7 +16,8 @@ # {:credo, "mix credo --format oneline"}, {:check_formatter, command: "mix spark.formatter --check"}, - {:check_migrations, command: "mix test.check_migrations"} + {:check_migrations, command: "mix test.check_migrations"}, + {:reuse, command: ["pipx", "run", "reuse", "lint", "-q"]} ## custom new tools may be added (mix tasks or arbitrary commands) # {:my_mix_task, command: "mix release", env: %{"MIX_ENV" => "prod"}}, # {:my_arbitrary_tool, command: "npm test", cd: "assets"}, diff --git a/.credo.exs b/.credo.exs index fa9affad..1e1ebe4c 100644 --- a/.credo.exs +++ b/.credo.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + # This file contains the configuration for Credo and you are probably reading # this after creating it with `mix credo.gen.config`. # diff --git a/.formatter.exs b/.formatter.exs index b9c6f498..07bd4f93 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + spark_locals_without_parens = [ all_tenants?: 1, base_filter_sql: 1, diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 597c8ec7..09b96595 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + --- updates: - directory: / diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index 084df209..cf4e4897 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + name: CI on: push: @@ -19,6 +23,6 @@ jobs: publish-docs: ${{ matrix.postgres-version == '16' }} release: ${{ matrix.postgres-version == '16' }} igniter-upgrade: ${{matrix.postgres-version == '16'}} - + reuse: true secrets: hex_api_key: ${{ secrets.HEX_API_KEY }} diff --git a/.gitignore b/.gitignore index 7d849d6b..b16f7ffb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + # The directory Mix will write compiled artifacts to. /_build/ diff --git a/.tool-versions b/.tool-versions index 6c947239..0fa52d96 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,3 @@ erlang 27.1.2 elixir 1.18.4-otp-27 +pipx 1.8.0 diff --git a/.tool-versions.license b/.tool-versions.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/.tool-versions.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/.vscode/settings.json.license b/.vscode/settings.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/.vscode/settings.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/CHANGELOG.md b/CHANGELOG.md index 2778d41d..4b045424 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ + + # Change Log All notable changes to this project will be documented in this file. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 4eb51a51..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Zachary Scott Daniel - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 00000000..d817195d --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,18 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 1bef9edc..98ba97ee 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ + + ![Logo](https://github.com/ash-project/ash/blob/main/logos/cropped-for-header-black-text.png?raw=true#gh-light-mode-only) ![Logo](https://github.com/ash-project/ash/blob/main/logos/cropped-for-header-white-text.png?raw=true#gh-dark-mode-only) @@ -5,6 +11,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/MIT) [![Hex version badge](https://img.shields.io/hexpm/v/ash_postgres.svg)](https://hex.pm/packages/ash_postgres) [![Hexdocs badge](https://img.shields.io/badge/docs-hexdocs-purple)](https://hexdocs.pm/ash_postgres) +[![REUSE status](https://api.reuse.software/badge/github.com/ash-project/ash_postgres)](https://api.reuse.software/info/github.com/ash-project/ash_postgres) # AshPostgres diff --git a/SECURITY.md b/SECURITY.md index 87d03b8b..8b1473d6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,3 +1,9 @@ + + # Security Policy This is a copy of the security policy in the core Ash repo. That is the authoritative source. diff --git a/benchmarks/bulk_create.exs b/benchmarks/bulk_create.exs index 99f235a1..5e665f19 100644 --- a/benchmarks/bulk_create.exs +++ b/benchmarks/bulk_create.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + alias AshPostgres.Test.{Domain, Post} AshPostgres.TestRepo.start_link() diff --git a/config/config.exs b/config/config.exs index 0041c0ac..5a179e32 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + import Config if Mix.env() == :dev do diff --git a/documentation/1.0-CHANGELOG.md b/documentation/1.0-CHANGELOG.md index 222e3265..0e65a587 100644 --- a/documentation/1.0-CHANGELOG.md +++ b/documentation/1.0-CHANGELOG.md @@ -1,3 +1,9 @@ + + ## [v2.0.0-rc.14](https://github.com/ash-project/ash_postgres/compare/v2.0.0-rc.13...v2.0.0-rc.14) (2024-04-29) ### Improvements: diff --git a/documentation/dsls/DSL-AshPostgres.DataLayer.md.license b/documentation/dsls/DSL-AshPostgres.DataLayer.md.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/documentation/dsls/DSL-AshPostgres.DataLayer.md.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/documentation/topics/about-ash-postgres/what-is-ash-postgres.md b/documentation/topics/about-ash-postgres/what-is-ash-postgres.md index 883b3512..b88bac60 100644 --- a/documentation/topics/about-ash-postgres/what-is-ash-postgres.md +++ b/documentation/topics/about-ash-postgres/what-is-ash-postgres.md @@ -1,3 +1,9 @@ + + # What is AshPostgres? AshPostgres is the PostgreSQL `Ash.DataLayer` for [Ash Framework](https://hexdocs.pm/ash). This is the most fully-featured Ash data layer, and unless you need a specific characteristic or feature of another data layer, you should use `AshPostgres`. diff --git a/documentation/topics/advanced/expressions.md b/documentation/topics/advanced/expressions.md index 953e402d..c5a6a759 100644 --- a/documentation/topics/advanced/expressions.md +++ b/documentation/topics/advanced/expressions.md @@ -1,3 +1,9 @@ + + # Expressions In addition to the expressions listed in the [Ash expressions guide](https://hexdocs.pm/ash/expressions.html), AshPostgres provides the following expressions diff --git a/documentation/topics/advanced/manual-relationships.md b/documentation/topics/advanced/manual-relationships.md index a7adaac3..1bd438b5 100644 --- a/documentation/topics/advanced/manual-relationships.md +++ b/documentation/topics/advanced/manual-relationships.md @@ -1,3 +1,9 @@ + + # Manual Relationships See [Manual Relationships](https://hexdocs.pm/ash/relationships.html#manual-relationships) for an idea of manual relationships in general. diff --git a/documentation/topics/advanced/schema-based-multitenancy.md b/documentation/topics/advanced/schema-based-multitenancy.md index 69d7add1..f1459c1f 100644 --- a/documentation/topics/advanced/schema-based-multitenancy.md +++ b/documentation/topics/advanced/schema-based-multitenancy.md @@ -1,3 +1,9 @@ + + # Schema Based Multitenancy Multitenancy in AshPostgres is implemented via postgres schemas. For more information on schemas, see postgres' [schema documentation](https://www.postgresql.org/docs/current/ddl-schemas.html) diff --git a/documentation/topics/advanced/using-multiple-repos.md b/documentation/topics/advanced/using-multiple-repos.md index 3c85ff5c..02378413 100644 --- a/documentation/topics/advanced/using-multiple-repos.md +++ b/documentation/topics/advanced/using-multiple-repos.md @@ -1,3 +1,9 @@ + + # Using Multiple Repos When scaling PostgreSQL you may want to setup _read_ replicas to improve diff --git a/documentation/topics/development/migrations-and-tasks.md b/documentation/topics/development/migrations-and-tasks.md index 592bb9a9..2d163da4 100644 --- a/documentation/topics/development/migrations-and-tasks.md +++ b/documentation/topics/development/migrations-and-tasks.md @@ -1,3 +1,9 @@ + + # Migrations ## Tasks diff --git a/documentation/topics/development/testing.md b/documentation/topics/development/testing.md index 3fe7662b..eaf826f1 100644 --- a/documentation/topics/development/testing.md +++ b/documentation/topics/development/testing.md @@ -1,3 +1,9 @@ + + # Testing with AshPostgres When using AshPostgres resources in tests, you will likely want to include use a test case similar to the following. This will ensure that your repo runs everything in a transaction. diff --git a/documentation/topics/development/upgrading-to-2.0.md b/documentation/topics/development/upgrading-to-2.0.md index 34eeb78c..fd3e1cc7 100644 --- a/documentation/topics/development/upgrading-to-2.0.md +++ b/documentation/topics/development/upgrading-to-2.0.md @@ -1,3 +1,9 @@ + + # Upgrading to 2.0 There are only three breaking changes in this release, one of them is very significant, the other two are minor. diff --git a/documentation/topics/resources/polymorphic-resources.md b/documentation/topics/resources/polymorphic-resources.md index e7852795..9f6d11ac 100644 --- a/documentation/topics/resources/polymorphic-resources.md +++ b/documentation/topics/resources/polymorphic-resources.md @@ -1,3 +1,9 @@ + + # Polymorphic Resources To support leveraging the same resource backed by multiple tables (useful for things like polymorphic associations), AshPostgres supports setting the `data_layer.table` context for a given resource. For this example, lets assume that you have a `MyApp.Post` resource and a `MyApp.Comment` resource. For each of those resources, users can submit `reactions`. However, you want a separate table for `post_reactions` and `comment_reactions`. You could accomplish that like so: diff --git a/documentation/topics/resources/references.md b/documentation/topics/resources/references.md index 10ed6575..494c73b7 100644 --- a/documentation/topics/resources/references.md +++ b/documentation/topics/resources/references.md @@ -1,3 +1,9 @@ + + # References To configure the behavior of generated foreign keys on a resource, we use the `references` section, within the `postgres` configuration block. diff --git a/documentation/tutorials/get-started-with-ash-postgres.md b/documentation/tutorials/get-started-with-ash-postgres.md index 8e02c72a..f96c8659 100644 --- a/documentation/tutorials/get-started-with-ash-postgres.md +++ b/documentation/tutorials/get-started-with-ash-postgres.md @@ -1,3 +1,9 @@ + + # Get Started With Postgres ## Installation diff --git a/documentation/tutorials/set-up-with-existing-database.md b/documentation/tutorials/set-up-with-existing-database.md index 0c5d92c0..79b6a061 100644 --- a/documentation/tutorials/set-up-with-existing-database.md +++ b/documentation/tutorials/set-up-with-existing-database.md @@ -1,3 +1,9 @@ + + # Setting AshPostgres up with an existing database If you already have a postgres database and you'd like to get diff --git a/lib/ash_postgres.ex b/lib/ash_postgres.ex index d26103e4..34f5cd43 100644 --- a/lib/ash_postgres.ex +++ b/lib/ash_postgres.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres do @moduledoc """ The AshPostgres extension gives you tools to map a resource to a postgres database table. diff --git a/lib/check_constraint.ex b/lib/check_constraint.ex index a16e7346..6534a464 100644 --- a/lib/check_constraint.ex +++ b/lib/check_constraint.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.CheckConstraint do @moduledoc "Represents a configured check constraint on the table backing a resource" diff --git a/lib/custom_aggregate.ex b/lib/custom_aggregate.ex index 9e581ce4..6a42b026 100644 --- a/lib/custom_aggregate.ex +++ b/lib/custom_aggregate.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.CustomAggregate do @moduledoc """ A custom aggregate implementation for ecto. diff --git a/lib/custom_extension.ex b/lib/custom_extension.ex index 9360dc5c..968a748c 100644 --- a/lib/custom_extension.ex +++ b/lib/custom_extension.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.CustomExtension do @moduledoc """ A custom extension implementation. diff --git a/lib/custom_index.ex b/lib/custom_index.ex index 29496ceb..240b30d2 100644 --- a/lib/custom_index.ex +++ b/lib/custom_index.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.CustomIndex do @moduledoc "Represents a custom index on the table backing a resource" @fields [ diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 6e3354d8..07812631 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DataLayer do require Ecto.Query require Ash.Expr diff --git a/lib/data_layer/info.ex b/lib/data_layer/info.ex index 696439ae..933ca6e8 100644 --- a/lib/data_layer/info.ex +++ b/lib/data_layer/info.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DataLayer.Info do @moduledoc "Introspection functions for " diff --git a/lib/ecto_migration_default.ex b/lib/ecto_migration_default.ex index d0ba6dbb..d865471b 100644 --- a/lib/ecto_migration_default.ex +++ b/lib/ecto_migration_default.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defprotocol EctoMigrationDefault do @moduledoc """ Allows configuring how values are translated to default values in migrations. diff --git a/lib/extensions/immutable_raise_error.ex b/lib/extensions/immutable_raise_error.ex index b7ccf347..22760442 100644 --- a/lib/extensions/immutable_raise_error.ex +++ b/lib/extensions/immutable_raise_error.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Extensions.ImmutableRaiseError do @moduledoc """ An extension that installs an immutable version of ash_raise_error. diff --git a/lib/extensions/vector.ex b/lib/extensions/vector.ex index 3280e629..c029dcf4 100644 --- a/lib/extensions/vector.ex +++ b/lib/extensions/vector.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Extensions.Vector do @moduledoc """ An extension that adds support for the `vector` type. diff --git a/lib/functions/binding.ex b/lib/functions/binding.ex index 92fc9d6f..df20a209 100644 --- a/lib/functions/binding.ex +++ b/lib/functions/binding.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Functions.Binding do @moduledoc """ Refers to the current table binding. diff --git a/lib/functions/ilike.ex b/lib/functions/ilike.ex index 8fa403d4..dd960f5f 100644 --- a/lib/functions/ilike.ex +++ b/lib/functions/ilike.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Functions.ILike do @moduledoc """ Maps to the builtin postgres function `ilike`. diff --git a/lib/functions/like.ex b/lib/functions/like.ex index 8b2d51b0..fdc76c6b 100644 --- a/lib/functions/like.ex +++ b/lib/functions/like.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Functions.Like do @moduledoc """ Maps to the builtin postgres function `like`. diff --git a/lib/functions/trigram_similarity.ex b/lib/functions/trigram_similarity.ex index 97177ae6..19622647 100644 --- a/lib/functions/trigram_similarity.ex +++ b/lib/functions/trigram_similarity.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Functions.TrigramSimilarity do @moduledoc """ Maps to the builtin postgres trigram similarity function. Requires `pgtrgm` extension to be installed. diff --git a/lib/functions/vector_cosine_distance.ex b/lib/functions/vector_cosine_distance.ex index 349c1977..1a811583 100644 --- a/lib/functions/vector_cosine_distance.ex +++ b/lib/functions/vector_cosine_distance.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Functions.VectorCosineDistance do @moduledoc """ Maps to the vector cosine distance operator. Requires `vector` extension to be installed. diff --git a/lib/functions/vector_l2_distance.ex b/lib/functions/vector_l2_distance.ex index c3f13ca0..063a1432 100644 --- a/lib/functions/vector_l2_distance.ex +++ b/lib/functions/vector_l2_distance.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Functions.VectorL2Distance do @moduledoc """ Maps to the vector l2 distance operator. Requires `vector` extension to be installed. diff --git a/lib/igniter.ex b/lib/igniter.ex index 02ef4476..aa20746d 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + if Code.ensure_loaded?(Igniter) do defmodule AshPostgres.Igniter do @moduledoc "Codemods and utilities for working with AshPostgres & Igniter" diff --git a/lib/manual_relationship.ex b/lib/manual_relationship.ex index 081aee13..b6322de9 100644 --- a/lib/manual_relationship.ex +++ b/lib/manual_relationship.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ManualRelationship do @moduledoc "A behavior for postgres-specific manual relationship functionality" diff --git a/lib/migration.ex b/lib/migration.ex index 78e76f97..9102d2a9 100644 --- a/lib/migration.ex +++ b/lib/migration.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Migration do @moduledoc "Utilities for use in migrations" diff --git a/lib/migration_compile_cache.ex b/lib/migration_compile_cache.ex index 802c21ad..f421d3b6 100644 --- a/lib/migration_compile_cache.ex +++ b/lib/migration_compile_cache.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MigrationCompileCache do @moduledoc """ A cache for the compiled migrations. diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index a9c4659c..1206d829 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MigrationGenerator.AshFunctions do @latest_version 5 diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 00276e25..bdd82fba 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MigrationGenerator do @moduledoc false diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 88525c11..21af504b 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MigrationGenerator.Operation do @moduledoc false diff --git a/lib/migration_generator/phase.ex b/lib/migration_generator/phase.ex index a4e5861b..9b13dadd 100644 --- a/lib/migration_generator/phase.ex +++ b/lib/migration_generator/phase.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MigrationGenerator.Phase do @moduledoc false diff --git a/lib/mix/helpers.ex b/lib/mix/helpers.ex index 316778fd..51db8a64 100644 --- a/lib/mix/helpers.ex +++ b/lib/mix/helpers.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Mix.Helpers do @moduledoc false def domains!(opts, args) do diff --git a/lib/mix/tasks/ash_postgres.create.ex b/lib/mix/tasks/ash_postgres.create.ex index a99baf33..61129c48 100644 --- a/lib/mix/tasks/ash_postgres.create.ex +++ b/lib/mix/tasks/ash_postgres.create.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.Create do use Mix.Task diff --git a/lib/mix/tasks/ash_postgres.drop.ex b/lib/mix/tasks/ash_postgres.drop.ex index e54ffddb..2c50e9b3 100644 --- a/lib/mix/tasks/ash_postgres.drop.ex +++ b/lib/mix/tasks/ash_postgres.drop.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.Drop do use Mix.Task diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index babac4f1..d207ea3f 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + if Code.ensure_loaded?(Igniter) do defmodule Mix.Tasks.AshPostgres.Gen.Resources do use Igniter.Mix.Task diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index 028ac8bb..ca16404d 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.GenerateMigrations do @moduledoc """ Generates migrations, and stores a snapshot of your resources. diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index 4935fdf1..e7b6e0fb 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + if Code.ensure_loaded?(Igniter) do defmodule Mix.Tasks.AshPostgres.Install do @moduledoc "Installs AshPostgres. Should be run with `mix igniter.install ash_postgres`" diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index 7da14a78..601a5daf 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.Migrate do use Mix.Task diff --git a/lib/mix/tasks/ash_postgres.rollback.ex b/lib/mix/tasks/ash_postgres.rollback.ex index d59fc1bf..da11f74c 100644 --- a/lib/mix/tasks/ash_postgres.rollback.ex +++ b/lib/mix/tasks/ash_postgres.rollback.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.Rollback do use Mix.Task diff --git a/lib/mix/tasks/ash_postgres.setup_vector.ex b/lib/mix/tasks/ash_postgres.setup_vector.ex index c58b6f56..209c8241 100644 --- a/lib/mix/tasks/ash_postgres.setup_vector.ex +++ b/lib/mix/tasks/ash_postgres.setup_vector.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.SetupVector.Docs do @moduledoc false diff --git a/lib/mix/tasks/ash_postgres.squash_snapshots.ex b/lib/mix/tasks/ash_postgres.squash_snapshots.ex index 84032c9b..8e40a597 100644 --- a/lib/mix/tasks/ash_postgres.squash_snapshots.ex +++ b/lib/mix/tasks/ash_postgres.squash_snapshots.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.SquashSnapshots do use Mix.Task diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 6d70aa49..5660e963 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultiTenancy do @moduledoc false diff --git a/lib/reference.ex b/lib/reference.ex index e724a0b6..f22abc1f 100644 --- a/lib/reference.ex +++ b/lib/reference.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Reference do @moduledoc "Represents the configuration of a reference (i.e foreign key)." defstruct [ diff --git a/lib/repo.ex b/lib/repo.ex index e1b0726d..fdc2d522 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Repo do @moduledoc """ Resources that use `AshPostgres.DataLayer` use a `Repo` to access the database. diff --git a/lib/repo/before_compile.ex b/lib/repo/before_compile.ex index c2e9a310..c8306507 100644 --- a/lib/repo/before_compile.ex +++ b/lib/repo/before_compile.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Repo.BeforeCompile do @moduledoc false diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index b3a507b7..0f633f7b 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + if Code.ensure_loaded?(Igniter) do defmodule AshPostgres.ResourceGenerator do @moduledoc false diff --git a/lib/resource_generator/sensitive_data.ex b/lib/resource_generator/sensitive_data.ex index 7b720aef..30c94857 100644 --- a/lib/resource_generator/sensitive_data.ex +++ b/lib/resource_generator/sensitive_data.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ResourceGenerator.SensitiveData do @moduledoc false # I got this from ChatGPT, but this is a best effort transformation diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index 9997bbac..c4d8088e 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ResourceGenerator.Spec do @moduledoc false require Logger diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 71b7f03d..84d31935 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.SqlImplementation do @moduledoc false use AshSql.Implementation diff --git a/lib/statement.ex b/lib/statement.ex index dfc49322..5902d730 100644 --- a/lib/statement.ex +++ b/lib/statement.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Statement do @moduledoc "Represents a custom statement to be run in generated migrations" diff --git a/lib/type.ex b/lib/type.ex index 22a3ec07..88c6ef63 100644 --- a/lib/type.ex +++ b/lib/type.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Type do @moduledoc """ Postgres specific callbacks for `Ash.Type`. diff --git a/lib/types/ci_string_wrapper.ex b/lib/types/ci_string_wrapper.ex index 74e47347..5c7bb8cb 100644 --- a/lib/types/ci_string_wrapper.ex +++ b/lib/types/ci_string_wrapper.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Type.CiStringWrapper do @moduledoc false use Ash.Type.NewType, subtype_of: :ci_string, constraints: [allow_empty?: true, trim?: false] diff --git a/lib/types/ltree.ex b/lib/types/ltree.ex index 512758e2..0997bdff 100644 --- a/lib/types/ltree.ex +++ b/lib/types/ltree.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Ltree do @constraints [ escape?: [ diff --git a/lib/types/string_wrapper.ex b/lib/types/string_wrapper.ex index 84b5cd2c..5d8c33ea 100644 --- a/lib/types/string_wrapper.ex +++ b/lib/types/string_wrapper.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Type.StringWrapper do @moduledoc false use Ash.Type.NewType, subtype_of: :string, constraints: [allow_empty?: true, trim?: false] diff --git a/lib/types/timestamptz.ex b/lib/types/timestamptz.ex index 11b007a3..c684751c 100644 --- a/lib/types/timestamptz.ex +++ b/lib/types/timestamptz.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Timestamptz do @moduledoc """ Implements the PostgresSQL [timestamptz](https://www.postgresql.org/docs/current/datatype-datetime.html) (aka `timestamp with time zone`) type. diff --git a/lib/types/timestamptz_usec.ex b/lib/types/timestamptz_usec.ex index f1dae8fd..8bd0a38d 100644 --- a/lib/types/timestamptz_usec.ex +++ b/lib/types/timestamptz_usec.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TimestamptzUsec do @moduledoc """ Implements the PostgresSQL [timestamptz](https://www.postgresql.org/docs/current/datatype-datetime.html) (aka `timestamp with time zone`) type with nanosecond precision. diff --git a/lib/types/tsquery.ex b/lib/types/tsquery.ex index 9115b0e1..8e1fb7ad 100644 --- a/lib/types/tsquery.ex +++ b/lib/types/tsquery.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Tsquery do @moduledoc """ A thin wrapper around `:string` for working with tsquery types in calculations. diff --git a/lib/types/tsvector.ex b/lib/types/tsvector.ex index f753b2b1..1a29a359 100644 --- a/lib/types/tsvector.ex +++ b/lib/types/tsvector.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Tsvector do @moduledoc """ A type for representing postgres' tsvectors. diff --git a/lib/verifiers/ensure_table_or_polymorphic.ex b/lib/verifiers/ensure_table_or_polymorphic.ex index c2e612ca..9c1d17bc 100644 --- a/lib/verifiers/ensure_table_or_polymorphic.ex +++ b/lib/verifiers/ensure_table_or_polymorphic.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Verifiers.EnsureTableOrPolymorphic do @moduledoc false use Spark.Dsl.Verifier diff --git a/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex b/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex index 5e0a25cc..a595c95c 100644 --- a/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex +++ b/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Verifiers.PreventAttributeMultitenancyAndNonFullMatchType do @moduledoc false use Spark.Dsl.Verifier diff --git a/lib/verifiers/prevent_multidimensional_array_aggregates.ex b/lib/verifiers/prevent_multidimensional_array_aggregates.ex index 82a38202..7589b277 100644 --- a/lib/verifiers/prevent_multidimensional_array_aggregates.ex +++ b/lib/verifiers/prevent_multidimensional_array_aggregates.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Verifiers.PreventMultidimensionalArrayAggregates do @moduledoc false use Spark.Dsl.Verifier diff --git a/lib/verifiers/validate_identity_index_names.ex b/lib/verifiers/validate_identity_index_names.ex index 82457eb2..1c2fbad8 100644 --- a/lib/verifiers/validate_identity_index_names.ex +++ b/lib/verifiers/validate_identity_index_names.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Verifiers.ValidateIdentityIndexNames do @moduledoc false use Spark.Dsl.Verifier diff --git a/lib/verifiers/validate_references.ex b/lib/verifiers/validate_references.ex index 40c47a8e..efcffd2d 100644 --- a/lib/verifiers/validate_references.ex +++ b/lib/verifiers/validate_references.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Verifiers.ValidateReferences do @moduledoc false use Spark.Dsl.Verifier diff --git a/lib/version_agent.ex b/lib/version_agent.ex index e69de29b..0db6f4ff 100644 --- a/lib/version_agent.ex +++ b/lib/version_agent.ex @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT diff --git a/logos/small-logo.png.license b/logos/small-logo.png.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/logos/small-logo.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/mix.exs b/mix.exs index f1d82380..cf59bf71 100644 --- a/mix.exs +++ b/mix.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MixProject do use Mix.Project @@ -54,13 +58,20 @@ defmodule AshPostgres.MixProject do defp package do [ - name: :ash_postgres, + maintainers: [ + "Zach Daniel " + ], licenses: ["MIT"], files: ~w(lib .formatter.exs mix.exs README* LICENSE* CHANGELOG* documentation usage-rules.md), links: %{ - Changelog: "https://hexdocs.pm/ash_postgres/changelog.html", - GitHub: "https://github.com/ash-project/ash_postgres" + "GitHub" => "https://github.com/ash-project/ash_postgres", + "Changelog" => "https://github.com/ash-project/ash_postgres/blob/main/CHANGELOG.md", + "Discord" => "https://discord.gg/HTHRaaVPUc", + "Website" => "https://ash-hq.org/", + "Forum" => "https://elixirforum.com/c/elixir-framework-forums/ash-framework-forum", + "REUSE Compliance" => + "https://api.reuse.software/info/github.com/ash-project/ash_postgres" } ] end diff --git a/mix.lock.license b/mix.lock.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/mix.lock.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs b/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs index 389b0b27..57fc3e50 100644 --- a/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs +++ b/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DevTestRepo.Migrations.MigrateResourcesExtensions1 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs b/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs index 3a56462c..bc0f2abf 100644 --- a/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs +++ b/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DevTestRepo.Migrations.MigrateResources1 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/resource_snapshots/dev_test_repo/extensions.json.license b/priv/resource_snapshots/dev_test_repo/extensions.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/dev_test_repo/extensions.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license b/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/accounts/20221217123726.json.license b/priv/resource_snapshots/test_repo/accounts/20221217123726.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/accounts/20221217123726.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/accounts/20240327211150.json.license b/priv/resource_snapshots/test_repo/accounts/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/accounts/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20220805191443.json.license b/priv/resource_snapshots/test_repo/authors/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20220914104733.json.license b/priv/resource_snapshots/test_repo/authors/20220914104733.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20220914104733.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20240327211150.json.license b/priv/resource_snapshots/test_repo/authors/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20240705113722.json.license b/priv/resource_snapshots/test_repo/authors/20240705113722.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20240705113722.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20250908212414.json.license b/priv/resource_snapshots/test_repo/authors/20250908212414.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20250908212414.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/chats/20250908093505.json.license b/priv/resource_snapshots/test_repo/chats/20250908093505.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/chats/20250908093505.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license b/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comedians/20241217232254.json.license b/priv/resource_snapshots/test_repo/comedians/20241217232254.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comedians/20241217232254.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comedians/20250413141328.json.license b/priv/resource_snapshots/test_repo/comedians/20250413141328.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comedians/20250413141328.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license b/priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license b/priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license b/priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comments/20220805191443.json.license b/priv/resource_snapshots/test_repo/comments/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comments/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comments/20240327211150.json.license b/priv/resource_snapshots/test_repo/comments/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comments/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comments/20240327211917.json.license b/priv/resource_snapshots/test_repo/comments/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/comments/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license b/priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license b/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license b/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license b/priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/content/20250123164209.json.license b/priv/resource_snapshots/test_repo/content/20250123164209.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/content/20250123164209.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license b/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/csv/20250320225052.json.license b/priv/resource_snapshots/test_repo/csv/20250320225052.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/csv/20250320225052.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/customers/20250908073737.json.license b/priv/resource_snapshots/test_repo/customers/20250908073737.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/customers/20250908073737.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/entities/20240109160153.json.license b/priv/resource_snapshots/test_repo/entities/20240109160153.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/entities/20240109160153.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/entities/20240327211150.json.license b/priv/resource_snapshots/test_repo/entities/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/entities/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/entities/20240327211917.json.license b/priv/resource_snapshots/test_repo/entities/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/entities/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/extensions.json.license b/priv/resource_snapshots/test_repo/extensions.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/extensions.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license b/priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/items/20240713134055.json.license b/priv/resource_snapshots/test_repo/items/20240713134055.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/items/20240713134055.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/items/20240717104854.json.license b/priv/resource_snapshots/test_repo/items/20240717104854.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/items/20240717104854.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/items/20240717153736.json.license b/priv/resource_snapshots/test_repo/items/20240717153736.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/items/20240717153736.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/jokes/20241217232254.json.license b/priv/resource_snapshots/test_repo/jokes/20241217232254.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/jokes/20241217232254.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/jokes/20250413141328.json.license b/priv/resource_snapshots/test_repo/jokes/20250413141328.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/jokes/20250413141328.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/managers/20230526144249.json.license b/priv/resource_snapshots/test_repo/managers/20230526144249.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/managers/20230526144249.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/managers/20240327211150.json.license b/priv/resource_snapshots/test_repo/managers/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/managers/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/messages/20250908093505.json.license b/priv/resource_snapshots/test_repo/messages/20250908093505.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/messages/20250908093505.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license b/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license b/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/note/20250123164209.json.license b/priv/resource_snapshots/test_repo/note/20250123164209.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/note/20250123164209.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orders/20250908073737.json.license b/priv/resource_snapshots/test_repo/orders/20250908073737.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/orders/20250908073737.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orgs/20230129050950.json.license b/priv/resource_snapshots/test_repo/orgs/20230129050950.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/orgs/20230129050950.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orgs/20240327211150.json.license b/priv/resource_snapshots/test_repo/orgs/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/orgs/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orgs/20250210191116.json.license b/priv/resource_snapshots/test_repo/orgs/20250210191116.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/orgs/20250210191116.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/other_items/20240713134055.json.license b/priv/resource_snapshots/test_repo/other_items/20240713134055.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/other_items/20240713134055.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/other_items/20240717151815.json.license b/priv/resource_snapshots/test_repo/other_items/20240717151815.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/other_items/20240717151815.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/points/20250313112823.json.license b/priv/resource_snapshots/test_repo/points/20250313112823.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/points/20250313112823.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license b/priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license b/priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license b/priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license b/priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license b/priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20220805191443.json.license b/priv/resource_snapshots/test_repo/post_links/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_links/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20221017133955.json.license b/priv/resource_snapshots/test_repo/post_links/20221017133955.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_links/20221017133955.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20221202194704.json.license b/priv/resource_snapshots/test_repo/post_links/20221202194704.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_links/20221202194704.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20240610195853.json.license b/priv/resource_snapshots/test_repo/post_links/20240610195853.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_links/20240610195853.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20240617193218.json.license b/priv/resource_snapshots/test_repo/post_links/20240617193218.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_links/20240617193218.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license b/priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license b/priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license b/priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_views/20230905050351.json.license b/priv/resource_snapshots/test_repo/post_views/20230905050351.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_views/20230905050351.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_views/20240327211917.json.license b/priv/resource_snapshots/test_repo/post_views/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_views/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20220805191443.json.license b/priv/resource_snapshots/test_repo/posts/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20221125171150.json.license b/priv/resource_snapshots/test_repo/posts/20221125171150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20221125171150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20221125171204.json.license b/priv/resource_snapshots/test_repo/posts/20221125171204.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20221125171204.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20230129050950.json.license b/priv/resource_snapshots/test_repo/posts/20230129050950.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20230129050950.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20230823161017.json.license b/priv/resource_snapshots/test_repo/posts/20230823161017.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20230823161017.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20231127215636.json.license b/priv/resource_snapshots/test_repo/posts/20231127215636.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20231127215636.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20231129141453.json.license b/priv/resource_snapshots/test_repo/posts/20231129141453.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20231129141453.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20231219132807.json.license b/priv/resource_snapshots/test_repo/posts/20231219132807.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20231219132807.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240129221511.json.license b/priv/resource_snapshots/test_repo/posts/20240129221511.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240129221511.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240224001913.json.license b/priv/resource_snapshots/test_repo/posts/20240224001913.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240224001913.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240327211150.json.license b/priv/resource_snapshots/test_repo/posts/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240327211917.json.license b/priv/resource_snapshots/test_repo/posts/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240503012410.json.license b/priv/resource_snapshots/test_repo/posts/20240503012410.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240503012410.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240504185511.json.license b/priv/resource_snapshots/test_repo/posts/20240504185511.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240504185511.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240524031113.json.license b/priv/resource_snapshots/test_repo/posts/20240524031113.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240524031113.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240524041750.json.license b/priv/resource_snapshots/test_repo/posts/20240524041750.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240524041750.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240617193218.json.license b/priv/resource_snapshots/test_repo/posts/20240617193218.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240617193218.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240618102809.json.license b/priv/resource_snapshots/test_repo/posts/20240618102809.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240618102809.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240712232026.json.license b/priv/resource_snapshots/test_repo/posts/20240712232026.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240712232026.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240715135403.json.license b/priv/resource_snapshots/test_repo/posts/20240715135403.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240715135403.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240910180107.json.license b/priv/resource_snapshots/test_repo/posts/20240910180107.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240910180107.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240911225320.json.license b/priv/resource_snapshots/test_repo/posts/20240911225320.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240911225320.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240918104740.json.license b/priv/resource_snapshots/test_repo/posts/20240918104740.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240918104740.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240929121224.json.license b/priv/resource_snapshots/test_repo/posts/20240929121224.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20240929121224.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250217054207.json.license b/priv/resource_snapshots/test_repo/posts/20250217054207.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250217054207.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250313112823.json.license b/priv/resource_snapshots/test_repo/posts/20250313112823.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250313112823.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250520130634.json.license b/priv/resource_snapshots/test_repo/posts/20250520130634.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250520130634.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250521105654.json.license b/priv/resource_snapshots/test_repo/posts/20250521105654.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250521105654.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250612113920.json.license b/priv/resource_snapshots/test_repo/posts/20250612113920.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250612113920.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250618011917.json.license b/priv/resource_snapshots/test_repo/posts/20250618011917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts/20250618011917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/products/20250908073737.json.license b/priv/resource_snapshots/test_repo/products/20250908073737.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/products/20250908073737.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/profile/20220805191443.json.license b/priv/resource_snapshots/test_repo/profile/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/profile/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license b/priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license b/priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records/20240109160153.json.license b/priv/resource_snapshots/test_repo/records/20240109160153.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/records/20240109160153.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records/20240327211150.json.license b/priv/resource_snapshots/test_repo/records/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/records/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records/20240327211917.json.license b/priv/resource_snapshots/test_repo/records/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/records/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license b/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license b/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license b/priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license b/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license b/priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license b/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license b/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license b/priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/string_points/20250313112823.json.license b/priv/resource_snapshots/test_repo/string_points/20250313112823.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/string_points/20250313112823.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license b/priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tags/20250810102512.json.license b/priv/resource_snapshots/test_repo/tags/20250810102512.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tags/20250810102512.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license b/priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license b/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license b/priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license b/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license b/priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20220805191443.json.license b/priv/resource_snapshots/test_repo/users/20220805191443.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20220805191443.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20221217123726.json.license b/priv/resource_snapshots/test_repo/users/20221217123726.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20221217123726.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20230129050950.json.license b/priv/resource_snapshots/test_repo/users/20230129050950.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20230129050950.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20240327211150.json.license b/priv/resource_snapshots/test_repo/users/20240327211150.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20240327211150.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20240727145758.json.license b/priv/resource_snapshots/test_repo/users/20240727145758.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20240727145758.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20240929124728.json.license b/priv/resource_snapshots/test_repo/users/20240929124728.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20240929124728.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20250320225052.json.license b/priv/resource_snapshots/test_repo/users/20250320225052.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20250320225052.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20250321142835.json.license b/priv/resource_snapshots/test_repo/users/20250321142835.json.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/resource_snapshots/test_repo/users/20250321142835.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/test_no_sandbox_repo/migrations/.gitkeep.license b/priv/test_no_sandbox_repo/migrations/.gitkeep.license new file mode 100644 index 00000000..815664f3 --- /dev/null +++ b/priv/test_no_sandbox_repo/migrations/.gitkeep.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2020 Zach Daniel + +SPDX-License-Identifier: MIT diff --git a/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs b/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs index 09446bc3..94e450c6 100644 --- a/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs +++ b/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestNoSandboxRepo.Migrations.Install5Extensions20240627223222 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs b/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs index 97101dca..ecf0a75f 100644 --- a/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs +++ b/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestNoSandboxRepo.Migrations.InstallAshFunctionsExtension420240712232023 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs b/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs index 9794c3be..01697a60 100644 --- a/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs +++ b/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestNoSandboxRepo.Migrations.MigrateResourcesExtensions1 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20220805191440_install_4_extensions.exs b/priv/test_repo/migrations/20220805191440_install_4_extensions.exs index f301710b..a20aa8e9 100644 --- a/priv/test_repo/migrations/20220805191440_install_4_extensions.exs +++ b/priv/test_repo/migrations/20220805191440_install_4_extensions.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.Install4Extensions do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20220805191443_migrate_resources1.exs b/priv/test_repo/migrations/20220805191443_migrate_resources1.exs index 886d2de2..b9b7fdd0 100644 --- a/priv/test_repo/migrations/20220805191443_migrate_resources1.exs +++ b/priv/test_repo/migrations/20220805191443_migrate_resources1.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources1 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20220914104733_migrate_resources2.exs b/priv/test_repo/migrations/20220914104733_migrate_resources2.exs index 17ecb49f..fbbeb8e0 100644 --- a/priv/test_repo/migrations/20220914104733_migrate_resources2.exs +++ b/priv/test_repo/migrations/20220914104733_migrate_resources2.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources2 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20221017133955_migrate_resources3.exs b/priv/test_repo/migrations/20221017133955_migrate_resources3.exs index b30a8ba4..12f282d6 100644 --- a/priv/test_repo/migrations/20221017133955_migrate_resources3.exs +++ b/priv/test_repo/migrations/20221017133955_migrate_resources3.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources3 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20221125171148_migrate_resources4.exs b/priv/test_repo/migrations/20221125171148_migrate_resources4.exs index e58db10c..b6749230 100644 --- a/priv/test_repo/migrations/20221125171148_migrate_resources4.exs +++ b/priv/test_repo/migrations/20221125171148_migrate_resources4.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources4 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20221125171150_migrate_resources5.exs b/priv/test_repo/migrations/20221125171150_migrate_resources5.exs index e9268571..f4d14b56 100644 --- a/priv/test_repo/migrations/20221125171150_migrate_resources5.exs +++ b/priv/test_repo/migrations/20221125171150_migrate_resources5.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources5 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20221202194704_migrate_resources6.exs b/priv/test_repo/migrations/20221202194704_migrate_resources6.exs index 2d77266a..6b6f174a 100644 --- a/priv/test_repo/migrations/20221202194704_migrate_resources6.exs +++ b/priv/test_repo/migrations/20221202194704_migrate_resources6.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources6 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20221217123726_migrate_resources7.exs b/priv/test_repo/migrations/20221217123726_migrate_resources7.exs index 8ca2e4f2..95edab52 100644 --- a/priv/test_repo/migrations/20221217123726_migrate_resources7.exs +++ b/priv/test_repo/migrations/20221217123726_migrate_resources7.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources7 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20230129050950_migrate_resources8.exs b/priv/test_repo/migrations/20230129050950_migrate_resources8.exs index 4cfaa7da..3aba9340 100644 --- a/priv/test_repo/migrations/20230129050950_migrate_resources8.exs +++ b/priv/test_repo/migrations/20230129050950_migrate_resources8.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources8 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20230526144249_migrate_resources9.exs b/priv/test_repo/migrations/20230526144249_migrate_resources9.exs index a4008d52..d3a907b8 100644 --- a/priv/test_repo/migrations/20230526144249_migrate_resources9.exs +++ b/priv/test_repo/migrations/20230526144249_migrate_resources9.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources9 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs b/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs index 8c0b5fef..6f9ee9e4 100644 --- a/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs +++ b/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.InstallAshFunctions do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs b/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs index 5521466e..edfac408 100644 --- a/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs +++ b/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.InstallDemoFunctionsV0 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs b/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs index b82ee5c7..2222a781 100644 --- a/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs +++ b/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.InstallDemoFunctionsV1 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs b/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs index 19ded080..1cc444b7 100644 --- a/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs +++ b/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationTables do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20230823161017_migrate_resources10.exs b/priv/test_repo/migrations/20230823161017_migrate_resources10.exs index 314d7bea..18e6f479 100644 --- a/priv/test_repo/migrations/20230823161017_migrate_resources10.exs +++ b/priv/test_repo/migrations/20230823161017_migrate_resources10.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources10 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20230905050351_add_post_views.exs b/priv/test_repo/migrations/20230905050351_add_post_views.exs index b09ea4af..3ea0cbb1 100644 --- a/priv/test_repo/migrations/20230905050351_add_post_views.exs +++ b/priv/test_repo/migrations/20230905050351_add_post_views.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddPostViews do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs b/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs index e090e448..c3f768f0 100644 --- a/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs +++ b/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationsChannels do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20231127212608_add_composite_type.exs b/priv/test_repo/migrations/20231127212608_add_composite_type.exs index 9f1217ff..8a85a46f 100644 --- a/priv/test_repo/migrations/20231127212608_add_composite_type.exs +++ b/priv/test_repo/migrations/20231127212608_add_composite_type.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddCompositeType do use Ecto.Migration diff --git a/priv/test_repo/migrations/20231127215636_migrate_resources11.exs b/priv/test_repo/migrations/20231127215636_migrate_resources11.exs index 06eb1c5b..c4da8e77 100644 --- a/priv/test_repo/migrations/20231127215636_migrate_resources11.exs +++ b/priv/test_repo/migrations/20231127215636_migrate_resources11.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources11 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20231129141453_migrate_resources12.exs b/priv/test_repo/migrations/20231129141453_migrate_resources12.exs index 1fbcbd28..613a6b42 100644 --- a/priv/test_repo/migrations/20231129141453_migrate_resources12.exs +++ b/priv/test_repo/migrations/20231129141453_migrate_resources12.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources12 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs b/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs index d3192fdc..e02f5467 100644 --- a/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs +++ b/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.InstallAshFunctionsExtension2 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20231219132807_migrate_resources13.exs b/priv/test_repo/migrations/20231219132807_migrate_resources13.exs index 088d2ae3..55fc4bbe 100644 --- a/priv/test_repo/migrations/20231219132807_migrate_resources13.exs +++ b/priv/test_repo/migrations/20231219132807_migrate_resources13.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources13 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs b/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs index 2417e5d7..e841dfba 100644 --- a/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs +++ b/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.InstallAshFunctionsExtension3 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20240109155951_create_temp_schema.exs b/priv/test_repo/migrations/20240109155951_create_temp_schema.exs index 2ecb9500..ada02c90 100644 --- a/priv/test_repo/migrations/20240109155951_create_temp_schema.exs +++ b/priv/test_repo/migrations/20240109155951_create_temp_schema.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.CreateTempSchema do use Ecto.Migration diff --git a/priv/test_repo/migrations/20240109160153_migrate_resources14.exs b/priv/test_repo/migrations/20240109160153_migrate_resources14.exs index 22bec37b..c70f9357 100644 --- a/priv/test_repo/migrations/20240109160153_migrate_resources14.exs +++ b/priv/test_repo/migrations/20240109160153_migrate_resources14.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources14 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240129221511_migrate_resources15.exs b/priv/test_repo/migrations/20240129221511_migrate_resources15.exs index 3ee35d6b..88ae8d08 100644 --- a/priv/test_repo/migrations/20240129221511_migrate_resources15.exs +++ b/priv/test_repo/migrations/20240129221511_migrate_resources15.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources15 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs b/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs index f54f17a0..36ad998e 100644 --- a/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs +++ b/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddResourcesForSubqueryTest do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240224001913_migrate_resources16.exs b/priv/test_repo/migrations/20240224001913_migrate_resources16.exs index a9b687e1..00decc17 100644 --- a/priv/test_repo/migrations/20240224001913_migrate_resources16.exs +++ b/priv/test_repo/migrations/20240224001913_migrate_resources16.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources16 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240227180858_migrate_resources17.exs b/priv/test_repo/migrations/20240227180858_migrate_resources17.exs index 1778a5e2..93fc8bd5 100644 --- a/priv/test_repo/migrations/20240227180858_migrate_resources17.exs +++ b/priv/test_repo/migrations/20240227180858_migrate_resources17.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources17 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240227181137_migrate_resources18.exs b/priv/test_repo/migrations/20240227181137_migrate_resources18.exs index f55f7b3c..4e6db225 100644 --- a/priv/test_repo/migrations/20240227181137_migrate_resources18.exs +++ b/priv/test_repo/migrations/20240227181137_migrate_resources18.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources18 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240229050455_install_5_extensions.exs b/priv/test_repo/migrations/20240229050455_install_5_extensions.exs index c3708b31..bdecc817 100644 --- a/priv/test_repo/migrations/20240229050455_install_5_extensions.exs +++ b/priv/test_repo/migrations/20240229050455_install_5_extensions.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.Install5Extensions do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20240327211150_migrate_resources19.exs b/priv/test_repo/migrations/20240327211150_migrate_resources19.exs index 787d0e26..7fc2c8c3 100644 --- a/priv/test_repo/migrations/20240327211150_migrate_resources19.exs +++ b/priv/test_repo/migrations/20240327211150_migrate_resources19.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources19 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240327211917_migrate_resources20.exs b/priv/test_repo/migrations/20240327211917_migrate_resources20.exs index 030206f5..bd30cc5b 100644 --- a/priv/test_repo/migrations/20240327211917_migrate_resources20.exs +++ b/priv/test_repo/migrations/20240327211917_migrate_resources20.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources20 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240503012410_migrate_resources21.exs b/priv/test_repo/migrations/20240503012410_migrate_resources21.exs index 70781d33..9230a78a 100644 --- a/priv/test_repo/migrations/20240503012410_migrate_resources21.exs +++ b/priv/test_repo/migrations/20240503012410_migrate_resources21.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources21 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240504185511_migrate_resources22.exs b/priv/test_repo/migrations/20240504185511_migrate_resources22.exs index 86257d61..19ae6c87 100644 --- a/priv/test_repo/migrations/20240504185511_migrate_resources22.exs +++ b/priv/test_repo/migrations/20240504185511_migrate_resources22.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources22 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240516205244_migrate_resources23.exs b/priv/test_repo/migrations/20240516205244_migrate_resources23.exs index 1d0eec51..cebacd08 100644 --- a/priv/test_repo/migrations/20240516205244_migrate_resources23.exs +++ b/priv/test_repo/migrations/20240516205244_migrate_resources23.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources23 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240517223946_migrate_resources24.exs b/priv/test_repo/migrations/20240517223946_migrate_resources24.exs index 22998699..09e71bd5 100644 --- a/priv/test_repo/migrations/20240517223946_migrate_resources24.exs +++ b/priv/test_repo/migrations/20240517223946_migrate_resources24.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources24 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240524031113_migrate_resources25.exs b/priv/test_repo/migrations/20240524031113_migrate_resources25.exs index 9c524d71..0b829659 100644 --- a/priv/test_repo/migrations/20240524031113_migrate_resources25.exs +++ b/priv/test_repo/migrations/20240524031113_migrate_resources25.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources25 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240524041750_migrate_resources26.exs b/priv/test_repo/migrations/20240524041750_migrate_resources26.exs index a65fb877..e27aff26 100644 --- a/priv/test_repo/migrations/20240524041750_migrate_resources26.exs +++ b/priv/test_repo/migrations/20240524041750_migrate_resources26.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources26 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240610195853_migrate_resources27.exs b/priv/test_repo/migrations/20240610195853_migrate_resources27.exs index c31f8819..f156231e 100644 --- a/priv/test_repo/migrations/20240610195853_migrate_resources27.exs +++ b/priv/test_repo/migrations/20240610195853_migrate_resources27.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources27 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240617193218_migrate_resources28.exs b/priv/test_repo/migrations/20240617193218_migrate_resources28.exs index d112c67a..d864e25b 100644 --- a/priv/test_repo/migrations/20240617193218_migrate_resources28.exs +++ b/priv/test_repo/migrations/20240617193218_migrate_resources28.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources28 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240618085942_migrate_resources29.exs b/priv/test_repo/migrations/20240618085942_migrate_resources29.exs index f8e6fe26..0c6b8de3 100644 --- a/priv/test_repo/migrations/20240618085942_migrate_resources29.exs +++ b/priv/test_repo/migrations/20240618085942_migrate_resources29.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources29 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240618102809_migrate_resources30.exs b/priv/test_repo/migrations/20240618102809_migrate_resources30.exs index f3cec44b..4d1f8ad8 100644 --- a/priv/test_repo/migrations/20240618102809_migrate_resources30.exs +++ b/priv/test_repo/migrations/20240618102809_migrate_resources30.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources30 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs b/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs index 17c00fcc..3a544490 100644 --- a/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs +++ b/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.InstallAshFunctionsExtension420240622192713 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20240627223225_migrate_resources31.exs b/priv/test_repo/migrations/20240627223225_migrate_resources31.exs index 8a90e3d4..cd97c368 100644 --- a/priv/test_repo/migrations/20240627223225_migrate_resources31.exs +++ b/priv/test_repo/migrations/20240627223225_migrate_resources31.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources31 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240703155134_migrate_resources32.exs b/priv/test_repo/migrations/20240703155134_migrate_resources32.exs index 47f472a2..1364a828 100644 --- a/priv/test_repo/migrations/20240703155134_migrate_resources32.exs +++ b/priv/test_repo/migrations/20240703155134_migrate_resources32.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources32 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240705113722_migrate_resources33.exs b/priv/test_repo/migrations/20240705113722_migrate_resources33.exs index e06ec7c7..e6f7a1a8 100644 --- a/priv/test_repo/migrations/20240705113722_migrate_resources33.exs +++ b/priv/test_repo/migrations/20240705113722_migrate_resources33.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources33 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240712232026_migrate_resources34.exs b/priv/test_repo/migrations/20240712232026_migrate_resources34.exs index af406cf3..22af731f 100644 --- a/priv/test_repo/migrations/20240712232026_migrate_resources34.exs +++ b/priv/test_repo/migrations/20240712232026_migrate_resources34.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources34 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs b/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs index 04dce9a0..d6c57db6 100644 --- a/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs +++ b/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MultiDomainCalculations do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240715135403_migrate_resources35.exs b/priv/test_repo/migrations/20240715135403_migrate_resources35.exs index 5819ea53..2349c59d 100644 --- a/priv/test_repo/migrations/20240715135403_migrate_resources35.exs +++ b/priv/test_repo/migrations/20240715135403_migrate_resources35.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources35 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs b/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs index 04a9f3f6..2c9269fa 100644 --- a/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs +++ b/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.NoAttributesCalculationTest do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240717151815_migrate_resources36.exs b/priv/test_repo/migrations/20240717151815_migrate_resources36.exs index 1a885fcf..e8b21183 100644 --- a/priv/test_repo/migrations/20240717151815_migrate_resources36.exs +++ b/priv/test_repo/migrations/20240717151815_migrate_resources36.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources36 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240717153736_migrate_resources37.exs b/priv/test_repo/migrations/20240717153736_migrate_resources37.exs index ba2f6bfe..4d5777a4 100644 --- a/priv/test_repo/migrations/20240717153736_migrate_resources37.exs +++ b/priv/test_repo/migrations/20240717153736_migrate_resources37.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources37 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240727145758_user_invites.exs b/priv/test_repo/migrations/20240727145758_user_invites.exs index abfce2fb..c054a440 100644 --- a/priv/test_repo/migrations/20240727145758_user_invites.exs +++ b/priv/test_repo/migrations/20240727145758_user_invites.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.UserInvites do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240906170759_migrate_resources38.exs b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs index f1211140..78637f88 100644 --- a/priv/test_repo/migrations/20240906170759_migrate_resources38.exs +++ b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources38 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240910180107_migrate_resources39.exs b/priv/test_repo/migrations/20240910180107_migrate_resources39.exs index adf27660..dc7f6502 100644 --- a/priv/test_repo/migrations/20240910180107_migrate_resources39.exs +++ b/priv/test_repo/migrations/20240910180107_migrate_resources39.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources39 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240911225319_install_1_extensions.exs b/priv/test_repo/migrations/20240911225319_install_1_extensions.exs index 0f2eb12b..dede4e89 100644 --- a/priv/test_repo/migrations/20240911225319_install_1_extensions.exs +++ b/priv/test_repo/migrations/20240911225319_install_1_extensions.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.Install1Extensions20240911225317 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20240911225320_migrate_resources40.exs b/priv/test_repo/migrations/20240911225320_migrate_resources40.exs index 1e1cd754..fd10a2f0 100644 --- a/priv/test_repo/migrations/20240911225320_migrate_resources40.exs +++ b/priv/test_repo/migrations/20240911225320_migrate_resources40.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources40 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240918104740_migrate_resources41.exs b/priv/test_repo/migrations/20240918104740_migrate_resources41.exs index 118fe8fc..41ce709a 100644 --- a/priv/test_repo/migrations/20240918104740_migrate_resources41.exs +++ b/priv/test_repo/migrations/20240918104740_migrate_resources41.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources41 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240929121224_migrate_resources42.exs b/priv/test_repo/migrations/20240929121224_migrate_resources42.exs index 529a2338..23a14e4a 100644 --- a/priv/test_repo/migrations/20240929121224_migrate_resources42.exs +++ b/priv/test_repo/migrations/20240929121224_migrate_resources42.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources42 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20240929124728_migrate_resources43.exs b/priv/test_repo/migrations/20240929124728_migrate_resources43.exs index 31e815f9..c91d401a 100644 --- a/priv/test_repo/migrations/20240929124728_migrate_resources43.exs +++ b/priv/test_repo/migrations/20240929124728_migrate_resources43.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources43 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20241208221219_migrate_resources44.exs b/priv/test_repo/migrations/20241208221219_migrate_resources44.exs index 3665d579..af546799 100644 --- a/priv/test_repo/migrations/20241208221219_migrate_resources44.exs +++ b/priv/test_repo/migrations/20241208221219_migrate_resources44.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources44 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20241217232254_migrate_resources45.exs b/priv/test_repo/migrations/20241217232254_migrate_resources45.exs index acfc2b39..94454ef2 100644 --- a/priv/test_repo/migrations/20241217232254_migrate_resources45.exs +++ b/priv/test_repo/migrations/20241217232254_migrate_resources45.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources45 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs b/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs index e6efdcb9..68c52ef7 100644 --- a/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs +++ b/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResourcesExtensions1 do @moduledoc """ Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback diff --git a/priv/test_repo/migrations/20250122190558_migrate_resources46.exs b/priv/test_repo/migrations/20250122190558_migrate_resources46.exs index 9f7eec04..c9cfed58 100644 --- a/priv/test_repo/migrations/20250122190558_migrate_resources46.exs +++ b/priv/test_repo/migrations/20250122190558_migrate_resources46.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources46 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250123161002_migrate_resources47.exs b/priv/test_repo/migrations/20250123161002_migrate_resources47.exs index 59036b61..32e5ff54 100644 --- a/priv/test_repo/migrations/20250123161002_migrate_resources47.exs +++ b/priv/test_repo/migrations/20250123161002_migrate_resources47.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources47 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250123164209_migrate_resources48.exs b/priv/test_repo/migrations/20250123164209_migrate_resources48.exs index 99bc4982..b07394fb 100644 --- a/priv/test_repo/migrations/20250123164209_migrate_resources48.exs +++ b/priv/test_repo/migrations/20250123164209_migrate_resources48.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources48 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250210191116_migrate_resources49.exs b/priv/test_repo/migrations/20250210191116_migrate_resources49.exs index 622dddc6..f147420b 100644 --- a/priv/test_repo/migrations/20250210191116_migrate_resources49.exs +++ b/priv/test_repo/migrations/20250210191116_migrate_resources49.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources49 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250217054207_migrate_resources50.exs b/priv/test_repo/migrations/20250217054207_migrate_resources50.exs index 58a69c80..1ea35a4a 100644 --- a/priv/test_repo/migrations/20250217054207_migrate_resources50.exs +++ b/priv/test_repo/migrations/20250217054207_migrate_resources50.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources50 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250313112823_migrate_resources51.exs b/priv/test_repo/migrations/20250313112823_migrate_resources51.exs index fe51caf5..37609641 100644 --- a/priv/test_repo/migrations/20250313112823_migrate_resources51.exs +++ b/priv/test_repo/migrations/20250313112823_migrate_resources51.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources51 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250320225052_add_csv_resource.exs b/priv/test_repo/migrations/20250320225052_add_csv_resource.exs index b02499d1..11159d77 100644 --- a/priv/test_repo/migrations/20250320225052_add_csv_resource.exs +++ b/priv/test_repo/migrations/20250320225052_add_csv_resource.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddCsvResource do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250321142835_migrate_resources52.exs b/priv/test_repo/migrations/20250321142835_migrate_resources52.exs index a347e279..68ee928c 100644 --- a/priv/test_repo/migrations/20250321142835_migrate_resources52.exs +++ b/priv/test_repo/migrations/20250321142835_migrate_resources52.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources52 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs b/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs index 1e565f40..ff4a368c 100644 --- a/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs +++ b/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddPunchlinesAndStandupClubs do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250519103535_migrate_resources53.exs b/priv/test_repo/migrations/20250519103535_migrate_resources53.exs index 6059ae3e..cabe0ee7 100644 --- a/priv/test_repo/migrations/20250519103535_migrate_resources53.exs +++ b/priv/test_repo/migrations/20250519103535_migrate_resources53.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources53 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250520130634_migrate_resources54.exs b/priv/test_repo/migrations/20250520130634_migrate_resources54.exs index 9d8a51cb..063d79b9 100644 --- a/priv/test_repo/migrations/20250520130634_migrate_resources54.exs +++ b/priv/test_repo/migrations/20250520130634_migrate_resources54.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources54 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs b/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs index bde744b0..734de6d5 100644 --- a/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs +++ b/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddModelTupleToPost do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs b/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs index fe910c8c..90c3fcba 100644 --- a/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs +++ b/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.CreateRecordTempEntitiesTable do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250612113920_migrate_resources55.exs b/priv/test_repo/migrations/20250612113920_migrate_resources55.exs index 082dad95..b91c4fa9 100644 --- a/priv/test_repo/migrations/20250612113920_migrate_resources55.exs +++ b/priv/test_repo/migrations/20250612113920_migrate_resources55.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources55 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250618011917_migrate_resources56.exs b/priv/test_repo/migrations/20250618011917_migrate_resources56.exs index 641aa008..97d68971 100644 --- a/priv/test_repo/migrations/20250618011917_migrate_resources56.exs +++ b/priv/test_repo/migrations/20250618011917_migrate_resources56.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources56 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs b/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs index 88d73d15..fdcd91e4 100644 --- a/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs +++ b/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationsFolderAndItems do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250731124648_migrate_resources57.exs b/priv/test_repo/migrations/20250731124648_migrate_resources57.exs index 3493fd6b..3fea4408 100644 --- a/priv/test_repo/migrations/20250731124648_migrate_resources57.exs +++ b/priv/test_repo/migrations/20250731124648_migrate_resources57.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources57 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250810102512_migrate_resources58.exs b/priv/test_repo/migrations/20250810102512_migrate_resources58.exs index 484e4dc0..de4bbd5a 100644 --- a/priv/test_repo/migrations/20250810102512_migrate_resources58.exs +++ b/priv/test_repo/migrations/20250810102512_migrate_resources58.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources58 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250908073737_migrate_resources59.exs b/priv/test_repo/migrations/20250908073737_migrate_resources59.exs index a4acd79a..dee8b387 100644 --- a/priv/test_repo/migrations/20250908073737_migrate_resources59.exs +++ b/priv/test_repo/migrations/20250908073737_migrate_resources59.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources59 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250908093505_migrate_resources60.exs b/priv/test_repo/migrations/20250908093505_migrate_resources60.exs index 404906e5..d3747224 100644 --- a/priv/test_repo/migrations/20250908093505_migrate_resources60.exs +++ b/priv/test_repo/migrations/20250908093505_migrate_resources60.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources60 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20250908212414_migrate_resources61.exs b/priv/test_repo/migrations/20250908212414_migrate_resources61.exs index 303a4e53..2bd3d6bf 100644 --- a/priv/test_repo/migrations/20250908212414_migrate_resources61.exs +++ b/priv/test_repo/migrations/20250908212414_migrate_resources61.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources61 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/migrations/20251002180954_migrate_resources62.exs b/priv/test_repo/migrations/20251002180954_migrate_resources62.exs index fe90b42c..8fd9c180 100644 --- a/priv/test_repo/migrations/20251002180954_migrate_resources62.exs +++ b/priv/test_repo/migrations/20251002180954_migrate_resources62.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.Migrations.MigrateResources62 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs b/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs index 0ce1caf3..5a5bd69b 100644 --- a/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs +++ b/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources1 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs b/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs index 0e4da87a..56751e6c 100644 --- a/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs +++ b/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources2 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs b/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs index dc378342..8c913034 100644 --- a/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs +++ b/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources3 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs b/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs index 36cbc1d1..ab537413 100644 --- a/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs +++ b/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources4 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs b/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs index 923ba511..2a52a954 100644 --- a/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs +++ b/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources5 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs b/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs index f5018509..18a7fdfd 100644 --- a/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs +++ b/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources6 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs b/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs index 42a6f5a3..6170f2f2 100644 --- a/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs +++ b/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources7 do @moduledoc """ Updates resources based on their most recent snapshots. diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 4803ec5c..ff51bf26 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshSql.AggregateTest do use AshPostgres.RepoCase, async: false import ExUnit.CaptureIO diff --git a/test/ash_postgres_test.exs b/test/ash_postgres_test.exs index a3318b57..41c46e31 100644 --- a/test/ash_postgres_test.exs +++ b/test/ash_postgres_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgresTest do use AshPostgres.RepoCase, async: false import ExUnit.CaptureLog diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 2439ab9d..b9443acf 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.AtomicsTest do alias AshPostgres.Test.Author alias AshPostgres.Test.Comment diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index d6fd8c17..e48d0238 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.BulkCreateTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.{Post, Record} diff --git a/test/bulk_destroy_test.exs b/test/bulk_destroy_test.exs index ff159a8f..24cf2395 100644 --- a/test/bulk_destroy_test.exs +++ b/test/bulk_destroy_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.BulkDestroyTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Permalink diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index 092f964d..38ce2f45 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.BulkUpdateTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.{CSV, Post, Record} diff --git a/test/calculation_test.exs b/test/calculation_test.exs index cf539f18..38e4cf5b 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.CalculationTest do alias AshPostgres.Test.RecordTempEntity use AshPostgres.RepoCase, async: false diff --git a/test/cascade_destroy_test.exs b/test/cascade_destroy_test.exs index a407ea35..062e0378 100644 --- a/test/cascade_destroy_test.exs +++ b/test/cascade_destroy_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgresTest.CascadeDestroyTest do use AshPostgres.RepoCase, async: true diff --git a/test/combination_test.exs b/test/combination_test.exs index 5faaa020..fdb55d35 100644 --- a/test/combination_test.exs +++ b/test/combination_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.CombinationTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index 5617a6d1..815071f7 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculationsTest do use AshPostgres.RepoCase, async: false diff --git a/test/composite_type_test.exs b/test/composite_type_test.exs index b1a3990c..7e73e198 100644 --- a/test/composite_type_test.exs +++ b/test/composite_type_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.CompositeTypeTest do use AshPostgres.RepoCase alias AshPostgres.Test.Post diff --git a/test/constraint_test.exs b/test/constraint_test.exs index b2ec9fb8..7c63f3c5 100644 --- a/test/constraint_test.exs +++ b/test/constraint_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ConstraintTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/create_test.exs b/test/create_test.exs index 84607880..92effd16 100644 --- a/test/create_test.exs +++ b/test/create_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.CreateTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/custom_expression_test.exs b/test/custom_expression_test.exs index e88737ad..7f204eef 100644 --- a/test/custom_expression_test.exs +++ b/test/custom_expression_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.CustomExpressionTest do use AshPostgres.RepoCase, async: false diff --git a/test/custom_index_test.exs b/test/custom_index_test.exs index 1b021813..9d02b655 100644 --- a/test/custom_index_test.exs +++ b/test/custom_index_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.CustomIndexTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs index 8b204f25..02d702f5 100644 --- a/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs +++ b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.EmptyAtomicNonBulkActionsPolicyBypassTest do @moduledoc """ This is test verifies the fix for the following CVE: diff --git a/test/destroy_test.exs b/test/destroy_test.exs index 974f2cb3..208b2038 100644 --- a/test/destroy_test.exs +++ b/test/destroy_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DestroyTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/dev_migrations_test.exs b/test/dev_migrations_test.exs index fdaeeff9..64cbb7c1 100644 --- a/test/dev_migrations_test.exs +++ b/test/dev_migrations_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DevMigrationsTest do use AshPostgres.RepoCase, async: false @moduletag :migration diff --git a/test/distinct_test.exs b/test/distinct_test.exs index 284ed5b5..a616cac8 100644 --- a/test/distinct_test.exs +++ b/test/distinct_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DistinctTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/ecto_compatibility_test.exs b/test/ecto_compatibility_test.exs index 3b3555ec..3670d021 100644 --- a/test/ecto_compatibility_test.exs +++ b/test/ecto_compatibility_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.EctoCompatibilityTest do use AshPostgres.RepoCase, async: false require Ash.Query diff --git a/test/embeddable_resource_test.exs b/test/embeddable_resource_test.exs index 4edb0903..d30c11c3 100644 --- a/test/embeddable_resource_test.exs +++ b/test/embeddable_resource_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.EmbeddableResourceTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/enum_test.exs b/test/enum_test.exs index 537944c4..0dea90a8 100644 --- a/test/enum_test.exs +++ b/test/enum_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.EnumTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/error_expr_test.exs b/test/error_expr_test.exs index d73577ad..98719104 100644 --- a/test/error_expr_test.exs +++ b/test/error_expr_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ErrorExprTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/filter_child_relationship_by_parent_relationship_test.exs b/test/filter_child_relationship_by_parent_relationship_test.exs index fb2f4e52..63a50eef 100644 --- a/test/filter_child_relationship_by_parent_relationship_test.exs +++ b/test/filter_child_relationship_by_parent_relationship_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Support.Relationships.FilterChileRelationshipByParentRelationshipTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.{Comment, Post} diff --git a/test/filter_field_policy_test.exs b/test/filter_field_policy_test.exs index a69f2429..6778e70b 100644 --- a/test/filter_field_policy_test.exs +++ b/test/filter_field_policy_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule FilterFieldPolicyTest do use AshPostgres.RepoCase, async: false diff --git a/test/filter_test.exs b/test/filter_test.exs index d0332301..0172fb81 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.FilterTest do use AshPostgres.RepoCase, async: false diff --git a/test/load_test.exs b/test/load_test.exs index 63b142cd..fa9c8aba 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.LoadTest do use AshPostgres.RepoCase, async: false diff --git a/test/lock_test.exs b/test/lock_test.exs index f36c8ed2..01122f50 100644 --- a/test/lock_test.exs +++ b/test/lock_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.LockTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/ltree_test.exs b/test/ltree_test.exs index cbd54ab1..33b3c1ba 100644 --- a/test/ltree_test.exs +++ b/test/ltree_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.LtreeTest do use AshPostgres.RepoCase, async: true use ExUnitProperties diff --git a/test/manual_relationships_test.exs b/test/manual_relationships_test.exs index c1921dde..3f4af170 100644 --- a/test/manual_relationships_test.exs +++ b/test/manual_relationships_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ManualRelationshipsTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.{Comment, Post} diff --git a/test/manual_update_test.exs b/test/manual_update_test.exs index e5a286cf..74a6ec35 100644 --- a/test/manual_update_test.exs +++ b/test/manual_update_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ManualUpdateTest do use AshPostgres.RepoCase, async: true diff --git a/test/many_to_many_expr_test.exs b/test/many_to_many_expr_test.exs index a19fe509..942168fc 100644 --- a/test/many_to_many_expr_test.exs +++ b/test/many_to_many_expr_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ManyToManyExprTest do use AshPostgres.RepoCase, async: false diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index a12a09a0..41b16774 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MigrationGeneratorTest do use AshPostgres.RepoCase, async: false @moduletag :migration diff --git a/test/mix/tasks/ash_postgres.install_test.exs b/test/mix/tasks/ash_postgres.install_test.exs index e90b69ee..e8ac1154 100644 --- a/test/mix/tasks/ash_postgres.install_test.exs +++ b/test/mix/tasks/ash_postgres.install_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Mix.Tasks.AshPostgres.InstallTest do use ExUnit.Case diff --git a/test/mix_squash_snapshots_test.exs b/test/mix_squash_snapshots_test.exs index dcdce819..352430ae 100644 --- a/test/mix_squash_snapshots_test.exs +++ b/test/mix_squash_snapshots_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MixSquashSnapshotsTest do use AshPostgres.RepoCase, async: false @moduletag :migration diff --git a/test/multi_domain_calculations_test.exs b/test/multi_domain_calculations_test.exs index 8cc9bc55..54652f63 100644 --- a/test/multi_domain_calculations_test.exs +++ b/test/multi_domain_calculations_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculationsTest do use AshPostgres.RepoCase, async: false diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 85a97cbe..3e17c1ad 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultitenancyTest do use AshPostgres.RepoCase, async: false diff --git a/test/parent_filter_test.exs b/test/parent_filter_test.exs index b7f8f8dc..42f8326e 100644 --- a/test/parent_filter_test.exs +++ b/test/parent_filter_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ParentFilterTest do use AshPostgres.RepoCase, async: false diff --git a/test/parent_sort_test.exs b/test/parent_sort_test.exs index 423d6634..7d472f2d 100644 --- a/test/parent_sort_test.exs +++ b/test/parent_sort_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ParentSortTest do use AshPostgres.RepoCase, async: false diff --git a/test/polymorphism_test.exs b/test/polymorphism_test.exs index 4612a3c8..ecd8dc9d 100644 --- a/test/polymorphism_test.exs +++ b/test/polymorphism_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.PolymorphismTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.{Post, Rating} diff --git a/test/primary_key_test.exs b/test/primary_key_test.exs index af12e799..8812bc0e 100644 --- a/test/primary_key_test.exs +++ b/test/primary_key_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.PrimaryKeyTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/references_test.exs b/test/references_test.exs index 7632c9f8..59151ba3 100644 --- a/test/references_test.exs +++ b/test/references_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ReferencesTest do use AshPostgres.RepoCase import ExUnit.CaptureIO diff --git a/test/rel_with_parent_filter_test.exs b/test/rel_with_parent_filter_test.exs index d8fa5161..bdcc301d 100644 --- a/test/rel_with_parent_filter_test.exs +++ b/test/rel_with_parent_filter_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.RelWithParentFilterTest do use AshPostgres.RepoCase, async: false diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index 4878cf6d..4c1f916c 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.ResourceGeenratorTests do use AshPostgres.RepoCase, async: false diff --git a/test/schema_test.exs b/test/schema_test.exs index c8be1cf8..be04d3bb 100644 --- a/test/schema_test.exs +++ b/test/schema_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.SchemaTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/select_test.exs b/test/select_test.exs index 219fdc77..7c440b10 100644 --- a/test/select_test.exs +++ b/test/select_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.SelectTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/sort_test.exs b/test/sort_test.exs index e7d949da..c1afc99a 100644 --- a/test/sort_test.exs +++ b/test/sort_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.SortTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/storage_types_test.exs b/test/storage_types_test.exs index ca433860..efdb0195 100644 --- a/test/storage_types_test.exs +++ b/test/storage_types_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.StorageTypesTest do use AshPostgres.RepoCase, async: false diff --git a/test/subquery_test.exs b/test/subquery_test.exs index 1a9e69dd..9795730b 100644 --- a/test/subquery_test.exs +++ b/test/subquery_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.SubqueryTest do use AshPostgres.RepoCase, async: false diff --git a/test/support/complex_calculations/domain.ex b/test/support/complex_calculations/domain.ex index 15a306ef..6356daa3 100644 --- a/test/support/complex_calculations/domain.ex +++ b/test/support/complex_calculations/domain.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculations.Domain do @moduledoc false use Ash.Domain diff --git a/test/support/complex_calculations/resources/certification.ex b/test/support/complex_calculations/resources/certification.ex index 6310d1c7..317a5dc1 100644 --- a/test/support/complex_calculations/resources/certification.ex +++ b/test/support/complex_calculations/resources/certification.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculations.Certification do @moduledoc false use Ash.Resource, diff --git a/test/support/complex_calculations/resources/channel.ex b/test/support/complex_calculations/resources/channel.ex index eed91879..af99ed29 100644 --- a/test/support/complex_calculations/resources/channel.ex +++ b/test/support/complex_calculations/resources/channel.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculations.Channel do @moduledoc false use Ash.Resource, diff --git a/test/support/complex_calculations/resources/channel_member.ex b/test/support/complex_calculations/resources/channel_member.ex index c9d99997..7feb3c9d 100644 --- a/test/support/complex_calculations/resources/channel_member.ex +++ b/test/support/complex_calculations/resources/channel_member.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculations.ChannelMember do @moduledoc false use Ash.Resource, diff --git a/test/support/complex_calculations/resources/dm_channel.ex b/test/support/complex_calculations/resources/dm_channel.ex index ed3a6397..2113a3d5 100644 --- a/test/support/complex_calculations/resources/dm_channel.ex +++ b/test/support/complex_calculations/resources/dm_channel.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculations.DMChannel do @moduledoc false use Ash.Resource, diff --git a/test/support/complex_calculations/resources/documentation.ex b/test/support/complex_calculations/resources/documentation.ex index 405c9dae..88a3b7df 100644 --- a/test/support/complex_calculations/resources/documentation.ex +++ b/test/support/complex_calculations/resources/documentation.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculations.Documentation do @moduledoc false use Ash.Resource, diff --git a/test/support/complex_calculations/resources/folder.ex b/test/support/complex_calculations/resources/folder.ex index d4b31e38..c0faefe6 100644 --- a/test/support/complex_calculations/resources/folder.ex +++ b/test/support/complex_calculations/resources/folder.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Support.ComplexCalculations.Folder do @moduledoc """ A tree structure using the ltree type. diff --git a/test/support/complex_calculations/resources/folder_item.ex b/test/support/complex_calculations/resources/folder_item.ex index ac115aef..7404970e 100644 --- a/test/support/complex_calculations/resources/folder_item.ex +++ b/test/support/complex_calculations/resources/folder_item.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Support.ComplexCalculations.FolderItem do @moduledoc false use Ash.Resource, diff --git a/test/support/complex_calculations/resources/skill.ex b/test/support/complex_calculations/resources/skill.ex index 6c81ceda..44e8dfff 100644 --- a/test/support/complex_calculations/resources/skill.ex +++ b/test/support/complex_calculations/resources/skill.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ComplexCalculations.Skill do @moduledoc false use Ash.Resource, diff --git a/test/support/concat.ex b/test/support/concat.ex index 353bbfa4..50b34373 100644 --- a/test/support/concat.ex +++ b/test/support/concat.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Concat do @moduledoc false use Ash.Resource.Calculation diff --git a/test/support/dev_test_repo.ex b/test/support/dev_test_repo.ex index 2b1fe929..c69abe43 100644 --- a/test/support/dev_test_repo.ex +++ b/test/support/dev_test_repo.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.DevTestRepo do @moduledoc false use AshPostgres.Repo, diff --git a/test/support/domain.ex b/test/support/domain.ex index ec992cbe..ecd82d96 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Domain do @moduledoc false use Ash.Domain diff --git a/test/support/multi_domain_calculations/domain_one.ex b/test/support/multi_domain_calculations/domain_one.ex index ff4e072f..b5e091f4 100644 --- a/test/support/multi_domain_calculations/domain_one.ex +++ b/test/support/multi_domain_calculations/domain_one.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculations.DomainOne do @moduledoc false use Ash.Domain diff --git a/test/support/multi_domain_calculations/domain_one/item.ex b/test/support/multi_domain_calculations/domain_one/item.ex index 36090798..fa07ac9a 100644 --- a/test/support/multi_domain_calculations/domain_one/item.ex +++ b/test/support/multi_domain_calculations/domain_one/item.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculations.DomainOne.Item do @moduledoc false diff --git a/test/support/multi_domain_calculations/domain_three.ex b/test/support/multi_domain_calculations/domain_three.ex index 95eda02d..a452e013 100644 --- a/test/support/multi_domain_calculations/domain_three.ex +++ b/test/support/multi_domain_calculations/domain_three.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculations.DomainThree do @moduledoc false use Ash.Domain diff --git a/test/support/multi_domain_calculations/domain_three/relationship_item.ex b/test/support/multi_domain_calculations/domain_three/relationship_item.ex index b90b93a7..9c15eb0c 100644 --- a/test/support/multi_domain_calculations/domain_three/relationship_item.ex +++ b/test/support/multi_domain_calculations/domain_three/relationship_item.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculations.DomainThree.RelationshipItem do @moduledoc false diff --git a/test/support/multi_domain_calculations/domain_two.ex b/test/support/multi_domain_calculations/domain_two.ex index f9ccde38..715960fb 100644 --- a/test/support/multi_domain_calculations/domain_two.ex +++ b/test/support/multi_domain_calculations/domain_two.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo do @moduledoc false use Ash.Domain diff --git a/test/support/multi_domain_calculations/domain_two/other_item.ex b/test/support/multi_domain_calculations/domain_two/other_item.ex index 1524b47d..b7e65fd7 100644 --- a/test/support/multi_domain_calculations/domain_two/other_item.ex +++ b/test/support/multi_domain_calculations/domain_two/other_item.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.OtherItem do @moduledoc false diff --git a/test/support/multi_domain_calculations/domain_two/sub_item.ex b/test/support/multi_domain_calculations/domain_two/sub_item.ex index c9f8b491..76550194 100644 --- a/test/support/multi_domain_calculations/domain_two/sub_item.ex +++ b/test/support/multi_domain_calculations/domain_two/sub_item.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.MultiDomainCalculations.DomainTwo.SubItem do @moduledoc false diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 6c1db197..1ee5e90b 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.Domain do @moduledoc false use Ash.Domain diff --git a/test/support/multitenancy/resources/composite_key_post.ex b/test/support/multitenancy/resources/composite_key_post.ex index 84f7881a..b7856998 100644 --- a/test/support/multitenancy/resources/composite_key_post.ex +++ b/test/support/multitenancy/resources/composite_key_post.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.CompositeKeyPost do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/cross_tenant_post_link.ex b/test/support/multitenancy/resources/cross_tenant_post_link.ex index 0bcc7111..e79e0cf8 100644 --- a/test/support/multitenancy/resources/cross_tenant_post_link.ex +++ b/test/support/multitenancy/resources/cross_tenant_post_link.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.CrossTenantPostLink do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/dev_migrations_org.ex b/test/support/multitenancy/resources/dev_migrations_org.ex index 6ebd3394..0cc59783 100644 --- a/test/support/multitenancy/resources/dev_migrations_org.ex +++ b/test/support/multitenancy/resources/dev_migrations_org.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.DevMigrationsOrg do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/named_org.ex b/test/support/multitenancy/resources/named_org.ex index 537ea337..714c090d 100644 --- a/test/support/multitenancy/resources/named_org.ex +++ b/test/support/multitenancy/resources/named_org.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.NamedOrg do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/non_multitenant_post_link.ex b/test/support/multitenancy/resources/non_multitenant_post_link.ex index 9d986bdb..8f2a990e 100644 --- a/test/support/multitenancy/resources/non_multitenant_post_link.ex +++ b/test/support/multitenancy/resources/non_multitenant_post_link.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.NonMultitenantPostLink do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex index 56dd8d26..0eb78386 100644 --- a/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex +++ b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.NonMultitenantPostMultitenantLink do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/org.ex b/test/support/multitenancy/resources/org.ex index aa68daf4..21638793 100644 --- a/test/support/multitenancy/resources/org.ex +++ b/test/support/multitenancy/resources/org.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.Org do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/post.ex b/test/support/multitenancy/resources/post.ex index 6f9a943a..cab27827 100644 --- a/test/support/multitenancy/resources/post.ex +++ b/test/support/multitenancy/resources/post.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.Post do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/post_link.ex b/test/support/multitenancy/resources/post_link.ex index bd22c558..dcdfdc41 100644 --- a/test/support/multitenancy/resources/post_link.ex +++ b/test/support/multitenancy/resources/post_link.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.PostLink do @moduledoc false use Ash.Resource, diff --git a/test/support/multitenancy/resources/user.ex b/test/support/multitenancy/resources/user.ex index 77149182..7406eb07 100644 --- a/test/support/multitenancy/resources/user.ex +++ b/test/support/multitenancy/resources/user.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.MultitenancyTest.User do @moduledoc false use Ash.Resource, diff --git a/test/support/relationships/comments_containing_title.ex b/test/support/relationships/comments_containing_title.ex index a58a6b93..e17ee933 100644 --- a/test/support/relationships/comments_containing_title.ex +++ b/test/support/relationships/comments_containing_title.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Post.CommentsContainingTitle do @moduledoc false diff --git a/test/support/repo_case.ex b/test/support/repo_case.ex index 28d9f3d2..708e2d42 100644 --- a/test/support/repo_case.ex +++ b/test/support/repo_case.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.RepoCase do @moduledoc false use ExUnit.CaseTemplate diff --git a/test/support/resources/account.ex b/test/support/resources/account.ex index c771b9ce..87e6544a 100644 --- a/test/support/resources/account.ex +++ b/test/support/resources/account.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Account do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index e30f7592..097a771c 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Author do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/bio.ex b/test/support/resources/bio.ex index 59dd2dfb..8c0b33f0 100644 --- a/test/support/resources/bio.ex +++ b/test/support/resources/bio.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Bio do @moduledoc false use Ash.Resource, data_layer: :embedded diff --git a/test/support/resources/chat.ex b/test/support/resources/chat.ex index 9a035f4c..5c04c1af 100644 --- a/test/support/resources/chat.ex +++ b/test/support/resources/chat.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Chat do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/co_authored_post.ex b/test/support/resources/co_authored_post.ex index 5519144b..022c9eca 100644 --- a/test/support/resources/co_authored_post.ex +++ b/test/support/resources/co_authored_post.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.CoAuthorPost do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/comedian.ex b/test/support/resources/comedian.ex index a61f3c41..2404d56c 100644 --- a/test/support/resources/comedian.ex +++ b/test/support/resources/comedian.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Comedian do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/comment.ex b/test/support/resources/comment.ex index 517c42af..cbbc6abb 100644 --- a/test/support/resources/comment.ex +++ b/test/support/resources/comment.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Comment do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/comment_link.ex b/test/support/resources/comment_link.ex index 2654ff0f..5caab846 100644 --- a/test/support/resources/comment_link.ex +++ b/test/support/resources/comment_link.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.CommentLink do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/content.ex b/test/support/resources/content.ex index 370d7016..8b823644 100644 --- a/test/support/resources/content.ex +++ b/test/support/resources/content.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Content do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/content_visibility_group.ex b/test/support/resources/content_visibility_group.ex index d618fcb4..797d7c7e 100644 --- a/test/support/resources/content_visibility_group.ex +++ b/test/support/resources/content_visibility_group.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.ContentVisibilityGroup do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/csv.ex b/test/support/resources/csv.ex index 91894ed4..ccf5b418 100644 --- a/test/support/resources/csv.ex +++ b/test/support/resources/csv.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.CSVColumnMatchingEmbedded do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/customer.ex b/test/support/resources/customer.ex index d5cff43e..834fcead 100644 --- a/test/support/resources/customer.ex +++ b/test/support/resources/customer.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Customer do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/db_point.ex b/test/support/resources/db_point.ex index 25b9ca93..cf018f4a 100644 --- a/test/support/resources/db_point.ex +++ b/test/support/resources/db_point.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.DbPoint do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/db_string_point.ex b/test/support/resources/db_string_point.ex index 8908527b..e78c7536 100644 --- a/test/support/resources/db_string_point.ex +++ b/test/support/resources/db_string_point.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.DbStringPoint do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/entity.ex b/test/support/resources/entity.ex index 732f760f..c693d02a 100644 --- a/test/support/resources/entity.ex +++ b/test/support/resources/entity.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Entity do @moduledoc false diff --git a/test/support/resources/integer_post.ex b/test/support/resources/integer_post.ex index 13b37b4b..2237e723 100644 --- a/test/support/resources/integer_post.ex +++ b/test/support/resources/integer_post.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.IntegerPost do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/invite.ex b/test/support/resources/invite.ex index 32406d1f..06d3ea70 100644 --- a/test/support/resources/invite.ex +++ b/test/support/resources/invite.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Invite do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/joke.ex b/test/support/resources/joke.ex index 7f6318f8..16414cb4 100644 --- a/test/support/resources/joke.ex +++ b/test/support/resources/joke.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Joke do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/manager.ex b/test/support/resources/manager.ex index 43105c21..e5b2cce9 100644 --- a/test/support/resources/manager.ex +++ b/test/support/resources/manager.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Manager do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/message.ex b/test/support/resources/message.ex index 25896e04..4cbc9533 100644 --- a/test/support/resources/message.ex +++ b/test/support/resources/message.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Message do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/note.ex b/test/support/resources/note.ex index b5880dfd..0facb927 100644 --- a/test/support/resources/note.ex +++ b/test/support/resources/note.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Note do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/order.ex b/test/support/resources/order.ex index 27566cb4..fead194c 100644 --- a/test/support/resources/order.ex +++ b/test/support/resources/order.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Order do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/organization.ex b/test/support/resources/organization.ex index 0013f909..d375a2db 100644 --- a/test/support/resources/organization.ex +++ b/test/support/resources/organization.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Organization do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/permalink.ex b/test/support/resources/permalink.ex index 21df7959..adca302f 100644 --- a/test/support/resources/permalink.ex +++ b/test/support/resources/permalink.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Permalink do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 69791a38..2b85570a 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule PassIfOriginalDataPresent do @moduledoc false use Ash.Policy.SimpleCheck diff --git a/test/support/resources/post_follower.ex b/test/support/resources/post_follower.ex index c00ef226..9e71b398 100644 --- a/test/support/resources/post_follower.ex +++ b/test/support/resources/post_follower.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.PostFollower do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/post_link.ex b/test/support/resources/post_link.ex index 910486b2..bc6390c8 100644 --- a/test/support/resources/post_link.ex +++ b/test/support/resources/post_link.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.PostLink do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/post_tag.ex b/test/support/resources/post_tag.ex index c1cb13e8..2ae47876 100644 --- a/test/support/resources/post_tag.ex +++ b/test/support/resources/post_tag.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.PostTag do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/post_views.ex b/test/support/resources/post_views.ex index 929fbb45..c3b3aaaa 100644 --- a/test/support/resources/post_views.ex +++ b/test/support/resources/post_views.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.PostView do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/post_with_empty_update.ex b/test/support/resources/post_with_empty_update.ex index da61629d..06693738 100644 --- a/test/support/resources/post_with_empty_update.ex +++ b/test/support/resources/post_with_empty_update.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.PostWithEmptyUpdate do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/product.ex b/test/support/resources/product.ex index 199bbff8..fa2bbee9 100644 --- a/test/support/resources/product.ex +++ b/test/support/resources/product.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Product do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/profile.ex b/test/support/resources/profile.ex index 862887c4..b06bab6f 100644 --- a/test/support/resources/profile.ex +++ b/test/support/resources/profile.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Profile do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/punchline.ex b/test/support/resources/punchline.ex index 90e905d9..66da6063 100644 --- a/test/support/resources/punchline.ex +++ b/test/support/resources/punchline.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Punchline do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/rating.ex b/test/support/resources/rating.ex index 99509206..1fab32b1 100644 --- a/test/support/resources/rating.ex +++ b/test/support/resources/rating.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Rating do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/record.ex b/test/support/resources/record.ex index 804c981a..0045db83 100644 --- a/test/support/resources/record.ex +++ b/test/support/resources/record.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Record do @moduledoc false diff --git a/test/support/resources/record_temp_entity.ex b/test/support/resources/record_temp_entity.ex index 7750a1df..ba0f73e3 100644 --- a/test/support/resources/record_temp_entity.ex +++ b/test/support/resources/record_temp_entity.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.RecordTempEntity do @moduledoc false diff --git a/test/support/resources/role.ex b/test/support/resources/role.ex index 5ce35a73..df3635be 100644 --- a/test/support/resources/role.ex +++ b/test/support/resources/role.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Role do @moduledoc false diff --git a/test/support/resources/rsvp.ex b/test/support/resources/rsvp.ex index 965f053d..f364c333 100644 --- a/test/support/resources/rsvp.ex +++ b/test/support/resources/rsvp.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.RSVP do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/settings.ex b/test/support/resources/settings.ex index b24b3afc..e348f847 100644 --- a/test/support/resources/settings.ex +++ b/test/support/resources/settings.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Settings do @moduledoc false use Ash.Resource, data_layer: :embedded diff --git a/test/support/resources/staff_group.ex b/test/support/resources/staff_group.ex index 3902ca07..4aafeca8 100644 --- a/test/support/resources/staff_group.ex +++ b/test/support/resources/staff_group.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.StaffGroup do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/staff_group_member.ex b/test/support/resources/staff_group_member.ex index 7624a9ce..a9ce9e97 100644 --- a/test/support/resources/staff_group_member.ex +++ b/test/support/resources/staff_group_member.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.StaffGroupMember do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/standup_club.ex b/test/support/resources/standup_club.ex index 3dd2e075..ffa91044 100644 --- a/test/support/resources/standup_club.ex +++ b/test/support/resources/standup_club.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.StandupClub do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/stateful_post_follwer.ex b/test/support/resources/stateful_post_follwer.ex index b6fd8dab..cb66359c 100644 --- a/test/support/resources/stateful_post_follwer.ex +++ b/test/support/resources/stateful_post_follwer.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.StatefulPostFollower do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/subquery/access.ex b/test/support/resources/subquery/access.ex index 90a356ff..9c971486 100644 --- a/test/support/resources/subquery/access.ex +++ b/test/support/resources/subquery/access.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Subquery.Access do @moduledoc false alias AshPostgres.Test.Subquery.Parent diff --git a/test/support/resources/subquery/child.ex b/test/support/resources/subquery/child.ex index cf089bd5..5a9cd6af 100644 --- a/test/support/resources/subquery/child.ex +++ b/test/support/resources/subquery/child.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Subquery.Child do @moduledoc false alias AshPostgres.Test.Subquery.Through diff --git a/test/support/resources/subquery/child_domain.ex b/test/support/resources/subquery/child_domain.ex index 7e427331..ab33df34 100644 --- a/test/support/resources/subquery/child_domain.ex +++ b/test/support/resources/subquery/child_domain.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Subquery.ChildDomain do @moduledoc false alias AshPostgres.Test.Subquery.Child diff --git a/test/support/resources/subquery/parent.ex b/test/support/resources/subquery/parent.ex index 9de04b9f..a72c0054 100644 --- a/test/support/resources/subquery/parent.ex +++ b/test/support/resources/subquery/parent.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Subquery.Parent do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/subquery/parent_domain.ex b/test/support/resources/subquery/parent_domain.ex index 9d73f6af..d2e200d3 100644 --- a/test/support/resources/subquery/parent_domain.ex +++ b/test/support/resources/subquery/parent_domain.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Subquery.ParentDomain do @moduledoc false alias AshPostgres.Test.Subquery.Access diff --git a/test/support/resources/subquery/through.ex b/test/support/resources/subquery/through.ex index 7f1e96e9..3c0f4e75 100644 --- a/test/support/resources/subquery/through.ex +++ b/test/support/resources/subquery/through.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Subquery.Through do @moduledoc false alias AshPostgres.Test.Subquery.Child diff --git a/test/support/resources/tag.ex b/test/support/resources/tag.ex index 20d8d5a8..66bec825 100644 --- a/test/support/resources/tag.ex +++ b/test/support/resources/tag.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Tag do @moduledoc false use Ash.Resource, diff --git a/test/support/resources/temp_entity.ex b/test/support/resources/temp_entity.ex index eb29bf1c..5507836e 100644 --- a/test/support/resources/temp_entity.ex +++ b/test/support/resources/temp_entity.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.TempEntity do @moduledoc false diff --git a/test/support/resources/user.ex b/test/support/resources/user.ex index b07b3e7c..1009dccd 100644 --- a/test/support/resources/user.ex +++ b/test/support/resources/user.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.User do @moduledoc false use Ash.Resource, diff --git a/test/support/string_agg.ex b/test/support/string_agg.ex index 53a6a950..e6f92821 100644 --- a/test/support/string_agg.ex +++ b/test/support/string_agg.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.StringAgg do @moduledoc false use Ash.Resource.Aggregate.CustomAggregate diff --git a/test/support/test_app.ex b/test/support/test_app.ex index 94c990d6..97d98fc2 100644 --- a/test/support/test_app.ex +++ b/test/support/test_app.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestApp do @moduledoc false def start(_type, _args) do diff --git a/test/support/test_custom_extension.ex b/test/support/test_custom_extension.ex index fba66809..bd6d26d3 100644 --- a/test/support/test_custom_extension.ex +++ b/test/support/test_custom_extension.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestCustomExtension do @moduledoc false diff --git a/test/support/test_no_sandbox_repo.ex b/test/support/test_no_sandbox_repo.ex index fca4bf13..14ec8160 100644 --- a/test/support/test_no_sandbox_repo.ex +++ b/test/support/test_no_sandbox_repo.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestNoSandboxRepo do @moduledoc false use AshPostgres.Repo, diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index 351c94ac..8dbc64c1 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.TestRepo do @moduledoc false use AshPostgres.Repo, diff --git a/test/support/trigram_word_similarity.ex b/test/support/trigram_word_similarity.ex index 4b7d0bfb..77c267c7 100644 --- a/test/support/trigram_word_similarity.ex +++ b/test/support/trigram_word_similarity.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Expressions.TrigramWordSimilarity do @moduledoc false use Ash.CustomExpression, diff --git a/test/support/types/composite_point.ex b/test/support/types/composite_point.ex index 6b6f37dc..b82887b9 100644 --- a/test/support/types/composite_point.ex +++ b/test/support/types/composite_point.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.CompositePoint do @moduledoc false use Ash.Type diff --git a/test/support/types/email.ex b/test/support/types/email.ex index c14190d5..9f552b6d 100644 --- a/test/support/types/email.ex +++ b/test/support/types/email.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule Test.Support.Types.Email do @moduledoc false use Ash.Type.NewType, diff --git a/test/support/types/money.ex b/test/support/types/money.ex index c1569be4..6b2d79f8 100644 --- a/test/support/types/money.ex +++ b/test/support/types/money.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Money do @moduledoc false use Ash.Resource, diff --git a/test/support/types/person_detail.ex b/test/support/types/person_detail.ex index 551d17d5..3666300f 100644 --- a/test/support/types/person_detail.ex +++ b/test/support/types/person_detail.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.PersonDetail do @moduledoc """ A tuple type for testing Ash.Type.Tuple diff --git a/test/support/types/point.ex b/test/support/types/point.ex index ea3db339..819d0287 100644 --- a/test/support/types/point.ex +++ b/test/support/types/point.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Point do @moduledoc false use Ash.Type diff --git a/test/support/types/response.ex b/test/support/types/response.ex index 51f475e0..9428ee15 100644 --- a/test/support/types/response.ex +++ b/test/support/types/response.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Types.Response do @moduledoc false use Ash.Type diff --git a/test/support/types/status.ex b/test/support/types/status.ex index 2aa3e4a7..7453e955 100644 --- a/test/support/types/status.ex +++ b/test/support/types/status.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Types.Status do @moduledoc false use Ash.Type.Enum, values: [:open, :closed] diff --git a/test/support/types/status_enum.ex b/test/support/types/status_enum.ex index dfd46a25..2a845ff2 100644 --- a/test/support/types/status_enum.ex +++ b/test/support/types/status_enum.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Types.StatusEnum do @moduledoc false use Ash.Type.Enum, values: [:open, :closed] diff --git a/test/support/types/status_enum_no_cast.ex b/test/support/types/status_enum_no_cast.ex index ec4a5e6b..032266de 100644 --- a/test/support/types/status_enum_no_cast.ex +++ b/test/support/types/status_enum_no_cast.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.Types.StatusEnumNoCast do @moduledoc false use Ash.Type.Enum, values: [:open, :closed] diff --git a/test/support/types/string_point.ex b/test/support/types/string_point.ex index 0550a904..1be38e28 100644 --- a/test/support/types/string_point.ex +++ b/test/support/types/string_point.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.StringPoint do @moduledoc false use Ash.Type diff --git a/test/support/unrelated_aggregates/profile.ex b/test/support/unrelated_aggregates/profile.ex index 87a9fa9f..257a44e3 100644 --- a/test/support/unrelated_aggregates/profile.ex +++ b/test/support/unrelated_aggregates/profile.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.UnrelatedAggregatesTest.Profile do @moduledoc false use Ash.Resource, diff --git a/test/support/unrelated_aggregates/report.ex b/test/support/unrelated_aggregates/report.ex index 652df03c..025e550c 100644 --- a/test/support/unrelated_aggregates/report.ex +++ b/test/support/unrelated_aggregates/report.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.UnrelatedAggregatesTest.Report do @moduledoc false use Ash.Resource, diff --git a/test/support/unrelated_aggregates/secure_profile.ex b/test/support/unrelated_aggregates/secure_profile.ex index 3f50bf73..7f380da2 100644 --- a/test/support/unrelated_aggregates/secure_profile.ex +++ b/test/support/unrelated_aggregates/secure_profile.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.UnrelatedAggregatesTest.SecureProfile do @moduledoc false use Ash.Resource, diff --git a/test/support/unrelated_aggregates/user.ex b/test/support/unrelated_aggregates/user.ex index ce143489..22529079 100644 --- a/test/support/unrelated_aggregates/user.ex +++ b/test/support/unrelated_aggregates/user.ex @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.UnrelatedAggregatesTest.User do @moduledoc false use Ash.Resource, diff --git a/test/test_helper.exs b/test/test_helper.exs index 6745f6eb..aba4a697 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + ExUnit.start(capture_log: true) Logger.configure(level: :debug) diff --git a/test/transaction_test.exs b/test/transaction_test.exs index 603fe0df..a4403a16 100644 --- a/test/transaction_test.exs +++ b/test/transaction_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.TransactionTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/tuple_test.exs b/test/tuple_test.exs index 1233ac28..5901f5c4 100644 --- a/test/tuple_test.exs +++ b/test/tuple_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.TupleTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/type_test.exs b/test/type_test.exs index 6355fe92..2e7c3132 100644 --- a/test/type_test.exs +++ b/test/type_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.TypeTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/unique_identity_test.exs b/test/unique_identity_test.exs index 47638025..618ead15 100644 --- a/test/unique_identity_test.exs +++ b/test/unique_identity_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.UniqueIdentityTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Organization diff --git a/test/unrelated_aggregates_test.exs b/test/unrelated_aggregates_test.exs index 0ec55535..1c4ca107 100644 --- a/test/unrelated_aggregates_test.exs +++ b/test/unrelated_aggregates_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.UnrelatedAggregatesTest do @moduledoc false use AshPostgres.RepoCase, async: false diff --git a/test/update_test.exs b/test/update_test.exs index d05f9863..22fb4af2 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.UpdateTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/test/upsert_test.exs b/test/upsert_test.exs index 08058701..0f3308a7 100644 --- a/test/upsert_test.exs +++ b/test/upsert_test.exs @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Zach Daniel +# +# SPDX-License-Identifier: MIT + defmodule AshPostgres.Test.UpsertTest do use AshPostgres.RepoCase, async: false alias AshPostgres.Test.Post diff --git a/usage-rules.md b/usage-rules.md index 632fc52d..84e0c138 100644 --- a/usage-rules.md +++ b/usage-rules.md @@ -1,3 +1,9 @@ + + # Rules for working with AshPostgres ## Understanding AshPostgres From efc4e38a6c1e43d713fa0ae2356fa53d1102898c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Oct 2025 16:54:36 -0400 Subject: [PATCH 673/690] chore(deps): bump ash in the production-dependencies group (#636) Bumps the production-dependencies group with 1 update: [ash](https://github.com/ash-project/ash). Updates `ash` from 3.5.43 to 3.6.2 - [Release notes](https://github.com/ash-project/ash/releases) - [Changelog](https://github.com/ash-project/ash/blob/main/CHANGELOG.md) - [Commits](https://github.com/ash-project/ash/compare/v3.5.43...v3.6.2) --- updated-dependencies: - dependency-name: ash dependency-version: 3.6.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 1827dcb4..05bd993c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.5.43", "222f9a8ac26ad3b029f8e69306cc83091c992d858b4538af12e33a148f301cab", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "48b2aa274c524f5b968c563dd56aec8f9b278c529c8aa46e6fe0ca564c26cc1c"}, + "ash": {:hex, :ash, "3.6.2", "90d1c8296be777b90caabf51b99323d6618a0b92594dfab92b02bdf848ac38bf", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "3546b5798dd24576cc451f6e03f3d6e3bb62666c0921bfe8aae700c599d9c38d"}, "ash_sql": {:hex, :ash_sql, "0.3.2", "e2d65dac1c813cbd2569a750bf1c063109778e840052e44535ced294d7638a19", [:mix], [{:ash, ">= 3.5.43 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", "1f6e5d827c0eb55fc5a07f58eb97f9bb3e6b290d83df75883f422537b98c9c68"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, From af0903f1380468bbe1b61fe65acb33772b5e24a5 Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Tue, 14 Oct 2025 02:03:13 +0200 Subject: [PATCH 674/690] fix: return skipped upserts in bulk_create (#626) --- lib/data_layer.ex | 125 ++++++++++++++++++++++++++++++++------ mix.exs | 4 +- test/bulk_create_test.exs | 61 +++++++++++++++++++ 3 files changed, 169 insertions(+), 21 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 07812631..9755eedf 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -662,6 +662,7 @@ defmodule AshPostgres.DataLayer do def can?(_, :combine), do: true def can?(_, {:combine, _}), do: true def can?(_, :bulk_create), do: true + def can?(_, :bulk_upsert_return_skipped), do: true def can?(_, :action_select), do: true @@ -2035,6 +2036,74 @@ defmodule AshPostgres.DataLayer do repo.insert_all(source, ecto_changesets, opts) end) + identity = options[:identity] + keys = Map.get(identity || %{}, :keys) || Ash.Resource.Info.primary_key(resource) + + # if it's single the return_skipped_upsert? is handled at the + # call site https://github.com/ash-project/ash_postgres/blob/0b21d4a99cc3f6d8676947e291ac9b9d57ad6e2e/lib/data_layer.ex#L3046-L3046 + result = + if options[:return_skipped_upsert?] && !opts[:single?] do + [changeset | _] = changesets + + results_by_identity = + result + |> elem(1) + |> List.wrap() + |> Enum.into(%{}, fn r -> + {Map.take(r, keys), r} + end) + + ash_query = + resource + |> Ash.Query.do_filter( + or: + changesets + |> Enum.filter(fn changeset -> + not Map.has_key?( + results_by_identity, + Map.take(changeset.attributes, keys) + ) + end) + |> Enum.map(fn changeset -> + changeset.attributes + |> Map.take(keys) + |> Keyword.new() + end) + ) + |> 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) + + skipped_upserts = + with {:ok, ecto_query} <- Ash.Query.data_layer_query(ash_query), + {:ok, results} <- run_query(ecto_query, resource) do + results + |> Enum.map(fn result -> + Ash.Resource.put_metadata(result, :upsert_skipped, true) + end) + |> Enum.reduce(%{}, fn r, acc -> + Map.put(acc, Map.take(r, keys), r) + end) + end + + results = + changesets + |> Enum.map(fn changeset -> + identity = + changeset.attributes + |> Map.take(keys) + + Map.get(results_by_identity, identity, Map.get(skipped_upserts, identity)) + end) + |> Enum.filter(& &1) + + {length(results), results} + else + result + end + case result do {_, nil} -> :ok @@ -2045,25 +2114,43 @@ defmodule AshPostgres.DataLayer do {:ok, results} else - {:ok, - Stream.zip_with(results, changesets, fn result, changeset -> - if !opts[:upsert?] do - maybe_create_tenant!(resource, result) - end - - case get_bulk_operation_metadata(changeset) do - {index, metadata_key} -> - Ash.Resource.put_metadata(result, metadata_key, index) - - nil -> - # Compatibility fallback - Ash.Resource.put_metadata( - result, - :bulk_create_index, - changeset.context[:bulk_create][:index] - ) - end - end)} + results_by_identity = + results + |> Enum.into(%{}, fn r -> + {Map.take(r, keys), r} + end) + + results = + changesets + |> Enum.map(fn changeset -> + identity = + changeset.attributes + |> Map.take(keys) + + result_for_changeset = Map.get(results_by_identity, identity) + + if result_for_changeset do + if !opts[:upsert?] do + maybe_create_tenant!(resource, result_for_changeset) + end + + case get_bulk_operation_metadata(changeset) do + {index, metadata_key} -> + Ash.Resource.put_metadata(result_for_changeset, metadata_key, index) + + nil -> + # Compatibility fallback + Ash.Resource.put_metadata( + result_for_changeset, + :bulk_create_index, + changeset.context[:bulk_create][:index] + ) + end + end + end) + |> Enum.filter(& &1) + + {:ok, results} end end rescue diff --git a/mix.exs b/mix.exs index cf59bf71..af4055bf 100644 --- a/mix.exs +++ b/mix.exs @@ -177,10 +177,10 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.5 and >= 3.5.35")}, + {:ash, ash_version("~> 3.5 and >= 3.6.2")}, {:spark, "~> 2.3 and >= 2.3.4"}, {:ash_sql, ash_sql_version("~> 0.3 and >= 0.3.2")}, - {:igniter, "~> 0.6 and >= 0.6.14", optional: true}, + {:igniter, "~> 0.6 and >= 0.6.29", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, {:jason, "~> 1.0"}, diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index e48d0238..420ff219 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -176,6 +176,67 @@ defmodule AshPostgres.BulkCreateTest do end) end + test "bulk upsert returns skipped records with return_skipped_upsert?" 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) + + results = + 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, + return_skipped_upsert?: true + ) + |> Enum.sort_by(fn + {:ok, result} -> + result.title + + _ -> + nil + end) + + assert [ + {:ok, skipped}, + {:ok, updated}, + {:ok, no_conflict} + ] = results + + assert skipped.title == "fredfoo" + assert skipped.price == 10 + assert Ash.Resource.get_metadata(skipped, :upsert_skipped) == true + + assert updated.title == "georgefoo" + assert updated.price == 20_000 + refute Ash.Resource.get_metadata(updated, :upsert_skipped) + + assert no_conflict.title == "herbert" + assert no_conflict.price == 30 + refute Ash.Resource.get_metadata(no_conflict, :upsert_skipped) + 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 From 10fa4c981476ee38ef355b34e8c8cc46aca474d1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 13 Oct 2025 22:28:40 -0400 Subject: [PATCH 675/690] improvement: leverage new aggregate loading optimization --- lib/data_layer.ex | 13 ++--- mix.lock | 6 +- test/aggregate_test.exs | 126 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 11 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 9755eedf..637b21f4 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -3619,14 +3619,11 @@ defmodule AshPostgres.DataLayer do end @impl true - def add_aggregates(query, aggregates, resource) do - AshSql.Aggregate.add_aggregates( - query, - aggregates, - resource, - true, - query.__ash_bindings__.root_binding - ) + def add_aggregates(query, aggregates, _resource) do + {:ok, + Map.update!(query, :__ash_bindings__, fn bindings -> + Map.put(bindings, :load_aggregates, aggregates) + end)} end @impl true diff --git a/mix.lock b/mix.lock index 05bd993c..96080205 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.6.2", "90d1c8296be777b90caabf51b99323d6618a0b92594dfab92b02bdf848ac38bf", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "3546b5798dd24576cc451f6e03f3d6e3bb62666c0921bfe8aae700c599d9c38d"}, - "ash_sql": {:hex, :ash_sql, "0.3.2", "e2d65dac1c813cbd2569a750bf1c063109778e840052e44535ced294d7638a19", [:mix], [{:ash, ">= 3.5.43 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", "1f6e5d827c0eb55fc5a07f58eb97f9bb3e6b290d83df75883f422537b98c9c68"}, + "ash_sql": {:hex, :ash_sql, "0.3.4", "c8c0446fbd6d3e6920f793b971c83ba3d14f96095036366d313b72656400509d", [:mix], [{:ash, ">= 3.5.43 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", "4edb1fb707048a41f7944274b1a0b571aa3c9117b8a7a12809ca023b6f955cb4"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -17,7 +17,7 @@ "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, "ex_doc": {:hex, :ex_doc, "0.38.4", "ab48dff7a8af84226bf23baddcdda329f467255d924380a0cf0cee97bb9a9ede", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "f7b62346408a83911c2580154e35613eb314e0278aeea72ed7fedef9c1f165b2"}, - "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, + "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [: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", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.9.0", "b74f6040084f523055b720cc7ef718da47f2cbe726a5f30c2871118635cb91c1", [: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]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "7fdf84be3490e5692c5dc1f8a1084eed47a221c1063e41938c73312f0bfea259"}, @@ -42,7 +42,7 @@ "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, "rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"}, "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, - "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"}, + "sobelow": {:hex, :sobelow, "0.14.1", "2f81e8632f15574cba2402bcddff5497b413c01e6f094bc0ab94e83c2f74db81", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8fac9a2bd90fdc4b15d6fca6e1608efb7f7c600fa75800813b794ee9364c87f2"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, "spark": {:hex, :spark, "2.3.5", "f30d30ecc3b4ab9b932d9aada66af7677fc1f297a2c349b0bcec3eafb9f996e8", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "0e9d339704d5d148f77f2b2fef3bcfc873a9e9bb4224fcf289c545d65827202f"}, "spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"}, diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index ff51bf26..3e64440f 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1734,4 +1734,130 @@ defmodule AshSql.AggregateTest do assert loaded_post.count_of_comments == 1 end + + test "aggregate with sort and limit is accurate" do + # Setup: Create an author with multiple posts + author = + Author + |> Ash.Changeset.for_create(:create, %{first_name: "John", last_name: "Doe"}) + |> Ash.create!() + + # Create posts with different titles to test sorting + post1 = + Post + |> Ash.Changeset.for_create(:create, %{title: "A First Post"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + post2 = + Post + |> Ash.Changeset.for_create(:create, %{title: "Z Last Post"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + post3 = + Post + |> Ash.Changeset.for_create(:create, %{title: "M Middle Post"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + # Add comments to posts + Comment + |> Ash.Changeset.for_create(:create, %{title: "Comment 1"}) + |> Ash.Changeset.manage_relationship(:post, post1, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "Comment 2"}) + |> Ash.Changeset.manage_relationship(:post, post1, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "Comment 3"}) + |> Ash.Changeset.manage_relationship(:post, post2, type: :append_and_remove) + |> Ash.create!() + + Comment + |> Ash.Changeset.for_create(:create, %{title: "Comment 4"}) + |> Ash.Changeset.manage_relationship(:post, post3, type: :append_and_remove) + |> Ash.create!() + + # Query with aggregate, sort, and limit + # This should ideally use a subquery to apply sort/limit before loading the aggregate + results = + Post + |> Ash.Query.load(:count_of_comments) + |> Ash.Query.sort(:title) + |> Ash.Query.limit(2) + |> Ash.read!() + + # Verify we got the right posts (sorted by title, limited to 2) + assert length(results) == 2 + assert Enum.at(results, 0).title == "A First Post" + assert Enum.at(results, 1).title == "M Middle Post" + + # Verify the aggregates are correct + assert Enum.at(results, 0).count_of_comments == 2 + assert Enum.at(results, 1).count_of_comments == 1 + end + + test "aggregate with sort by aggregate value and limit is accurate" do + # This tests sorting by the aggregate itself, not by another field + author = + Author + |> Ash.Changeset.for_create(:create, %{first_name: "Jane", last_name: "Smith"}) + |> Ash.create!() + + # Create posts with different numbers of comments + post1 = + Post + |> Ash.Changeset.for_create(:create, %{title: "Post with 3 comments"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + post2 = + Post + |> Ash.Changeset.for_create(:create, %{title: "Post with 1 comment"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + post3 = + Post + |> Ash.Changeset.for_create(:create, %{title: "Post with 2 comments"}) + |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) + |> Ash.create!() + + # Add varying numbers of comments + for _i <- 1..3 do + Comment + |> Ash.Changeset.for_create(:create, %{title: "Comment on post 1"}) + |> Ash.Changeset.manage_relationship(:post, post1, type: :append_and_remove) + |> Ash.create!() + end + + Comment + |> Ash.Changeset.for_create(:create, %{title: "Comment on post 2"}) + |> Ash.Changeset.manage_relationship(:post, post2, type: :append_and_remove) + |> Ash.create!() + + for _i <- 1..2 do + Comment + |> Ash.Changeset.for_create(:create, %{title: "Comment on post 3"}) + |> Ash.Changeset.manage_relationship(:post, post3, type: :append_and_remove) + |> Ash.create!() + end + + # Query sorting by the aggregate value itself + results = + Post + |> Ash.Query.load(:count_of_comments) + |> Ash.Query.sort(count_of_comments: :desc) + |> Ash.Query.limit(2) + |> Ash.read!() + + # Should get the posts with most comments first + assert length(results) == 2 + assert Enum.at(results, 0).count_of_comments == 3 + assert Enum.at(results, 1).count_of_comments == 2 + end end From d011d0ef554b5d9be747965d32e3bcd87b82bcb4 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 13 Oct 2025 22:55:09 -0400 Subject: [PATCH 676/690] chore: release version v2.6.22 --- CHANGELOG.md | 13 +++++++++++++ mix.exs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b045424..67570853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,19 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.22](https://github.com/ash-project/ash_postgres/compare/v2.6.21...v2.6.22) (2025-10-14) + + + + +### Bug Fixes: + +* return skipped upserts in bulk_create (#626) by Barnabas Jovanovics + +### Improvements: + +* leverage new aggregate loading optimization by Zach Daniel + ## [v2.6.21](https://github.com/ash-project/ash_postgres/compare/v2.6.20...v2.6.21) (2025-10-10) diff --git a/mix.exs b/mix.exs index af4055bf..0bd7385a 100644 --- a/mix.exs +++ b/mix.exs @@ -9,7 +9,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.21" + @version "2.6.22" def project do [ From 4da5f3b00cdf6b3d2d0292659494ecebb5a2928c Mon Sep 17 00:00:00 2001 From: James Harton Date: Wed, 15 Oct 2025 08:43:52 +1300 Subject: [PATCH 677/690] chore: Fix REUSE copyright attributions --- .check.exs | 2 +- .credo.exs | 2 +- .formatter.exs | 2 +- .github/dependabot.yml | 2 +- .github/workflows/elixir.yml | 2 +- .gitignore | 2 +- .tool-versions.license | 2 +- .vscode/settings.json.license | 2 +- benchmarks/bulk_create.exs | 2 +- config/config.exs | 2 +- documentation/dsls/DSL-AshPostgres.DataLayer.md.license | 2 +- lib/ash_postgres.ex | 2 +- lib/check_constraint.ex | 2 +- lib/custom_aggregate.ex | 2 +- lib/custom_extension.ex | 2 +- lib/custom_index.ex | 2 +- lib/data_layer.ex | 2 +- lib/data_layer/info.ex | 2 +- lib/ecto_migration_default.ex | 2 +- lib/extensions/immutable_raise_error.ex | 2 +- lib/extensions/vector.ex | 2 +- lib/functions/binding.ex | 2 +- lib/functions/ilike.ex | 2 +- lib/functions/like.ex | 2 +- lib/functions/trigram_similarity.ex | 2 +- lib/functions/vector_cosine_distance.ex | 2 +- lib/functions/vector_l2_distance.ex | 2 +- lib/igniter.ex | 2 +- lib/manual_relationship.ex | 2 +- lib/migration.ex | 2 +- lib/migration_compile_cache.ex | 2 +- lib/migration_generator/ash_functions.ex | 2 +- lib/migration_generator/migration_generator.ex | 2 +- lib/migration_generator/operation.ex | 2 +- lib/migration_generator/phase.ex | 2 +- lib/mix/helpers.ex | 2 +- lib/mix/tasks/ash_postgres.create.ex | 2 +- lib/mix/tasks/ash_postgres.drop.ex | 2 +- lib/mix/tasks/ash_postgres.gen.resources.ex | 2 +- lib/mix/tasks/ash_postgres.generate_migrations.ex | 2 +- lib/mix/tasks/ash_postgres.install.ex | 2 +- lib/mix/tasks/ash_postgres.migrate.ex | 2 +- lib/mix/tasks/ash_postgres.rollback.ex | 2 +- lib/mix/tasks/ash_postgres.setup_vector.ex | 2 +- lib/mix/tasks/ash_postgres.squash_snapshots.ex | 2 +- lib/multitenancy.ex | 2 +- lib/reference.ex | 2 +- lib/repo.ex | 2 +- lib/repo/before_compile.ex | 2 +- lib/resource_generator/resource_generator.ex | 2 +- lib/resource_generator/sensitive_data.ex | 2 +- lib/resource_generator/spec.ex | 2 +- lib/sql_implementation.ex | 2 +- lib/statement.ex | 2 +- lib/type.ex | 2 +- lib/types/ci_string_wrapper.ex | 2 +- lib/types/ltree.ex | 2 +- lib/types/string_wrapper.ex | 2 +- lib/types/timestamptz.ex | 2 +- lib/types/timestamptz_usec.ex | 2 +- lib/types/tsquery.ex | 2 +- lib/types/tsvector.ex | 2 +- lib/verifiers/ensure_table_or_polymorphic.ex | 2 +- .../prevent_attribute_multitenancy_and_non_full_match_type.ex | 2 +- lib/verifiers/prevent_multidimensional_array_aggregates.ex | 2 +- lib/verifiers/validate_identity_index_names.ex | 2 +- lib/verifiers/validate_references.ex | 2 +- lib/version_agent.ex | 2 +- logos/small-logo.png.license | 2 +- mix.exs | 2 +- mix.lock.license | 2 +- .../20250526214825_migrate_resources_extensions_1.exs | 2 +- .../migrations/20250526214827_migrate_resources1.exs | 2 +- priv/resource_snapshots/dev_test_repo/extensions.json.license | 2 +- .../multitenant_orgs/20250526214827.json.license | 2 +- .../test_no_sandbox_repo/extensions.json.license | 2 +- .../test_repo/accounts/20221217123726.json.license | 2 +- .../test_repo/accounts/20240327211150.json.license | 2 +- .../test_repo/authors/20220805191443.json.license | 2 +- .../test_repo/authors/20220914104733.json.license | 2 +- .../test_repo/authors/20240327211150.json.license | 2 +- .../test_repo/authors/20240705113722.json.license | 2 +- .../test_repo/authors/20250908212414.json.license | 2 +- .../test_repo/chats/20250908093505.json.license | 2 +- .../test_repo/co_authored_posts/20241208221219.json.license | 2 +- .../test_repo/comedians/20241217232254.json.license | 2 +- .../test_repo/comedians/20250413141328.json.license | 2 +- .../test_repo/comment_links/20250123161002.json.license | 2 +- .../test_repo/comment_ratings/20220805191443.json.license | 2 +- .../test_repo/comment_ratings/20240327211150.json.license | 2 +- .../test_repo/comments/20220805191443.json.license | 2 +- .../test_repo/comments/20240327211150.json.license | 2 +- .../test_repo/comments/20240327211917.json.license | 2 +- .../20230816231942.json.license | 2 +- .../20240327211150.json.license | 2 +- .../20231116013020.json.license | 2 +- .../20240327211150.json.license | 2 +- .../20240327211917.json.license | 2 +- .../complex_calculations_channels/20231116013020.json.license | 2 +- .../complex_calculations_channels/20240327211150.json.license | 2 +- .../complex_calculations_channels/20240327211917.json.license | 2 +- .../20230816231942.json.license | 2 +- .../20240327211150.json.license | 2 +- .../20240327211917.json.license | 2 +- .../20250714225304.json.license | 2 +- .../complex_calculations_folders/20250714225304.json.license | 2 +- .../complex_calculations_skills/20230816231942.json.license | 2 +- .../complex_calculations_skills/20240327211150.json.license | 2 +- .../test_repo/content/20250123164209.json.license | 2 +- .../content_visibility_group/20250123164209.json.license | 2 +- .../test_repo/csv/20250320225052.json.license | 2 +- .../test_repo/customers/20250908073737.json.license | 2 +- .../test_repo/entities/20240109160153.json.license | 2 +- .../test_repo/entities/20240327211150.json.license | 2 +- .../test_repo/entities/20240327211917.json.license | 2 +- priv/resource_snapshots/test_repo/extensions.json.license | 2 +- .../test_repo/integer_posts/20220805191443.json.license | 2 +- .../test_repo/items/20240713134055.json.license | 2 +- .../test_repo/items/20240717104854.json.license | 2 +- .../test_repo/items/20240717153736.json.license | 2 +- .../test_repo/jokes/20241217232254.json.license | 2 +- .../test_repo/jokes/20250413141328.json.license | 2 +- .../test_repo/managers/20230526144249.json.license | 2 +- .../test_repo/managers/20240327211150.json.license | 2 +- .../test_repo/messages/20250908093505.json.license | 2 +- .../multitenant_named_orgs/20250519103535.json.license | 2 +- .../test_repo/multitenant_orgs/20220805191443.json.license | 2 +- .../test_repo/multitenant_orgs/20240327211150.json.license | 2 +- .../test_repo/multitenant_orgs/20240627223225.json.license | 2 +- .../test_repo/multitenant_orgs/20240702164513.json.license | 2 +- .../test_repo/multitenant_orgs/20240703155134.json.license | 2 +- .../non_multitenant_post_links/20250122190558.json.license | 2 +- .../test_repo/note/20250123164209.json.license | 2 +- .../test_repo/orders/20250908073737.json.license | 2 +- .../test_repo/orgs/20230129050950.json.license | 2 +- .../test_repo/orgs/20240327211150.json.license | 2 +- .../test_repo/orgs/20250210191116.json.license | 2 +- .../test_repo/other_items/20240713134055.json.license | 2 +- .../test_repo/other_items/20240717151815.json.license | 2 +- .../test_repo/points/20250313112823.json.license | 2 +- .../test_repo/post_followers/20240227180858.json.license | 2 +- .../test_repo/post_followers/20240227181137.json.license | 2 +- .../test_repo/post_followers/20240327211150.json.license | 2 +- .../test_repo/post_followers/20240516205244.json.license | 2 +- .../test_repo/post_followers/20240517223946.json.license | 2 +- .../test_repo/post_links/20220805191443.json.license | 2 +- .../test_repo/post_links/20221017133955.json.license | 2 +- .../test_repo/post_links/20221202194704.json.license | 2 +- .../test_repo/post_links/20240610195853.json.license | 2 +- .../test_repo/post_links/20240617193218.json.license | 2 +- .../test_repo/post_permalinks/20240906170759.json.license | 2 +- .../test_repo/post_ratings/20220805191443.json.license | 2 +- .../test_repo/post_ratings/20240327211150.json.license | 2 +- .../test_repo/post_tags/20250810102512.json.license | 2 +- .../test_repo/post_views/20230905050351.json.license | 2 +- .../test_repo/post_views/20240327211917.json.license | 2 +- .../test_repo/posts/20220805191443.json.license | 2 +- .../test_repo/posts/20221125171150.json.license | 2 +- .../test_repo/posts/20221125171204.json.license | 2 +- .../test_repo/posts/20230129050950.json.license | 2 +- .../test_repo/posts/20230823161017.json.license | 2 +- .../test_repo/posts/20231127215636.json.license | 2 +- .../test_repo/posts/20231129141453.json.license | 2 +- .../test_repo/posts/20231219132807.json.license | 2 +- .../test_repo/posts/20240129221511.json.license | 2 +- .../test_repo/posts/20240224001913.json.license | 2 +- .../test_repo/posts/20240327211150.json.license | 2 +- .../test_repo/posts/20240327211917.json.license | 2 +- .../test_repo/posts/20240503012410.json.license | 2 +- .../test_repo/posts/20240504185511.json.license | 2 +- .../test_repo/posts/20240524031113.json.license | 2 +- .../test_repo/posts/20240524041750.json.license | 2 +- .../test_repo/posts/20240617193218.json.license | 2 +- .../test_repo/posts/20240618102809.json.license | 2 +- .../test_repo/posts/20240712232026.json.license | 2 +- .../test_repo/posts/20240715135403.json.license | 2 +- .../test_repo/posts/20240910180107.json.license | 2 +- .../test_repo/posts/20240911225320.json.license | 2 +- .../test_repo/posts/20240918104740.json.license | 2 +- .../test_repo/posts/20240929121224.json.license | 2 +- .../test_repo/posts/20250217054207.json.license | 2 +- .../test_repo/posts/20250313112823.json.license | 2 +- .../test_repo/posts/20250520130634.json.license | 2 +- .../test_repo/posts/20250521105654.json.license | 2 +- .../test_repo/posts/20250612113920.json.license | 2 +- .../test_repo/posts/20250618011917.json.license | 2 +- .../test_repo/products/20250908073737.json.license | 2 +- .../test_repo/profile/20220805191443.json.license | 2 +- .../test_repo/profiles.profile/20240327211150.json.license | 2 +- .../test_repo/punchlines/20250413141328.json.license | 2 +- .../test_repo/records/20240109160153.json.license | 2 +- .../test_repo/records/20240327211150.json.license | 2 +- .../test_repo/records/20240327211917.json.license | 2 +- .../records_temp_entities/20250605230457.json.license | 2 +- .../test_repo/relationship_items/20240717153736.json.license | 2 +- .../test_repo/rsvps/20251002180954.json.license | 2 +- .../test_repo/schematic_groups/20240821213522.json.license | 2 +- .../test_repo/staff_group/20250123164209.json.license | 2 +- .../test_repo/staff_group_member/20250123164209.json.license | 2 +- .../test_repo/standup_clubs/20250413141328.json.license | 2 +- .../stateful_post_followers/20240618085942.json.license | 2 +- .../test_repo/string_points/20250313112823.json.license | 2 +- .../test_repo/sub_items/20240713134055.json.license | 2 +- .../test_repo/subquery_access/20240130133933.json.license | 2 +- .../test_repo/subquery_child/20240130133933.json.license | 2 +- .../test_repo/subquery_parent/20240130133933.json.license | 2 +- .../test_repo/subquery_through/20240130133933.json.license | 2 +- .../test_repo/tags/20250810102512.json.license | 2 +- .../test_repo/temp.temp_entities/20240327211150.json.license | 2 +- .../test_repo/temp.temp_entities/20240327211917.json.license | 2 +- .../test_repo/temp_entities/20240109160153.json.license | 2 +- .../tenants/composite_key/20250220073135.json.license | 2 +- .../tenants/composite_key/20250220073141.json.license | 2 +- .../cross_tenant_post_links/20250122203454.json.license | 2 +- .../tenants/friend_links/20240610162043.json.license | 2 +- .../tenants/multitenant_posts/20220805191441.json.license | 2 +- .../tenants/multitenant_posts/20240327211149.json.license | 2 +- .../20251001120813.json.license | 2 +- .../test_repo/unrelated_profiles/20250731124648.json.license | 2 +- .../test_repo/unrelated_reports/20250731124648.json.license | 2 +- .../unrelated_secure_profiles/20250731124648.json.license | 2 +- .../test_repo/unrelated_users/20250731124648.json.license | 2 +- .../test_repo/user_invites/20240727145758.json.license | 2 +- .../test_repo/users/20220805191443.json.license | 2 +- .../test_repo/users/20221217123726.json.license | 2 +- .../test_repo/users/20230129050950.json.license | 2 +- .../test_repo/users/20240327211150.json.license | 2 +- .../test_repo/users/20240727145758.json.license | 2 +- .../test_repo/users/20240929124728.json.license | 2 +- .../test_repo/users/20250320225052.json.license | 2 +- .../test_repo/users/20250321142835.json.license | 2 +- priv/test_no_sandbox_repo/migrations/.gitkeep.license | 2 +- .../migrations/20240627223224_install_5_extensions.exs | 2 +- .../20240712232025_install_ash-functions_extension_4.exs | 2 +- .../20250113205301_migrate_resources_extensions_1.exs | 2 +- .../migrations/20220805191440_install_4_extensions.exs | 4 ++-- .../migrations/20220805191443_migrate_resources1.exs | 2 +- .../migrations/20220914104733_migrate_resources2.exs | 4 ++-- .../migrations/20221017133955_migrate_resources3.exs | 4 ++-- .../migrations/20221125171148_migrate_resources4.exs | 4 ++-- .../migrations/20221125171150_migrate_resources5.exs | 4 ++-- .../migrations/20221202194704_migrate_resources6.exs | 4 ++-- .../migrations/20221217123726_migrate_resources7.exs | 4 ++-- .../migrations/20230129050950_migrate_resources8.exs | 4 ++-- .../migrations/20230526144249_migrate_resources9.exs | 4 ++-- .../20230712182523_install_ash-functions_extension.exs | 2 +- .../20230804223759_install_demo-functions_v0_extension.exs | 4 ++-- .../20230804223818_install_demo-functions_v1_extension.exs | 4 ++-- .../20230816231942_add_complex_calculation_tables.exs | 4 ++-- .../migrations/20230823161017_migrate_resources10.exs | 4 ++-- priv/test_repo/migrations/20230905050351_add_post_views.exs | 4 ++-- .../20231116013020_add_complex_calculations_channels.exs | 4 ++-- .../migrations/20231127212608_add_composite_type.exs | 2 +- .../migrations/20231127215636_migrate_resources11.exs | 2 +- .../migrations/20231129141453_migrate_resources12.exs | 4 ++-- .../20231214220937_install_ash-functions_extension_2.exs | 2 +- .../migrations/20231219132807_migrate_resources13.exs | 4 ++-- .../20231231051611_install_ash-functions_extension_3.exs | 4 ++-- .../migrations/20240109155951_create_temp_schema.exs | 2 +- .../migrations/20240109160153_migrate_resources14.exs | 4 ++-- .../migrations/20240129221511_migrate_resources15.exs | 4 ++-- .../20240130133933_add_resources_for_subquery_test.exs | 2 +- .../migrations/20240224001913_migrate_resources16.exs | 4 ++-- .../migrations/20240227180858_migrate_resources17.exs | 4 ++-- .../migrations/20240227181137_migrate_resources18.exs | 4 ++-- .../migrations/20240229050455_install_5_extensions.exs | 2 +- .../migrations/20240327211150_migrate_resources19.exs | 2 +- .../migrations/20240327211917_migrate_resources20.exs | 2 +- .../migrations/20240503012410_migrate_resources21.exs | 2 +- .../migrations/20240504185511_migrate_resources22.exs | 2 +- .../migrations/20240516205244_migrate_resources23.exs | 2 +- .../migrations/20240517223946_migrate_resources24.exs | 2 +- .../migrations/20240524031113_migrate_resources25.exs | 2 +- .../migrations/20240524041750_migrate_resources26.exs | 2 +- .../migrations/20240610195853_migrate_resources27.exs | 2 +- .../migrations/20240617193218_migrate_resources28.exs | 2 +- .../migrations/20240618085942_migrate_resources29.exs | 2 +- .../migrations/20240618102809_migrate_resources30.exs | 2 +- .../20240622192715_install_ash-functions_extension_4.exs | 2 +- .../migrations/20240627223225_migrate_resources31.exs | 2 +- .../migrations/20240703155134_migrate_resources32.exs | 2 +- .../migrations/20240705113722_migrate_resources33.exs | 2 +- .../migrations/20240712232026_migrate_resources34.exs | 2 +- .../migrations/20240713134055_multi_domain_calculations.exs | 2 +- .../migrations/20240715135403_migrate_resources35.exs | 2 +- .../20240717104854_no_attributes_calculation_test.exs | 2 +- .../migrations/20240717151815_migrate_resources36.exs | 2 +- .../migrations/20240717153736_migrate_resources37.exs | 2 +- priv/test_repo/migrations/20240727145758_user_invites.exs | 2 +- .../migrations/20240906170759_migrate_resources38.exs | 2 +- .../migrations/20240910180107_migrate_resources39.exs | 2 +- .../migrations/20240911225319_install_1_extensions.exs | 2 +- .../migrations/20240911225320_migrate_resources40.exs | 2 +- .../migrations/20240918104740_migrate_resources41.exs | 2 +- .../migrations/20240929121224_migrate_resources42.exs | 2 +- .../migrations/20240929124728_migrate_resources43.exs | 2 +- .../migrations/20241208221219_migrate_resources44.exs | 2 +- .../migrations/20241217232254_migrate_resources45.exs | 2 +- .../20250113205259_migrate_resources_extensions_1.exs | 2 +- .../migrations/20250122190558_migrate_resources46.exs | 2 +- .../migrations/20250123161002_migrate_resources47.exs | 2 +- .../migrations/20250123164209_migrate_resources48.exs | 2 +- .../migrations/20250210191116_migrate_resources49.exs | 2 +- .../migrations/20250217054207_migrate_resources50.exs | 2 +- .../migrations/20250313112823_migrate_resources51.exs | 2 +- priv/test_repo/migrations/20250320225052_add_csv_resource.exs | 2 +- .../migrations/20250321142835_migrate_resources52.exs | 2 +- .../20250413141328_add_punchlines_and_standup_clubs.exs | 2 +- .../migrations/20250519103535_migrate_resources53.exs | 2 +- .../migrations/20250520130634_migrate_resources54.exs | 2 +- .../migrations/20250521105654_add_model_tuple_to_post.exs | 2 +- .../20250605230457_create_record_temp_entities_table.exs | 2 +- .../migrations/20250612113920_migrate_resources55.exs | 2 +- .../migrations/20250618011917_migrate_resources56.exs | 2 +- ...250714225304_add_complex_calculations_folder_and_items.exs | 2 +- .../migrations/20250731124648_migrate_resources57.exs | 2 +- .../migrations/20250810102512_migrate_resources58.exs | 2 +- .../migrations/20250908073737_migrate_resources59.exs | 2 +- .../migrations/20250908093505_migrate_resources60.exs | 2 +- .../migrations/20250908212414_migrate_resources61.exs | 2 +- .../migrations/20251002180954_migrate_resources62.exs | 2 +- .../tenant_migrations/20220805191441_migrate_resources1.exs | 4 ++-- .../tenant_migrations/20240327211149_migrate_resources2.exs | 2 +- .../tenant_migrations/20240610162043_migrate_resources3.exs | 2 +- .../tenant_migrations/20250122203454_migrate_resources4.exs | 2 +- .../tenant_migrations/20250220073135_migrate_resources5.exs | 2 +- .../tenant_migrations/20250220073141_migrate_resources6.exs | 2 +- .../tenant_migrations/20251001120813_migrate_resources7.exs | 2 +- test/aggregate_test.exs | 2 +- test/ash_postgres_test.exs | 2 +- test/atomics_test.exs | 2 +- test/bulk_create_test.exs | 2 +- test/bulk_destroy_test.exs | 2 +- test/bulk_update_test.exs | 2 +- test/calculation_test.exs | 2 +- test/cascade_destroy_test.exs | 2 +- test/combination_test.exs | 2 +- test/complex_calculations_test.exs | 2 +- test/composite_type_test.exs | 2 +- test/constraint_test.exs | 2 +- test/create_test.exs | 2 +- test/custom_expression_test.exs | 2 +- test/custom_index_test.exs | 2 +- test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs | 2 +- test/destroy_test.exs | 2 +- test/dev_migrations_test.exs | 2 +- test/distinct_test.exs | 2 +- test/ecto_compatibility_test.exs | 2 +- test/embeddable_resource_test.exs | 2 +- test/enum_test.exs | 2 +- test/error_expr_test.exs | 2 +- .../filter_child_relationship_by_parent_relationship_test.exs | 2 +- test/filter_field_policy_test.exs | 2 +- test/filter_test.exs | 2 +- test/load_test.exs | 2 +- test/lock_test.exs | 2 +- test/ltree_test.exs | 2 +- test/manual_relationships_test.exs | 2 +- test/manual_update_test.exs | 2 +- test/many_to_many_expr_test.exs | 2 +- test/migration_generator_test.exs | 2 +- test/mix/tasks/ash_postgres.install_test.exs | 2 +- test/mix_squash_snapshots_test.exs | 2 +- test/multi_domain_calculations_test.exs | 2 +- test/multitenancy_test.exs | 2 +- test/parent_filter_test.exs | 2 +- test/parent_sort_test.exs | 2 +- test/polymorphism_test.exs | 2 +- test/primary_key_test.exs | 2 +- test/references_test.exs | 2 +- test/rel_with_parent_filter_test.exs | 2 +- test/resource_generator_test.exs | 2 +- test/schema_test.exs | 2 +- test/select_test.exs | 2 +- test/sort_test.exs | 2 +- test/storage_types_test.exs | 2 +- test/subquery_test.exs | 2 +- test/support/complex_calculations/domain.ex | 2 +- test/support/complex_calculations/resources/certification.ex | 2 +- test/support/complex_calculations/resources/channel.ex | 2 +- test/support/complex_calculations/resources/channel_member.ex | 2 +- test/support/complex_calculations/resources/dm_channel.ex | 2 +- test/support/complex_calculations/resources/documentation.ex | 2 +- test/support/complex_calculations/resources/folder.ex | 2 +- test/support/complex_calculations/resources/folder_item.ex | 2 +- test/support/complex_calculations/resources/skill.ex | 2 +- test/support/concat.ex | 2 +- test/support/dev_test_repo.ex | 2 +- test/support/domain.ex | 2 +- test/support/multi_domain_calculations/domain_one.ex | 2 +- test/support/multi_domain_calculations/domain_one/item.ex | 2 +- test/support/multi_domain_calculations/domain_three.ex | 2 +- .../domain_three/relationship_item.ex | 2 +- test/support/multi_domain_calculations/domain_two.ex | 2 +- .../multi_domain_calculations/domain_two/other_item.ex | 2 +- test/support/multi_domain_calculations/domain_two/sub_item.ex | 2 +- test/support/multitenancy/domain.ex | 2 +- test/support/multitenancy/resources/composite_key_post.ex | 2 +- test/support/multitenancy/resources/cross_tenant_post_link.ex | 2 +- test/support/multitenancy/resources/dev_migrations_org.ex | 2 +- test/support/multitenancy/resources/named_org.ex | 2 +- .../multitenancy/resources/non_multitenant_post_link.ex | 2 +- .../resources/non_multitenant_post_multitenant_link.ex | 2 +- test/support/multitenancy/resources/org.ex | 2 +- test/support/multitenancy/resources/post.ex | 2 +- test/support/multitenancy/resources/post_link.ex | 2 +- test/support/multitenancy/resources/user.ex | 2 +- test/support/relationships/comments_containing_title.ex | 2 +- test/support/repo_case.ex | 2 +- test/support/resources/account.ex | 2 +- test/support/resources/author.ex | 2 +- test/support/resources/bio.ex | 2 +- test/support/resources/chat.ex | 2 +- test/support/resources/co_authored_post.ex | 2 +- test/support/resources/comedian.ex | 2 +- test/support/resources/comment.ex | 2 +- test/support/resources/comment_link.ex | 2 +- test/support/resources/content.ex | 2 +- test/support/resources/content_visibility_group.ex | 2 +- test/support/resources/csv.ex | 2 +- test/support/resources/customer.ex | 2 +- test/support/resources/db_point.ex | 2 +- test/support/resources/db_string_point.ex | 2 +- test/support/resources/entity.ex | 2 +- test/support/resources/integer_post.ex | 2 +- test/support/resources/invite.ex | 2 +- test/support/resources/joke.ex | 2 +- test/support/resources/manager.ex | 2 +- test/support/resources/message.ex | 2 +- test/support/resources/note.ex | 2 +- test/support/resources/order.ex | 2 +- test/support/resources/organization.ex | 2 +- test/support/resources/permalink.ex | 2 +- test/support/resources/post.ex | 2 +- test/support/resources/post_follower.ex | 2 +- test/support/resources/post_link.ex | 2 +- test/support/resources/post_tag.ex | 2 +- test/support/resources/post_views.ex | 2 +- test/support/resources/post_with_empty_update.ex | 2 +- test/support/resources/product.ex | 2 +- test/support/resources/profile.ex | 2 +- test/support/resources/punchline.ex | 2 +- test/support/resources/rating.ex | 2 +- test/support/resources/record.ex | 2 +- test/support/resources/record_temp_entity.ex | 2 +- test/support/resources/role.ex | 2 +- test/support/resources/rsvp.ex | 2 +- test/support/resources/settings.ex | 2 +- test/support/resources/staff_group.ex | 2 +- test/support/resources/staff_group_member.ex | 2 +- test/support/resources/standup_club.ex | 2 +- test/support/resources/stateful_post_follwer.ex | 2 +- test/support/resources/subquery/access.ex | 2 +- test/support/resources/subquery/child.ex | 2 +- test/support/resources/subquery/child_domain.ex | 2 +- test/support/resources/subquery/parent.ex | 2 +- test/support/resources/subquery/parent_domain.ex | 2 +- test/support/resources/subquery/through.ex | 2 +- test/support/resources/tag.ex | 2 +- test/support/resources/temp_entity.ex | 2 +- test/support/resources/user.ex | 2 +- test/support/string_agg.ex | 2 +- test/support/test_app.ex | 2 +- test/support/test_custom_extension.ex | 2 +- test/support/test_no_sandbox_repo.ex | 2 +- test/support/test_repo.ex | 2 +- test/support/trigram_word_similarity.ex | 2 +- test/support/types/composite_point.ex | 2 +- test/support/types/email.ex | 2 +- test/support/types/money.ex | 2 +- test/support/types/person_detail.ex | 2 +- test/support/types/point.ex | 2 +- test/support/types/response.ex | 2 +- test/support/types/status.ex | 2 +- test/support/types/status_enum.ex | 2 +- test/support/types/status_enum_no_cast.ex | 2 +- test/support/types/string_point.ex | 2 +- test/support/unrelated_aggregates/profile.ex | 2 +- test/support/unrelated_aggregates/report.ex | 2 +- test/support/unrelated_aggregates/secure_profile.ex | 2 +- test/support/unrelated_aggregates/user.ex | 2 +- test/test_helper.exs | 2 +- test/transaction_test.exs | 2 +- test/tuple_test.exs | 2 +- test/type_test.exs | 2 +- test/unique_identity_test.exs | 2 +- test/unrelated_aggregates_test.exs | 2 +- test/update_test.exs | 2 +- test/upsert_test.exs | 2 +- 489 files changed, 513 insertions(+), 513 deletions(-) diff --git a/.check.exs b/.check.exs index cecfbc08..25e480f8 100644 --- a/.check.exs +++ b/.check.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/.credo.exs b/.credo.exs index 1e1ebe4c..233f96e7 100644 --- a/.credo.exs +++ b/.credo.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/.formatter.exs b/.formatter.exs index 07bd4f93..71cf7ae6 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 09b96595..16a96790 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index cf4e4897..bec3b86f 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/.gitignore b/.gitignore index b16f7ffb..b7c11866 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/.tool-versions.license b/.tool-versions.license index 815664f3..b0a44fab 100644 --- a/.tool-versions.license +++ b/.tool-versions.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/.vscode/settings.json.license b/.vscode/settings.json.license index 815664f3..b0a44fab 100644 --- a/.vscode/settings.json.license +++ b/.vscode/settings.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/benchmarks/bulk_create.exs b/benchmarks/bulk_create.exs index 5e665f19..c242f236 100644 --- a/benchmarks/bulk_create.exs +++ b/benchmarks/bulk_create.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/config/config.exs b/config/config.exs index 5a179e32..b7f0c0b3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/documentation/dsls/DSL-AshPostgres.DataLayer.md.license b/documentation/dsls/DSL-AshPostgres.DataLayer.md.license index 815664f3..b0a44fab 100644 --- a/documentation/dsls/DSL-AshPostgres.DataLayer.md.license +++ b/documentation/dsls/DSL-AshPostgres.DataLayer.md.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/lib/ash_postgres.ex b/lib/ash_postgres.ex index 34f5cd43..f3c69313 100644 --- a/lib/ash_postgres.ex +++ b/lib/ash_postgres.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/check_constraint.ex b/lib/check_constraint.ex index 6534a464..679ee2a4 100644 --- a/lib/check_constraint.ex +++ b/lib/check_constraint.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/custom_aggregate.ex b/lib/custom_aggregate.ex index 6a42b026..af5936a9 100644 --- a/lib/custom_aggregate.ex +++ b/lib/custom_aggregate.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/custom_extension.ex b/lib/custom_extension.ex index 968a748c..95262e6a 100644 --- a/lib/custom_extension.ex +++ b/lib/custom_extension.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/custom_index.ex b/lib/custom_index.ex index 240b30d2..909dc07d 100644 --- a/lib/custom_index.ex +++ b/lib/custom_index.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 637b21f4..894de3fb 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/data_layer/info.ex b/lib/data_layer/info.ex index 933ca6e8..b36e9f86 100644 --- a/lib/data_layer/info.ex +++ b/lib/data_layer/info.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/ecto_migration_default.ex b/lib/ecto_migration_default.ex index d865471b..1e417126 100644 --- a/lib/ecto_migration_default.ex +++ b/lib/ecto_migration_default.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/extensions/immutable_raise_error.ex b/lib/extensions/immutable_raise_error.ex index 22760442..a1a4032c 100644 --- a/lib/extensions/immutable_raise_error.ex +++ b/lib/extensions/immutable_raise_error.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/extensions/vector.ex b/lib/extensions/vector.ex index c029dcf4..ffd281af 100644 --- a/lib/extensions/vector.ex +++ b/lib/extensions/vector.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/functions/binding.ex b/lib/functions/binding.ex index df20a209..9f6a15e7 100644 --- a/lib/functions/binding.ex +++ b/lib/functions/binding.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/functions/ilike.ex b/lib/functions/ilike.ex index dd960f5f..35ee4bf0 100644 --- a/lib/functions/ilike.ex +++ b/lib/functions/ilike.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/functions/like.ex b/lib/functions/like.ex index fdc76c6b..bd160f66 100644 --- a/lib/functions/like.ex +++ b/lib/functions/like.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/functions/trigram_similarity.ex b/lib/functions/trigram_similarity.ex index 19622647..20250d90 100644 --- a/lib/functions/trigram_similarity.ex +++ b/lib/functions/trigram_similarity.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/functions/vector_cosine_distance.ex b/lib/functions/vector_cosine_distance.ex index 1a811583..afbb9b89 100644 --- a/lib/functions/vector_cosine_distance.ex +++ b/lib/functions/vector_cosine_distance.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/functions/vector_l2_distance.ex b/lib/functions/vector_l2_distance.ex index 063a1432..5d1ec62b 100644 --- a/lib/functions/vector_l2_distance.ex +++ b/lib/functions/vector_l2_distance.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/igniter.ex b/lib/igniter.ex index aa20746d..8d9e0808 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/manual_relationship.ex b/lib/manual_relationship.ex index b6322de9..c3c4f030 100644 --- a/lib/manual_relationship.ex +++ b/lib/manual_relationship.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/migration.ex b/lib/migration.ex index 9102d2a9..9ff83c94 100644 --- a/lib/migration.ex +++ b/lib/migration.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/migration_compile_cache.ex b/lib/migration_compile_cache.ex index f421d3b6..5993dffd 100644 --- a/lib/migration_compile_cache.ex +++ b/lib/migration_compile_cache.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/migration_generator/ash_functions.ex b/lib/migration_generator/ash_functions.ex index 1206d829..0ad49bdc 100644 --- a/lib/migration_generator/ash_functions.ex +++ b/lib/migration_generator/ash_functions.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index bdd82fba..6cdbc469 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/migration_generator/operation.ex b/lib/migration_generator/operation.ex index 21af504b..b7b09792 100644 --- a/lib/migration_generator/operation.ex +++ b/lib/migration_generator/operation.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/migration_generator/phase.ex b/lib/migration_generator/phase.ex index 9b13dadd..28e380d9 100644 --- a/lib/migration_generator/phase.ex +++ b/lib/migration_generator/phase.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/helpers.ex b/lib/mix/helpers.ex index 51db8a64..be9b15ea 100644 --- a/lib/mix/helpers.ex +++ b/lib/mix/helpers.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.create.ex b/lib/mix/tasks/ash_postgres.create.ex index 61129c48..392f8d40 100644 --- a/lib/mix/tasks/ash_postgres.create.ex +++ b/lib/mix/tasks/ash_postgres.create.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.drop.ex b/lib/mix/tasks/ash_postgres.drop.ex index 2c50e9b3..9c3c3888 100644 --- a/lib/mix/tasks/ash_postgres.drop.ex +++ b/lib/mix/tasks/ash_postgres.drop.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.gen.resources.ex b/lib/mix/tasks/ash_postgres.gen.resources.ex index d207ea3f..1bd6125c 100644 --- a/lib/mix/tasks/ash_postgres.gen.resources.ex +++ b/lib/mix/tasks/ash_postgres.gen.resources.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.generate_migrations.ex b/lib/mix/tasks/ash_postgres.generate_migrations.ex index ca16404d..41936ce7 100644 --- a/lib/mix/tasks/ash_postgres.generate_migrations.ex +++ b/lib/mix/tasks/ash_postgres.generate_migrations.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.install.ex b/lib/mix/tasks/ash_postgres.install.ex index e7b6e0fb..321ac0e5 100644 --- a/lib/mix/tasks/ash_postgres.install.ex +++ b/lib/mix/tasks/ash_postgres.install.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.migrate.ex b/lib/mix/tasks/ash_postgres.migrate.ex index 601a5daf..9295d7d4 100644 --- a/lib/mix/tasks/ash_postgres.migrate.ex +++ b/lib/mix/tasks/ash_postgres.migrate.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.rollback.ex b/lib/mix/tasks/ash_postgres.rollback.ex index da11f74c..30e39780 100644 --- a/lib/mix/tasks/ash_postgres.rollback.ex +++ b/lib/mix/tasks/ash_postgres.rollback.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.setup_vector.ex b/lib/mix/tasks/ash_postgres.setup_vector.ex index 209c8241..80c12911 100644 --- a/lib/mix/tasks/ash_postgres.setup_vector.ex +++ b/lib/mix/tasks/ash_postgres.setup_vector.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/mix/tasks/ash_postgres.squash_snapshots.ex b/lib/mix/tasks/ash_postgres.squash_snapshots.ex index 8e40a597..8729d870 100644 --- a/lib/mix/tasks/ash_postgres.squash_snapshots.ex +++ b/lib/mix/tasks/ash_postgres.squash_snapshots.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/multitenancy.ex b/lib/multitenancy.ex index 5660e963..56d3f721 100644 --- a/lib/multitenancy.ex +++ b/lib/multitenancy.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/reference.ex b/lib/reference.ex index f22abc1f..68763581 100644 --- a/lib/reference.ex +++ b/lib/reference.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/repo.ex b/lib/repo.ex index fdc2d522..696c2442 100644 --- a/lib/repo.ex +++ b/lib/repo.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/repo/before_compile.ex b/lib/repo/before_compile.ex index c8306507..adb79837 100644 --- a/lib/repo/before_compile.ex +++ b/lib/repo/before_compile.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/resource_generator/resource_generator.ex b/lib/resource_generator/resource_generator.ex index 0f633f7b..b61a0f56 100644 --- a/lib/resource_generator/resource_generator.ex +++ b/lib/resource_generator/resource_generator.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/resource_generator/sensitive_data.ex b/lib/resource_generator/sensitive_data.ex index 30c94857..2adf0c18 100644 --- a/lib/resource_generator/sensitive_data.ex +++ b/lib/resource_generator/sensitive_data.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/resource_generator/spec.ex b/lib/resource_generator/spec.ex index c4d8088e..1a39a960 100644 --- a/lib/resource_generator/spec.ex +++ b/lib/resource_generator/spec.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 84d31935..3aed4340 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/statement.ex b/lib/statement.ex index 5902d730..926d6169 100644 --- a/lib/statement.ex +++ b/lib/statement.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/type.ex b/lib/type.ex index 88c6ef63..d0870002 100644 --- a/lib/type.ex +++ b/lib/type.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/types/ci_string_wrapper.ex b/lib/types/ci_string_wrapper.ex index 5c7bb8cb..b243f71e 100644 --- a/lib/types/ci_string_wrapper.ex +++ b/lib/types/ci_string_wrapper.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/types/ltree.ex b/lib/types/ltree.ex index 0997bdff..29d7f9f7 100644 --- a/lib/types/ltree.ex +++ b/lib/types/ltree.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/types/string_wrapper.ex b/lib/types/string_wrapper.ex index 5d8c33ea..18bedc34 100644 --- a/lib/types/string_wrapper.ex +++ b/lib/types/string_wrapper.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/types/timestamptz.ex b/lib/types/timestamptz.ex index c684751c..83746e1b 100644 --- a/lib/types/timestamptz.ex +++ b/lib/types/timestamptz.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/types/timestamptz_usec.ex b/lib/types/timestamptz_usec.ex index 8bd0a38d..6c998a00 100644 --- a/lib/types/timestamptz_usec.ex +++ b/lib/types/timestamptz_usec.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/types/tsquery.ex b/lib/types/tsquery.ex index 8e1fb7ad..d4a97470 100644 --- a/lib/types/tsquery.ex +++ b/lib/types/tsquery.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/types/tsvector.ex b/lib/types/tsvector.ex index 1a29a359..193a4c0b 100644 --- a/lib/types/tsvector.ex +++ b/lib/types/tsvector.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/verifiers/ensure_table_or_polymorphic.ex b/lib/verifiers/ensure_table_or_polymorphic.ex index 9c1d17bc..a4268f8c 100644 --- a/lib/verifiers/ensure_table_or_polymorphic.ex +++ b/lib/verifiers/ensure_table_or_polymorphic.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex b/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex index a595c95c..2ac5e693 100644 --- a/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex +++ b/lib/verifiers/prevent_attribute_multitenancy_and_non_full_match_type.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/verifiers/prevent_multidimensional_array_aggregates.ex b/lib/verifiers/prevent_multidimensional_array_aggregates.ex index 7589b277..f2c76924 100644 --- a/lib/verifiers/prevent_multidimensional_array_aggregates.ex +++ b/lib/verifiers/prevent_multidimensional_array_aggregates.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/verifiers/validate_identity_index_names.ex b/lib/verifiers/validate_identity_index_names.ex index 1c2fbad8..e5cf22c4 100644 --- a/lib/verifiers/validate_identity_index_names.ex +++ b/lib/verifiers/validate_identity_index_names.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/verifiers/validate_references.ex b/lib/verifiers/validate_references.ex index efcffd2d..50be8a30 100644 --- a/lib/verifiers/validate_references.ex +++ b/lib/verifiers/validate_references.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/lib/version_agent.ex b/lib/version_agent.ex index 0db6f4ff..da93d184 100644 --- a/lib/version_agent.ex +++ b/lib/version_agent.ex @@ -1,3 +1,3 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/logos/small-logo.png.license b/logos/small-logo.png.license index 815664f3..b0a44fab 100644 --- a/logos/small-logo.png.license +++ b/logos/small-logo.png.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/mix.exs b/mix.exs index 0bd7385a..2c0f979c 100644 --- a/mix.exs +++ b/mix.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/mix.lock.license b/mix.lock.license index 815664f3..b0a44fab 100644 --- a/mix.lock.license +++ b/mix.lock.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs b/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs index 57fc3e50..1b4d0d71 100644 --- a/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs +++ b/priv/dev_test_repo/migrations/20250526214825_migrate_resources_extensions_1.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs b/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs index bc0f2abf..da8cdb0f 100644 --- a/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs +++ b/priv/dev_test_repo/migrations/20250526214827_migrate_resources1.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/dev_test_repo/extensions.json.license b/priv/resource_snapshots/dev_test_repo/extensions.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/dev_test_repo/extensions.json.license +++ b/priv/resource_snapshots/dev_test_repo/extensions.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license b/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license +++ b/priv/resource_snapshots/dev_test_repo/multitenant_orgs/20250526214827.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license +++ b/priv/resource_snapshots/test_no_sandbox_repo/extensions.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/accounts/20221217123726.json.license b/priv/resource_snapshots/test_repo/accounts/20221217123726.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/accounts/20221217123726.json.license +++ b/priv/resource_snapshots/test_repo/accounts/20221217123726.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/accounts/20240327211150.json.license b/priv/resource_snapshots/test_repo/accounts/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/accounts/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/accounts/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20220805191443.json.license b/priv/resource_snapshots/test_repo/authors/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/authors/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/authors/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20220914104733.json.license b/priv/resource_snapshots/test_repo/authors/20220914104733.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/authors/20220914104733.json.license +++ b/priv/resource_snapshots/test_repo/authors/20220914104733.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20240327211150.json.license b/priv/resource_snapshots/test_repo/authors/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/authors/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/authors/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20240705113722.json.license b/priv/resource_snapshots/test_repo/authors/20240705113722.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/authors/20240705113722.json.license +++ b/priv/resource_snapshots/test_repo/authors/20240705113722.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20250908212414.json.license b/priv/resource_snapshots/test_repo/authors/20250908212414.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/authors/20250908212414.json.license +++ b/priv/resource_snapshots/test_repo/authors/20250908212414.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/chats/20250908093505.json.license b/priv/resource_snapshots/test_repo/chats/20250908093505.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/chats/20250908093505.json.license +++ b/priv/resource_snapshots/test_repo/chats/20250908093505.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license b/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license +++ b/priv/resource_snapshots/test_repo/co_authored_posts/20241208221219.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comedians/20241217232254.json.license b/priv/resource_snapshots/test_repo/comedians/20241217232254.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comedians/20241217232254.json.license +++ b/priv/resource_snapshots/test_repo/comedians/20241217232254.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comedians/20250413141328.json.license b/priv/resource_snapshots/test_repo/comedians/20250413141328.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comedians/20250413141328.json.license +++ b/priv/resource_snapshots/test_repo/comedians/20250413141328.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license b/priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license +++ b/priv/resource_snapshots/test_repo/comment_links/20250123161002.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license b/priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/comment_ratings/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license b/priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/comment_ratings/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comments/20220805191443.json.license b/priv/resource_snapshots/test_repo/comments/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comments/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/comments/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comments/20240327211150.json.license b/priv/resource_snapshots/test_repo/comments/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comments/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/comments/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/comments/20240327211917.json.license b/priv/resource_snapshots/test_repo/comments/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/comments/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/comments/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20230816231942.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20231116013020.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_certifications_channel_members/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license b/priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_channels/20231116013020.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_channels/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20230816231942.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_documentations/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license b/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_folder_items/20250714225304.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license b/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_folders/20250714225304.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license b/priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_skills/20230816231942.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license b/priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/complex_calculations_skills/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/content/20250123164209.json.license b/priv/resource_snapshots/test_repo/content/20250123164209.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/content/20250123164209.json.license +++ b/priv/resource_snapshots/test_repo/content/20250123164209.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license b/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license +++ b/priv/resource_snapshots/test_repo/content_visibility_group/20250123164209.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/csv/20250320225052.json.license b/priv/resource_snapshots/test_repo/csv/20250320225052.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/csv/20250320225052.json.license +++ b/priv/resource_snapshots/test_repo/csv/20250320225052.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/customers/20250908073737.json.license b/priv/resource_snapshots/test_repo/customers/20250908073737.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/customers/20250908073737.json.license +++ b/priv/resource_snapshots/test_repo/customers/20250908073737.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/entities/20240109160153.json.license b/priv/resource_snapshots/test_repo/entities/20240109160153.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/entities/20240109160153.json.license +++ b/priv/resource_snapshots/test_repo/entities/20240109160153.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/entities/20240327211150.json.license b/priv/resource_snapshots/test_repo/entities/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/entities/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/entities/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/entities/20240327211917.json.license b/priv/resource_snapshots/test_repo/entities/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/entities/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/entities/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/extensions.json.license b/priv/resource_snapshots/test_repo/extensions.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/extensions.json.license +++ b/priv/resource_snapshots/test_repo/extensions.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license b/priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/integer_posts/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/items/20240713134055.json.license b/priv/resource_snapshots/test_repo/items/20240713134055.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/items/20240713134055.json.license +++ b/priv/resource_snapshots/test_repo/items/20240713134055.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/items/20240717104854.json.license b/priv/resource_snapshots/test_repo/items/20240717104854.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/items/20240717104854.json.license +++ b/priv/resource_snapshots/test_repo/items/20240717104854.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/items/20240717153736.json.license b/priv/resource_snapshots/test_repo/items/20240717153736.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/items/20240717153736.json.license +++ b/priv/resource_snapshots/test_repo/items/20240717153736.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/jokes/20241217232254.json.license b/priv/resource_snapshots/test_repo/jokes/20241217232254.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/jokes/20241217232254.json.license +++ b/priv/resource_snapshots/test_repo/jokes/20241217232254.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/jokes/20250413141328.json.license b/priv/resource_snapshots/test_repo/jokes/20250413141328.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/jokes/20250413141328.json.license +++ b/priv/resource_snapshots/test_repo/jokes/20250413141328.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/managers/20230526144249.json.license b/priv/resource_snapshots/test_repo/managers/20230526144249.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/managers/20230526144249.json.license +++ b/priv/resource_snapshots/test_repo/managers/20230526144249.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/managers/20240327211150.json.license b/priv/resource_snapshots/test_repo/managers/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/managers/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/managers/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/messages/20250908093505.json.license b/priv/resource_snapshots/test_repo/messages/20250908093505.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/messages/20250908093505.json.license +++ b/priv/resource_snapshots/test_repo/messages/20250908093505.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license b/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license +++ b/priv/resource_snapshots/test_repo/multitenant_named_orgs/20250519103535.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240627223225.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240702164513.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license b/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license +++ b/priv/resource_snapshots/test_repo/multitenant_orgs/20240703155134.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license b/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license +++ b/priv/resource_snapshots/test_repo/non_multitenant_post_links/20250122190558.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/note/20250123164209.json.license b/priv/resource_snapshots/test_repo/note/20250123164209.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/note/20250123164209.json.license +++ b/priv/resource_snapshots/test_repo/note/20250123164209.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orders/20250908073737.json.license b/priv/resource_snapshots/test_repo/orders/20250908073737.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/orders/20250908073737.json.license +++ b/priv/resource_snapshots/test_repo/orders/20250908073737.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orgs/20230129050950.json.license b/priv/resource_snapshots/test_repo/orgs/20230129050950.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/orgs/20230129050950.json.license +++ b/priv/resource_snapshots/test_repo/orgs/20230129050950.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orgs/20240327211150.json.license b/priv/resource_snapshots/test_repo/orgs/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/orgs/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/orgs/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/orgs/20250210191116.json.license b/priv/resource_snapshots/test_repo/orgs/20250210191116.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/orgs/20250210191116.json.license +++ b/priv/resource_snapshots/test_repo/orgs/20250210191116.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/other_items/20240713134055.json.license b/priv/resource_snapshots/test_repo/other_items/20240713134055.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/other_items/20240713134055.json.license +++ b/priv/resource_snapshots/test_repo/other_items/20240713134055.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/other_items/20240717151815.json.license b/priv/resource_snapshots/test_repo/other_items/20240717151815.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/other_items/20240717151815.json.license +++ b/priv/resource_snapshots/test_repo/other_items/20240717151815.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/points/20250313112823.json.license b/priv/resource_snapshots/test_repo/points/20250313112823.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/points/20250313112823.json.license +++ b/priv/resource_snapshots/test_repo/points/20250313112823.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license b/priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license +++ b/priv/resource_snapshots/test_repo/post_followers/20240227180858.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license b/priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license +++ b/priv/resource_snapshots/test_repo/post_followers/20240227181137.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license b/priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/post_followers/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license b/priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license +++ b/priv/resource_snapshots/test_repo/post_followers/20240516205244.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license b/priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license +++ b/priv/resource_snapshots/test_repo/post_followers/20240517223946.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20220805191443.json.license b/priv/resource_snapshots/test_repo/post_links/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_links/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/post_links/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20221017133955.json.license b/priv/resource_snapshots/test_repo/post_links/20221017133955.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_links/20221017133955.json.license +++ b/priv/resource_snapshots/test_repo/post_links/20221017133955.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20221202194704.json.license b/priv/resource_snapshots/test_repo/post_links/20221202194704.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_links/20221202194704.json.license +++ b/priv/resource_snapshots/test_repo/post_links/20221202194704.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20240610195853.json.license b/priv/resource_snapshots/test_repo/post_links/20240610195853.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_links/20240610195853.json.license +++ b/priv/resource_snapshots/test_repo/post_links/20240610195853.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_links/20240617193218.json.license b/priv/resource_snapshots/test_repo/post_links/20240617193218.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_links/20240617193218.json.license +++ b/priv/resource_snapshots/test_repo/post_links/20240617193218.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license +++ b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license b/priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/post_ratings/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license b/priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/post_ratings/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license b/priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license +++ b/priv/resource_snapshots/test_repo/post_tags/20250810102512.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_views/20230905050351.json.license b/priv/resource_snapshots/test_repo/post_views/20230905050351.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_views/20230905050351.json.license +++ b/priv/resource_snapshots/test_repo/post_views/20230905050351.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/post_views/20240327211917.json.license b/priv/resource_snapshots/test_repo/post_views/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/post_views/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/post_views/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20220805191443.json.license b/priv/resource_snapshots/test_repo/posts/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/posts/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20221125171150.json.license b/priv/resource_snapshots/test_repo/posts/20221125171150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20221125171150.json.license +++ b/priv/resource_snapshots/test_repo/posts/20221125171150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20221125171204.json.license b/priv/resource_snapshots/test_repo/posts/20221125171204.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20221125171204.json.license +++ b/priv/resource_snapshots/test_repo/posts/20221125171204.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20230129050950.json.license b/priv/resource_snapshots/test_repo/posts/20230129050950.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20230129050950.json.license +++ b/priv/resource_snapshots/test_repo/posts/20230129050950.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20230823161017.json.license b/priv/resource_snapshots/test_repo/posts/20230823161017.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20230823161017.json.license +++ b/priv/resource_snapshots/test_repo/posts/20230823161017.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20231127215636.json.license b/priv/resource_snapshots/test_repo/posts/20231127215636.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20231127215636.json.license +++ b/priv/resource_snapshots/test_repo/posts/20231127215636.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20231129141453.json.license b/priv/resource_snapshots/test_repo/posts/20231129141453.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20231129141453.json.license +++ b/priv/resource_snapshots/test_repo/posts/20231129141453.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20231219132807.json.license b/priv/resource_snapshots/test_repo/posts/20231219132807.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20231219132807.json.license +++ b/priv/resource_snapshots/test_repo/posts/20231219132807.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240129221511.json.license b/priv/resource_snapshots/test_repo/posts/20240129221511.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240129221511.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240129221511.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240224001913.json.license b/priv/resource_snapshots/test_repo/posts/20240224001913.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240224001913.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240224001913.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240327211150.json.license b/priv/resource_snapshots/test_repo/posts/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240327211917.json.license b/priv/resource_snapshots/test_repo/posts/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240503012410.json.license b/priv/resource_snapshots/test_repo/posts/20240503012410.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240503012410.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240503012410.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240504185511.json.license b/priv/resource_snapshots/test_repo/posts/20240504185511.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240504185511.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240504185511.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240524031113.json.license b/priv/resource_snapshots/test_repo/posts/20240524031113.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240524031113.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240524031113.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240524041750.json.license b/priv/resource_snapshots/test_repo/posts/20240524041750.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240524041750.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240524041750.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240617193218.json.license b/priv/resource_snapshots/test_repo/posts/20240617193218.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240617193218.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240617193218.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240618102809.json.license b/priv/resource_snapshots/test_repo/posts/20240618102809.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240618102809.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240618102809.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240712232026.json.license b/priv/resource_snapshots/test_repo/posts/20240712232026.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240712232026.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240712232026.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240715135403.json.license b/priv/resource_snapshots/test_repo/posts/20240715135403.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240715135403.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240715135403.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240910180107.json.license b/priv/resource_snapshots/test_repo/posts/20240910180107.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240910180107.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240910180107.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240911225320.json.license b/priv/resource_snapshots/test_repo/posts/20240911225320.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240911225320.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240911225320.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240918104740.json.license b/priv/resource_snapshots/test_repo/posts/20240918104740.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240918104740.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240918104740.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20240929121224.json.license b/priv/resource_snapshots/test_repo/posts/20240929121224.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20240929121224.json.license +++ b/priv/resource_snapshots/test_repo/posts/20240929121224.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250217054207.json.license b/priv/resource_snapshots/test_repo/posts/20250217054207.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20250217054207.json.license +++ b/priv/resource_snapshots/test_repo/posts/20250217054207.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250313112823.json.license b/priv/resource_snapshots/test_repo/posts/20250313112823.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20250313112823.json.license +++ b/priv/resource_snapshots/test_repo/posts/20250313112823.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250520130634.json.license b/priv/resource_snapshots/test_repo/posts/20250520130634.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20250520130634.json.license +++ b/priv/resource_snapshots/test_repo/posts/20250520130634.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250521105654.json.license b/priv/resource_snapshots/test_repo/posts/20250521105654.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20250521105654.json.license +++ b/priv/resource_snapshots/test_repo/posts/20250521105654.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250612113920.json.license b/priv/resource_snapshots/test_repo/posts/20250612113920.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20250612113920.json.license +++ b/priv/resource_snapshots/test_repo/posts/20250612113920.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/posts/20250618011917.json.license b/priv/resource_snapshots/test_repo/posts/20250618011917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/posts/20250618011917.json.license +++ b/priv/resource_snapshots/test_repo/posts/20250618011917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/products/20250908073737.json.license b/priv/resource_snapshots/test_repo/products/20250908073737.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/products/20250908073737.json.license +++ b/priv/resource_snapshots/test_repo/products/20250908073737.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/profile/20220805191443.json.license b/priv/resource_snapshots/test_repo/profile/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/profile/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/profile/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license b/priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/profiles.profile/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license b/priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license +++ b/priv/resource_snapshots/test_repo/punchlines/20250413141328.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records/20240109160153.json.license b/priv/resource_snapshots/test_repo/records/20240109160153.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/records/20240109160153.json.license +++ b/priv/resource_snapshots/test_repo/records/20240109160153.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records/20240327211150.json.license b/priv/resource_snapshots/test_repo/records/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/records/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/records/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records/20240327211917.json.license b/priv/resource_snapshots/test_repo/records/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/records/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/records/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license b/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license +++ b/priv/resource_snapshots/test_repo/records_temp_entities/20250605230457.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license b/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license +++ b/priv/resource_snapshots/test_repo/relationship_items/20240717153736.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license b/priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license +++ b/priv/resource_snapshots/test_repo/rsvps/20251002180954.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license b/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license +++ b/priv/resource_snapshots/test_repo/schematic_groups/20240821213522.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license b/priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license +++ b/priv/resource_snapshots/test_repo/staff_group/20250123164209.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license b/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license +++ b/priv/resource_snapshots/test_repo/staff_group_member/20250123164209.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license b/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license +++ b/priv/resource_snapshots/test_repo/standup_clubs/20250413141328.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license b/priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license +++ b/priv/resource_snapshots/test_repo/stateful_post_followers/20240618085942.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/string_points/20250313112823.json.license b/priv/resource_snapshots/test_repo/string_points/20250313112823.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/string_points/20250313112823.json.license +++ b/priv/resource_snapshots/test_repo/string_points/20250313112823.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license b/priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license +++ b/priv/resource_snapshots/test_repo/sub_items/20240713134055.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license +++ b/priv/resource_snapshots/test_repo/subquery_access/20240130133933.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license +++ b/priv/resource_snapshots/test_repo/subquery_child/20240130133933.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license +++ b/priv/resource_snapshots/test_repo/subquery_parent/20240130133933.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license b/priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license +++ b/priv/resource_snapshots/test_repo/subquery_through/20240130133933.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tags/20250810102512.json.license b/priv/resource_snapshots/test_repo/tags/20250810102512.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tags/20250810102512.json.license +++ b/priv/resource_snapshots/test_repo/tags/20250810102512.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license +++ b/priv/resource_snapshots/test_repo/temp.temp_entities/20240327211917.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license b/priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license +++ b/priv/resource_snapshots/test_repo/temp_entities/20240109160153.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license +++ b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073135.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license +++ b/priv/resource_snapshots/test_repo/tenants/composite_key/20250220073141.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license b/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license +++ b/priv/resource_snapshots/test_repo/tenants/cross_tenant_post_links/20250122203454.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license b/priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license +++ b/priv/resource_snapshots/test_repo/tenants/friend_links/20240610162043.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license +++ b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20220805191441.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license +++ b/priv/resource_snapshots/test_repo/tenants/multitenant_posts/20240327211149.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license b/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license +++ b/priv/resource_snapshots/test_repo/tenants/non_multitenant_post_multitenant_links/20251001120813.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license +++ b/priv/resource_snapshots/test_repo/unrelated_profiles/20250731124648.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license +++ b/priv/resource_snapshots/test_repo/unrelated_reports/20250731124648.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license +++ b/priv/resource_snapshots/test_repo/unrelated_secure_profiles/20250731124648.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license b/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license +++ b/priv/resource_snapshots/test_repo/unrelated_users/20250731124648.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license b/priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license +++ b/priv/resource_snapshots/test_repo/user_invites/20240727145758.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20220805191443.json.license b/priv/resource_snapshots/test_repo/users/20220805191443.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20220805191443.json.license +++ b/priv/resource_snapshots/test_repo/users/20220805191443.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20221217123726.json.license b/priv/resource_snapshots/test_repo/users/20221217123726.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20221217123726.json.license +++ b/priv/resource_snapshots/test_repo/users/20221217123726.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20230129050950.json.license b/priv/resource_snapshots/test_repo/users/20230129050950.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20230129050950.json.license +++ b/priv/resource_snapshots/test_repo/users/20230129050950.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20240327211150.json.license b/priv/resource_snapshots/test_repo/users/20240327211150.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20240327211150.json.license +++ b/priv/resource_snapshots/test_repo/users/20240327211150.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20240727145758.json.license b/priv/resource_snapshots/test_repo/users/20240727145758.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20240727145758.json.license +++ b/priv/resource_snapshots/test_repo/users/20240727145758.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20240929124728.json.license b/priv/resource_snapshots/test_repo/users/20240929124728.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20240929124728.json.license +++ b/priv/resource_snapshots/test_repo/users/20240929124728.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20250320225052.json.license b/priv/resource_snapshots/test_repo/users/20250320225052.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20250320225052.json.license +++ b/priv/resource_snapshots/test_repo/users/20250320225052.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/users/20250321142835.json.license b/priv/resource_snapshots/test_repo/users/20250321142835.json.license index 815664f3..b0a44fab 100644 --- a/priv/resource_snapshots/test_repo/users/20250321142835.json.license +++ b/priv/resource_snapshots/test_repo/users/20250321142835.json.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/test_no_sandbox_repo/migrations/.gitkeep.license b/priv/test_no_sandbox_repo/migrations/.gitkeep.license index 815664f3..b0a44fab 100644 --- a/priv/test_no_sandbox_repo/migrations/.gitkeep.license +++ b/priv/test_no_sandbox_repo/migrations/.gitkeep.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2020 Zach Daniel +SPDX-FileCopyrightText: 2019 ash_postgres contributors SPDX-License-Identifier: MIT diff --git a/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs b/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs index 94e450c6..f64c49e7 100644 --- a/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs +++ b/priv/test_no_sandbox_repo/migrations/20240627223224_install_5_extensions.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs b/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs index ecf0a75f..3b0c3d9d 100644 --- a/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs +++ b/priv/test_no_sandbox_repo/migrations/20240712232025_install_ash-functions_extension_4.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs b/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs index 01697a60..8ab2eb47 100644 --- a/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs +++ b/priv/test_no_sandbox_repo/migrations/20250113205301_migrate_resources_extensions_1.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20220805191440_install_4_extensions.exs b/priv/test_repo/migrations/20220805191440_install_4_extensions.exs index a20aa8e9..a1d465dc 100644 --- a/priv/test_repo/migrations/20220805191440_install_4_extensions.exs +++ b/priv/test_repo/migrations/20220805191440_install_4_extensions.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -88,4 +88,4 @@ defmodule AshPostgres.TestRepo.Migrations.Install4Extensions do # execute("DROP EXTENSION IF EXISTS \"pg_trgm\"") # execute("DROP EXTENSION IF EXISTS \"citext\"") end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20220805191443_migrate_resources1.exs b/priv/test_repo/migrations/20220805191443_migrate_resources1.exs index b9b7fdd0..8cb31e0c 100644 --- a/priv/test_repo/migrations/20220805191443_migrate_resources1.exs +++ b/priv/test_repo/migrations/20220805191443_migrate_resources1.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20220914104733_migrate_resources2.exs b/priv/test_repo/migrations/20220914104733_migrate_resources2.exs index fbbeb8e0..b7da4e0d 100644 --- a/priv/test_repo/migrations/20220914104733_migrate_resources2.exs +++ b/priv/test_repo/migrations/20220914104733_migrate_resources2.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources2 do remove :badges end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20221017133955_migrate_resources3.exs b/priv/test_repo/migrations/20221017133955_migrate_resources3.exs index 12f282d6..f0593998 100644 --- a/priv/test_repo/migrations/20221017133955_migrate_resources3.exs +++ b/priv/test_repo/migrations/20221017133955_migrate_resources3.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources3 do name: "post_links_unique_link_index" ) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20221125171148_migrate_resources4.exs b/priv/test_repo/migrations/20221125171148_migrate_resources4.exs index b6749230..9e65c9a7 100644 --- a/priv/test_repo/migrations/20221125171148_migrate_resources4.exs +++ b/priv/test_repo/migrations/20221125171148_migrate_resources4.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -24,4 +24,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources4 do remove :uniq_custom_one end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20221125171150_migrate_resources5.exs b/priv/test_repo/migrations/20221125171150_migrate_resources5.exs index f4d14b56..acccc8af 100644 --- a/priv/test_repo/migrations/20221125171150_migrate_resources5.exs +++ b/priv/test_repo/migrations/20221125171150_migrate_resources5.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -23,4 +23,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources5 do name: "posts_uniq_custom_one_uniq_custom_two_index" ) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20221202194704_migrate_resources6.exs b/priv/test_repo/migrations/20221202194704_migrate_resources6.exs index 6b6f174a..57200540 100644 --- a/priv/test_repo/migrations/20221202194704_migrate_resources6.exs +++ b/priv/test_repo/migrations/20221202194704_migrate_resources6.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources6 do remove :state end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20221217123726_migrate_resources7.exs b/priv/test_repo/migrations/20221217123726_migrate_resources7.exs index 95edab52..2793bd5c 100644 --- a/priv/test_repo/migrations/20221217123726_migrate_resources7.exs +++ b/priv/test_repo/migrations/20221217123726_migrate_resources7.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -39,4 +39,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources7 do remove :is_active end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20230129050950_migrate_resources8.exs b/priv/test_repo/migrations/20230129050950_migrate_resources8.exs index 3aba9340..30a4ab95 100644 --- a/priv/test_repo/migrations/20230129050950_migrate_resources8.exs +++ b/priv/test_repo/migrations/20230129050950_migrate_resources8.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -76,4 +76,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources8 do remove :organization_id end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20230526144249_migrate_resources9.exs b/priv/test_repo/migrations/20230526144249_migrate_resources9.exs index d3a907b8..1ff50786 100644 --- a/priv/test_repo/migrations/20230526144249_migrate_resources9.exs +++ b/priv/test_repo/migrations/20230526144249_migrate_resources9.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -38,4 +38,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources9 do drop table(:managers) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs b/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs index 6f9ee9e4..9aad4684 100644 --- a/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs +++ b/priv/test_repo/migrations/20230712182523_install_ash-functions_extension.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs b/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs index edfac408..79f9f0d0 100644 --- a/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs +++ b/priv/test_repo/migrations/20230804223759_install_demo-functions_v0_extension.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -27,4 +27,4 @@ defmodule AshPostgres.TestRepo.Migrations.InstallDemoFunctionsV0 do DROP FUNCTION IF EXISTS ash_demo_functions() """) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs b/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs index 2222a781..5b88cec1 100644 --- a/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs +++ b/priv/test_repo/migrations/20230804223818_install_demo-functions_v1_extension.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -27,4 +27,4 @@ defmodule AshPostgres.TestRepo.Migrations.InstallDemoFunctionsV1 do DROP FUNCTION IF EXISTS ash_demo_functions() """) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs b/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs index 1cc444b7..4070e6d3 100644 --- a/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs +++ b/priv/test_repo/migrations/20230816231942_add_complex_calculation_tables.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -70,4 +70,4 @@ defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationTables do drop table(:complex_calculations_skills) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20230823161017_migrate_resources10.exs b/priv/test_repo/migrations/20230823161017_migrate_resources10.exs index 18e6f479..6cf19472 100644 --- a/priv/test_repo/migrations/20230823161017_migrate_resources10.exs +++ b/priv/test_repo/migrations/20230823161017_migrate_resources10.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources10 do remove :stuff end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20230905050351_add_post_views.exs b/priv/test_repo/migrations/20230905050351_add_post_views.exs index 3ea0cbb1..e19c1d62 100644 --- a/priv/test_repo/migrations/20230905050351_add_post_views.exs +++ b/priv/test_repo/migrations/20230905050351_add_post_views.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.AddPostViews do def down do drop table(:post_views) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs b/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs index c3f768f0..29045f0f 100644 --- a/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs +++ b/priv/test_repo/migrations/20231116013020_add_complex_calculations_channels.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -56,4 +56,4 @@ defmodule AshPostgres.TestRepo.Migrations.AddComplexCalculationsChannels do drop table(:complex_calculations_channels) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20231127212608_add_composite_type.exs b/priv/test_repo/migrations/20231127212608_add_composite_type.exs index 8a85a46f..1ae28125 100644 --- a/priv/test_repo/migrations/20231127212608_add_composite_type.exs +++ b/priv/test_repo/migrations/20231127212608_add_composite_type.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20231127215636_migrate_resources11.exs b/priv/test_repo/migrations/20231127215636_migrate_resources11.exs index c4da8e77..97ce50c1 100644 --- a/priv/test_repo/migrations/20231127215636_migrate_resources11.exs +++ b/priv/test_repo/migrations/20231127215636_migrate_resources11.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20231129141453_migrate_resources12.exs b/priv/test_repo/migrations/20231129141453_migrate_resources12.exs index 613a6b42..0063cd3e 100644 --- a/priv/test_repo/migrations/20231129141453_migrate_resources12.exs +++ b/priv/test_repo/migrations/20231129141453_migrate_resources12.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources12 do modify :composite_point, :point end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs b/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs index e02f5467..8b3a89f4 100644 --- a/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs +++ b/priv/test_repo/migrations/20231214220937_install_ash-functions_extension_2.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20231219132807_migrate_resources13.exs b/priv/test_repo/migrations/20231219132807_migrate_resources13.exs index 55fc4bbe..b73022f0 100644 --- a/priv/test_repo/migrations/20231219132807_migrate_resources13.exs +++ b/priv/test_repo/migrations/20231219132807_migrate_resources13.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -18,4 +18,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources13 do def down do rename table(:posts), :title_column, to: :title end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs b/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs index e841dfba..75e5d807 100644 --- a/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs +++ b/priv/test_repo/migrations/20231231051611_install_ash-functions_extension_3.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -64,4 +64,4 @@ defmodule AshPostgres.TestRepo.Migrations.InstallAshFunctionsExtension3 do $$ LANGUAGE plpgsql; """) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20240109155951_create_temp_schema.exs b/priv/test_repo/migrations/20240109155951_create_temp_schema.exs index ada02c90..c528b9d0 100644 --- a/priv/test_repo/migrations/20240109155951_create_temp_schema.exs +++ b/priv/test_repo/migrations/20240109155951_create_temp_schema.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240109160153_migrate_resources14.exs b/priv/test_repo/migrations/20240109160153_migrate_resources14.exs index c70f9357..de65bcfa 100644 --- a/priv/test_repo/migrations/20240109160153_migrate_resources14.exs +++ b/priv/test_repo/migrations/20240109160153_migrate_resources14.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -41,4 +41,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources14 do drop table(:temp_entities, prefix: "temp") end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20240129221511_migrate_resources15.exs b/priv/test_repo/migrations/20240129221511_migrate_resources15.exs index 88ae8d08..6f8f055a 100644 --- a/priv/test_repo/migrations/20240129221511_migrate_resources15.exs +++ b/priv/test_repo/migrations/20240129221511_migrate_resources15.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources15 do remove :list_containing_nils end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs b/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs index 36ad998e..4d45ac33 100644 --- a/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs +++ b/priv/test_repo/migrations/20240130133933_add_resources_for_subquery_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240224001913_migrate_resources16.exs b/priv/test_repo/migrations/20240224001913_migrate_resources16.exs index 00decc17..f3b7a8ed 100644 --- a/priv/test_repo/migrations/20240224001913_migrate_resources16.exs +++ b/priv/test_repo/migrations/20240224001913_migrate_resources16.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -22,4 +22,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources16 do remove :list_of_stuff end end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20240227180858_migrate_resources17.exs b/priv/test_repo/migrations/20240227180858_migrate_resources17.exs index 93fc8bd5..f59df09c 100644 --- a/priv/test_repo/migrations/20240227180858_migrate_resources17.exs +++ b/priv/test_repo/migrations/20240227180858_migrate_resources17.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -42,4 +42,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources17 do drop table(:post_followers) end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20240227181137_migrate_resources18.exs b/priv/test_repo/migrations/20240227181137_migrate_resources18.exs index 4e6db225..7e831d9e 100644 --- a/priv/test_repo/migrations/20240227181137_migrate_resources18.exs +++ b/priv/test_repo/migrations/20240227181137_migrate_resources18.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -46,4 +46,4 @@ defmodule AshPostgres.TestRepo.Migrations.MigrateResources18 do rename table(:post_followers), :follower_id, to: :user_id end -end \ No newline at end of file +end diff --git a/priv/test_repo/migrations/20240229050455_install_5_extensions.exs b/priv/test_repo/migrations/20240229050455_install_5_extensions.exs index bdecc817..4bb4f7fa 100644 --- a/priv/test_repo/migrations/20240229050455_install_5_extensions.exs +++ b/priv/test_repo/migrations/20240229050455_install_5_extensions.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240327211150_migrate_resources19.exs b/priv/test_repo/migrations/20240327211150_migrate_resources19.exs index 7fc2c8c3..100d11a9 100644 --- a/priv/test_repo/migrations/20240327211150_migrate_resources19.exs +++ b/priv/test_repo/migrations/20240327211150_migrate_resources19.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240327211917_migrate_resources20.exs b/priv/test_repo/migrations/20240327211917_migrate_resources20.exs index bd30cc5b..8358e319 100644 --- a/priv/test_repo/migrations/20240327211917_migrate_resources20.exs +++ b/priv/test_repo/migrations/20240327211917_migrate_resources20.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240503012410_migrate_resources21.exs b/priv/test_repo/migrations/20240503012410_migrate_resources21.exs index 9230a78a..7f66c108 100644 --- a/priv/test_repo/migrations/20240503012410_migrate_resources21.exs +++ b/priv/test_repo/migrations/20240503012410_migrate_resources21.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240504185511_migrate_resources22.exs b/priv/test_repo/migrations/20240504185511_migrate_resources22.exs index 19ae6c87..ef35bc07 100644 --- a/priv/test_repo/migrations/20240504185511_migrate_resources22.exs +++ b/priv/test_repo/migrations/20240504185511_migrate_resources22.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240516205244_migrate_resources23.exs b/priv/test_repo/migrations/20240516205244_migrate_resources23.exs index cebacd08..1ee5dfad 100644 --- a/priv/test_repo/migrations/20240516205244_migrate_resources23.exs +++ b/priv/test_repo/migrations/20240516205244_migrate_resources23.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240517223946_migrate_resources24.exs b/priv/test_repo/migrations/20240517223946_migrate_resources24.exs index 09e71bd5..e7f09782 100644 --- a/priv/test_repo/migrations/20240517223946_migrate_resources24.exs +++ b/priv/test_repo/migrations/20240517223946_migrate_resources24.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240524031113_migrate_resources25.exs b/priv/test_repo/migrations/20240524031113_migrate_resources25.exs index 0b829659..38e5384f 100644 --- a/priv/test_repo/migrations/20240524031113_migrate_resources25.exs +++ b/priv/test_repo/migrations/20240524031113_migrate_resources25.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240524041750_migrate_resources26.exs b/priv/test_repo/migrations/20240524041750_migrate_resources26.exs index e27aff26..255bf9c9 100644 --- a/priv/test_repo/migrations/20240524041750_migrate_resources26.exs +++ b/priv/test_repo/migrations/20240524041750_migrate_resources26.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240610195853_migrate_resources27.exs b/priv/test_repo/migrations/20240610195853_migrate_resources27.exs index f156231e..e22c4de7 100644 --- a/priv/test_repo/migrations/20240610195853_migrate_resources27.exs +++ b/priv/test_repo/migrations/20240610195853_migrate_resources27.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240617193218_migrate_resources28.exs b/priv/test_repo/migrations/20240617193218_migrate_resources28.exs index d864e25b..019a5dbe 100644 --- a/priv/test_repo/migrations/20240617193218_migrate_resources28.exs +++ b/priv/test_repo/migrations/20240617193218_migrate_resources28.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240618085942_migrate_resources29.exs b/priv/test_repo/migrations/20240618085942_migrate_resources29.exs index 0c6b8de3..9c8fbf81 100644 --- a/priv/test_repo/migrations/20240618085942_migrate_resources29.exs +++ b/priv/test_repo/migrations/20240618085942_migrate_resources29.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240618102809_migrate_resources30.exs b/priv/test_repo/migrations/20240618102809_migrate_resources30.exs index 4d1f8ad8..37399ecc 100644 --- a/priv/test_repo/migrations/20240618102809_migrate_resources30.exs +++ b/priv/test_repo/migrations/20240618102809_migrate_resources30.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs b/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs index 3a544490..d4ce735f 100644 --- a/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs +++ b/priv/test_repo/migrations/20240622192715_install_ash-functions_extension_4.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240627223225_migrate_resources31.exs b/priv/test_repo/migrations/20240627223225_migrate_resources31.exs index cd97c368..7b9f813b 100644 --- a/priv/test_repo/migrations/20240627223225_migrate_resources31.exs +++ b/priv/test_repo/migrations/20240627223225_migrate_resources31.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240703155134_migrate_resources32.exs b/priv/test_repo/migrations/20240703155134_migrate_resources32.exs index 1364a828..1895ad19 100644 --- a/priv/test_repo/migrations/20240703155134_migrate_resources32.exs +++ b/priv/test_repo/migrations/20240703155134_migrate_resources32.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240705113722_migrate_resources33.exs b/priv/test_repo/migrations/20240705113722_migrate_resources33.exs index e6f7a1a8..adf3fa29 100644 --- a/priv/test_repo/migrations/20240705113722_migrate_resources33.exs +++ b/priv/test_repo/migrations/20240705113722_migrate_resources33.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240712232026_migrate_resources34.exs b/priv/test_repo/migrations/20240712232026_migrate_resources34.exs index 22af731f..da51100e 100644 --- a/priv/test_repo/migrations/20240712232026_migrate_resources34.exs +++ b/priv/test_repo/migrations/20240712232026_migrate_resources34.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs b/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs index d6c57db6..60a98ad1 100644 --- a/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs +++ b/priv/test_repo/migrations/20240713134055_multi_domain_calculations.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240715135403_migrate_resources35.exs b/priv/test_repo/migrations/20240715135403_migrate_resources35.exs index 2349c59d..a818451a 100644 --- a/priv/test_repo/migrations/20240715135403_migrate_resources35.exs +++ b/priv/test_repo/migrations/20240715135403_migrate_resources35.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs b/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs index 2c9269fa..7d0b19b7 100644 --- a/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs +++ b/priv/test_repo/migrations/20240717104854_no_attributes_calculation_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240717151815_migrate_resources36.exs b/priv/test_repo/migrations/20240717151815_migrate_resources36.exs index e8b21183..df6b0087 100644 --- a/priv/test_repo/migrations/20240717151815_migrate_resources36.exs +++ b/priv/test_repo/migrations/20240717151815_migrate_resources36.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240717153736_migrate_resources37.exs b/priv/test_repo/migrations/20240717153736_migrate_resources37.exs index 4d5777a4..8e14b6ce 100644 --- a/priv/test_repo/migrations/20240717153736_migrate_resources37.exs +++ b/priv/test_repo/migrations/20240717153736_migrate_resources37.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240727145758_user_invites.exs b/priv/test_repo/migrations/20240727145758_user_invites.exs index c054a440..61c522bc 100644 --- a/priv/test_repo/migrations/20240727145758_user_invites.exs +++ b/priv/test_repo/migrations/20240727145758_user_invites.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240906170759_migrate_resources38.exs b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs index 78637f88..7a7ab279 100644 --- a/priv/test_repo/migrations/20240906170759_migrate_resources38.exs +++ b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240910180107_migrate_resources39.exs b/priv/test_repo/migrations/20240910180107_migrate_resources39.exs index dc7f6502..da7e7728 100644 --- a/priv/test_repo/migrations/20240910180107_migrate_resources39.exs +++ b/priv/test_repo/migrations/20240910180107_migrate_resources39.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240911225319_install_1_extensions.exs b/priv/test_repo/migrations/20240911225319_install_1_extensions.exs index dede4e89..2bac3ea7 100644 --- a/priv/test_repo/migrations/20240911225319_install_1_extensions.exs +++ b/priv/test_repo/migrations/20240911225319_install_1_extensions.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240911225320_migrate_resources40.exs b/priv/test_repo/migrations/20240911225320_migrate_resources40.exs index fd10a2f0..95f01067 100644 --- a/priv/test_repo/migrations/20240911225320_migrate_resources40.exs +++ b/priv/test_repo/migrations/20240911225320_migrate_resources40.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240918104740_migrate_resources41.exs b/priv/test_repo/migrations/20240918104740_migrate_resources41.exs index 41ce709a..3d604b97 100644 --- a/priv/test_repo/migrations/20240918104740_migrate_resources41.exs +++ b/priv/test_repo/migrations/20240918104740_migrate_resources41.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240929121224_migrate_resources42.exs b/priv/test_repo/migrations/20240929121224_migrate_resources42.exs index 23a14e4a..91c49fb4 100644 --- a/priv/test_repo/migrations/20240929121224_migrate_resources42.exs +++ b/priv/test_repo/migrations/20240929121224_migrate_resources42.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20240929124728_migrate_resources43.exs b/priv/test_repo/migrations/20240929124728_migrate_resources43.exs index c91d401a..86b28970 100644 --- a/priv/test_repo/migrations/20240929124728_migrate_resources43.exs +++ b/priv/test_repo/migrations/20240929124728_migrate_resources43.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20241208221219_migrate_resources44.exs b/priv/test_repo/migrations/20241208221219_migrate_resources44.exs index af546799..35a52b61 100644 --- a/priv/test_repo/migrations/20241208221219_migrate_resources44.exs +++ b/priv/test_repo/migrations/20241208221219_migrate_resources44.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20241217232254_migrate_resources45.exs b/priv/test_repo/migrations/20241217232254_migrate_resources45.exs index 94454ef2..c44417ca 100644 --- a/priv/test_repo/migrations/20241217232254_migrate_resources45.exs +++ b/priv/test_repo/migrations/20241217232254_migrate_resources45.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs b/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs index 68c52ef7..842097ce 100644 --- a/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs +++ b/priv/test_repo/migrations/20250113205259_migrate_resources_extensions_1.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250122190558_migrate_resources46.exs b/priv/test_repo/migrations/20250122190558_migrate_resources46.exs index c9cfed58..a4455b1b 100644 --- a/priv/test_repo/migrations/20250122190558_migrate_resources46.exs +++ b/priv/test_repo/migrations/20250122190558_migrate_resources46.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250123161002_migrate_resources47.exs b/priv/test_repo/migrations/20250123161002_migrate_resources47.exs index 32e5ff54..582a215e 100644 --- a/priv/test_repo/migrations/20250123161002_migrate_resources47.exs +++ b/priv/test_repo/migrations/20250123161002_migrate_resources47.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250123164209_migrate_resources48.exs b/priv/test_repo/migrations/20250123164209_migrate_resources48.exs index b07394fb..8f4eccef 100644 --- a/priv/test_repo/migrations/20250123164209_migrate_resources48.exs +++ b/priv/test_repo/migrations/20250123164209_migrate_resources48.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250210191116_migrate_resources49.exs b/priv/test_repo/migrations/20250210191116_migrate_resources49.exs index f147420b..1df9270e 100644 --- a/priv/test_repo/migrations/20250210191116_migrate_resources49.exs +++ b/priv/test_repo/migrations/20250210191116_migrate_resources49.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250217054207_migrate_resources50.exs b/priv/test_repo/migrations/20250217054207_migrate_resources50.exs index 1ea35a4a..7d077e11 100644 --- a/priv/test_repo/migrations/20250217054207_migrate_resources50.exs +++ b/priv/test_repo/migrations/20250217054207_migrate_resources50.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250313112823_migrate_resources51.exs b/priv/test_repo/migrations/20250313112823_migrate_resources51.exs index 37609641..98fd8624 100644 --- a/priv/test_repo/migrations/20250313112823_migrate_resources51.exs +++ b/priv/test_repo/migrations/20250313112823_migrate_resources51.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250320225052_add_csv_resource.exs b/priv/test_repo/migrations/20250320225052_add_csv_resource.exs index 11159d77..e1d72242 100644 --- a/priv/test_repo/migrations/20250320225052_add_csv_resource.exs +++ b/priv/test_repo/migrations/20250320225052_add_csv_resource.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250321142835_migrate_resources52.exs b/priv/test_repo/migrations/20250321142835_migrate_resources52.exs index 68ee928c..7856790b 100644 --- a/priv/test_repo/migrations/20250321142835_migrate_resources52.exs +++ b/priv/test_repo/migrations/20250321142835_migrate_resources52.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs b/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs index ff4a368c..638be99f 100644 --- a/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs +++ b/priv/test_repo/migrations/20250413141328_add_punchlines_and_standup_clubs.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250519103535_migrate_resources53.exs b/priv/test_repo/migrations/20250519103535_migrate_resources53.exs index cabe0ee7..3f56a6cb 100644 --- a/priv/test_repo/migrations/20250519103535_migrate_resources53.exs +++ b/priv/test_repo/migrations/20250519103535_migrate_resources53.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250520130634_migrate_resources54.exs b/priv/test_repo/migrations/20250520130634_migrate_resources54.exs index 063d79b9..e70723cd 100644 --- a/priv/test_repo/migrations/20250520130634_migrate_resources54.exs +++ b/priv/test_repo/migrations/20250520130634_migrate_resources54.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs b/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs index 734de6d5..ccc88809 100644 --- a/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs +++ b/priv/test_repo/migrations/20250521105654_add_model_tuple_to_post.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs b/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs index 90c3fcba..264c19e2 100644 --- a/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs +++ b/priv/test_repo/migrations/20250605230457_create_record_temp_entities_table.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250612113920_migrate_resources55.exs b/priv/test_repo/migrations/20250612113920_migrate_resources55.exs index b91c4fa9..7ab54998 100644 --- a/priv/test_repo/migrations/20250612113920_migrate_resources55.exs +++ b/priv/test_repo/migrations/20250612113920_migrate_resources55.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250618011917_migrate_resources56.exs b/priv/test_repo/migrations/20250618011917_migrate_resources56.exs index 97d68971..5c4105b3 100644 --- a/priv/test_repo/migrations/20250618011917_migrate_resources56.exs +++ b/priv/test_repo/migrations/20250618011917_migrate_resources56.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs b/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs index fdcd91e4..16dd2efc 100644 --- a/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs +++ b/priv/test_repo/migrations/20250714225304_add_complex_calculations_folder_and_items.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250731124648_migrate_resources57.exs b/priv/test_repo/migrations/20250731124648_migrate_resources57.exs index 3fea4408..2c54e133 100644 --- a/priv/test_repo/migrations/20250731124648_migrate_resources57.exs +++ b/priv/test_repo/migrations/20250731124648_migrate_resources57.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250810102512_migrate_resources58.exs b/priv/test_repo/migrations/20250810102512_migrate_resources58.exs index de4bbd5a..592824b4 100644 --- a/priv/test_repo/migrations/20250810102512_migrate_resources58.exs +++ b/priv/test_repo/migrations/20250810102512_migrate_resources58.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250908073737_migrate_resources59.exs b/priv/test_repo/migrations/20250908073737_migrate_resources59.exs index dee8b387..962338ef 100644 --- a/priv/test_repo/migrations/20250908073737_migrate_resources59.exs +++ b/priv/test_repo/migrations/20250908073737_migrate_resources59.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250908093505_migrate_resources60.exs b/priv/test_repo/migrations/20250908093505_migrate_resources60.exs index d3747224..f3137214 100644 --- a/priv/test_repo/migrations/20250908093505_migrate_resources60.exs +++ b/priv/test_repo/migrations/20250908093505_migrate_resources60.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20250908212414_migrate_resources61.exs b/priv/test_repo/migrations/20250908212414_migrate_resources61.exs index 2bd3d6bf..9730c75e 100644 --- a/priv/test_repo/migrations/20250908212414_migrate_resources61.exs +++ b/priv/test_repo/migrations/20250908212414_migrate_resources61.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20251002180954_migrate_resources62.exs b/priv/test_repo/migrations/20251002180954_migrate_resources62.exs index 8fd9c180..9c2dd09c 100644 --- a/priv/test_repo/migrations/20251002180954_migrate_resources62.exs +++ b/priv/test_repo/migrations/20251002180954_migrate_resources62.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs b/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs index 5a5bd69b..6ef57f23 100644 --- a/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs +++ b/priv/test_repo/tenant_migrations/20220805191441_migrate_resources1.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT @@ -41,4 +41,4 @@ defmodule AshPostgres.TestRepo.TenantMigrations.MigrateResources1 do drop table(:multitenant_posts, prefix: prefix()) end -end \ No newline at end of file +end diff --git a/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs b/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs index 56751e6c..a97ed282 100644 --- a/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs +++ b/priv/test_repo/tenant_migrations/20240327211149_migrate_resources2.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs b/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs index 8c913034..795b70c4 100644 --- a/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs +++ b/priv/test_repo/tenant_migrations/20240610162043_migrate_resources3.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs b/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs index ab537413..b4b10a97 100644 --- a/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs +++ b/priv/test_repo/tenant_migrations/20250122203454_migrate_resources4.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs b/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs index 2a52a954..881bde93 100644 --- a/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs +++ b/priv/test_repo/tenant_migrations/20250220073135_migrate_resources5.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs b/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs index 18a7fdfd..a195cfce 100644 --- a/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs +++ b/priv/test_repo/tenant_migrations/20250220073141_migrate_resources6.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs b/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs index 6170f2f2..85509bbf 100644 --- a/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs +++ b/priv/test_repo/tenant_migrations/20251001120813_migrate_resources7.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/aggregate_test.exs b/test/aggregate_test.exs index 3e64440f..ad66b36e 100644 --- a/test/aggregate_test.exs +++ b/test/aggregate_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/ash_postgres_test.exs b/test/ash_postgres_test.exs index 41c46e31..cfb6b0d7 100644 --- a/test/ash_postgres_test.exs +++ b/test/ash_postgres_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/atomics_test.exs b/test/atomics_test.exs index b9443acf..d5680ac8 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index 420ff219..296742fd 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/bulk_destroy_test.exs b/test/bulk_destroy_test.exs index 24cf2395..cd07a684 100644 --- a/test/bulk_destroy_test.exs +++ b/test/bulk_destroy_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/bulk_update_test.exs b/test/bulk_update_test.exs index 38ce2f45..4dc7dc30 100644 --- a/test/bulk_update_test.exs +++ b/test/bulk_update_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 38e4cf5b..cdad5c18 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/cascade_destroy_test.exs b/test/cascade_destroy_test.exs index 062e0378..aa9408ac 100644 --- a/test/cascade_destroy_test.exs +++ b/test/cascade_destroy_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/combination_test.exs b/test/combination_test.exs index fdb55d35..c1143721 100644 --- a/test/combination_test.exs +++ b/test/combination_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index 815071f7..39cccefc 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/composite_type_test.exs b/test/composite_type_test.exs index 7e73e198..edf1af9c 100644 --- a/test/composite_type_test.exs +++ b/test/composite_type_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/constraint_test.exs b/test/constraint_test.exs index 7c63f3c5..5266f194 100644 --- a/test/constraint_test.exs +++ b/test/constraint_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/create_test.exs b/test/create_test.exs index 92effd16..e605910f 100644 --- a/test/create_test.exs +++ b/test/create_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/custom_expression_test.exs b/test/custom_expression_test.exs index 7f204eef..959cbd89 100644 --- a/test/custom_expression_test.exs +++ b/test/custom_expression_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/custom_index_test.exs b/test/custom_index_test.exs index 9d02b655..7e866f62 100644 --- a/test/custom_index_test.exs +++ b/test/custom_index_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs index 02d702f5..d0911302 100644 --- a/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs +++ b/test/cve/empty_atomic_non_bulk_actions_policy_bypass_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/destroy_test.exs b/test/destroy_test.exs index 208b2038..65ee4365 100644 --- a/test/destroy_test.exs +++ b/test/destroy_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/dev_migrations_test.exs b/test/dev_migrations_test.exs index 64cbb7c1..5716fffb 100644 --- a/test/dev_migrations_test.exs +++ b/test/dev_migrations_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/distinct_test.exs b/test/distinct_test.exs index a616cac8..8e7ccaac 100644 --- a/test/distinct_test.exs +++ b/test/distinct_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/ecto_compatibility_test.exs b/test/ecto_compatibility_test.exs index 3670d021..178ea920 100644 --- a/test/ecto_compatibility_test.exs +++ b/test/ecto_compatibility_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/embeddable_resource_test.exs b/test/embeddable_resource_test.exs index d30c11c3..ba2609b0 100644 --- a/test/embeddable_resource_test.exs +++ b/test/embeddable_resource_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/enum_test.exs b/test/enum_test.exs index 0dea90a8..07ee697d 100644 --- a/test/enum_test.exs +++ b/test/enum_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/error_expr_test.exs b/test/error_expr_test.exs index 98719104..f4a4f35b 100644 --- a/test/error_expr_test.exs +++ b/test/error_expr_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/filter_child_relationship_by_parent_relationship_test.exs b/test/filter_child_relationship_by_parent_relationship_test.exs index 63a50eef..5b224ddb 100644 --- a/test/filter_child_relationship_by_parent_relationship_test.exs +++ b/test/filter_child_relationship_by_parent_relationship_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/filter_field_policy_test.exs b/test/filter_field_policy_test.exs index 6778e70b..a6485bf9 100644 --- a/test/filter_field_policy_test.exs +++ b/test/filter_field_policy_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/filter_test.exs b/test/filter_test.exs index 0172fb81..5492864b 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/load_test.exs b/test/load_test.exs index fa9c8aba..64300139 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/lock_test.exs b/test/lock_test.exs index 01122f50..40cebf44 100644 --- a/test/lock_test.exs +++ b/test/lock_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/ltree_test.exs b/test/ltree_test.exs index 33b3c1ba..36de46fc 100644 --- a/test/ltree_test.exs +++ b/test/ltree_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/manual_relationships_test.exs b/test/manual_relationships_test.exs index 3f4af170..b1a7689b 100644 --- a/test/manual_relationships_test.exs +++ b/test/manual_relationships_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/manual_update_test.exs b/test/manual_update_test.exs index 74a6ec35..bfc5e322 100644 --- a/test/manual_update_test.exs +++ b/test/manual_update_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/many_to_many_expr_test.exs b/test/many_to_many_expr_test.exs index 942168fc..4067fb51 100644 --- a/test/many_to_many_expr_test.exs +++ b/test/many_to_many_expr_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/migration_generator_test.exs b/test/migration_generator_test.exs index 41b16774..b3d1fd17 100644 --- a/test/migration_generator_test.exs +++ b/test/migration_generator_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/mix/tasks/ash_postgres.install_test.exs b/test/mix/tasks/ash_postgres.install_test.exs index e8ac1154..44e00c46 100644 --- a/test/mix/tasks/ash_postgres.install_test.exs +++ b/test/mix/tasks/ash_postgres.install_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/mix_squash_snapshots_test.exs b/test/mix_squash_snapshots_test.exs index 352430ae..68f34973 100644 --- a/test/mix_squash_snapshots_test.exs +++ b/test/mix_squash_snapshots_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/multi_domain_calculations_test.exs b/test/multi_domain_calculations_test.exs index 54652f63..fd9a8059 100644 --- a/test/multi_domain_calculations_test.exs +++ b/test/multi_domain_calculations_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/multitenancy_test.exs b/test/multitenancy_test.exs index 3e17c1ad..56ee9ef6 100644 --- a/test/multitenancy_test.exs +++ b/test/multitenancy_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/parent_filter_test.exs b/test/parent_filter_test.exs index 42f8326e..4e364211 100644 --- a/test/parent_filter_test.exs +++ b/test/parent_filter_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/parent_sort_test.exs b/test/parent_sort_test.exs index 7d472f2d..b1532416 100644 --- a/test/parent_sort_test.exs +++ b/test/parent_sort_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/polymorphism_test.exs b/test/polymorphism_test.exs index ecd8dc9d..630b7da1 100644 --- a/test/polymorphism_test.exs +++ b/test/polymorphism_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/primary_key_test.exs b/test/primary_key_test.exs index 8812bc0e..792520c3 100644 --- a/test/primary_key_test.exs +++ b/test/primary_key_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/references_test.exs b/test/references_test.exs index 59151ba3..49a661bd 100644 --- a/test/references_test.exs +++ b/test/references_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/rel_with_parent_filter_test.exs b/test/rel_with_parent_filter_test.exs index bdcc301d..ba178713 100644 --- a/test/rel_with_parent_filter_test.exs +++ b/test/rel_with_parent_filter_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/resource_generator_test.exs b/test/resource_generator_test.exs index 4c1f916c..1c793ba0 100644 --- a/test/resource_generator_test.exs +++ b/test/resource_generator_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/schema_test.exs b/test/schema_test.exs index be04d3bb..235a027a 100644 --- a/test/schema_test.exs +++ b/test/schema_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/select_test.exs b/test/select_test.exs index 7c440b10..cf21a6cb 100644 --- a/test/select_test.exs +++ b/test/select_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/sort_test.exs b/test/sort_test.exs index c1afc99a..da34a304 100644 --- a/test/sort_test.exs +++ b/test/sort_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/storage_types_test.exs b/test/storage_types_test.exs index efdb0195..ad414bf8 100644 --- a/test/storage_types_test.exs +++ b/test/storage_types_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/subquery_test.exs b/test/subquery_test.exs index 9795730b..6d4da873 100644 --- a/test/subquery_test.exs +++ b/test/subquery_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/domain.ex b/test/support/complex_calculations/domain.ex index 6356daa3..bf5b416d 100644 --- a/test/support/complex_calculations/domain.ex +++ b/test/support/complex_calculations/domain.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/certification.ex b/test/support/complex_calculations/resources/certification.ex index 317a5dc1..ea5ae573 100644 --- a/test/support/complex_calculations/resources/certification.ex +++ b/test/support/complex_calculations/resources/certification.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/channel.ex b/test/support/complex_calculations/resources/channel.ex index af99ed29..a59f14bf 100644 --- a/test/support/complex_calculations/resources/channel.ex +++ b/test/support/complex_calculations/resources/channel.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/channel_member.ex b/test/support/complex_calculations/resources/channel_member.ex index 7feb3c9d..ba4d1b8f 100644 --- a/test/support/complex_calculations/resources/channel_member.ex +++ b/test/support/complex_calculations/resources/channel_member.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/dm_channel.ex b/test/support/complex_calculations/resources/dm_channel.ex index 2113a3d5..2dd67b9b 100644 --- a/test/support/complex_calculations/resources/dm_channel.ex +++ b/test/support/complex_calculations/resources/dm_channel.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/documentation.ex b/test/support/complex_calculations/resources/documentation.ex index 88a3b7df..aadc0c81 100644 --- a/test/support/complex_calculations/resources/documentation.ex +++ b/test/support/complex_calculations/resources/documentation.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/folder.ex b/test/support/complex_calculations/resources/folder.ex index c0faefe6..5b131c25 100644 --- a/test/support/complex_calculations/resources/folder.ex +++ b/test/support/complex_calculations/resources/folder.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/folder_item.ex b/test/support/complex_calculations/resources/folder_item.ex index 7404970e..38f7cac7 100644 --- a/test/support/complex_calculations/resources/folder_item.ex +++ b/test/support/complex_calculations/resources/folder_item.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/complex_calculations/resources/skill.ex b/test/support/complex_calculations/resources/skill.ex index 44e8dfff..20874506 100644 --- a/test/support/complex_calculations/resources/skill.ex +++ b/test/support/complex_calculations/resources/skill.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/concat.ex b/test/support/concat.ex index 50b34373..cb2ffd7c 100644 --- a/test/support/concat.ex +++ b/test/support/concat.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/dev_test_repo.ex b/test/support/dev_test_repo.ex index c69abe43..23fcbe37 100644 --- a/test/support/dev_test_repo.ex +++ b/test/support/dev_test_repo.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/domain.ex b/test/support/domain.ex index ecd82d96..2fb81323 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multi_domain_calculations/domain_one.ex b/test/support/multi_domain_calculations/domain_one.ex index b5e091f4..0414e955 100644 --- a/test/support/multi_domain_calculations/domain_one.ex +++ b/test/support/multi_domain_calculations/domain_one.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multi_domain_calculations/domain_one/item.ex b/test/support/multi_domain_calculations/domain_one/item.ex index fa07ac9a..709ef7a0 100644 --- a/test/support/multi_domain_calculations/domain_one/item.ex +++ b/test/support/multi_domain_calculations/domain_one/item.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multi_domain_calculations/domain_three.ex b/test/support/multi_domain_calculations/domain_three.ex index a452e013..4689f0a5 100644 --- a/test/support/multi_domain_calculations/domain_three.ex +++ b/test/support/multi_domain_calculations/domain_three.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multi_domain_calculations/domain_three/relationship_item.ex b/test/support/multi_domain_calculations/domain_three/relationship_item.ex index 9c15eb0c..67185dfc 100644 --- a/test/support/multi_domain_calculations/domain_three/relationship_item.ex +++ b/test/support/multi_domain_calculations/domain_three/relationship_item.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multi_domain_calculations/domain_two.ex b/test/support/multi_domain_calculations/domain_two.ex index 715960fb..8ff13982 100644 --- a/test/support/multi_domain_calculations/domain_two.ex +++ b/test/support/multi_domain_calculations/domain_two.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multi_domain_calculations/domain_two/other_item.ex b/test/support/multi_domain_calculations/domain_two/other_item.ex index b7e65fd7..be9d7e95 100644 --- a/test/support/multi_domain_calculations/domain_two/other_item.ex +++ b/test/support/multi_domain_calculations/domain_two/other_item.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multi_domain_calculations/domain_two/sub_item.ex b/test/support/multi_domain_calculations/domain_two/sub_item.ex index 76550194..941368e5 100644 --- a/test/support/multi_domain_calculations/domain_two/sub_item.ex +++ b/test/support/multi_domain_calculations/domain_two/sub_item.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/domain.ex b/test/support/multitenancy/domain.ex index 1ee5e90b..c711e7be 100644 --- a/test/support/multitenancy/domain.ex +++ b/test/support/multitenancy/domain.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/composite_key_post.ex b/test/support/multitenancy/resources/composite_key_post.ex index b7856998..55bc4b45 100644 --- a/test/support/multitenancy/resources/composite_key_post.ex +++ b/test/support/multitenancy/resources/composite_key_post.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/cross_tenant_post_link.ex b/test/support/multitenancy/resources/cross_tenant_post_link.ex index e79e0cf8..eee4b60f 100644 --- a/test/support/multitenancy/resources/cross_tenant_post_link.ex +++ b/test/support/multitenancy/resources/cross_tenant_post_link.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/dev_migrations_org.ex b/test/support/multitenancy/resources/dev_migrations_org.ex index 0cc59783..33d19785 100644 --- a/test/support/multitenancy/resources/dev_migrations_org.ex +++ b/test/support/multitenancy/resources/dev_migrations_org.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/named_org.ex b/test/support/multitenancy/resources/named_org.ex index 714c090d..0b800106 100644 --- a/test/support/multitenancy/resources/named_org.ex +++ b/test/support/multitenancy/resources/named_org.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/non_multitenant_post_link.ex b/test/support/multitenancy/resources/non_multitenant_post_link.ex index 8f2a990e..e8e0cca6 100644 --- a/test/support/multitenancy/resources/non_multitenant_post_link.ex +++ b/test/support/multitenancy/resources/non_multitenant_post_link.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex index 0eb78386..79478246 100644 --- a/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex +++ b/test/support/multitenancy/resources/non_multitenant_post_multitenant_link.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/org.ex b/test/support/multitenancy/resources/org.ex index 21638793..66e75a23 100644 --- a/test/support/multitenancy/resources/org.ex +++ b/test/support/multitenancy/resources/org.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/post.ex b/test/support/multitenancy/resources/post.ex index cab27827..871e504b 100644 --- a/test/support/multitenancy/resources/post.ex +++ b/test/support/multitenancy/resources/post.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/post_link.ex b/test/support/multitenancy/resources/post_link.ex index dcdfdc41..6d45a2ae 100644 --- a/test/support/multitenancy/resources/post_link.ex +++ b/test/support/multitenancy/resources/post_link.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/multitenancy/resources/user.ex b/test/support/multitenancy/resources/user.ex index 7406eb07..0713b966 100644 --- a/test/support/multitenancy/resources/user.ex +++ b/test/support/multitenancy/resources/user.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/relationships/comments_containing_title.ex b/test/support/relationships/comments_containing_title.ex index e17ee933..156d4ec7 100644 --- a/test/support/relationships/comments_containing_title.ex +++ b/test/support/relationships/comments_containing_title.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/repo_case.ex b/test/support/repo_case.ex index 708e2d42..5e94fe98 100644 --- a/test/support/repo_case.ex +++ b/test/support/repo_case.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/account.ex b/test/support/resources/account.ex index 87e6544a..cf4b7f30 100644 --- a/test/support/resources/account.ex +++ b/test/support/resources/account.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index 097a771c..16ca5a8e 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/bio.ex b/test/support/resources/bio.ex index 8c0b33f0..e173bc05 100644 --- a/test/support/resources/bio.ex +++ b/test/support/resources/bio.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/chat.ex b/test/support/resources/chat.ex index 5c04c1af..c237fe42 100644 --- a/test/support/resources/chat.ex +++ b/test/support/resources/chat.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/co_authored_post.ex b/test/support/resources/co_authored_post.ex index 022c9eca..c49c3c2b 100644 --- a/test/support/resources/co_authored_post.ex +++ b/test/support/resources/co_authored_post.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/comedian.ex b/test/support/resources/comedian.ex index 2404d56c..f2b14cbf 100644 --- a/test/support/resources/comedian.ex +++ b/test/support/resources/comedian.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/comment.ex b/test/support/resources/comment.ex index cbbc6abb..133005db 100644 --- a/test/support/resources/comment.ex +++ b/test/support/resources/comment.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/comment_link.ex b/test/support/resources/comment_link.ex index 5caab846..42fba683 100644 --- a/test/support/resources/comment_link.ex +++ b/test/support/resources/comment_link.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/content.ex b/test/support/resources/content.ex index 8b823644..4e57c7be 100644 --- a/test/support/resources/content.ex +++ b/test/support/resources/content.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/content_visibility_group.ex b/test/support/resources/content_visibility_group.ex index 797d7c7e..b261f1f3 100644 --- a/test/support/resources/content_visibility_group.ex +++ b/test/support/resources/content_visibility_group.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/csv.ex b/test/support/resources/csv.ex index ccf5b418..c4e14393 100644 --- a/test/support/resources/csv.ex +++ b/test/support/resources/csv.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/customer.ex b/test/support/resources/customer.ex index 834fcead..0ab674b9 100644 --- a/test/support/resources/customer.ex +++ b/test/support/resources/customer.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/db_point.ex b/test/support/resources/db_point.ex index cf018f4a..e9e20131 100644 --- a/test/support/resources/db_point.ex +++ b/test/support/resources/db_point.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/db_string_point.ex b/test/support/resources/db_string_point.ex index e78c7536..48edf2dd 100644 --- a/test/support/resources/db_string_point.ex +++ b/test/support/resources/db_string_point.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/entity.ex b/test/support/resources/entity.ex index c693d02a..18c1b3f2 100644 --- a/test/support/resources/entity.ex +++ b/test/support/resources/entity.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/integer_post.ex b/test/support/resources/integer_post.ex index 2237e723..d270a933 100644 --- a/test/support/resources/integer_post.ex +++ b/test/support/resources/integer_post.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/invite.ex b/test/support/resources/invite.ex index 06d3ea70..07456bfc 100644 --- a/test/support/resources/invite.ex +++ b/test/support/resources/invite.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/joke.ex b/test/support/resources/joke.ex index 16414cb4..b66c1970 100644 --- a/test/support/resources/joke.ex +++ b/test/support/resources/joke.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/manager.ex b/test/support/resources/manager.ex index e5b2cce9..9ef2a0a1 100644 --- a/test/support/resources/manager.ex +++ b/test/support/resources/manager.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/message.ex b/test/support/resources/message.ex index 4cbc9533..1085c337 100644 --- a/test/support/resources/message.ex +++ b/test/support/resources/message.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/note.ex b/test/support/resources/note.ex index 0facb927..98ccef89 100644 --- a/test/support/resources/note.ex +++ b/test/support/resources/note.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/order.ex b/test/support/resources/order.ex index fead194c..76c7ef6f 100644 --- a/test/support/resources/order.ex +++ b/test/support/resources/order.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/organization.ex b/test/support/resources/organization.ex index d375a2db..e5dfd492 100644 --- a/test/support/resources/organization.ex +++ b/test/support/resources/organization.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/permalink.ex b/test/support/resources/permalink.ex index adca302f..e3aadaa9 100644 --- a/test/support/resources/permalink.ex +++ b/test/support/resources/permalink.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 2b85570a..c15b6b0e 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/post_follower.ex b/test/support/resources/post_follower.ex index 9e71b398..aa28f149 100644 --- a/test/support/resources/post_follower.ex +++ b/test/support/resources/post_follower.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/post_link.ex b/test/support/resources/post_link.ex index bc6390c8..147e09a9 100644 --- a/test/support/resources/post_link.ex +++ b/test/support/resources/post_link.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/post_tag.ex b/test/support/resources/post_tag.ex index 2ae47876..96306f91 100644 --- a/test/support/resources/post_tag.ex +++ b/test/support/resources/post_tag.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/post_views.ex b/test/support/resources/post_views.ex index c3b3aaaa..37bc2f54 100644 --- a/test/support/resources/post_views.ex +++ b/test/support/resources/post_views.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/post_with_empty_update.ex b/test/support/resources/post_with_empty_update.ex index 06693738..2e808ea4 100644 --- a/test/support/resources/post_with_empty_update.ex +++ b/test/support/resources/post_with_empty_update.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/product.ex b/test/support/resources/product.ex index fa2bbee9..194f0586 100644 --- a/test/support/resources/product.ex +++ b/test/support/resources/product.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/profile.ex b/test/support/resources/profile.ex index b06bab6f..9a14ee30 100644 --- a/test/support/resources/profile.ex +++ b/test/support/resources/profile.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/punchline.ex b/test/support/resources/punchline.ex index 66da6063..701fe540 100644 --- a/test/support/resources/punchline.ex +++ b/test/support/resources/punchline.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/rating.ex b/test/support/resources/rating.ex index 1fab32b1..b4ac159c 100644 --- a/test/support/resources/rating.ex +++ b/test/support/resources/rating.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/record.ex b/test/support/resources/record.ex index 0045db83..658b5f3d 100644 --- a/test/support/resources/record.ex +++ b/test/support/resources/record.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/record_temp_entity.ex b/test/support/resources/record_temp_entity.ex index ba0f73e3..c44bfdbf 100644 --- a/test/support/resources/record_temp_entity.ex +++ b/test/support/resources/record_temp_entity.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/role.ex b/test/support/resources/role.ex index df3635be..894e83bc 100644 --- a/test/support/resources/role.ex +++ b/test/support/resources/role.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/rsvp.ex b/test/support/resources/rsvp.ex index f364c333..af39eab0 100644 --- a/test/support/resources/rsvp.ex +++ b/test/support/resources/rsvp.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/settings.ex b/test/support/resources/settings.ex index e348f847..b18acb2c 100644 --- a/test/support/resources/settings.ex +++ b/test/support/resources/settings.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/staff_group.ex b/test/support/resources/staff_group.ex index 4aafeca8..dc3a23b1 100644 --- a/test/support/resources/staff_group.ex +++ b/test/support/resources/staff_group.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/staff_group_member.ex b/test/support/resources/staff_group_member.ex index a9ce9e97..fad757a6 100644 --- a/test/support/resources/staff_group_member.ex +++ b/test/support/resources/staff_group_member.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/standup_club.ex b/test/support/resources/standup_club.ex index ffa91044..af3047a2 100644 --- a/test/support/resources/standup_club.ex +++ b/test/support/resources/standup_club.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/stateful_post_follwer.ex b/test/support/resources/stateful_post_follwer.ex index cb66359c..017e979c 100644 --- a/test/support/resources/stateful_post_follwer.ex +++ b/test/support/resources/stateful_post_follwer.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/subquery/access.ex b/test/support/resources/subquery/access.ex index 9c971486..2ef87bb7 100644 --- a/test/support/resources/subquery/access.ex +++ b/test/support/resources/subquery/access.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/subquery/child.ex b/test/support/resources/subquery/child.ex index 5a9cd6af..4a078ebd 100644 --- a/test/support/resources/subquery/child.ex +++ b/test/support/resources/subquery/child.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/subquery/child_domain.ex b/test/support/resources/subquery/child_domain.ex index ab33df34..3ab11eef 100644 --- a/test/support/resources/subquery/child_domain.ex +++ b/test/support/resources/subquery/child_domain.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/subquery/parent.ex b/test/support/resources/subquery/parent.ex index a72c0054..66b5d0ea 100644 --- a/test/support/resources/subquery/parent.ex +++ b/test/support/resources/subquery/parent.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/subquery/parent_domain.ex b/test/support/resources/subquery/parent_domain.ex index d2e200d3..77d3d246 100644 --- a/test/support/resources/subquery/parent_domain.ex +++ b/test/support/resources/subquery/parent_domain.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/subquery/through.ex b/test/support/resources/subquery/through.ex index 3c0f4e75..a0e59604 100644 --- a/test/support/resources/subquery/through.ex +++ b/test/support/resources/subquery/through.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/tag.ex b/test/support/resources/tag.ex index 66bec825..b29a2cd0 100644 --- a/test/support/resources/tag.ex +++ b/test/support/resources/tag.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/temp_entity.ex b/test/support/resources/temp_entity.ex index 5507836e..308c6f75 100644 --- a/test/support/resources/temp_entity.ex +++ b/test/support/resources/temp_entity.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/resources/user.ex b/test/support/resources/user.ex index 1009dccd..8dd88866 100644 --- a/test/support/resources/user.ex +++ b/test/support/resources/user.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/string_agg.ex b/test/support/string_agg.ex index e6f92821..9cc5a8da 100644 --- a/test/support/string_agg.ex +++ b/test/support/string_agg.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/test_app.ex b/test/support/test_app.ex index 97d98fc2..bcc80e91 100644 --- a/test/support/test_app.ex +++ b/test/support/test_app.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/test_custom_extension.ex b/test/support/test_custom_extension.ex index bd6d26d3..35955d79 100644 --- a/test/support/test_custom_extension.ex +++ b/test/support/test_custom_extension.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/test_no_sandbox_repo.ex b/test/support/test_no_sandbox_repo.ex index 14ec8160..fb1437d6 100644 --- a/test/support/test_no_sandbox_repo.ex +++ b/test/support/test_no_sandbox_repo.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index 8dbc64c1..cf45c646 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/trigram_word_similarity.ex b/test/support/trigram_word_similarity.ex index 77c267c7..7b23166b 100644 --- a/test/support/trigram_word_similarity.ex +++ b/test/support/trigram_word_similarity.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/composite_point.ex b/test/support/types/composite_point.ex index b82887b9..db660894 100644 --- a/test/support/types/composite_point.ex +++ b/test/support/types/composite_point.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/email.ex b/test/support/types/email.ex index 9f552b6d..5f7412ea 100644 --- a/test/support/types/email.ex +++ b/test/support/types/email.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/money.ex b/test/support/types/money.ex index 6b2d79f8..09cc162d 100644 --- a/test/support/types/money.ex +++ b/test/support/types/money.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/person_detail.ex b/test/support/types/person_detail.ex index 3666300f..5b80861a 100644 --- a/test/support/types/person_detail.ex +++ b/test/support/types/person_detail.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/point.ex b/test/support/types/point.ex index 819d0287..7647688c 100644 --- a/test/support/types/point.ex +++ b/test/support/types/point.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/response.ex b/test/support/types/response.ex index 9428ee15..8c20dbf3 100644 --- a/test/support/types/response.ex +++ b/test/support/types/response.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/status.ex b/test/support/types/status.ex index 7453e955..b6eab647 100644 --- a/test/support/types/status.ex +++ b/test/support/types/status.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/status_enum.ex b/test/support/types/status_enum.ex index 2a845ff2..ac93d3b9 100644 --- a/test/support/types/status_enum.ex +++ b/test/support/types/status_enum.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/status_enum_no_cast.ex b/test/support/types/status_enum_no_cast.ex index 032266de..94cc6125 100644 --- a/test/support/types/status_enum_no_cast.ex +++ b/test/support/types/status_enum_no_cast.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/types/string_point.ex b/test/support/types/string_point.ex index 1be38e28..42430c6d 100644 --- a/test/support/types/string_point.ex +++ b/test/support/types/string_point.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/unrelated_aggregates/profile.ex b/test/support/unrelated_aggregates/profile.ex index 257a44e3..4f17f63e 100644 --- a/test/support/unrelated_aggregates/profile.ex +++ b/test/support/unrelated_aggregates/profile.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/unrelated_aggregates/report.ex b/test/support/unrelated_aggregates/report.ex index 025e550c..4619aa12 100644 --- a/test/support/unrelated_aggregates/report.ex +++ b/test/support/unrelated_aggregates/report.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/unrelated_aggregates/secure_profile.ex b/test/support/unrelated_aggregates/secure_profile.ex index 7f380da2..f345769b 100644 --- a/test/support/unrelated_aggregates/secure_profile.ex +++ b/test/support/unrelated_aggregates/secure_profile.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/support/unrelated_aggregates/user.ex b/test/support/unrelated_aggregates/user.ex index 22529079..f3a20de8 100644 --- a/test/support/unrelated_aggregates/user.ex +++ b/test/support/unrelated_aggregates/user.ex @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/test_helper.exs b/test/test_helper.exs index aba4a697..81659b92 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/transaction_test.exs b/test/transaction_test.exs index a4403a16..7939024f 100644 --- a/test/transaction_test.exs +++ b/test/transaction_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/tuple_test.exs b/test/tuple_test.exs index 5901f5c4..364c0e69 100644 --- a/test/tuple_test.exs +++ b/test/tuple_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/type_test.exs b/test/type_test.exs index 2e7c3132..99c866ac 100644 --- a/test/type_test.exs +++ b/test/type_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/unique_identity_test.exs b/test/unique_identity_test.exs index 618ead15..10c3d4aa 100644 --- a/test/unique_identity_test.exs +++ b/test/unique_identity_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/unrelated_aggregates_test.exs b/test/unrelated_aggregates_test.exs index 1c4ca107..82d466ae 100644 --- a/test/unrelated_aggregates_test.exs +++ b/test/unrelated_aggregates_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/update_test.exs b/test/update_test.exs index 22fb4af2..17756840 100644 --- a/test/update_test.exs +++ b/test/update_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT diff --git a/test/upsert_test.exs b/test/upsert_test.exs index 0f3308a7..dc1accaa 100644 --- a/test/upsert_test.exs +++ b/test/upsert_test.exs @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Zach Daniel +# SPDX-FileCopyrightText: 2019 ash_postgres contributors # # SPDX-License-Identifier: MIT From f44cee5e185da7dff4ddb26b8bd65bbc78e75238 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 14 Oct 2025 22:23:15 -0400 Subject: [PATCH 678/690] chore: check `upsert?` as well inside of new code not technically necessary but doesn't hurt --- lib/data_layer.ex | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 894de3fb..7dbb19d2 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2042,7 +2042,7 @@ defmodule AshPostgres.DataLayer do # if it's single the return_skipped_upsert? is handled at the # call site https://github.com/ash-project/ash_postgres/blob/0b21d4a99cc3f6d8676947e291ac9b9d57ad6e2e/lib/data_layer.ex#L3046-L3046 result = - if options[:return_skipped_upsert?] && !opts[:single?] do + if options[:upsert?] && options[:return_skipped_upsert?] && !opts[:single?] do [changeset | _] = changesets results_by_identity = diff --git a/mix.lock b/mix.lock index 96080205..03a5fd8e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.6.2", "90d1c8296be777b90caabf51b99323d6618a0b92594dfab92b02bdf848ac38bf", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "3546b5798dd24576cc451f6e03f3d6e3bb62666c0921bfe8aae700c599d9c38d"}, + "ash": {:hex, :ash, "3.6.3", "526ec1989a6be80798f585a8ad9e08752330e8a5e32e223fe7161955f994dfd4", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "23f9b85d545aee27011e371ffc4a19f7af9195e89c2038e50007084cdd1d31b5"}, "ash_sql": {:hex, :ash_sql, "0.3.4", "c8c0446fbd6d3e6920f793b971c83ba3d14f96095036366d313b72656400509d", [:mix], [{:ash, ">= 3.5.43 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", "4edb1fb707048a41f7944274b1a0b571aa3c9117b8a7a12809ca023b6f955cb4"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, From eb3f91682464e29a971dc3e188093d841facc55c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Tue, 14 Oct 2025 23:08:03 -0400 Subject: [PATCH 679/690] chore: cleanup function_exported? checks --- lib/migration_generator/migration_generator.ex | 2 +- lib/sql_implementation.ex | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 6cdbc469..9881818c 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -3227,7 +3227,7 @@ defmodule AshPostgres.MigrationGenerator do migration_type(attribute.type, attribute.constraints) type = - if :erlang.function_exported(repo, :override_migration_type, 1) do + if function_exported?(repo, :override_migration_type, 1) do repo.override_migration_type(type) else type diff --git a/lib/sql_implementation.ex b/lib/sql_implementation.ex index 3aed4340..fae3fede 100644 --- a/lib/sql_implementation.ex +++ b/lib/sql_implementation.ex @@ -311,11 +311,7 @@ defmodule AshPostgres.SqlImplementation do def parameterized_type(type, constraints) do if Ash.Type.ash_type?(type) do cast_in_query? = - if function_exported?(Ash.Type, :cast_in_query?, 2) do - Ash.Type.cast_in_query?(type, constraints) - else - Ash.Type.cast_in_query?(type) - end + Ash.Type.cast_in_query?(type, constraints) if cast_in_query? do type = Ash.Type.ecto_type(type) From 7375bfb0d90138e4dd943848ae49102bca39f5ae Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 15 Oct 2025 18:36:47 -0400 Subject: [PATCH 680/690] improvement: implement combination_acc/1 --- lib/data_layer.ex | 3 +++ mix.exs | 4 ++-- mix.lock | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 7dbb19d2..3bad7f45 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -889,6 +889,9 @@ defmodule AshPostgres.DataLayer do end end + @impl true + def combination_acc(query), do: AshSql.Query.combination_acc(query) + @impl true def run_aggregate_query(original_query, aggregates, resource) do AshSql.AggregateQuery.run_aggregate_query( diff --git a/mix.exs b/mix.exs index 2c0f979c..9c70ce1d 100644 --- a/mix.exs +++ b/mix.exs @@ -177,9 +177,9 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.5 and >= 3.6.2")}, + {:ash, ash_version("~> 3.7")}, {:spark, "~> 2.3 and >= 2.3.4"}, - {:ash_sql, ash_sql_version("~> 0.3 and >= 0.3.2")}, + {:ash_sql, ash_sql_version("~> 0.3 and >= 0.3.6")}, {:igniter, "~> 0.6 and >= 0.6.29", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, diff --git a/mix.lock b/mix.lock index 03a5fd8e..dd24d9a9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.6.3", "526ec1989a6be80798f585a8ad9e08752330e8a5e32e223fe7161955f994dfd4", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "23f9b85d545aee27011e371ffc4a19f7af9195e89c2038e50007084cdd1d31b5"}, - "ash_sql": {:hex, :ash_sql, "0.3.4", "c8c0446fbd6d3e6920f793b971c83ba3d14f96095036366d313b72656400509d", [:mix], [{:ash, ">= 3.5.43 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", "4edb1fb707048a41f7944274b1a0b571aa3c9117b8a7a12809ca023b6f955cb4"}, + "ash_sql": {:hex, :ash_sql, "0.3.6", "6036e57243448b1cc20f8afa0b8f6dcdbd14d4ccc4aa32e7feb5ca2465b3e13a", [:mix], [{:ash, ">= 3.5.43 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", "2cab83c09bc0a3d32c545691f35bb94199b4058dca6e254e8d99532d995fb8f7"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, @@ -41,7 +41,7 @@ "reactor": {:hex, :reactor, "0.17.0", "eb8bdb530dbae824e2d36a8538f8ec4f3aa7c2d1b61b04959fa787c634f88b49", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, ">= 2.3.3 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "3c3bf71693adbad9117b11ec83cfed7d5851b916ade508ed9718de7ae165bf25"}, "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, "rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"}, - "simple_sat": {:hex, :simple_sat, "0.1.3", "f650fc3c184a5fe741868b5ac56dc77fdbb428468f6dbf1978e14d0334497578", [:mix], [], "hexpm", "a54305066a356b7194dc81db2a89232bacdc0b3edaef68ed9aba28dcbc34887b"}, + "simple_sat": {:hex, :simple_sat, "0.1.4", "39baf72cdca14f93c0b6ce2b6418b72bbb67da98fa9ca4384e2f79bbc299899d", [:mix], [], "hexpm", "3569b68e346a5fd7154b8d14173ff8bcc829f2eb7b088c30c3f42a383443930b"}, "sobelow": {:hex, :sobelow, "0.14.1", "2f81e8632f15574cba2402bcddff5497b413c01e6f094bc0ab94e83c2f74db81", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8fac9a2bd90fdc4b15d6fca6e1608efb7f7c600fa75800813b794ee9364c87f2"}, "sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"}, "spark": {:hex, :spark, "2.3.5", "f30d30ecc3b4ab9b932d9aada66af7677fc1f297a2c349b0bcec3eafb9f996e8", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "0e9d339704d5d148f77f2b2fef3bcfc873a9e9bb4224fcf289c545d65827202f"}, From 9bc0bede7f8d482d5c8e85b54cabbed61fa68629 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 15 Oct 2025 18:42:01 -0400 Subject: [PATCH 681/690] chore: update ash --- mix.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index dd24d9a9..7b15d0ea 100644 --- a/mix.lock +++ b/mix.lock @@ -1,9 +1,10 @@ %{ - "ash": {:hex, :ash, "3.6.3", "526ec1989a6be80798f585a8ad9e08752330e8a5e32e223fe7161955f994dfd4", [: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "23f9b85d545aee27011e371ffc4a19f7af9195e89c2038e50007084cdd1d31b5"}, - "ash_sql": {:hex, :ash_sql, "0.3.6", "6036e57243448b1cc20f8afa0b8f6dcdbd14d4ccc4aa32e7feb5ca2465b3e13a", [:mix], [{:ash, ">= 3.5.43 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", "2cab83c09bc0a3d32c545691f35bb94199b4058dca6e254e8d99532d995fb8f7"}, + "ash": {:hex, :ash, "3.7.0", "711b9eb200f81e0a071e8fe52272fde27e3548a5f3d30589dfcf23eaf34b0d12", [:mix], [{:crux, "~> 0.1.0", [hex: :crux, repo: "hexpm", optional: false]}, {: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "2581e3e2ad21aff8157b25c0f58c884524bee8d06ae8dc94d38ef0b8ae67b2a3"}, + "ash_sql": {:hex, :ash_sql, "0.3.7", "80affa5446075d71deb157c67290685a84b392d723be766bfb684f58fe0143de", [:mix], [{:ash, "~> 3.7", [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", "ce4d974b8e784171c5a2a62593b3672b42dfd4888fa2239f01a6b32bad769038"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, + "crux": {:hex, :crux, "0.1.1", "94f2f97d2a6079ae3c57f356412bc3b307f9579a80e43f526447b1d508dd4a72", [:mix], [{:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:stream_data, "~> 1.0", [hex: :stream_data, repo: "hexpm", optional: true]}], "hexpm", "e59d498f038193cbe31e448f9199f5b4c53a4c67cece9922bb839595189dd2b6"}, "db_connection": {:hex, :db_connection, "2.8.1", "9abdc1e68c34c6163f6fb96a96532272d13ad7ca45262156ae8b7ec6d9dc4bec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61a3d489b239d76f326e03b98794fb8e45168396c925ef25feb405ed09da8fd"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, From f48e1a4f0a210c822e564c8834e5a494272b5562 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 15 Oct 2025 18:51:47 -0400 Subject: [PATCH 682/690] chore: update ash_sql --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 9c70ce1d..9463f940 100644 --- a/mix.exs +++ b/mix.exs @@ -179,7 +179,7 @@ defmodule AshPostgres.MixProject do [ {:ash, ash_version("~> 3.7")}, {:spark, "~> 2.3 and >= 2.3.4"}, - {:ash_sql, ash_sql_version("~> 0.3 and >= 0.3.6")}, + {:ash_sql, ash_sql_version("~> 0.3 and >= 0.3.7")}, {:igniter, "~> 0.6 and >= 0.6.29", optional: true}, {:ecto_sql, "~> 3.13"}, {:ecto, "~> 3.13"}, From d54f93c1937962fe17f3a412c91d144f1b8abfb7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 15 Oct 2025 18:51:57 -0400 Subject: [PATCH 683/690] chore: release version v2.6.23 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67570853..cd50c84d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,15 @@ See [Conventional Commits](https://www.conventionalcommits.org) for commit guide +## [v2.6.23](https://github.com/ash-project/ash_postgres/compare/v2.6.22...v2.6.23) (2025-10-15) + + + + +### Improvements: + +* implement combination_acc/1 by Zach Daniel + ## [v2.6.22](https://github.com/ash-project/ash_postgres/compare/v2.6.21...v2.6.22) (2025-10-14) diff --git a/mix.exs b/mix.exs index 9463f940..5e14da8d 100644 --- a/mix.exs +++ b/mix.exs @@ -9,7 +9,7 @@ defmodule AshPostgres.MixProject do The PostgreSQL data layer for Ash Framework """ - @version "2.6.22" + @version "2.6.23" def project do [ From f9bd1715b5aa8981caff4887495f376e18dfbf5f Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Thu, 16 Oct 2025 21:16:58 +0200 Subject: [PATCH 684/690] fix: handle results that can't be mapped to the changeset in bulk_create (#638) * fix: handle results that can't be mapped to the changeset in bulk_create If the identity used has attibutes that can be generated by the datalayer, we can't map the result back to the changeset and we need to just zip the results with the changesets and return them that way. * refactor: do a simple check for `upsert?` instead --- lib/data_layer.ex | 49 ++++++++++++++++++++++++++++----------- test/bulk_create_test.exs | 14 ++++++++++- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 3bad7f45..b984c4db 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2124,34 +2124,57 @@ defmodule AshPostgres.DataLayer do end) results = - changesets - |> Enum.map(fn changeset -> - identity = - changeset.attributes - |> Map.take(keys) + if opts[:upsert?] do + changesets + |> Enum.map(fn changeset -> + identity = + changeset.attributes + |> Map.take(keys) - result_for_changeset = Map.get(results_by_identity, identity) + result_for_changeset = Map.get(results_by_identity, identity) - if result_for_changeset do + if result_for_changeset do + if !opts[:upsert?] do + maybe_create_tenant!(resource, result_for_changeset) + end + + case get_bulk_operation_metadata(changeset) do + {index, metadata_key} -> + Ash.Resource.put_metadata(result_for_changeset, metadata_key, index) + + nil -> + # Compatibility fallback + Ash.Resource.put_metadata( + result_for_changeset, + :bulk_create_index, + changeset.context[:bulk_create][:index] + ) + end + end + end) + |> Enum.filter(& &1) + else + results + |> Enum.zip(changesets) + |> Enum.map(fn {result, changeset} -> if !opts[:upsert?] do - maybe_create_tenant!(resource, result_for_changeset) + maybe_create_tenant!(resource, result) end case get_bulk_operation_metadata(changeset) do {index, metadata_key} -> - Ash.Resource.put_metadata(result_for_changeset, metadata_key, index) + Ash.Resource.put_metadata(result, metadata_key, index) nil -> # Compatibility fallback Ash.Resource.put_metadata( - result_for_changeset, + result, :bulk_create_index, changeset.context[:bulk_create][:index] ) end - end - end) - |> Enum.filter(& &1) + end) + end {:ok, results} end diff --git a/test/bulk_create_test.exs b/test/bulk_create_test.exs index 296742fd..c18d8d1a 100644 --- a/test/bulk_create_test.exs +++ b/test/bulk_create_test.exs @@ -4,7 +4,7 @@ defmodule AshPostgres.BulkCreateTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Post, Record} + alias AshPostgres.Test.{IntegerPost, Post, Record} require Ash.Query import Ash.Expr @@ -356,6 +356,18 @@ defmodule AshPostgres.BulkCreateTest do |> Ash.Query.load(:ratings) |> Ash.read!() end + + test "bulk creates with integer primary key return records" do + %Ash.BulkResult{records: records} = + Ash.bulk_create!( + [%{title: "first"}, %{title: "second"}, %{title: "third"}], + IntegerPost, + :create, + return_records?: true + ) + + assert length(records) == 3 + end end describe "validation errors" do From 39475a7a278b4eb0731683bee9fca1f7e96ba611 Mon Sep 17 00:00:00 2001 From: Steve Brambilla Date: Fri, 17 Oct 2025 17:55:17 -0400 Subject: [PATCH 685/690] * feat: support building error payloads using immutable functions (#639) Citus compatibility: replace `jsonb_build_object` with immutable functions when `immutable_expr_error?` is true --- lib/extensions/immutable_raise_error.ex | 153 ++++++++---- .../test_repo/extensions.json | 1 + .../20251015134240.json | 226 ++++++++++++++++++ .../20251015134240.json.license | 3 + ...all_immutable_raise_error_v2_extension.exs | 69 ++++++ .../20251015134240_migrate_resources63.exs | 39 +++ test/immutable_raise_error_test.exs | 124 ++++++++++ test/support/domain.ex | 1 + .../resources/immutable_error_tester/error.ex | 31 +++ .../immutable_error_tester.ex | 67 ++++++ .../immutable_error_tester/struct.ex | 14 ++ .../validations/update_literal.ex | 33 +++ .../validations/update_many.ex | 45 ++++ .../validations/update_one.ex | 32 +++ test/support/test_repo.ex | 14 +- 15 files changed, 799 insertions(+), 53 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json create mode 100644 priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json.license create mode 100644 priv/test_repo/migrations/20251015134238_install_immutable_raise_error_v2_extension.exs create mode 100644 priv/test_repo/migrations/20251015134240_migrate_resources63.exs create mode 100644 test/immutable_raise_error_test.exs create mode 100644 test/support/resources/immutable_error_tester/error.ex create mode 100644 test/support/resources/immutable_error_tester/immutable_error_tester.ex create mode 100644 test/support/resources/immutable_error_tester/struct.ex create mode 100644 test/support/resources/immutable_error_tester/validations/update_literal.ex create mode 100644 test/support/resources/immutable_error_tester/validations/update_many.ex create mode 100644 test/support/resources/immutable_error_tester/validations/update_one.ex diff --git a/lib/extensions/immutable_raise_error.ex b/lib/extensions/immutable_raise_error.ex index a1a4032c..3026602c 100644 --- a/lib/extensions/immutable_raise_error.ex +++ b/lib/extensions/immutable_raise_error.ex @@ -30,25 +30,37 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do ``` """ - use AshPostgres.CustomExtension, name: "immutable_raise_error", latest_version: 1 + use AshPostgres.CustomExtension, name: "immutable_raise_error", latest_version: 2 require Ecto.Query @impl true def install(0) do - ash_raise_error_immutable() + """ + #{ash_raise_error_immutable()} + + #{ash_to_jsonb_immutable()} + """ + end + + def install(1) do + ash_to_jsonb_immutable() end @impl true + def uninstall(2) do + "execute(\"DROP FUNCTION IF EXISTS ash_to_jsonb_immutable(anyelement)\")" + end + def uninstall(_version) do - "execute(\"DROP FUNCTION IF EXISTS ash_raise_error_immutable(jsonb, ANYCOMPATIBLE), ash_raise_error_immutable(jsonb, ANYELEMENT, ANYCOMPATIBLE)\")" + "execute(\"DROP FUNCTION IF EXISTS ash_to_jsonb_immutable(anyelement), ash_raise_error_immutable(jsonb, anycompatible), ash_raise_error_immutable(jsonb, anyelement, anycompatible)\")" end defp ash_raise_error_immutable do """ execute(\"\"\" - CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, token ANYCOMPATIBLE) - RETURNS BOOLEAN AS $$ + CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, token anycompatible) + RETURNS boolean AS $$ BEGIN -- Raise an error with the provided JSON data. -- The JSON object is converted to text for inclusion in the error message. @@ -62,8 +74,8 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do \"\"\") execute(\"\"\" - CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, type_signal ANYELEMENT, token ANYCOMPATIBLE) - RETURNS ANYELEMENT AS $$ + CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, type_signal anyelement, token anycompatible) + RETURNS anyelement AS $$ BEGIN -- Raise an error with the provided JSON data. -- The JSON object is converted to text for inclusion in the error message. @@ -78,60 +90,48 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do """ end + # Wraps to_jsonb and pins session GUCs that affect JSON. This makes the function’s result + # deterministic, so it is safe to mark IMMUTABLE. + defp ash_to_jsonb_immutable do + """ + execute(\"\"\" + CREATE OR REPLACE FUNCTION ash_to_jsonb_immutable(value anyelement) + RETURNS jsonb + LANGUAGE plpgsql + IMMUTABLE + SET search_path TO 'pg_catalog' + SET \"TimeZone\" TO 'UTC' + SET \"DateStyle\" TO 'ISO, YMD' + SET \"IntervalStyle\" TO 'iso_8601' + SET extra_float_digits TO '0' + SET bytea_output TO 'hex' + AS $function$ + BEGIN + RETURN COALESCE(to_jsonb(value), 'null'::jsonb); + END; + $function$ + \"\"\") + """ + end + @doc false def immutable_error_expr( query, %Ash.Query.Function.Error{arguments: [exception, input]} = value, bindings, - embedded?, + _embedded?, acc, type ) do + if !(Keyword.keyword?(input) or is_map(input)) do + raise "Input expression to `error` must be a map or keyword list" + end + acc = %{acc | has_error?: true} - {encoded, acc} = + {error_payload, acc} = if Ash.Expr.expr?(input) do - frag_parts = - Enum.flat_map(input, fn {key, value} -> - if Ash.Expr.expr?(value) do - [ - expr: to_string(key), - raw: "::text, ", - expr: value, - raw: ", " - ] - else - [ - expr: to_string(key), - raw: "::text, ", - expr: value, - raw: "::jsonb, " - ] - end - end) - - frag_parts = - List.update_at(frag_parts, -1, fn {:raw, text} -> - {:raw, String.trim_trailing(text, ", ") <> "))"} - end) - - AshSql.Expr.dynamic_expr( - query, - %Ash.Query.Function.Fragment{ - embedded?: false, - arguments: - [ - raw: "jsonb_build_object('exception', ", - expr: inspect(exception), - raw: "::text, 'input', jsonb_build_object(" - ] ++ - frag_parts - }, - bindings, - embedded?, - nil, - acc - ) + expression_error_payload(exception, input, query, bindings, acc) else {Jason.encode!(%{exception: inspect(exception), input: Map.new(input)}), acc} end @@ -163,7 +163,7 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do {nil, row_token} -> {:ok, Ecto.Query.dynamic( - fragment("ash_raise_error_immutable(?::jsonb, ?)", ^encoded, ^row_token) + fragment("ash_raise_error_immutable(?::jsonb, ?)", ^error_payload, ^row_token) ), acc} {dynamic_type, row_token} -> @@ -171,7 +171,7 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do Ecto.Query.dynamic( fragment( "ash_raise_error_immutable(?::jsonb, ?, ?)", - ^encoded, + ^error_payload, ^dynamic_type, ^row_token ) @@ -179,6 +179,55 @@ defmodule AshPostgres.Extensions.ImmutableRaiseError do end end + # Encodes an error payload as jsonb using only IMMUTABLE SQL functions. + # + # Strategy: + # * Split the 'input' into Ash expressions and literal values + # * Build the base json map with the exception name and literal input values + # * For each expression value, use nested calls to `jsonb_set` (IMMUTABLE) to add the value to + # 'input', converting each expression to jsonb using `ash_to_jsonb_immutable` (which pins + # session GUCs for deterministic encoding) + defp expression_error_payload(exception, input, query, bindings, acc) do + {expr_inputs, literal_inputs} = + Enum.split_with(input, fn {_key, value} -> Ash.Expr.expr?(value) end) + + base_json = %{exception: inspect(exception), input: Map.new(literal_inputs)} + + Enum.reduce(expr_inputs, {base_json, acc}, fn + {key, expr_value}, {current_payload, acc} -> + path_expr = %Ash.Query.Function.Type{ + arguments: [["input", to_string(key)], {:array, :string}, []] + } + + new_value_jsonb = + %Ash.Query.Function.Fragment{ + arguments: [raw: "ash_to_jsonb_immutable(", expr: expr_value, raw: ")"] + } + + {%Ecto.Query.DynamicExpr{} = new_payload, acc} = + AshSql.Expr.dynamic_expr( + query, + %Ash.Query.Function.Fragment{ + arguments: [ + raw: "jsonb_set(", + expr: current_payload, + raw: "::jsonb, ", + expr: path_expr, + raw: ", ", + expr: new_value_jsonb, + raw: "::jsonb, true)" + ] + }, + bindings, + false, + nil, + acc + ) + + {new_payload, acc} + end) + end + # Returns a row-dependent token to prevent constant-folding for immutable functions. defp immutable_error_expr_token(query, bindings) do resource = query.__ash_bindings__.resource diff --git a/priv/resource_snapshots/test_repo/extensions.json b/priv/resource_snapshots/test_repo/extensions.json index d1c5a122..35a36695 100644 --- a/priv/resource_snapshots/test_repo/extensions.json +++ b/priv/resource_snapshots/test_repo/extensions.json @@ -6,6 +6,7 @@ "pg_trgm", "citext", "demo-functions_v1", + "immutable_raise_error_v2", "ltree" ] } \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json b/priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json new file mode 100644 index 00000000..5917eec5 --- /dev/null +++ b/priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json @@ -0,0 +1,226 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "atom_value", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "string_value", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "integer_value", + "type": "bigint" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "float_value", + "type": "float" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "boolean_value", + "type": "boolean" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "struct_value", + "type": "map" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "uuid_value", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "date_value", + "type": "date" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "time_value", + "type": "time" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "ci_string_value", + "type": "citext" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "naive_datetime_value", + "type": "naive_datetime" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "utc_datetime_value", + "type": "utc_datetime" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "timestamptz_value", + "type": "timestamptz" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "string_array_value", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "response_value", + "type": "integer" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "nullable_string_value", + "type": "text" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "BB177B855B058F50CA20AFCF6F624072C1395BFDF3FB0B2F60BDC14A15A053F1", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "immutable_error_testers" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json.license b/priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json.license new file mode 100644 index 00000000..b0a44fab --- /dev/null +++ b/priv/resource_snapshots/test_repo/immutable_error_testers/20251015134240.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019 ash_postgres contributors + +SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20251015134238_install_immutable_raise_error_v2_extension.exs b/priv/test_repo/migrations/20251015134238_install_immutable_raise_error_v2_extension.exs new file mode 100644 index 00000000..eb4a8d77 --- /dev/null +++ b/priv/test_repo/migrations/20251015134238_install_immutable_raise_error_v2_extension.exs @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.TestRepo.Migrations.InstallImmutableRaiseErrorV220251015134237 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, token anycompatible) + RETURNS boolean AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + -- 'token' is intentionally ignored; its presence makes the call non-constant at the call site. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql + IMMUTABLE + SET search_path = ''; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error_immutable(json_data jsonb, type_signal anyelement, token anycompatible) + RETURNS anyelement AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + -- 'token' is intentionally ignored; its presence makes the call non-constant at the call site. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql + IMMUTABLE + SET search_path = ''; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_to_jsonb_immutable(value anyelement) + RETURNS jsonb + LANGUAGE plpgsql + IMMUTABLE + SET search_path TO 'pg_catalog' + SET "TimeZone" TO 'UTC' + SET "DateStyle" TO 'ISO, YMD' + SET "IntervalStyle" TO 'iso_8601' + SET extra_float_digits TO '0' + SET bytea_output TO 'hex' + AS $function$ + BEGIN + RETURN COALESCE(to_jsonb(value), 'null'::jsonb); + END; + $function$ + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute("DROP FUNCTION IF EXISTS ash_to_jsonb_immutable(anyelement)") + end +end diff --git a/priv/test_repo/migrations/20251015134240_migrate_resources63.exs b/priv/test_repo/migrations/20251015134240_migrate_resources63.exs new file mode 100644 index 00000000..0454f8a4 --- /dev/null +++ b/priv/test_repo/migrations/20251015134240_migrate_resources63.exs @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.TestRepo.Migrations.MigrateResources63 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:immutable_error_testers, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + add(:atom_value, :text, null: false) + add(:string_value, :text, null: false) + add(:integer_value, :bigint, null: false) + add(:float_value, :float, null: false) + add(:boolean_value, :boolean, null: false) + add(:struct_value, :map, null: false) + add(:uuid_value, :uuid, null: false) + add(:date_value, :date, null: false) + add(:time_value, :time, null: false) + add(:ci_string_value, :citext, null: false) + add(:naive_datetime_value, :naive_datetime, null: false) + add(:utc_datetime_value, :utc_datetime, null: false) + add(:timestamptz_value, :timestamptz, null: false) + add(:string_array_value, {:array, :text}, null: false) + add(:response_value, :integer, null: false) + add(:nullable_string_value, :text) + end + end + + def down do + drop(table(:immutable_error_testers)) + end +end diff --git a/test/immutable_raise_error_test.exs b/test/immutable_raise_error_test.exs new file mode 100644 index 00000000..076efeaf --- /dev/null +++ b/test/immutable_raise_error_test.exs @@ -0,0 +1,124 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.ImmutableRaiseErrorTest do + use AshPostgres.RepoCase, async: false + + alias AshPostgres.Test.ImmutableErrorTester + + require Ash.Query + + setup do + original = Application.get_env(:ash_postgres, :test_repo_use_immutable_errors?) + Application.put_env(:ash_postgres, :test_repo_use_immutable_errors?, true) + + on_exit(fn -> + if is_nil(original) do + Application.delete_env(:ash_postgres, :test_repo_use_immutable_errors?) + else + Application.put_env(:ash_postgres, :test_repo_use_immutable_errors?, original) + end + end) + + :ok + end + + describe "atomic error payloads" do + test "update_one returns InvalidAttribute error with expression value" do + tester = create_tester() + + # The :update_one validation builds an error with a single expression value and literal + # values (non-empty base input). + assert {:error, %Ash.Error.Invalid{errors: [error]}} = + tester + |> Ash.Changeset.for_update(:update_one, %{integer_value: 99}) + |> Ash.update() + + assert %Ash.Error.Changes.InvalidAttribute{} = error + assert error.field == :integer_value + assert error.value == 99 + end + + test "update_many returns custom error containing all expression values" do + tester = create_tester() + + # The :update_many validation builds an error that include many (all attributes) value + # expressions, and zero literal values (empty base input). + assert {:error, %Ash.Error.Invalid{errors: [error]}} = + tester + |> Ash.Changeset.for_update(:update_many, %{}) + |> Ash.update() + + assert %ImmutableErrorTester.Error{} = error + + assert error.atom_value == "initial_atom" + assert error.string_value == "initial string" + assert error.integer_value == 10 + assert error.float_value == 1.5 + assert error.boolean_value == true + + assert error.struct_value == %{ + "active?" => true, + "count" => 1, + "name" => "initial" + } + + assert error.uuid_value == "00000000-0000-0000-0000-000000000000" + assert error.date_value == "2024-01-01" + assert error.time_value == "12:00:00" + assert error.ci_string_value == "Initial String" + assert error.naive_datetime_value == "2024-01-01T12:00:00" + assert error.utc_datetime_value == "2024-01-01T00:01:00" + assert error.timestamptz_value == "2024-01-01T00:02:00+00:00" + assert error.string_array_value == ["one", "two"] + + # Native value for :awaiting is 0 + assert error.response_value == 0 + assert error.nullable_string_value == nil + end + + test "update_literal returns literal payload" do + tester = create_tester() + + # The :update_literal validation builds an error with only literal values, zero expression values. + assert {:error, %Ash.Error.Invalid{errors: [error]}} = + tester + |> Ash.Changeset.for_update(:update_literal, %{}) + |> Ash.update() + + assert error.string_value == "literal string" + assert error.integer_value == 123 + assert error.float_value == 9.99 + assert error.boolean_value == false + assert error.string_array_value == ["alpha", "beta"] + assert error.nullable_string_value == nil + end + end + + defp create_tester do + input = + %{ + atom_value: :initial_atom, + string_value: "initial string", + integer_value: 10, + float_value: 1.5, + boolean_value: true, + struct_value: ImmutableErrorTester.Struct.new!(name: "initial", count: 1, active?: true), + uuid_value: "00000000-0000-0000-0000-000000000000", + date_value: ~D[2024-01-01], + time_value: ~T[12:00:00], + ci_string_value: "Initial String", + naive_datetime_value: ~N[2024-01-01 12:00:00], + utc_datetime_value: ~U[2024-01-01 00:01:00.00Z], + timestamptz_value: ~U[2024-01-01 00:02:00.00Z], + string_array_value: ["one", "two"], + response_value: :awaiting, + nullable_string_value: nil + } + + ImmutableErrorTester + |> Ash.Changeset.for_create(:create, input) + |> Ash.create!() + end +end diff --git a/test/support/domain.ex b/test/support/domain.ex index 2fb81323..8e9a19d3 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -58,6 +58,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Chat) resource(AshPostgres.Test.Message) resource(AshPostgres.Test.RSVP) + resource(AshPostgres.Test.ImmutableErrorTester) end authorization do diff --git a/test/support/resources/immutable_error_tester/error.ex b/test/support/resources/immutable_error_tester/error.ex new file mode 100644 index 00000000..15dca8ee --- /dev/null +++ b/test/support/resources/immutable_error_tester/error.ex @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.ImmutableErrorTester.Error do + @moduledoc false + use Splode.Error, + class: :invalid, + fields: [ + :atom_value, + :string_value, + :integer_value, + :float_value, + :boolean_value, + :struct_value, + :uuid_value, + :date_value, + :time_value, + :ci_string_value, + :naive_datetime_value, + :utc_datetime_value, + :timestamptz_value, + :string_array_value, + :response_value, + :nullable_string_value + ] + + def message(_error) do + "Immutable Error" + end +end diff --git a/test/support/resources/immutable_error_tester/immutable_error_tester.ex b/test/support/resources/immutable_error_tester/immutable_error_tester.ex new file mode 100644 index 00000000..50ec1613 --- /dev/null +++ b/test/support/resources/immutable_error_tester/immutable_error_tester.ex @@ -0,0 +1,67 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.ImmutableErrorTester do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + require Ash.Expr + import Ash.Expr + + postgres do + table "immutable_error_testers" + repo(AshPostgres.TestRepo) + end + + attributes do + uuid_primary_key(:id) + + attribute(:atom_value, :atom, allow_nil?: false, public?: true) + attribute(:string_value, :string, allow_nil?: false, public?: true) + attribute(:integer_value, :integer, allow_nil?: false, public?: true) + attribute(:float_value, :float, allow_nil?: false, public?: true) + attribute(:boolean_value, :boolean, allow_nil?: false, public?: true) + + attribute(:struct_value, AshPostgres.Test.ImmutableErrorTester.Struct, + allow_nil?: false, + public?: true + ) + + attribute(:uuid_value, Ash.Type.UUID, allow_nil?: false, public?: true) + attribute(:date_value, :date, allow_nil?: false, public?: true) + attribute(:time_value, :time, allow_nil?: false, public?: true) + attribute(:ci_string_value, :ci_string, allow_nil?: false, public?: true) + attribute(:naive_datetime_value, :naive_datetime, allow_nil?: false, public?: true) + attribute(:utc_datetime_value, :utc_datetime, allow_nil?: false, public?: true) + attribute(:timestamptz_value, AshPostgres.Timestamptz, allow_nil?: false, public?: true) + attribute(:string_array_value, {:array, :string}, allow_nil?: false, public?: true) + attribute(:response_value, AshPostgres.Test.Types.Response, allow_nil?: false, public?: true) + attribute(:nullable_string_value, :string, public?: true) + end + + actions do + defaults([:read]) + + create :create do + accept(:*) + end + + update :update_one do + argument(:integer_value, :integer, allow_nil?: false) + change(atomic_update(:integer_value, expr(^arg(:integer_value)))) + validate(AshPostgres.Test.ImmutableErrorTester.Validations.UpdateOne) + end + + update :update_many do + accept(:*) + validate(AshPostgres.Test.ImmutableErrorTester.Validations.UpdateMany) + end + + update :update_literal do + validate(AshPostgres.Test.ImmutableErrorTester.Validations.UpdateLiteral) + end + end +end diff --git a/test/support/resources/immutable_error_tester/struct.ex b/test/support/resources/immutable_error_tester/struct.ex new file mode 100644 index 00000000..2b24494f --- /dev/null +++ b/test/support/resources/immutable_error_tester/struct.ex @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.ImmutableErrorTester.Struct do + @moduledoc false + use Ash.TypedStruct + + typed_struct do + field(:name, :string, allow_nil?: false) + field(:count, :integer, allow_nil?: false) + field(:active?, :boolean, allow_nil?: false) + end +end diff --git a/test/support/resources/immutable_error_tester/validations/update_literal.ex b/test/support/resources/immutable_error_tester/validations/update_literal.ex new file mode 100644 index 00000000..453ec37e --- /dev/null +++ b/test/support/resources/immutable_error_tester/validations/update_literal.ex @@ -0,0 +1,33 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.ImmutableErrorTester.Validations.UpdateLiteral do + @moduledoc false + use Ash.Resource.Validation + + import Ash.Expr + + @impl true + def init(opts), do: {:ok, opts} + + # Validation that always fails. Builds an error with only literal values, zero expression values. + # + # Use fragment with PG function to ensure the validation runs as part of the query. + @impl true + def atomic(_changeset, _opts, _context) do + [ + {:atomic, :*, expr(fragment("pg_column_size(?) != 0", ^ref(:id))), + expr( + error(AshPostgres.Test.ImmutableErrorTester.Error, + string_value: "literal string", + integer_value: 123, + float_value: 9.99, + boolean_value: false, + string_array_value: ["alpha", "beta"], + nullable_string_value: nil + ) + )} + ] + end +end diff --git a/test/support/resources/immutable_error_tester/validations/update_many.ex b/test/support/resources/immutable_error_tester/validations/update_many.ex new file mode 100644 index 00000000..e41959dc --- /dev/null +++ b/test/support/resources/immutable_error_tester/validations/update_many.ex @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.ImmutableErrorTester.Validations.UpdateMany do + @moduledoc false + use Ash.Resource.Validation + + import Ash.Expr + + @impl true + def init(opts), do: {:ok, opts} + + # Validation that always fails. Builds an error that include many (all attributes) value + # expressions, and zero literal values (empty base input). + # + # Use fragment with PG function to ensure the validation runs as part of the query. + @impl true + def atomic(_changeset, _opts, _context) do + [ + {:atomic, :*, expr(fragment("pg_column_size(?) != 0", ^ref(:id))), + expr( + error( + AshPostgres.Test.ImmutableErrorTester.Error, + atom_value: ^atomic_ref(:atom_value), + string_value: ^atomic_ref(:string_value), + integer_value: ^atomic_ref(:integer_value), + float_value: ^atomic_ref(:float_value), + boolean_value: ^atomic_ref(:boolean_value), + struct_value: ^atomic_ref(:struct_value), + uuid_value: ^atomic_ref(:uuid_value), + date_value: ^atomic_ref(:date_value), + time_value: ^atomic_ref(:time_value), + ci_string_value: ^atomic_ref(:ci_string_value), + naive_datetime_value: ^atomic_ref(:naive_datetime_value), + utc_datetime_value: ^atomic_ref(:utc_datetime_value), + timestamptz_value: ^atomic_ref(:timestamptz_value), + string_array_value: ^atomic_ref(:string_array_value), + response_value: ^atomic_ref(:response_value), + nullable_string_value: ^atomic_ref(:nullable_string_value) + ) + )} + ] + end +end diff --git a/test/support/resources/immutable_error_tester/validations/update_one.ex b/test/support/resources/immutable_error_tester/validations/update_one.ex new file mode 100644 index 00000000..a7351e56 --- /dev/null +++ b/test/support/resources/immutable_error_tester/validations/update_one.ex @@ -0,0 +1,32 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.ImmutableErrorTester.Validations.UpdateOne do + @moduledoc false + use Ash.Resource.Validation + + import Ash.Expr + + @impl true + def init(opts), do: {:ok, opts} + + # Validation that always fails. Builds an error with a single expression value and literal + # values (non-empty base input). + # + # Use fragment with PG function to ensure the validation runs as part of the query. + @impl true + def atomic(_changeset, _opts, _context) do + [ + {:atomic, [:integer_value, :id], expr(fragment("pg_column_size(?) != 0", ^ref(:id))), + expr( + error( + Ash.Error.Changes.InvalidAttribute, + field: :integer_value, + value: ^atomic_ref(:integer_value), + message: "integer_value failed validation" + ) + )} + ] + end +end diff --git a/test/support/test_repo.ex b/test/support/test_repo.ex index cf45c646..b21721e8 100644 --- a/test/support/test_repo.ex +++ b/test/support/test_repo.ex @@ -16,7 +16,15 @@ defmodule AshPostgres.TestRepo do def prefer_transaction_for_atomic_updates?, do: false def installed_extensions do - ["ash-functions", "uuid-ossp", "pg_trgm", "citext", AshPostgres.TestCustomExtension, "ltree"] -- + [ + "ash-functions", + "uuid-ossp", + "pg_trgm", + "citext", + AshPostgres.TestCustomExtension, + AshPostgres.Extensions.ImmutableRaiseError, + "ltree" + ] -- Application.get_env(:ash_postgres, :no_extensions, []) end @@ -40,4 +48,8 @@ defmodule AshPostgres.TestRepo do |> Ash.read!() |> Enum.map(&"org_#{&1.id}") end + + def immutable_expr_error? do + Application.get_env(:ash_postgres, :test_repo_use_immutable_errors?, false) + end end From b2216c4b509137ca9c364ac5368e91f542827e7a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 18 Oct 2025 01:28:08 -0400 Subject: [PATCH 686/690] test: add tests for ash_sql fix for exists paths in calculations chore: update ash --- mix.lock | 2 +- test/calculation_test.exs | 21 +++++++++++++++++++++ test/support/resources/author.ex | 6 ++++++ test/support/resources/post.ex | 6 ++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 7b15d0ea..c988302d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "3.7.0", "711b9eb200f81e0a071e8fe52272fde27e3548a5f3d30589dfcf23eaf34b0d12", [:mix], [{:crux, "~> 0.1.0", [hex: :crux, repo: "hexpm", optional: false]}, {: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "2581e3e2ad21aff8157b25c0f58c884524bee8d06ae8dc94d38ef0b8ae67b2a3"}, + "ash": {:hex, :ash, "3.7.1", "abb55dee19e0959e529e52fe0622468825ae05400f535484919713e492d9a9e7", [:mix], [{:crux, "~> 0.1.0", [hex: :crux, repo: "hexpm", optional: false]}, {: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "4474ce9befe9862d1ed73cadf8a755e836c45a14a7b3b952d02e1a12f2b2e529"}, "ash_sql": {:hex, :ash_sql, "0.3.7", "80affa5446075d71deb157c67290685a84b392d723be766bfb684f58fe0143de", [:mix], [{:ash, "~> 3.7", [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", "ce4d974b8e784171c5a2a62593b3672b42dfd4888fa2239f01a6b32bad769038"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, diff --git a/test/calculation_test.exs b/test/calculation_test.exs index cdad5c18..5e3a2a68 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -1121,4 +1121,25 @@ defmodule AshPostgres.CalculationTest do first_comment_by_author.created_at ) end + + test "nested calculation with parent() in exists works" do + author = + Author + |> Ash.Changeset.for_create(:create, %{first_name: "John", last_name: "Doe"}) + |> Ash.create!() + + _post = + Post + |> Ash.Changeset.for_create(:create, %{title: "test", author_id: author.id}) + |> Ash.create!() + + result = + Post + |> Ash.Query.load(:author_has_post_with_title_matching_their_first_name) + |> Ash.read!() + |> List.first() + + # Should be false since post title doesn't match author first name + refute result.author_has_post_with_title_matching_their_first_name + end end diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index 16ca5a8e..3530513c 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -181,6 +181,12 @@ defmodule AshPostgres.Test.Author do calculate(:has_posts, :boolean, expr(exists(posts, true == true))) calculate(:has_no_posts, :boolean, expr(has_posts == false)) + calculate( + :has_post_with_title_matching_first_name, + :boolean, + expr(exists(posts, title == parent(first_name))) + ) + calculate(:profile_description_calc, :string, expr(profile.description), allow_nil?: true) end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index c15b6b0e..a4f04f7d 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -924,6 +924,12 @@ defmodule AshPostgres.Test.Post do ) ) + calculate( + :author_has_post_with_title_matching_their_first_name, + :boolean, + expr(author.has_post_with_title_matching_first_name) + ) + calculate(:has_author, :boolean, expr(exists(author, true == true))) calculate(:has_comments, :boolean, expr(exists(comments, true == true))) From 449ae3ff8715c3bb5598ff19d844e1ac728e25b7 Mon Sep 17 00:00:00 2001 From: Torkild Gundersen Kjevik Date: Sun, 19 Oct 2025 05:17:31 +0200 Subject: [PATCH 687/690] test: typed struct arrays with storage_type :jsonb & {:array, map} (#640) --- .../test_repo/authors/20251018130654_dev.json | 133 ++++++++++++++++++ .../authors/20251018130654_dev.json.license | 3 + ...20251018130654_migrate_resources64_dev.exs | 27 ++++ test/storage_types_test.exs | 82 +++++++++++ test/support/resources/author.ex | 6 +- test/support/resources/identity.ex | 13 ++ test/support/resources/preference.ex | 13 ++ 7 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/authors/20251018130654_dev.json create mode 100644 priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license create mode 100644 priv/test_repo/migrations/20251018130654_migrate_resources64_dev.exs create mode 100644 test/support/resources/identity.ex create mode 100644 test/support/resources/preference.ex diff --git a/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json b/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json new file mode 100644 index 00000000..e14b635e --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json @@ -0,0 +1,133 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "first_name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "last_name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "bio", + "type": "map" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "bios", + "type": "jsonb" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "badges", + "type": [ + "array", + "text" + ] + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "settings", + "type": "jsonb" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "identities", + "type": "jsonb" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "preferences", + "type": [ + "array", + "map" + ] + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "55CFEDA4CB07DD89D2807B080A6F0E14A0370D7EA0C48E67C36ACAC568137D95", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "authors" +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license b/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license new file mode 100644 index 00000000..b0a44fab --- /dev/null +++ b/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019 ash_postgres contributors + +SPDX-License-Identifier: MIT diff --git a/priv/test_repo/migrations/20251018130654_migrate_resources64_dev.exs b/priv/test_repo/migrations/20251018130654_migrate_resources64_dev.exs new file mode 100644 index 00000000..ba9e1baf --- /dev/null +++ b/priv/test_repo/migrations/20251018130654_migrate_resources64_dev.exs @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.TestRepo.Migrations.MigrateResources64 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:authors) do + add(:identities, :jsonb) + add(:preferences, {:array, :map}) + end + end + + def down do + alter table(:authors) do + remove(:preferences) + remove(:identities) + end + end +end diff --git a/test/storage_types_test.exs b/test/storage_types_test.exs index ad414bf8..0f818048 100644 --- a/test/storage_types_test.exs +++ b/test/storage_types_test.exs @@ -93,4 +93,86 @@ defmodule AshPostgres.StorageTypesTest do |> Ash.Query.filter(not is_nil(settings["dues_reminders"])) |> Ash.read!() end + + test "can bulk update {:array, CustomTypedStruct} stored as jsonb" do + %{id: id} = + Author + |> Ash.Changeset.for_create( + :create, + %{ + first_name: "Test", + last_name: "User", + identities: [%{provider: "github", uid: "123"}, %{provider: "google", uid: "456"}] + } + ) + |> Ash.create!() + + %BulkResult{records: [author]} = + Author + |> Ash.Query.filter(id == ^id) + |> Ash.bulk_update(:update, %{identities: [%{provider: "gitlab", uid: "789"}]}, + return_errors?: true, + notify?: true, + strategy: [:atomic, :stream, :atomic_batches], + allow_stream_with: :full_read, + return_records?: true + ) + + assert length(author.identities) == 1 + assert %{provider: "gitlab", uid: "789"} = hd(author.identities) + + %BulkResult{records: [author]} = + Author + |> Ash.Query.filter(id == ^id) + |> Ash.bulk_update(:update, %{identities: []}, + return_errors?: true, + notify?: true, + strategy: [:atomic, :stream, :atomic_batches], + allow_stream_with: :full_read, + return_records?: true + ) + + assert author.identities == [] + end + + test "can bulk update {:array, CustomTypedStruct} stored as {:array, :map}" do + %{id: id} = + Author + |> Ash.Changeset.for_create( + :create, + %{ + first_name: "Test", + last_name: "User", + preferences: [%{key: "theme", value: "dark"}, %{key: "lang", value: "en"}] + } + ) + |> Ash.create!() + + %BulkResult{records: [author]} = + Author + |> Ash.Query.filter(id == ^id) + |> Ash.bulk_update(:update, %{preferences: [%{key: "theme", value: "light"}]}, + return_errors?: true, + notify?: true, + strategy: [:atomic, :stream, :atomic_batches], + allow_stream_with: :full_read, + return_records?: true + ) + + assert length(author.preferences) == 1 + assert %{key: "theme", value: "light"} = hd(author.preferences) + + %BulkResult{records: [author]} = + Author + |> Ash.Query.filter(id == ^id) + |> Ash.bulk_update(:update, %{preferences: []}, + return_errors?: true, + notify?: true, + strategy: [:atomic, :stream, :atomic_batches], + allow_stream_with: :full_read, + return_records?: true + ) + + assert author.preferences == [] + end end diff --git a/test/support/resources/author.ex b/test/support/resources/author.ex index 3530513c..4203b262 100644 --- a/test/support/resources/author.ex +++ b/test/support/resources/author.ex @@ -23,8 +23,8 @@ defmodule AshPostgres.Test.Author do table("authors") repo(AshPostgres.TestRepo) - migration_types bios: :jsonb, settings: :jsonb - storage_types(bios: :jsonb, settings: :jsonb) + migration_types bios: :jsonb, settings: :jsonb, identities: :jsonb + storage_types(bios: :jsonb, settings: :jsonb, identities: :jsonb) end attributes do @@ -35,6 +35,8 @@ defmodule AshPostgres.Test.Author do attribute(:bios, {:array, :map}, public?: true) attribute(:badges, {:array, :atom}, public?: true) attribute(:settings, AshPostgres.Test.Settings, public?: true) + attribute(:identities, {:array, AshPostgres.Test.Identity}, public?: true) + attribute(:preferences, {:array, AshPostgres.Test.Preference}, public?: true) end actions do diff --git a/test/support/resources/identity.ex b/test/support/resources/identity.ex new file mode 100644 index 00000000..d29aaa07 --- /dev/null +++ b/test/support/resources/identity.ex @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.Identity do + @moduledoc false + use Ash.TypedStruct + + typed_struct do + field(:provider, :string, allow_nil?: false) + field(:uid, :string, allow_nil?: false) + end +end diff --git a/test/support/resources/preference.ex b/test/support/resources/preference.ex new file mode 100644 index 00000000..b5e707fa --- /dev/null +++ b/test/support/resources/preference.ex @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2019 ash_postgres contributors +# +# SPDX-License-Identifier: MIT + +defmodule AshPostgres.Test.Preference do + @moduledoc false + use Ash.TypedStruct + + typed_struct do + field(:key, :string, allow_nil?: false) + field(:value, :string, allow_nil?: false) + end +end From 1023dedf41af0f9772240c42f7cf369b1b29b5c1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 19 Oct 2025 12:27:55 -0400 Subject: [PATCH 688/690] improvement: remove unused bulk operation metadata function & update ash --- lib/data_layer.ex | 52 +++++++++++------------------------------------ mix.exs | 2 +- mix.lock | 6 +++--- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index b984c4db..4469f369 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -2138,18 +2138,12 @@ defmodule AshPostgres.DataLayer do maybe_create_tenant!(resource, result_for_changeset) end - case get_bulk_operation_metadata(changeset) do - {index, metadata_key} -> - Ash.Resource.put_metadata(result_for_changeset, metadata_key, index) - - nil -> - # Compatibility fallback - Ash.Resource.put_metadata( - result_for_changeset, - :bulk_create_index, - changeset.context[:bulk_create][:index] - ) - end + # Compatibility fallback + Ash.Resource.put_metadata( + result_for_changeset, + :bulk_create_index, + changeset.context[:bulk_create][:index] + ) end end) |> Enum.filter(& &1) @@ -2161,18 +2155,12 @@ defmodule AshPostgres.DataLayer do maybe_create_tenant!(resource, result) end - case get_bulk_operation_metadata(changeset) do - {index, metadata_key} -> - Ash.Resource.put_metadata(result, metadata_key, index) - - nil -> - # Compatibility fallback - Ash.Resource.put_metadata( - result, - :bulk_create_index, - changeset.context[:bulk_create][:index] - ) - end + # Compatibility fallback + Ash.Resource.put_metadata( + result, + :bulk_create_index, + changeset.context[:bulk_create][:index] + ) end) end @@ -3759,20 +3747,4 @@ defmodule AshPostgres.DataLayer do resource end end - - defp get_bulk_operation_metadata(changeset) do - changeset.context - |> Enum.find_value(fn - # New format: {{:bulk_create, ref}, value} -> {index, metadata_key} - {{:bulk_create, ref}, value} -> - {value.index, {:bulk_create_index, ref}} - - # Fallback for old format: {:bulk_create, value} -> {index, metadata_key} - {:bulk_create, value} when is_map(value) -> - {value.index, :bulk_create_index} - - _ -> - nil - end) - end end diff --git a/mix.exs b/mix.exs index 5e14da8d..526064c2 100644 --- a/mix.exs +++ b/mix.exs @@ -177,7 +177,7 @@ defmodule AshPostgres.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 3.7")}, + {:ash, ash_version("~> 3.7 and >= 3.7.5")}, {:spark, "~> 2.3 and >= 2.3.4"}, {:ash_sql, ash_sql_version("~> 0.3 and >= 0.3.7")}, {:igniter, "~> 0.6 and >= 0.6.29", optional: true}, diff --git a/mix.lock b/mix.lock index c988302d..a40b623c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,10 +1,10 @@ %{ - "ash": {:hex, :ash, "3.7.1", "abb55dee19e0959e529e52fe0622468825ae05400f535484919713e492d9a9e7", [:mix], [{:crux, "~> 0.1.0", [hex: :crux, repo: "hexpm", optional: false]}, {: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "4474ce9befe9862d1ed73cadf8a755e836c45a14a7b3b952d02e1a12f2b2e529"}, + "ash": {:hex, :ash, "3.7.5", "91e926d14f51a6b406660bd136c3165316d37f2ce68f0ca6118d7c0e41174f0c", [:mix], [{:crux, ">= 0.1.2 and < 1.0.0-0", [hex: :crux, repo: "hexpm", optional: false]}, {: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "df839ac2321768dde1216e317e5a824a136251699f8837a1e8a9ee4508f7e47a"}, "ash_sql": {:hex, :ash_sql, "0.3.7", "80affa5446075d71deb157c67290685a84b392d723be766bfb684f58fe0143de", [:mix], [{:ash, "~> 3.7", [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", "ce4d974b8e784171c5a2a62593b3672b42dfd4888fa2239f01a6b32bad769038"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, - "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, - "crux": {:hex, :crux, "0.1.1", "94f2f97d2a6079ae3c57f356412bc3b307f9579a80e43f526447b1d508dd4a72", [:mix], [{:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:stream_data, "~> 1.0", [hex: :stream_data, repo: "hexpm", optional: true]}], "hexpm", "e59d498f038193cbe31e448f9199f5b4c53a4c67cece9922bb839595189dd2b6"}, + "credo": {:hex, :credo, "1.7.13", "126a0697df6b7b71cd18c81bc92335297839a806b6f62b61d417500d1070ff4e", [: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", "47641e6d2bbff1e241e87695b29f617f1a8f912adea34296fb10ecc3d7e9e84f"}, + "crux": {:hex, :crux, "0.1.2", "4441c9e3a34f1e340954ce96b9ad5a2de13ceb4f97b3f910211227bb92e2ca90", [:mix], [{:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:stream_data, "~> 1.0", [hex: :stream_data, repo: "hexpm", optional: true]}], "hexpm", "563ea3748ebfba9cc078e6d198a1d6a06015a8fae503f0b721363139f0ddb350"}, "db_connection": {:hex, :db_connection, "2.8.1", "9abdc1e68c34c6163f6fb96a96532272d13ad7ca45262156ae8b7ec6d9dc4bec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61a3d489b239d76f326e03b98794fb8e45168396c925ef25feb405ed09da8fd"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, From 89ca1fe164cb9c24ac1ff822ec6891d23a5bf91f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 19 Oct 2025 12:30:18 -0400 Subject: [PATCH 689/690] chore: update mix.lock --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index a40b623c..9b2bc487 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "ash": {:hex, :ash, "3.7.5", "91e926d14f51a6b406660bd136c3165316d37f2ce68f0ca6118d7c0e41174f0c", [:mix], [{:crux, ">= 0.1.2 and < 1.0.0-0", [hex: :crux, repo: "hexpm", optional: false]}, {: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.6.29 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, 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.3.3 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", "df839ac2321768dde1216e317e5a824a136251699f8837a1e8a9ee4508f7e47a"}, - "ash_sql": {:hex, :ash_sql, "0.3.7", "80affa5446075d71deb157c67290685a84b392d723be766bfb684f58fe0143de", [:mix], [{:ash, "~> 3.7", [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", "ce4d974b8e784171c5a2a62593b3672b42dfd4888fa2239f01a6b32bad769038"}, + "ash_sql": {:hex, :ash_sql, "0.3.8", "9f55866149b4fc092eb37c346e0734143f70dbfae8793c86a5a46803c2b47a12", [:mix], [{:ash, "~> 3.7", [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", "0b58a8191744347bb349ace9affb3effc5ceaf8f1bc572915a5cf2ec4c45b72d"}, "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.13", "126a0697df6b7b71cd18c81bc92335297839a806b6f62b61d417500d1070ff4e", [: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", "47641e6d2bbff1e241e87695b29f617f1a8f912adea34296fb10ecc3d7e9e84f"}, From 913f9360a5c590c56ed80b984d2f434133ff773c Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 19 Oct 2025 22:41:24 -0400 Subject: [PATCH 690/690] chore: fix tests & don't do normal rollbacks with `--tenant` option --- lib/data_layer.ex | 130 +++++++++--------- .../migration_generator.ex | 14 +- .../authors/20251018130654_dev.json.license | 3 - ...018130654_dev.json => 20251020024026.json} | 2 +- ...=> 20251020024026_migrate_resources64.exs} | 4 - 5 files changed, 69 insertions(+), 84 deletions(-) delete mode 100644 priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license rename priv/resource_snapshots/test_repo/authors/{20251018130654_dev.json => 20251020024026.json} (97%) rename priv/test_repo/migrations/{20251018130654_migrate_resources64_dev.exs => 20251020024026_migrate_resources64.exs} (75%) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 4469f369..910e0e87 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -453,72 +453,74 @@ defmodule AshPostgres.DataLayer do migrations_path = AshPostgres.Mix.Helpers.migrations_path([], repo) tenant_migrations_path = AshPostgres.Mix.Helpers.tenant_migrations_path([], repo) - current_migrations = - Ecto.Query.from(row in "schema_migrations", - select: row.version - ) - |> repo.all() - |> Enum.map(&to_string/1) + if "--tenants" not in args do + current_migrations = + Ecto.Query.from(row in "schema_migrations", + select: row.version + ) + |> repo.all() + |> Enum.map(&to_string/1) + + files = + migrations_path + |> Path.join("**/*.exs") + |> Path.wildcard() + |> Enum.sort() + |> Enum.reverse() + |> Enum.filter(fn file -> + Enum.any?(current_migrations, &String.starts_with?(Path.basename(file), &1)) + end) + |> Enum.take(20) + |> Enum.map(&String.trim_leading(&1, migrations_path)) + |> Enum.map(&String.trim_leading(&1, "/")) + + indexed = + files + |> Enum.with_index() + |> Enum.map(fn {file, index} -> "#{index + 1}: #{file}" end) + + to = + Mix.shell().prompt( + """ + How many migrations should be rolled back#{for_repo}? (default: 0) + + Last 20 migration names, with the input you must provide to + rollback up to *and including* that migration: + + #{Enum.join(indexed, "\n")} + Rollback to: + """ + |> String.trim_trailing() + ) + |> String.trim() + |> case do + "" -> + nil - files = - migrations_path - |> Path.join("**/*.exs") - |> Path.wildcard() - |> Enum.sort() - |> Enum.reverse() - |> Enum.filter(fn file -> - Enum.any?(current_migrations, &String.starts_with?(Path.basename(file), &1)) - end) - |> Enum.take(20) - |> Enum.map(&String.trim_leading(&1, migrations_path)) - |> Enum.map(&String.trim_leading(&1, "/")) - - indexed = - files - |> Enum.with_index() - |> Enum.map(fn {file, index} -> "#{index + 1}: #{file}" end) - - to = - Mix.shell().prompt( - """ - How many migrations should be rolled back#{for_repo}? (default: 0) - - Last 20 migration names, with the input you must provide to - rollback up to *and including* that migration: - - #{Enum.join(indexed, "\n")} - Rollback to: - """ - |> String.trim_trailing() - ) - |> String.trim() - |> case do - "" -> - nil - - "0" -> - nil - - n -> - try do - files - |> Enum.at(String.to_integer(n) - 1) - rescue - _ -> - reraise "Required an integer value, got: #{n}", __STACKTRACE__ - end - |> String.split("_", parts: 2) - |> Enum.at(0) - |> String.to_integer() - end + "0" -> + nil - if to do - Mix.Task.run( - "ash_postgres.rollback", - args ++ ["-r", inspect(repo), "--to", to_string(to)] - ) + n -> + try do + files + |> Enum.at(String.to_integer(n) - 1) + rescue + _ -> + reraise "Required an integer value, got: #{n}", __STACKTRACE__ + end + |> String.split("_", parts: 2) + |> Enum.at(0) + |> String.to_integer() + end - Mix.Task.reenable("ash_postgres.rollback") + if to do + Mix.Task.run( + "ash_postgres.rollback", + args ++ ["-r", inspect(repo), "--to", to_string(to)] + ) + + Mix.Task.reenable("ash_postgres.rollback") + end end tenant_files = @@ -599,7 +601,7 @@ defmodule AshPostgres.DataLayer do if to do Mix.Task.run( "ash_postgres.rollback", - args ++ ["--tenants", "-r", inspect(repo), "--to", to] + args ++ ["--tenants", "-r", inspect(repo), "--to", to_string(to)] ) Mix.Task.reenable("ash_postgres.rollback") diff --git a/lib/migration_generator/migration_generator.ex b/lib/migration_generator/migration_generator.ex index 9881818c..425ccb53 100644 --- a/lib/migration_generator/migration_generator.ex +++ b/lib/migration_generator/migration_generator.ex @@ -514,16 +514,6 @@ defmodule AshPostgres.MigrationGenerator do end end - if Mix.env() == :test do - defp with_repo_not_in_test(repo, fun) do - fun.(repo) - end - else - defp with_repo_not_in_test(repo, fun) do - Ecto.Migrator.with_repo(repo, fun) - end - end - defp require_name!(opts) do if !opts.name && !opts.dry_run && !opts.check && !opts.snapshots_only && !opts.dev && !opts.auto_name do @@ -548,7 +538,7 @@ defmodule AshPostgres.MigrationGenerator do end) if tenant? do - with_repo_not_in_test(repo, fn repo -> + Ecto.Migrator.with_repo(repo, fn repo -> for prefix <- repo.all_tenants() do {repo, query, opts} = Ecto.Migration.SchemaMigration.versions(repo, [], prefix) @@ -583,7 +573,7 @@ defmodule AshPostgres.MigrationGenerator do end end) else - with_repo_not_in_test(repo, fn repo -> + Ecto.Migrator.with_repo(repo, fn repo -> {repo, query, opts} = Ecto.Migration.SchemaMigration.versions(repo, [], nil) repo.transaction(fn -> diff --git a/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license b/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license deleted file mode 100644 index b0a44fab..00000000 --- a/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2019 ash_postgres contributors - -SPDX-License-Identifier: MIT diff --git a/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json b/priv/resource_snapshots/test_repo/authors/20251020024026.json similarity index 97% rename from priv/resource_snapshots/test_repo/authors/20251018130654_dev.json rename to priv/resource_snapshots/test_repo/authors/20251020024026.json index e14b635e..761a9e2a 100644 --- a/priv/resource_snapshots/test_repo/authors/20251018130654_dev.json +++ b/priv/resource_snapshots/test_repo/authors/20251020024026.json @@ -120,7 +120,7 @@ "custom_indexes": [], "custom_statements": [], "has_create_action": true, - "hash": "55CFEDA4CB07DD89D2807B080A6F0E14A0370D7EA0C48E67C36ACAC568137D95", + "hash": "DEDCEFDB71DE94818B8D624B0BFE438AD7AEDC6279FD05B83C11C216E7A0F991", "identities": [], "multitenancy": { "attribute": null, diff --git a/priv/test_repo/migrations/20251018130654_migrate_resources64_dev.exs b/priv/test_repo/migrations/20251020024026_migrate_resources64.exs similarity index 75% rename from priv/test_repo/migrations/20251018130654_migrate_resources64_dev.exs rename to priv/test_repo/migrations/20251020024026_migrate_resources64.exs index ba9e1baf..ff7d63f3 100644 --- a/priv/test_repo/migrations/20251018130654_migrate_resources64_dev.exs +++ b/priv/test_repo/migrations/20251020024026_migrate_resources64.exs @@ -1,7 +1,3 @@ -# SPDX-FileCopyrightText: 2019 ash_postgres contributors -# -# SPDX-License-Identifier: MIT - defmodule AshPostgres.TestRepo.Migrations.MigrateResources64 do @moduledoc """ Updates resources based on their most recent snapshots.