mirror of
https://github.com/ash-project/ash_archival.git
synced 2024-09-19 13:02:55 +12:00
test: more tests for archival, including postgres tests
This commit is contained in:
parent
1ae3ce69ef
commit
e2a0e1cabd
16 changed files with 407 additions and 3 deletions
3
.github/workflows/elixir.yml
vendored
3
.github/workflows/elixir.yml
vendored
|
@ -9,3 +9,6 @@ on:
|
|||
jobs:
|
||||
ash-ci:
|
||||
uses: ash-project/ash/.github/workflows/ash-ci.yml@main
|
||||
with:
|
||||
postgres: true
|
||||
postgres-version: "16"
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
import Config
|
||||
|
||||
if Mix.env() == :test do
|
||||
config :ash_archival, ash_domains: [AshArchival.Test.Domain]
|
||||
|
||||
config :ash_archival,
|
||||
ecto_repos: [AshArchival.TestRepo]
|
||||
|
||||
config :ash, :validate_domain_resource_inclusion?, false
|
||||
config :ash, :validate_domain_config_inclusion?, false
|
||||
config :logger, level: :warning
|
||||
|
||||
config :ash_archival, AshArchival.TestRepo,
|
||||
username: "postgres",
|
||||
database: "ash_archival_test",
|
||||
hostname: "localhost",
|
||||
pool: Ecto.Adapters.SQL.Sandbox
|
||||
end
|
||||
|
||||
if Mix.env() == :dev do
|
||||
|
|
|
@ -21,6 +21,7 @@ A section for configuring how archival is configured for a resource.
|
|||
| Name | Type | Default | Docs |
|
||||
|------|------|---------|------|
|
||||
| [`attribute`](#archive-attribute){: #archive-attribute } | `atom` | `:archived_at` | The attribute in which to store the archival flag (the current datetime). |
|
||||
| [`attribute_type`](#archive-attribute_type){: #archive-attribute_type } | `atom` | `:utc_datetime_usec` | The attribute type. |
|
||||
| [`base_filter?`](#archive-base_filter?){: #archive-base_filter? } | `atom` | `false` | Whether or not a base filter exists that applies the `is_nil(archived_at)` rule. |
|
||||
| [`exclude_read_actions`](#archive-exclude_read_actions){: #archive-exclude_read_actions } | `atom \| list(atom)` | `[]` | A read action or actions that should show archived items. They will not get the automatic `is_nil(archived_at)` filter. |
|
||||
| [`exclude_upsert_actions`](#archive-exclude_upsert_actions){: #archive-exclude_upsert_actions } | `atom \| list(atom)` | `[]` | This option is deprecated as it no longer has any effect. Upserts are handled according to the upsert identity. See the upserts guide for more. |
|
||||
|
|
9
mix.exs
9
mix.exs
|
@ -13,6 +13,7 @@ defmodule AshArchival.MixProject do
|
|||
elixir: "~> 1.13",
|
||||
source_url: "https://github.com/ash-project/ash_archival",
|
||||
homepage_url: "https://github.com/ash-project/ash_archival",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
start_permanent: Mix.env() == :prod,
|
||||
description: @description,
|
||||
aliases: aliases(),
|
||||
|
@ -23,6 +24,9 @@ defmodule AshArchival.MixProject do
|
|||
]
|
||||
end
|
||||
|
||||
defp elixirc_paths(:test), do: ["lib", "test/support"]
|
||||
defp elixirc_paths(_), do: ["lib"]
|
||||
|
||||
defp package do
|
||||
[
|
||||
name: :ash_archival,
|
||||
|
@ -93,6 +97,7 @@ defmodule AshArchival.MixProject do
|
|||
[
|
||||
{:ash, ash_version("~> 3.0 and >= 3.0.5")},
|
||||
# dev/test dependencies
|
||||
{:ash_postgres, "~> 2.3", only: [:dev, :test]},
|
||||
{:simple_sat, "~> 0.1.0", only: [:dev, :test]},
|
||||
{:git_ops, "~> 2.5", only: [:dev, :test]},
|
||||
{:ex_doc, github: "elixir-lang/ex_doc", only: [:dev, :test], runtime: false},
|
||||
|
@ -125,8 +130,8 @@ defmodule AshArchival.MixProject do
|
|||
defp ash_version(default_version) do
|
||||
case System.get_env("ASH_VERSION") do
|
||||
nil -> default_version
|
||||
"local" -> [path: "../ash"]
|
||||
"main" -> [git: "https://github.com/ash-project/ash.git"]
|
||||
"local" -> [path: "../ash", override: true]
|
||||
"main" -> [git: "https://github.com/ash-project/ash.git", override: true]
|
||||
version -> "~> #{version}"
|
||||
end
|
||||
end
|
||||
|
|
7
mix.lock
7
mix.lock
|
@ -1,11 +1,15 @@
|
|||
%{
|
||||
"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.5", "ea5cb8f2ce11c4610cb8874c3d7e8952a822759d34bc01c6dd5c8ec6174b9146", [: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", "cecc2a3a3e5c9998fd5415eb53aaf8511ad5acc4e71cc8bdbf1ec5acb6383faa"},
|
||||
"ash_postgres": {:hex, :ash_postgres, "2.3.1", "23eaa95063a25d1332845089dbb0ae64e01ef4ed413abfc9168738e9b7f23f54", [:mix], [{:ash, ">= 3.4.2 and < 4.0.0-0", [hex: :ash, repo: "hexpm", optional: false]}, {:ash_sql, ">= 0.2.30 and < 1.0.0-0", [hex: :ash_sql, repo: "hexpm", optional: false]}, {:ecto, ">= 3.12.1 and < 4.0.0-0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:igniter, ">= 0.3.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:inflex, "~> 2.1", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "886659fe8e5013f2b4c2382a5dc71b3f06b566f663a39e6310d7d116db0bdace"},
|
||||
"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"},
|
||||
"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"},
|
||||
"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"},
|
||||
"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.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"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"},
|
||||
"ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"},
|
||||
|
@ -26,6 +30,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.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"},
|
||||
|
|
6
priv/resource_snapshots/test_repo/extensions.json
Normal file
6
priv/resource_snapshots/test_repo/extensions.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"ash_functions_version": 4,
|
||||
"installed": [
|
||||
"ash-functions"
|
||||
]
|
||||
}
|
39
priv/resource_snapshots/test_repo/posts/20240905173414.json
Normal file
39
priv/resource_snapshots/test_repo/posts/20240905173414.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"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": "archived_at",
|
||||
"type": "utc_datetime_usec"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "89AA75CB853B0B701A5E6C2BC611C10DB1612064CE32E005DA70FBADC5B2983F",
|
||||
"identities": [],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.AshArchival.TestRepo",
|
||||
"schema": null,
|
||||
"table": "posts"
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
defmodule AshArchival.TestRepo.Migrations.InstallAshFunctionsExtension420240905173230 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 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), 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
|
||||
end
|
20
priv/test_repo/migrations/20240905173414_add_posts.exs
Normal file
20
priv/test_repo/migrations/20240905173414_add_posts.exs
Normal file
|
@ -0,0 +1,20 @@
|
|||
defmodule AshArchival.TestRepo.Migrations.AddPosts 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(:posts, primary_key: false) do
|
||||
add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true)
|
||||
add(:archived_at, :utc_datetime_usec)
|
||||
end
|
||||
end
|
||||
|
||||
def down do
|
||||
drop(table(:posts))
|
||||
end
|
||||
end
|
|
@ -75,6 +75,12 @@ defmodule ArchivalTest do
|
|||
create(:upsert)
|
||||
|
||||
read(:all_posts)
|
||||
|
||||
update :unarchive do
|
||||
accept([])
|
||||
atomic_upgrade_with(:all_posts)
|
||||
change(set_attribute(:archived_at, nil))
|
||||
end
|
||||
end
|
||||
|
||||
attributes do
|
||||
|
@ -100,6 +106,39 @@ defmodule ArchivalTest do
|
|||
end
|
||||
end
|
||||
|
||||
defmodule UnarchivablePost do
|
||||
use Ash.Resource,
|
||||
domain: ArchivalTest.Domain,
|
||||
data_layer: Ash.DataLayer.Ets,
|
||||
extensions: [AshArchival.Resource]
|
||||
|
||||
ets do
|
||||
table(:posts)
|
||||
private?(true)
|
||||
end
|
||||
|
||||
archive do
|
||||
exclude_read_actions :all_posts
|
||||
end
|
||||
|
||||
actions do
|
||||
default_accept(:*)
|
||||
defaults([:create, :read, :update, :destroy])
|
||||
|
||||
read(:all_posts)
|
||||
|
||||
update :unarchive do
|
||||
accept([])
|
||||
atomic_upgrade_with(:all_posts)
|
||||
change(set_attribute(:archived_at, nil))
|
||||
end
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule PostWithArchive do
|
||||
use Ash.Resource,
|
||||
domain: ArchivalTest.Domain,
|
||||
|
@ -177,6 +216,7 @@ defmodule ArchivalTest do
|
|||
resource(Author)
|
||||
resource(AuthorWithArchive)
|
||||
resource(Post)
|
||||
resource(UnarchivablePost)
|
||||
resource(PostWithArchive)
|
||||
resource(Comment)
|
||||
resource(CommentWithArchive)
|
||||
|
@ -207,6 +247,15 @@ defmodule ArchivalTest do
|
|||
assert [] = Ash.read!(Post)
|
||||
end
|
||||
|
||||
test "archived records can be unarchived" do
|
||||
assert %UnarchivablePost{} =
|
||||
UnarchivablePost
|
||||
|> Ash.Changeset.for_create(:create)
|
||||
|> Ash.create!()
|
||||
|> Ash.Changeset.for_update(:unarchive)
|
||||
|> Ash.update!()
|
||||
end
|
||||
|
||||
test "upserts don't consider archived records if included in the identity" do
|
||||
post =
|
||||
Post
|
||||
|
|
35
test/postgres_test.exs
Normal file
35
test/postgres_test.exs
Normal file
|
@ -0,0 +1,35 @@
|
|||
defmodule AshArchival.PostgresTest do
|
||||
use AshArchival.RepoCase
|
||||
|
||||
alias AshArchival.Test.Post
|
||||
require Ash.Query
|
||||
|
||||
test "unarchival works" do
|
||||
Logger.configure(level: :debug)
|
||||
|
||||
assert %Post{} =
|
||||
Post
|
||||
|> Ash.Changeset.for_create(:create)
|
||||
|> Ash.create!()
|
||||
|> Ash.Changeset.for_destroy(:destroy)
|
||||
|> Ash.destroy!(return_destroyed?: true)
|
||||
|> Ash.Changeset.for_update(:unarchive)
|
||||
|> Ash.update!()
|
||||
end
|
||||
|
||||
test "bulk unarchival works" do
|
||||
Logger.configure(level: :debug)
|
||||
|
||||
assert %Ash.BulkResult{records: [%Post{}]} =
|
||||
Post
|
||||
|> Ash.Changeset.for_create(:create)
|
||||
|> Ash.create!()
|
||||
|> Ash.Changeset.for_destroy(:destroy)
|
||||
|> Ash.destroy!(return_destroyed?: true)
|
||||
|> then(fn post ->
|
||||
Post
|
||||
|> Ash.Query.filter(id == ^post.id)
|
||||
end)
|
||||
|> Ash.bulk_update!(:unarchive, %{}, return_records?: true)
|
||||
end
|
||||
end
|
8
test/support/domain.ex
Normal file
8
test/support/domain.ex
Normal file
|
@ -0,0 +1,8 @@
|
|||
defmodule AshArchival.Test.Domain do
|
||||
@moduledoc false
|
||||
use Ash.Domain
|
||||
|
||||
resources do
|
||||
resource(AshArchival.Test.Post)
|
||||
end
|
||||
end
|
33
test/support/post.ex
Normal file
33
test/support/post.ex
Normal file
|
@ -0,0 +1,33 @@
|
|||
defmodule AshArchival.Test.Post do
|
||||
@moduledoc false
|
||||
use Ash.Resource,
|
||||
domain: AshArchival.Test.Domain,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshArchival.Resource]
|
||||
|
||||
archive do
|
||||
exclude_read_actions :all_posts
|
||||
end
|
||||
|
||||
postgres do
|
||||
table("posts")
|
||||
repo(AshArchival.TestRepo)
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
end
|
||||
|
||||
actions do
|
||||
default_accept(:*)
|
||||
defaults([:create, :read, :update, :destroy])
|
||||
|
||||
read(:all_posts)
|
||||
|
||||
update :unarchive do
|
||||
accept([])
|
||||
atomic_upgrade_with(:all_posts)
|
||||
change(set_attribute(:archived_at, nil))
|
||||
end
|
||||
end
|
||||
end
|
20
test/support/repo.ex
Normal file
20
test/support/repo.ex
Normal file
|
@ -0,0 +1,20 @@
|
|||
defmodule AshArchival.TestRepo do
|
||||
@moduledoc false
|
||||
use AshPostgres.Repo,
|
||||
otp_app: :ash_archival
|
||||
|
||||
def on_transaction_begin(data) do
|
||||
send(self(), data)
|
||||
end
|
||||
|
||||
def installed_extensions do
|
||||
["ash-functions"]
|
||||
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
|
||||
end
|
28
test/support/repo_case.ex
Normal file
28
test/support/repo_case.ex
Normal file
|
@ -0,0 +1,28 @@
|
|||
defmodule AshArchival.RepoCase do
|
||||
@moduledoc false
|
||||
use ExUnit.CaseTemplate
|
||||
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
using do
|
||||
quote do
|
||||
alias AshArchival.TestRepo
|
||||
|
||||
import Ecto
|
||||
import Ecto.Query
|
||||
import AshArchival.RepoCase
|
||||
|
||||
# and any other stuff
|
||||
end
|
||||
end
|
||||
|
||||
setup tags do
|
||||
:ok = Sandbox.checkout(AshArchival.TestRepo)
|
||||
|
||||
unless tags[:async] do
|
||||
Sandbox.mode(AshArchival.TestRepo, {:shared, self()})
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
|
@ -1 +1,3 @@
|
|||
ExUnit.start()
|
||||
|
||||
AshArchival.TestRepo.start_link()
|
||||
|
|
Loading…
Reference in a new issue