From dc3e75163d85de216f0815866d8be049e905aa1c Mon Sep 17 00:00:00 2001 From: mithereal Date: Wed, 29 Mar 2023 21:37:35 -0700 Subject: [PATCH 01/61] add restore functionality --- lib/ecto/soft_delete_repo.ex | 45 +++++++++++++++++++++++-- test/soft_delete_repo_test.exs | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 0643fe1..10c3d88 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -26,6 +26,21 @@ defmodule Ecto.SoftDelete.Repo do """ @callback soft_delete_all(queryable :: Ecto.Queryable.t()) :: {integer, nil | [term]} + @doc """ + Soft restores all entries matching the given query. + + It returns a tuple containing the number of entries and any returned + result as second element. The second element is `nil` by default + unless a `select` is supplied in the update query. + + ## Examples + + MyRepo.soft_delete_all(Post) + from(p in Post, where: p.id < 10) |> MyRepo.soft_delete_all() + + """ + @callback soft_restore_all(queryable :: Ecto.Queryable.t()) :: {integer, nil | [term]} + @doc """ Soft deletes a struct. Updates the `deleted_at` field with the current datetime in UTC. @@ -37,8 +52,8 @@ defmodule Ecto.SoftDelete.Repo do post = MyRepo.get!(Post, 42) case MyRepo.soft_delete post do - {:ok, struct} -> # Soft deleted with success - {:error, changeset} -> # Something went wrong + {:ok, struct} -> "Soft deleted with success" + {:error, changeset} -> "Something went wrong" end """ @@ -51,6 +66,15 @@ defmodule Ecto.SoftDelete.Repo do @callback soft_delete!(struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t()) :: Ecto.Schema.t() + @callback soft_restore(struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t()) :: + {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()} + + @doc """ + Same as `c:soft_restore/1` but returns the struct or raises if the changeset is invalid. + """ + @callback soft_restore!(struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t()) :: + Ecto.Schema.t() + defmacro __using__(_opts) do quote do import Ecto.Query @@ -71,6 +95,23 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end + + def soft_restore_all(queryable) do + update_all(queryable, set: [deleted_at: nil]) + end + + def soft_restore(struct_or_changeset) do + struct_or_changeset + |> Ecto.Changeset.change(deleted_at: nil) + |> update() + end + + def soft_restore!(struct_or_changeset) do + struct_or_changeset + |> Ecto.Changeset.change(deleted_at: nil) + |> update!() + end + @doc """ Overrides all query operations to exclude soft deleted records if the schema in the from clause has a deleted_at column diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 6d4d9e3..f05e03a 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -90,6 +90,66 @@ defmodule Ecto.SoftDelete.Repo.Test do end end + describe "soft_restore/1" do + test "should soft restore the queryable" do + user = Repo.insert!(%User{email: "test0@example.com"}) + + assert {:ok, %User{}} = Repo.soft_restore(user) + + assert nil + Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at + end + + test "should return an error deleting" do + user = Repo.insert!(%User{email: "test0@example.com"}) + Repo.delete!(user) + + assert_raise Ecto.StaleEntryError, fn -> + Repo.soft_restore(user) + end + end + end + + describe "soft_restore_all/1" do + test "soft deleted the query" do + Repo.insert!(%User{email: "test0@example.com"}) + Repo.insert!(%User{email: "test1@example.com"}) + Repo.insert!(%User{email: "test2@example.com"}) + + assert Repo.soft_delete_all(User) == {3, nil} + + assert User |> Repo.all(with_deleted: true) |> length() == 3 + + assert %DateTime{} = + Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at + + assert %DateTime{} = + Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at + + assert %DateTime{} = + Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at + + + assert Repo.soft_restore_all(User) == {3, nil} + + assert User |> Repo.all(with_deleted: true) |> length() == 3 + + assert nil = + Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at + + assert nil = + Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at + + assert nil = + Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at + end + + test "when no results are found" do + assert Repo.soft_delete_all(User) == {0, nil} + end + end + + describe "prepare_query/3" do test "excludes soft deleted records by default" do user = Repo.insert!(%User{email: "test0@example.com"}) From 163efdffa60cd8d5d705798621f9f171ab3a3319 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 16:16:30 -0700 Subject: [PATCH 02/61] fix travis test --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index a9657a0..0a6cbb2 100644 --- a/mix.exs +++ b/mix.exs @@ -51,7 +51,7 @@ defmodule EctoSoftDelete.Mixfile do maintainers: ["Bryan Joseph", "Luke Ledet"], licenses: ["MIT"], links: %{ - "GitHub" => "https://github.com/revelrylabs/ecto_soft_delete" + "GitHub" => "https://github.com/data-twister/ecto_soft_delete" }, build_tools: ["mix"] ] From ae2d7b6628d49068af831d779d1349678b8eb41e Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 16:25:09 -0700 Subject: [PATCH 03/61] fix travis test --- test/soft_delete_repo_test.exs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index f05e03a..f3e84c7 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,22 +92,11 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - user = Repo.insert!(%User{email: "test0@example.com"}) - - assert {:ok, %User{}} = Repo.soft_restore(user) + Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() assert nil Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at end - - test "should return an error deleting" do - user = Repo.insert!(%User{email: "test0@example.com"}) - Repo.delete!(user) - - assert_raise Ecto.StaleEntryError, fn -> - Repo.soft_restore(user) - end - end end describe "soft_restore_all/1" do @@ -118,7 +107,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert Repo.soft_delete_all(User) == {3, nil} - assert User |> Repo.all(with_deleted: true) |> length() == 3 + assert User |> Repo.all(with_deleted: true) |> length() == 0 assert %DateTime{} = Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at @@ -130,7 +119,7 @@ defmodule Ecto.SoftDelete.Repo.Test do Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.soft_restore_all(User) == {3, nil} + assert Repo.soft_restore_all(User) == {0, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 From d43cd7784c4ca75412d7c5241d5671f09ed3bd35 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 16:25:09 -0700 Subject: [PATCH 04/61] fix travis test --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 0a6cbb2..a9657a0 100644 --- a/mix.exs +++ b/mix.exs @@ -51,7 +51,7 @@ defmodule EctoSoftDelete.Mixfile do maintainers: ["Bryan Joseph", "Luke Ledet"], licenses: ["MIT"], links: %{ - "GitHub" => "https://github.com/data-twister/ecto_soft_delete" + "GitHub" => "https://github.com/revelrylabs/ecto_soft_delete" }, build_tools: ["mix"] ] From 4f9d9634eed593515a2774a252316f4eb189a9fc Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 16:41:57 -0700 Subject: [PATCH 05/61] fix travis test --- test/soft_delete_repo_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index f3e84c7..3a4337e 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -94,7 +94,7 @@ defmodule Ecto.SoftDelete.Repo.Test do test "should soft restore the queryable" do Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() - assert nil + assert nil = Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at end end @@ -107,7 +107,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert Repo.soft_delete_all(User) == {3, nil} - assert User |> Repo.all(with_deleted: true) |> length() == 0 + assert User |> Repo.all(with_deleted: true) |> length() == 3 assert %DateTime{} = Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at From 93aade41fe241c24d5e1524d08d0afd3c2dd4545 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 16:49:46 -0700 Subject: [PATCH 06/61] fix travis test --- test/soft_delete_repo_test.exs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 3a4337e..33863d4 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -94,8 +94,7 @@ defmodule Ecto.SoftDelete.Repo.Test do test "should soft restore the queryable" do Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() - assert nil = - Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at + assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil end end @@ -123,14 +122,11 @@ defmodule Ecto.SoftDelete.Repo.Test do assert User |> Repo.all(with_deleted: true) |> length() == 3 - assert nil = - Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at + assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil - assert nil = - Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at + assert Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at == nil - assert nil = - Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at + assert Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at == nil end test "when no results are found" do From 5c584edad372ca70417279ce004de2e25944926e Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 18:48:38 -0700 Subject: [PATCH 07/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 10c3d88..b18c291 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -35,8 +35,8 @@ defmodule Ecto.SoftDelete.Repo do ## Examples - MyRepo.soft_delete_all(Post) - from(p in Post, where: p.id < 10) |> MyRepo.soft_delete_all() + MyRepo.soft_restore_all(Post) + from(p in Post, where: p.id < 10) |> MyRepo.soft_restore_all() """ @callback soft_restore_all(queryable :: Ecto.Queryable.t()) :: {integer, nil | [term]} @@ -66,6 +66,22 @@ defmodule Ecto.SoftDelete.Repo do @callback soft_delete!(struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t()) :: Ecto.Schema.t() + @doc """ + Soft restores a struct. + Updates the `deleted_at` to null. + It returns `{:ok, struct}` if the struct has been successfully + soft deleted or `{:error, changeset}` if there was a validation + or a known constraint error. + + ## Examples + + post = MyRepo.get!(Post, 42) + case MyRepo.soft_restore post do + {:ok, struct} -> "Soft restore with success" + {:error, changeset} -> "Something went wrong" + end + + """ @callback soft_restore(struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()} @@ -97,18 +113,18 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore_all(queryable) do - update_all(queryable, set: [deleted_at: nil]) + update_all(queryable, set: [deleted_at: "NULL"]) end def soft_restore(struct_or_changeset) do struct_or_changeset - |> Ecto.Changeset.change(deleted_at: nil) + |> Ecto.Changeset.change(deleted_at: "NULL") |> update() end def soft_restore!(struct_or_changeset) do struct_or_changeset - |> Ecto.Changeset.change(deleted_at: nil) + |> Ecto.Changeset.change(deleted_at: "NULL") |> update!() end From 99888dca49f29483abdf660d6cb874a7b6d97664 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 18:52:58 -0700 Subject: [PATCH 08/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index b18c291..3379d98 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -113,18 +113,18 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore_all(queryable) do - update_all(queryable, set: [deleted_at: "NULL"]) + update_all(queryable, set: [deleted_at: nil]) end def soft_restore(struct_or_changeset) do struct_or_changeset - |> Ecto.Changeset.change(deleted_at: "NULL") + |> Ecto.Changeset.change(deleted_at: nil) |> update() end def soft_restore!(struct_or_changeset) do struct_or_changeset - |> Ecto.Changeset.change(deleted_at: "NULL") + |> Ecto.Changeset.change(deleted_at: nil) |> update!() end From 50a6d1710c8d4f490341fbdb0ff5bddf145b8a06 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 19:08:45 -0700 Subject: [PATCH 09/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 3379d98..c496275 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -113,7 +113,7 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore_all(queryable) do - update_all(queryable, set: [deleted_at: nil]) + update_all(queryable, set: [deleted_at: 'NULL']) end def soft_restore(struct_or_changeset) do From b274dbf777aa0c91f944929b94b8547e765647b1 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 19:24:22 -0700 Subject: [PATCH 10/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index c496275..3379d98 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -113,7 +113,7 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore_all(queryable) do - update_all(queryable, set: [deleted_at: 'NULL']) + update_all(queryable, set: [deleted_at: nil]) end def soft_restore(struct_or_changeset) do From 767da99c16e043d0932fa540a8a072c8d9b485c6 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:18:08 -0700 Subject: [PATCH 11/61] fix travis test --- .formatter.exs | 4 ++++ config/config.exs | 2 +- lib/ecto/soft_delete_query.ex | 2 +- lib/ecto/soft_delete_repo.ex | 13 +++++++++++-- lib/ecto/soft_delete_schema.ex | 2 +- test/soft_delete_migration_test.exs | 10 +++++++--- test/soft_delete_repo_test.exs | 18 ++++++++++-------- test/test_helper.exs | 9 +++++---- 8 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 .formatter.exs diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/config/config.exs b/config/config.exs index a21eadd..de16861 100644 --- a/config/config.exs +++ b/config/config.exs @@ -27,4 +27,4 @@ use Mix.Config # Configuration from the imported file will override the ones defined # here (which is why it is important to import them last). # - import_config "#{Mix.env}.exs" +import_config "#{Mix.env()}.exs" diff --git a/lib/ecto/soft_delete_query.ex b/lib/ecto/soft_delete_query.ex index d5bd2f7..568dc3f 100644 --- a/lib/ecto/soft_delete_query.ex +++ b/lib/ecto/soft_delete_query.ex @@ -14,7 +14,7 @@ defmodule Ecto.SoftDelete.Query do results = Repo.all(query) """ - @spec with_undeleted(Ecto.Queryable.t) :: Ecto.Queryable.t + @spec with_undeleted(Ecto.Queryable.t()) :: Ecto.Queryable.t() def with_undeleted(query) do query |> where([t], is_nil(t.deleted_at)) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 3379d98..d4a5274 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,9 +111,18 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(queryable) do - update_all(queryable, set: [deleted_at: nil]) + queryable = from(x in ^queryable, where: !is_nil(x.deleted_at)) + + get(queryable) + |> Enum.each(fn x -> + table = x.__struct__.__schema__(:source) + Ecto.Adapters.SQL.query!( + Repo, + "Update deleted_at = NULL FROM #{table} where id = $1", + [x.id] + ) + end) end def soft_restore(struct_or_changeset) do diff --git a/lib/ecto/soft_delete_schema.ex b/lib/ecto/soft_delete_schema.ex index c1a73b0..dff8816 100644 --- a/lib/ecto/soft_delete_schema.ex +++ b/lib/ecto/soft_delete_schema.ex @@ -19,7 +19,7 @@ defmodule Ecto.SoftDelete.Schema do """ defmacro soft_delete_schema do quote do - field :deleted_at, :utc_datetime_usec + field(:deleted_at, :utc_datetime_usec) end end end diff --git a/test/soft_delete_migration_test.exs b/test/soft_delete_migration_test.exs index 733b6aa..ca1f720 100644 --- a/test/soft_delete_migration_test.exs +++ b/test/soft_delete_migration_test.exs @@ -7,7 +7,12 @@ defmodule Ecto.SoftDelete.Migration.Test do setup meta do :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo) - {:ok, runner} = Runner.start_link({self(), Repo, __MODULE__, meta[:direction] || :forward, :up, %{level: false, sql: false}}) + + {:ok, runner} = + Runner.start_link( + {self(), Repo, __MODULE__, meta[:direction] || :forward, :up, %{level: false, sql: false}} + ) + Runner.metadata(runner, meta) {:ok, runner: runner} end @@ -21,7 +26,6 @@ defmodule Ecto.SoftDelete.Migration.Test do flush() - assert {:create, _, - [{:add, :deleted_at, :utc_datetime_usec, []}]} = create_command + assert {:create, _, [{:add, :deleted_at, :utc_datetime_usec, []}]} = create_command end end diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 33863d4..2ce771f 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,9 +92,10 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() + Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() - assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil + assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == + nil end end @@ -117,16 +118,18 @@ defmodule Ecto.SoftDelete.Repo.Test do assert %DateTime{} = Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - - assert Repo.soft_restore_all(User) == {0, nil} + assert Repo.soft_restore_all(User) == {3, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 - assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil + assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == + nil - assert Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at == nil + assert Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at == + nil - assert Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at == nil + assert Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at == + nil end test "when no results are found" do @@ -134,7 +137,6 @@ defmodule Ecto.SoftDelete.Repo.Test do end end - describe "prepare_query/3" do test "excludes soft deleted records by default" do user = Repo.insert!(%User{email: "test0@example.com"}) diff --git a/test/test_helper.exs b/test/test_helper.exs index b1e8af0..9bc7977 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,19 +1,20 @@ {:ok, _} = Application.ensure_all_started(:postgrex) -{:ok, _pid} = Ecto.SoftDelete.Test.Repo.start_link +{:ok, _pid} = Ecto.SoftDelete.Test.Repo.start_link() defmodule Ecto.SoftDelete.Test.Migrations do use Ecto.Migration import Ecto.SoftDelete.Migration def change do - drop_if_exists table(:users) + drop_if_exists(table(:users)) + create table(:users) do - add :email, :string + add(:email, :string) soft_delete_columns() end create table(:nondeletable) do - add :value, :string + add(:value, :string) end end end From 74765ca9c5c5c35a8f44d8f7adbc16f67da0f2b8 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:21:33 -0700 Subject: [PATCH 12/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index d4a5274..c48636f 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -116,25 +116,39 @@ defmodule Ecto.SoftDelete.Repo do get(queryable) |> Enum.each(fn x -> - table = x.__struct__.__schema__(:source) + source = x.__struct__.__schema__(:source) Ecto.Adapters.SQL.query!( Repo, - "Update deleted_at = NULL FROM #{table} where id = $1", + "Update deleted_at = NULL FROM #{source} where id = $1", [x.id] ) end) end def soft_restore(struct_or_changeset) do - struct_or_changeset - |> Ecto.Changeset.change(deleted_at: nil) - |> update() + changeset = struct_or_changeset + |> Ecto.Changeset.apply() + + source = changeset.__struct__.__schema__(:source) + + Ecto.Adapters.SQL.query( + Repo, + "Update deleted_at = NULL FROM #{source} where id = $1", + [changeset.id] + ) end def soft_restore!(struct_or_changeset) do - struct_or_changeset - |> Ecto.Changeset.change(deleted_at: nil) - |> update!() + changeset = struct_or_changeset + |> Ecto.Changeset.apply() + + source = changeset.__struct__.__schema__(:source) + + Ecto.Adapters.SQL.query!( + Repo, + "Update deleted_at = NULL FROM #{source} where id = $1", + [changeset.id] + ) end @doc """ From e5b295ecbfaecd6db1ac2f972dd6850fa586aa8e Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:21:42 -0700 Subject: [PATCH 13/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index c48636f..e9afba2 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -116,7 +116,8 @@ defmodule Ecto.SoftDelete.Repo do get(queryable) |> Enum.each(fn x -> - source = x.__struct__.__schema__(:source) + source = x.__struct__.__schema__(:source) + Ecto.Adapters.SQL.query!( Repo, "Update deleted_at = NULL FROM #{source} where id = $1", @@ -126,8 +127,9 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore(struct_or_changeset) do - changeset = struct_or_changeset - |> Ecto.Changeset.apply() + changeset = + struct_or_changeset + |> Ecto.Changeset.apply() source = changeset.__struct__.__schema__(:source) @@ -139,8 +141,9 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore!(struct_or_changeset) do - changeset = struct_or_changeset - |> Ecto.Changeset.apply() + changeset = + struct_or_changeset + |> Ecto.Changeset.apply() source = changeset.__struct__.__schema__(:source) From b6ed4be2153e134603a092cf89a02012a2cbd593 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:29:41 -0700 Subject: [PATCH 14/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index e9afba2..bba81ce 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(queryable) do - queryable = from(x in ^queryable, where: !is_nil(x.deleted_at)) + queryable = from(x in ^queryable, where: not is_nil(x.deleted_at)) get(queryable) |> Enum.each(fn x -> From 26b39fdbd56b88ff7803704e407e86932d69546c Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:33:13 -0700 Subject: [PATCH 15/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index bba81ce..2867c98 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(queryable) do - queryable = from(x in ^queryable, where: not is_nil(x.deleted_at)) + queryable = from(x in queryable, where: not is_nil(x.deleted_at)) get(queryable) |> Enum.each(fn x -> From e4875cc0154626b6ae12de6ea6cb2d89e8af7e09 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:36:54 -0700 Subject: [PATCH 16/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 2867c98..abd81e0 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -114,7 +114,7 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore_all(queryable) do queryable = from(x in queryable, where: not is_nil(x.deleted_at)) - get(queryable) + Repo.get(queryable) |> Enum.each(fn x -> source = x.__struct__.__schema__(:source) From 268264f65c52cdb271bb2168581b291e1a4122d4 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:47:27 -0700 Subject: [PATCH 17/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index abd81e0..b36175e 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -126,31 +126,35 @@ defmodule Ecto.SoftDelete.Repo do end) end - def soft_restore(struct_or_changeset) do + def soft_restore(struct_or_changeset, key \\ "id") do changeset = struct_or_changeset - |> Ecto.Changeset.apply() + |> Ecto.Changeset.apply_changes() + + value = Map.fetch(changeset, String.to_atom(key)) source = changeset.__struct__.__schema__(:source) Ecto.Adapters.SQL.query( Repo, - "Update deleted_at = NULL FROM #{source} where id = $1", - [changeset.id] + "Update deleted_at = NULL FROM #{source} where #{key} = $1", + [value] ) end - def soft_restore!(struct_or_changeset) do + def soft_restore!(struct_or_changeset, key \\ "id") do changeset = struct_or_changeset - |> Ecto.Changeset.apply() + |> Ecto.Changeset.apply_changes() + + value = Map.fetch(changeset, String.to_atom(key)) source = changeset.__struct__.__schema__(:source) Ecto.Adapters.SQL.query!( Repo, - "Update deleted_at = NULL FROM #{source} where id = $1", - [changeset.id] + "Update deleted_at = NULL FROM #{source} where #{key} = $1", + [value] ) end From f0ff87ce78c589718f6b252f3c856d52ff77ab09 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:49:21 -0700 Subject: [PATCH 18/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index b36175e..836a2ba 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,17 +111,18 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(queryable) do + def soft_restore_all(queryable, key \\ "id") do queryable = from(x in queryable, where: not is_nil(x.deleted_at)) Repo.get(queryable) |> Enum.each(fn x -> source = x.__struct__.__schema__(:source) + value = Map.fetch(x, String.to_atom(key)) Ecto.Adapters.SQL.query!( Repo, "Update deleted_at = NULL FROM #{source} where id = $1", - [x.id] + [value] ) end) end From b8a1fa36cfdb1b04d0a3d1a52989b8630eb95a79 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 20:49:47 -0700 Subject: [PATCH 19/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 836a2ba..bb626d7 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -121,7 +121,7 @@ defmodule Ecto.SoftDelete.Repo do Ecto.Adapters.SQL.query!( Repo, - "Update deleted_at = NULL FROM #{source} where id = $1", + "Update deleted_at = NULL FROM #{source} where #{key} = $1", [value] ) end) From 8338dda64874aa29a5dbbb243ea71532cf638f45 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 21:14:28 -0700 Subject: [PATCH 20/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 14 +++++++------- test/soft_delete_repo_test.exs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index bb626d7..9916d9f 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,23 +111,23 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(queryable, key \\ "id") do + def soft_restore_all(queryable, repo, key \\ "id") do queryable = from(x in queryable, where: not is_nil(x.deleted_at)) - Repo.get(queryable) + all(queryable) |> Enum.each(fn x -> source = x.__struct__.__schema__(:source) value = Map.fetch(x, String.to_atom(key)) Ecto.Adapters.SQL.query!( - Repo, + repo, "Update deleted_at = NULL FROM #{source} where #{key} = $1", [value] ) end) end - def soft_restore(struct_or_changeset, key \\ "id") do + def soft_restore(struct_or_changeset, repo,key \\ "id") do changeset = struct_or_changeset |> Ecto.Changeset.apply_changes() @@ -137,13 +137,13 @@ defmodule Ecto.SoftDelete.Repo do source = changeset.__struct__.__schema__(:source) Ecto.Adapters.SQL.query( - Repo, + repo, "Update deleted_at = NULL FROM #{source} where #{key} = $1", [value] ) end - def soft_restore!(struct_or_changeset, key \\ "id") do + def soft_restore!(struct_or_changeset, repo, key \\ "id") do changeset = struct_or_changeset |> Ecto.Changeset.apply_changes() @@ -153,7 +153,7 @@ defmodule Ecto.SoftDelete.Repo do source = changeset.__struct__.__schema__(:source) Ecto.Adapters.SQL.query!( - Repo, + repo, "Update deleted_at = NULL FROM #{source} where #{key} = $1", [value] ) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 2ce771f..066f66d 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,7 +92,7 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() + Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore(Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil @@ -118,7 +118,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert %DateTime{} = Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.soft_restore_all(User) == {3, nil} + assert Repo.soft_restore_all(User, Repo) == {3, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 From 67793ba067c17ecc51ae317d2f3b309ff3630449 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 21:14:43 -0700 Subject: [PATCH 21/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 9916d9f..4a7f963 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -127,7 +127,7 @@ defmodule Ecto.SoftDelete.Repo do end) end - def soft_restore(struct_or_changeset, repo,key \\ "id") do + def soft_restore(struct_or_changeset, repo, key \\ "id") do changeset = struct_or_changeset |> Ecto.Changeset.apply_changes() From 851d4169a37ad3a5fb1bac7daa2b57b161b35eee Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 21:19:50 -0700 Subject: [PATCH 22/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 4a7f963..762f7bf 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -130,7 +130,6 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, repo, key \\ "id") do changeset = struct_or_changeset - |> Ecto.Changeset.apply_changes() value = Map.fetch(changeset, String.to_atom(key)) @@ -146,7 +145,6 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore!(struct_or_changeset, repo, key \\ "id") do changeset = struct_or_changeset - |> Ecto.Changeset.apply_changes() value = Map.fetch(changeset, String.to_atom(key)) From de3b5212ed2c407839967279e11dd1f9ffb430e2 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 21:27:55 -0700 Subject: [PATCH 23/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 762f7bf..aebf837 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -121,7 +121,7 @@ defmodule Ecto.SoftDelete.Repo do Ecto.Adapters.SQL.query!( repo, - "Update deleted_at = NULL FROM #{source} where #{key} = $1", + "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", [value] ) end) @@ -137,7 +137,7 @@ defmodule Ecto.SoftDelete.Repo do Ecto.Adapters.SQL.query( repo, - "Update deleted_at = NULL FROM #{source} where #{key} = $1", + "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", [value] ) end @@ -152,7 +152,7 @@ defmodule Ecto.SoftDelete.Repo do Ecto.Adapters.SQL.query!( repo, - "Update deleted_at = NULL FROM #{source} where #{key} = $1", + "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", [value] ) end From 598598eca278418f9a0b4f8082f01dd6d14f0332 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 21:36:49 -0700 Subject: [PATCH 24/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index aebf837..16dc5f4 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -115,7 +115,7 @@ defmodule Ecto.SoftDelete.Repo do queryable = from(x in queryable, where: not is_nil(x.deleted_at)) all(queryable) - |> Enum.each(fn x -> + |> Enum.each(fn {_,x} -> source = x.__struct__.__schema__(:source) value = Map.fetch(x, String.to_atom(key)) @@ -131,7 +131,7 @@ defmodule Ecto.SoftDelete.Repo do changeset = struct_or_changeset - value = Map.fetch(changeset, String.to_atom(key)) + {_,value} = Map.fetch(changeset, String.to_atom(key)) source = changeset.__struct__.__schema__(:source) @@ -146,7 +146,7 @@ defmodule Ecto.SoftDelete.Repo do changeset = struct_or_changeset - value = Map.fetch(changeset, String.to_atom(key)) + {_,value} = Map.fetch(changeset, String.to_atom(key)) source = changeset.__struct__.__schema__(:source) From 991e30e01e6b33e54e7acc9b492d9f148c67fcc9 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 21:39:02 -0700 Subject: [PATCH 25/61] fix travis test --- config/config.exs | 2 +- config/dev.exs | 2 +- config/prod.exs | 2 +- config/test.exs | 2 +- config/test.exs.travis | 2 +- lib/ecto/soft_delete_repo.ex | 16 +++++----------- 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/config/config.exs b/config/config.exs index de16861..61fc384 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,6 +1,6 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. -use Mix.Config +import Config # This configuration is loaded before any dependency and is restricted # to this project. If another project depends on this project, this diff --git a/config/dev.exs b/config/dev.exs index d2d855e..becde76 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1 +1 @@ -use Mix.Config +import Config diff --git a/config/prod.exs b/config/prod.exs index d2d855e..becde76 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -1 +1 @@ -use Mix.Config +import Config diff --git a/config/test.exs b/config/test.exs index f674c6b..f58e5f7 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :ecto_soft_delete, ecto_repos: [Ecto.SoftDelete.Test.Repo] diff --git a/config/test.exs.travis b/config/test.exs.travis index c5464c6..ff5b4bf 100644 --- a/config/test.exs.travis +++ b/config/test.exs.travis @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :ecto_soft_delete, ecto_repos: [Ecto.SoftDelete.Test.Repo] diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 16dc5f4..87d43de 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -115,7 +115,7 @@ defmodule Ecto.SoftDelete.Repo do queryable = from(x in queryable, where: not is_nil(x.deleted_at)) all(queryable) - |> Enum.each(fn {_,x} -> + |> Enum.each(fn {_, x} -> source = x.__struct__.__schema__(:source) value = Map.fetch(x, String.to_atom(key)) @@ -128,12 +128,9 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore(struct_or_changeset, repo, key \\ "id") do - changeset = - struct_or_changeset + {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - {_,value} = Map.fetch(changeset, String.to_atom(key)) - - source = changeset.__struct__.__schema__(:source) + source = struct_or_changeset.__struct__.__schema__(:source) Ecto.Adapters.SQL.query( repo, @@ -143,12 +140,9 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore!(struct_or_changeset, repo, key \\ "id") do - changeset = - struct_or_changeset - - {_,value} = Map.fetch(changeset, String.to_atom(key)) + {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - source = changeset.__struct__.__schema__(:source) + source = struct_or_changeset.__struct__.__schema__(:source) Ecto.Adapters.SQL.query!( repo, From 8bf9591575b947c2983bbd2920c775f82b6cf7a1 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 22:33:14 -0700 Subject: [PATCH 26/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 87d43de..f031da8 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,7 +111,7 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(queryable, repo, key \\ "id") do + def soft_restore_all(queryable, repo, key \\ "id") when is_list(queryable) do queryable = from(x in queryable, where: not is_nil(x.deleted_at)) all(queryable) @@ -127,6 +127,15 @@ defmodule Ecto.SoftDelete.Repo do end) end + def soft_restore_all(queryable, repo) do + source = queryable.__struct__.__schema__(:source) + + Ecto.Adapters.SQL.query!( + repo, + "UPDATE #{source} SET deleted_at = NULL" + ) + end + def soft_restore(struct_or_changeset, repo, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) From e5518b0be028c21b439b970799a9de5e9b46ddcc Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 22:36:57 -0700 Subject: [PATCH 27/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index f031da8..f190e1b 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,22 +111,6 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(queryable, repo, key \\ "id") when is_list(queryable) do - queryable = from(x in queryable, where: not is_nil(x.deleted_at)) - - all(queryable) - |> Enum.each(fn {_, x} -> - source = x.__struct__.__schema__(:source) - value = Map.fetch(x, String.to_atom(key)) - - Ecto.Adapters.SQL.query!( - repo, - "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", - [value] - ) - end) - end - def soft_restore_all(queryable, repo) do source = queryable.__struct__.__schema__(:source) From 629160c1fdd7d0288fc14a23ab56c172992d6d45 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 22:46:00 -0700 Subject: [PATCH 28/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 15 ++++++++------- test/soft_delete_repo_test.exs | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index f190e1b..6f8e16a 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,22 +111,23 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(queryable, repo) do - source = queryable.__struct__.__schema__(:source) + def soft_restore_all(queryable) do + source = Ecto.Schema.Metadata.source(queryable) + context = Ecto.Schema.Metadata.context(queryable) Ecto.Adapters.SQL.query!( - repo, + context, "UPDATE #{source} SET deleted_at = NULL" ) end - def soft_restore(struct_or_changeset, repo, key \\ "id") do + def soft_restore(struct_or_changeset, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - - source = struct_or_changeset.__struct__.__schema__(:source) + source = Ecto.Schema.Metadata.source(struct_or_changeset) + context = Ecto.Schema.Metadata.context(struct_or_changeset) Ecto.Adapters.SQL.query( - repo, + context, "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", [value] ) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 066f66d..2ce771f 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,7 +92,7 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore(Repo) + Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil @@ -118,7 +118,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert %DateTime{} = Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.soft_restore_all(User, Repo) == {3, nil} + assert Repo.soft_restore_all(User) == {3, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 From 06b3284c4ba1e662e4a3851849791aef66c7946c Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 23:30:33 -0700 Subject: [PATCH 29/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 22 +++++++++++----------- mix.exs | 2 +- test/soft_delete_repo_test.exs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 6f8e16a..adeda84 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,35 +111,35 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(queryable) do - source = Ecto.Schema.Metadata.source(queryable) - context = Ecto.Schema.Metadata.context(queryable) + def soft_restore_all(struct_or_changeset, repo) do + source = Map.get(struct_or_changeset, __meta__)[:schema] Ecto.Adapters.SQL.query!( - context, + repo, "UPDATE #{source} SET deleted_at = NULL" ) end - def soft_restore(struct_or_changeset, key \\ "id") do + def soft_restore(struct_or_changeset, repo, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - source = Ecto.Schema.Metadata.source(struct_or_changeset) - context = Ecto.Schema.Metadata.context(struct_or_changeset) + + source = Map.get(struct_or_changeset, __meta__)[:schema] Ecto.Adapters.SQL.query( - context, + repo, "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", [value] ) end - def soft_restore!(struct_or_changeset, repo, key \\ "id") do + def soft_restore!(struct_or_changeset, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - source = struct_or_changeset.__struct__.__schema__(:source) + source = Map.get(struct_or_changeset, __meta__)[:schema] + context = Map.get(struct_or_changeset, __meta__)[:context] Ecto.Adapters.SQL.query!( - repo, + context, "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", [value] ) diff --git a/mix.exs b/mix.exs index a9657a0..55891e3 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule EctoSoftDelete.Mixfile do def project do [ app: :ecto_soft_delete, - version: "2.0.2", + version: "2.0.3", elixir: "~> 1.9", elixirc_paths: elixirc_paths(Mix.env()), build_embedded: Mix.env() == :prod, diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 2ce771f..e99dbd2 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -118,7 +118,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert %DateTime{} = Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.soft_restore_all(User) == {3, nil} + assert Repo.soft_restore_all(User, Repo) == {3, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 From 6b5328f795894d24660b59178808579f3e03ab9c Mon Sep 17 00:00:00 2001 From: mithereal Date: Sat, 18 Nov 2023 23:35:05 -0700 Subject: [PATCH 30/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index adeda84..ab1631b 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - source = Map.get(struct_or_changeset, __meta__)[:schema] + source = Map.get(struct_or_changeset, :__meta__)[:schema] Ecto.Adapters.SQL.query!( repo, @@ -135,8 +135,8 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore!(struct_or_changeset, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - source = Map.get(struct_or_changeset, __meta__)[:schema] - context = Map.get(struct_or_changeset, __meta__)[:context] + source = Map.get(struct_or_changeset, :__meta__)[:schema] + context = Map.get(struct_or_changeset, :__meta__)[:context] Ecto.Adapters.SQL.query!( context, From ea40e69a0304a7a155c0dbf9b3ede8bef8613206 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:01:49 -0700 Subject: [PATCH 31/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index ab1631b..e5e9e2e 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -123,7 +123,7 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, repo, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - source = Map.get(struct_or_changeset, __meta__)[:schema] + source = Map.get(struct_or_changeset, :__meta__)[:schema] Ecto.Adapters.SQL.query( repo, From 1db064b55558941494eb70649dbc69e0f0d17ccb Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:14:18 -0700 Subject: [PATCH 32/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index e5e9e2e..4d258c2 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - source = Map.get(struct_or_changeset, :__meta__)[:schema] + source = struct_or_changeset.__struct__()[:schema] Ecto.Adapters.SQL.query!( repo, @@ -123,7 +123,7 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, repo, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - source = Map.get(struct_or_changeset, :__meta__)[:schema] + source = struct_or_changeset.__struct__()[:schema] Ecto.Adapters.SQL.query( repo, @@ -135,8 +135,8 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore!(struct_or_changeset, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) - source = Map.get(struct_or_changeset, :__meta__)[:schema] - context = Map.get(struct_or_changeset, :__meta__)[:context] + source = struct_or_changeset.__struct__()[:schema] + context = struct_or_changeset.__struct__()[:context] Ecto.Adapters.SQL.query!( context, From e833b92b04a9406109f8922af352a4d9abc06556 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:24:11 -0700 Subject: [PATCH 33/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 4d258c2..ebb7c8e 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -132,7 +132,7 @@ defmodule Ecto.SoftDelete.Repo do ) end - def soft_restore!(struct_or_changeset, key \\ "id") do + def soft_restore(struct_or_changeset, key \\ "id") do {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) source = struct_or_changeset.__struct__()[:schema] From db6e5024b22a15e3a662cc458200a42e5590b7b1 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:26:44 -0700 Subject: [PATCH 34/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index ebb7c8e..5148f2b 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -121,7 +121,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore(struct_or_changeset, repo, key \\ "id") do - {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) + value = struct_or_changeset[String.to_atom(key)] source = struct_or_changeset.__struct__()[:schema] @@ -133,7 +133,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore(struct_or_changeset, key \\ "id") do - {_, value} = Map.fetch(struct_or_changeset, String.to_atom(key)) + value = struct_or_changeset[String.to_atom(key)] source = struct_or_changeset.__struct__()[:schema] context = struct_or_changeset.__struct__()[:context] From b1e1c226f4e42c2081002f5c1cdd89ac255da894 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:29:58 -0700 Subject: [PATCH 35/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 5148f2b..b934146 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -120,18 +120,6 @@ defmodule Ecto.SoftDelete.Repo do ) end - def soft_restore(struct_or_changeset, repo, key \\ "id") do - value = struct_or_changeset[String.to_atom(key)] - - source = struct_or_changeset.__struct__()[:schema] - - Ecto.Adapters.SQL.query( - repo, - "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", - [value] - ) - end - def soft_restore(struct_or_changeset, key \\ "id") do value = struct_or_changeset[String.to_atom(key)] From 18a1670c58405f62b12d9e6b0a287d77e423aa32 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:43:40 -0700 Subject: [PATCH 36/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index b934146..cd9d775 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - source = struct_or_changeset.__struct__()[:schema] + source = get_in struct_or_changeset.__struct__(), [Access.key(:schema)] Ecto.Adapters.SQL.query!( repo, @@ -122,9 +122,8 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, key \\ "id") do value = struct_or_changeset[String.to_atom(key)] - - source = struct_or_changeset.__struct__()[:schema] - context = struct_or_changeset.__struct__()[:context] + source = get_in struct_or_changeset.__struct__(), [Access.key(:schema)] + context = get_in struct_or_changeset.__struct__(), [Access.key(:schema)] Ecto.Adapters.SQL.query!( context, From 32910ca7520f91f7325c3407674e1ec48bb9737e Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:50:21 -0700 Subject: [PATCH 37/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index cd9d775..36edc15 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - source = get_in struct_or_changeset.__struct__(), [Access.key(:schema)] + source = get_in struct_or_changeset.__struct__(), [:schema] Ecto.Adapters.SQL.query!( repo, @@ -122,8 +122,8 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, key \\ "id") do value = struct_or_changeset[String.to_atom(key)] - source = get_in struct_or_changeset.__struct__(), [Access.key(:schema)] - context = get_in struct_or_changeset.__struct__(), [Access.key(:schema)] + source = get_in struct_or_changeset.__struct__(), [:schema] + context = get_in struct_or_changeset.__struct__(), [:context] Ecto.Adapters.SQL.query!( context, From 8e5a229e114fc69284d118ccb8945d9728ccfbed Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 00:59:08 -0700 Subject: [PATCH 38/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 36edc15..09848f2 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - source = get_in struct_or_changeset.__struct__(), [:schema] + source = Ecto.get_meta(struct_or_changeset, :schema) Ecto.Adapters.SQL.query!( repo, @@ -122,8 +122,8 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, key \\ "id") do value = struct_or_changeset[String.to_atom(key)] - source = get_in struct_or_changeset.__struct__(), [:schema] - context = get_in struct_or_changeset.__struct__(), [:context] + source = Ecto.get_meta(struct_or_changeset, :schema) + context = Ecto.get_meta(struct_or_changeset, :context) Ecto.Adapters.SQL.query!( context, From e0313446161059f2f583845e0aca798e45931d73 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 01:03:53 -0700 Subject: [PATCH 39/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 09848f2..72c2ec5 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - source = Ecto.get_meta(struct_or_changeset, :schema) + source = Ecto.get_meta(struct_or_changeset, :source) Ecto.Adapters.SQL.query!( repo, @@ -122,7 +122,7 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, key \\ "id") do value = struct_or_changeset[String.to_atom(key)] - source = Ecto.get_meta(struct_or_changeset, :schema) + source = Ecto.get_meta(struct_or_changeset, :source) context = Ecto.get_meta(struct_or_changeset, :context) Ecto.Adapters.SQL.query!( From 72c932c5cab5cdad12febc3f5df5a9342b1e1c60 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 01:06:10 -0700 Subject: [PATCH 40/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 72c2ec5..450c988 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - source = Ecto.get_meta(struct_or_changeset, :source) + {_,source} = Ecto.get_meta(struct_or_changeset, :source) Ecto.Adapters.SQL.query!( repo, @@ -122,7 +122,7 @@ defmodule Ecto.SoftDelete.Repo do def soft_restore(struct_or_changeset, key \\ "id") do value = struct_or_changeset[String.to_atom(key)] - source = Ecto.get_meta(struct_or_changeset, :source) + {_,source} = Ecto.get_meta(struct_or_changeset, :source) context = Ecto.get_meta(struct_or_changeset, :context) Ecto.Adapters.SQL.query!( From 5a17175634930548bbeab2a18148c8a458dad1cf Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 01:15:30 -0700 Subject: [PATCH 41/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 450c988..2aa5dff 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -121,6 +121,8 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore(struct_or_changeset, key \\ "id") do + require Logger + Logger.error(struct_or_changeset) value = struct_or_changeset[String.to_atom(key)] {_,source} = Ecto.get_meta(struct_or_changeset, :source) context = Ecto.get_meta(struct_or_changeset, :context) From 37071e405f0525e707b590f1af31754accfa8104 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 02:11:10 -0700 Subject: [PATCH 42/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 2aa5dff..724c76e 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -112,7 +112,7 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore_all(struct_or_changeset, repo) do - {_,source} = Ecto.get_meta(struct_or_changeset, :source) + source = Ecto.get_meta(struct_or_changeset, :source) Ecto.Adapters.SQL.query!( repo, @@ -121,11 +121,12 @@ defmodule Ecto.SoftDelete.Repo do end def soft_restore(struct_or_changeset, key \\ "id") do - require Logger - Logger.error(struct_or_changeset) - value = struct_or_changeset[String.to_atom(key)] - {_,source} = Ecto.get_meta(struct_or_changeset, :source) - context = Ecto.get_meta(struct_or_changeset, :context) + value = + Map.from_struct(struct_or_changeset) + |> Map.get(String.to_atom(key)) + + source = Ecto.get_meta(struct_or_changeset, :source) + context = Ecto.get_meta(struct_or_changeset, :context) Ecto.Adapters.SQL.query!( context, From fca9455da9fe524aa98e33d14dc7cd49388c3994 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 02:18:36 -0700 Subject: [PATCH 43/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 724c76e..7dbc8a6 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,22 +111,33 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(struct_or_changeset, repo) do + def soft_restore_all(struct_or_changeset, repo \\ :context) do source = Ecto.get_meta(struct_or_changeset, :source) + context = + case repo do + :context -> Ecto.get_meta(struct_or_changeset, :context) + _ -> repo + end + Ecto.Adapters.SQL.query!( - repo, + context, "UPDATE #{source} SET deleted_at = NULL" ) end - def soft_restore(struct_or_changeset, key \\ "id") do + def soft_restore(struct_or_changeset, key \\ "id", repo \\ :context) do value = Map.from_struct(struct_or_changeset) |> Map.get(String.to_atom(key)) source = Ecto.get_meta(struct_or_changeset, :source) - context = Ecto.get_meta(struct_or_changeset, :context) + + context = + case repo do + :context -> Ecto.get_meta(struct_or_changeset, :context) + _ -> repo + end Ecto.Adapters.SQL.query!( context, From 40952c537d2ba4a01f70a26529bfa18aea5e3d94 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 02:19:27 -0700 Subject: [PATCH 44/61] fix travis test --- test/soft_delete_repo_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index e99dbd2..066f66d 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,7 +92,7 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore() + Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore(Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil From 6fc852057d076c48bb6dd8514cc8e2b2803e0d98 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 02:37:22 -0700 Subject: [PATCH 45/61] fix travis test --- test/soft_delete_repo_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 066f66d..c2d8bae 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,7 +92,7 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_restore(Repo) + Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_delete(Repo) |> Repo.soft_restore(Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil @@ -118,7 +118,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert %DateTime{} = Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.soft_restore_all(User, Repo) == {3, nil} + assert Repo.soft_restore_all(%User{}, Repo) == {3, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 From 3d22526b9e14083f8c93b99da3834a7afbfc8c44 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 02:50:57 -0700 Subject: [PATCH 46/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 38 ++++++++++++++++++++++++++-------- test/soft_delete_repo_test.exs | 4 +++- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 7dbc8a6..b6477bd 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -120,10 +120,20 @@ defmodule Ecto.SoftDelete.Repo do _ -> repo end - Ecto.Adapters.SQL.query!( - context, - "UPDATE #{source} SET deleted_at = NULL" - ) + %{ + columns: _, + command: _, + connection_id: _, + messages: _, + num_rows: num_rows, + rows: rows + } = + Ecto.Adapters.SQL.query!( + context, + "UPDATE #{source} SET deleted_at = NULL" + ) + + {num_rows, rows} end def soft_restore(struct_or_changeset, key \\ "id", repo \\ :context) do @@ -139,11 +149,21 @@ defmodule Ecto.SoftDelete.Repo do _ -> repo end - Ecto.Adapters.SQL.query!( - context, - "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", - [value] - ) + %{ + columns: _, + command: _, + connection_id: _, + messages: _, + num_rows: num_rows, + rows: rows + } = + Ecto.Adapters.SQL.query!( + context, + "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", + [value] + ) + + {num_rows, rows} end @doc """ diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index c2d8bae..5ffed2a 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,7 +92,9 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - Repo.insert!(%User{email: "test0@example.com"}) |> Repo.soft_delete(Repo) |> Repo.soft_restore(Repo) + Repo.insert!(%User{email: "test0@example.com"}) + |> Repo.soft_delete() + |> Repo.soft_restore(Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil From c87543aef24f011bece9237f98212d78017c9144 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 02:58:03 -0700 Subject: [PATCH 47/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 14 +++++++------- test/soft_delete_repo_test.exs | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index b6477bd..5eb2203 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,12 +111,12 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(struct_or_changeset, repo \\ :context) do - source = Ecto.get_meta(struct_or_changeset, :source) + def soft_restore_all(struct, repo \\ :context) do + source = Ecto.get_meta(struct, :source) context = case repo do - :context -> Ecto.get_meta(struct_or_changeset, :context) + :context -> Ecto.get_meta(struct, :context) _ -> repo end @@ -136,16 +136,16 @@ defmodule Ecto.SoftDelete.Repo do {num_rows, rows} end - def soft_restore(struct_or_changeset, key \\ "id", repo \\ :context) do + def soft_restore(struct, key \\ "id", repo \\ :context) do value = - Map.from_struct(struct_or_changeset) + Map.from_struct(struct) |> Map.get(String.to_atom(key)) - source = Ecto.get_meta(struct_or_changeset, :source) + source = Ecto.get_meta(struct, :source) context = case repo do - :context -> Ecto.get_meta(struct_or_changeset, :context) + :context -> Ecto.get_meta(struct, :context) _ -> repo end diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 5ffed2a..1c34c90 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -92,9 +92,9 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do - Repo.insert!(%User{email: "test0@example.com"}) - |> Repo.soft_delete() - |> Repo.soft_restore(Repo) + user = Repo.insert!(%User{email: "test0@example.com"}) + Repo.soft_delete(user) + Repo.soft_restore(user, Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil From 391583d0b254edb9438ea00049f1ce51c938b51d Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 03:16:06 -0700 Subject: [PATCH 48/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 5eb2203..327181c 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -35,11 +35,11 @@ defmodule Ecto.SoftDelete.Repo do ## Examples - MyRepo.soft_restore_all(Post) - from(p in Post, where: p.id < 10) |> MyRepo.soft_restore_all() + MyRepo.soft_restore_all(%Post{}, MyRepo) + """ - @callback soft_restore_all(queryable :: Ecto.Queryable.t()) :: {integer, nil | [term]} + @callback soft_restore_all(struct :: Ecto.Schema.t()) :: {integer, nil | [term]} @doc """ Soft deletes a struct. @@ -82,13 +82,13 @@ defmodule Ecto.SoftDelete.Repo do end """ - @callback soft_restore(struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t()) :: + @callback soft_restore(struct :: Ecto.Schema.t()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()} @doc """ Same as `c:soft_restore/1` but returns the struct or raises if the changeset is invalid. """ - @callback soft_restore!(struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t()) :: + @callback soft_restore!(struct :: Ecto.Schema.t()) :: Ecto.Schema.t() defmacro __using__(_opts) do From d7f2f624d29853c0b2a3469b94a9dbc3f5e1e645 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 03:37:15 -0700 Subject: [PATCH 49/61] fix travis test --- test/soft_delete_repo_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 1c34c90..4db1a9f 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -94,7 +94,7 @@ defmodule Ecto.SoftDelete.Repo.Test do test "should soft restore the queryable" do user = Repo.insert!(%User{email: "test0@example.com"}) Repo.soft_delete(user) - Repo.soft_restore(user, Repo) + # Repo.soft_restore(user, Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil From dfdb307714da32fdf037ea8834c002abf6c36ffd Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 03:42:06 -0700 Subject: [PATCH 50/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 4 ++-- test/soft_delete_repo_test.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 327181c..8cc0730 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -136,7 +136,7 @@ defmodule Ecto.SoftDelete.Repo do {num_rows, rows} end - def soft_restore(struct, key \\ "id", repo \\ :context) do + def soft_restore(struct, key \\ "id", repo \\ nil) do value = Map.from_struct(struct) |> Map.get(String.to_atom(key)) @@ -145,7 +145,7 @@ defmodule Ecto.SoftDelete.Repo do context = case repo do - :context -> Ecto.get_meta(struct, :context) + nil -> Ecto.get_meta(struct, :context) _ -> repo end diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 4db1a9f..1c34c90 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -94,7 +94,7 @@ defmodule Ecto.SoftDelete.Repo.Test do test "should soft restore the queryable" do user = Repo.insert!(%User{email: "test0@example.com"}) Repo.soft_delete(user) - # Repo.soft_restore(user, Repo) + Repo.soft_restore(user, Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil From 8e446f575c7947e5c64a0bbce5010923c5f97af6 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 03:53:38 -0700 Subject: [PATCH 51/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 4 ++-- test/soft_delete_repo_test.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 8cc0730..327181c 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -136,7 +136,7 @@ defmodule Ecto.SoftDelete.Repo do {num_rows, rows} end - def soft_restore(struct, key \\ "id", repo \\ nil) do + def soft_restore(struct, key \\ "id", repo \\ :context) do value = Map.from_struct(struct) |> Map.get(String.to_atom(key)) @@ -145,7 +145,7 @@ defmodule Ecto.SoftDelete.Repo do context = case repo do - nil -> Ecto.get_meta(struct, :context) + :context -> Ecto.get_meta(struct, :context) _ -> repo end diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 1c34c90..275903d 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -94,7 +94,7 @@ defmodule Ecto.SoftDelete.Repo.Test do test "should soft restore the queryable" do user = Repo.insert!(%User{email: "test0@example.com"}) Repo.soft_delete(user) - Repo.soft_restore(user, Repo) + Repo.soft_restore(user) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil From 0fdfc3642bfde3fc9b59c9d8da5fbd9c041fd557 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 04:00:44 -0700 Subject: [PATCH 52/61] fix travis test --- lib/ecto/soft_delete_repo.ex | 2 +- test/soft_delete_repo_test.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 327181c..71841db 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -136,7 +136,7 @@ defmodule Ecto.SoftDelete.Repo do {num_rows, rows} end - def soft_restore(struct, key \\ "id", repo \\ :context) do + def soft_restore(struct, repo \\ :context, key \\ "id") do value = Map.from_struct(struct) |> Map.get(String.to_atom(key)) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 275903d..1c34c90 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -94,7 +94,7 @@ defmodule Ecto.SoftDelete.Repo.Test do test "should soft restore the queryable" do user = Repo.insert!(%User{email: "test0@example.com"}) Repo.soft_delete(user) - Repo.soft_restore(user) + Repo.soft_restore(user, Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil From f3291094016f082f96ea748d8116d895c0b4c955 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 04:19:26 -0700 Subject: [PATCH 53/61] add deleted_at index --- lib/ecto/soft_delete_migration.ex | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ecto/soft_delete_migration.ex b/lib/ecto/soft_delete_migration.ex index 5545012..a329c10 100644 --- a/lib/ecto/soft_delete_migration.ex +++ b/lib/ecto/soft_delete_migration.ex @@ -18,6 +18,7 @@ defmodule Ecto.SoftDelete.Migration do add :password, :string timestamps() soft_delete_columns() + soft_delete_index(:users) end end end @@ -26,4 +27,8 @@ defmodule Ecto.SoftDelete.Migration do def soft_delete_columns do add(:deleted_at, :utc_datetime_usec, []) end + + def soft_delete_index(table) do + create index(table, [:deleted_at]) + end end From ec92a16bbbcc1f9a6577355f3c421dc87d94b534 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 04:54:51 -0700 Subject: [PATCH 54/61] fix #159 --- lib/ecto/soft_delete_migration.ex | 2 +- lib/ecto/soft_delete_repo.ex | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/ecto/soft_delete_migration.ex b/lib/ecto/soft_delete_migration.ex index a329c10..7d0b504 100644 --- a/lib/ecto/soft_delete_migration.ex +++ b/lib/ecto/soft_delete_migration.ex @@ -29,6 +29,6 @@ defmodule Ecto.SoftDelete.Migration do end def soft_delete_index(table) do - create index(table, [:deleted_at]) + create(index(table, [:deleted_at])) end end diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 71841db..14808e4 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -176,11 +176,17 @@ defmodule Ecto.SoftDelete.Repo do fields = if schema_module, do: schema_module.__schema__(:fields), else: [] soft_deletable? = Enum.member?(fields, :deleted_at) - if has_include_deleted_at_clause?(query) || opts[:with_deleted] || !soft_deletable? do - {query, opts} - else - query = from(x in query, where: is_nil(x.deleted_at)) - {query, opts} + case has_include_deleted_at_clause?(query) || opts[:with_deleted] || !soft_deletable? do + true -> + {query, opts} + + false -> + if has_excluded_deleted_at_clause?(query) do + {query, []} + else + query = from(x in query, where: is_nil(x.deleted_at)) + {query, opts} + end end end @@ -192,6 +198,12 @@ defmodule Ecto.SoftDelete.Repo do end) end + defp has_excluded_deleted_at_clause?(%Ecto.Query{wheres: wheres}) do + Enum.any?(wheres, fn %{expr: expr} -> + expr == {:is_nil, [], [{{:., [], [{:&, [], [0]}, :deleted_at]}, [], []}]} + end) + end + defp get_schema_module_from_query(%Ecto.Query{from: %{source: {_name, module}}}) do module end From f13c1ed5484a24ef05127d7c0c953d7e5e48970c Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 19 Nov 2023 05:01:26 -0700 Subject: [PATCH 55/61] Revert "fix #159" This reverts commit ec92a16bbbcc1f9a6577355f3c421dc87d94b534. --- lib/ecto/soft_delete_migration.ex | 2 +- lib/ecto/soft_delete_repo.ex | 22 +++++----------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/lib/ecto/soft_delete_migration.ex b/lib/ecto/soft_delete_migration.ex index 7d0b504..a329c10 100644 --- a/lib/ecto/soft_delete_migration.ex +++ b/lib/ecto/soft_delete_migration.ex @@ -29,6 +29,6 @@ defmodule Ecto.SoftDelete.Migration do end def soft_delete_index(table) do - create(index(table, [:deleted_at])) + create index(table, [:deleted_at]) end end diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 14808e4..71841db 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -176,17 +176,11 @@ defmodule Ecto.SoftDelete.Repo do fields = if schema_module, do: schema_module.__schema__(:fields), else: [] soft_deletable? = Enum.member?(fields, :deleted_at) - case has_include_deleted_at_clause?(query) || opts[:with_deleted] || !soft_deletable? do - true -> - {query, opts} - - false -> - if has_excluded_deleted_at_clause?(query) do - {query, []} - else - query = from(x in query, where: is_nil(x.deleted_at)) - {query, opts} - end + if has_include_deleted_at_clause?(query) || opts[:with_deleted] || !soft_deletable? do + {query, opts} + else + query = from(x in query, where: is_nil(x.deleted_at)) + {query, opts} end end @@ -198,12 +192,6 @@ defmodule Ecto.SoftDelete.Repo do end) end - defp has_excluded_deleted_at_clause?(%Ecto.Query{wheres: wheres}) do - Enum.any?(wheres, fn %{expr: expr} -> - expr == {:is_nil, [], [{{:., [], [{:&, [], [0]}, :deleted_at]}, [], []}]} - end) - end - defp get_schema_module_from_query(%Ecto.Query{from: %{source: {_name, module}}}) do module end From 85a123cf1db3493bd313418955197cff64a2a3d5 Mon Sep 17 00:00:00 2001 From: mithereal Date: Tue, 21 Nov 2023 12:56:24 -0700 Subject: [PATCH 56/61] rename soft_restore to restore --- lib/ecto/soft_delete_repo.ex | 18 +++++++++--------- test/soft_delete_repo_test.exs | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 71841db..07e3d6b 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -27,7 +27,7 @@ defmodule Ecto.SoftDelete.Repo do @callback soft_delete_all(queryable :: Ecto.Queryable.t()) :: {integer, nil | [term]} @doc """ - Soft restores all entries matching the given query. + Restores all entries matching the given query. It returns a tuple containing the number of entries and any returned result as second element. The second element is `nil` by default @@ -35,11 +35,11 @@ defmodule Ecto.SoftDelete.Repo do ## Examples - MyRepo.soft_restore_all(%Post{}, MyRepo) + MyRepo.restore_all(%Post{}, MyRepo) """ - @callback soft_restore_all(struct :: Ecto.Schema.t()) :: {integer, nil | [term]} + @callback restore_all(struct :: Ecto.Schema.t()) :: {integer, nil | [term]} @doc """ Soft deletes a struct. @@ -76,19 +76,19 @@ defmodule Ecto.SoftDelete.Repo do ## Examples post = MyRepo.get!(Post, 42) - case MyRepo.soft_restore post do + case MyRepo.restore post do {:ok, struct} -> "Soft restore with success" {:error, changeset} -> "Something went wrong" end """ - @callback soft_restore(struct :: Ecto.Schema.t()) :: + @callback restore(struct :: Ecto.Schema.t()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()} @doc """ - Same as `c:soft_restore/1` but returns the struct or raises if the changeset is invalid. + Same as `c:restore/1` but returns the struct or raises if the changeset is invalid. """ - @callback soft_restore!(struct :: Ecto.Schema.t()) :: + @callback restore!(struct :: Ecto.Schema.t()) :: Ecto.Schema.t() defmacro __using__(_opts) do @@ -111,7 +111,7 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(struct, repo \\ :context) do + def restore_all(struct, repo \\ :context) do source = Ecto.get_meta(struct, :source) context = @@ -136,7 +136,7 @@ defmodule Ecto.SoftDelete.Repo do {num_rows, rows} end - def soft_restore(struct, repo \\ :context, key \\ "id") do + def restore(struct, repo \\ :context, key \\ "id") do value = Map.from_struct(struct) |> Map.get(String.to_atom(key)) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 1c34c90..5dde9f0 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -90,18 +90,18 @@ defmodule Ecto.SoftDelete.Repo.Test do end end - describe "soft_restore/1" do + describe "restore/1" do test "should soft restore the queryable" do user = Repo.insert!(%User{email: "test0@example.com"}) Repo.soft_delete(user) - Repo.soft_restore(user, Repo) + Repo.restore(user, Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil end end - describe "soft_restore_all/1" do + describe "restore_all/1" do test "soft deleted the query" do Repo.insert!(%User{email: "test0@example.com"}) Repo.insert!(%User{email: "test1@example.com"}) @@ -120,7 +120,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert %DateTime{} = Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.soft_restore_all(%User{}, Repo) == {3, nil} + assert Repo.restore_all(%User{}, Repo) == {3, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 From 13ac95ddc3bae9b37b59312db138b7a551357aee Mon Sep 17 00:00:00 2001 From: mithereal Date: Tue, 21 Nov 2023 13:02:47 -0700 Subject: [PATCH 57/61] Revert "rename soft_restore to restore" This reverts commit 85a123cf1db3493bd313418955197cff64a2a3d5. --- lib/ecto/soft_delete_repo.ex | 18 +++++++++--------- test/soft_delete_repo_test.exs | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 07e3d6b..71841db 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -27,7 +27,7 @@ defmodule Ecto.SoftDelete.Repo do @callback soft_delete_all(queryable :: Ecto.Queryable.t()) :: {integer, nil | [term]} @doc """ - Restores all entries matching the given query. + Soft restores all entries matching the given query. It returns a tuple containing the number of entries and any returned result as second element. The second element is `nil` by default @@ -35,11 +35,11 @@ defmodule Ecto.SoftDelete.Repo do ## Examples - MyRepo.restore_all(%Post{}, MyRepo) + MyRepo.soft_restore_all(%Post{}, MyRepo) """ - @callback restore_all(struct :: Ecto.Schema.t()) :: {integer, nil | [term]} + @callback soft_restore_all(struct :: Ecto.Schema.t()) :: {integer, nil | [term]} @doc """ Soft deletes a struct. @@ -76,19 +76,19 @@ defmodule Ecto.SoftDelete.Repo do ## Examples post = MyRepo.get!(Post, 42) - case MyRepo.restore post do + case MyRepo.soft_restore post do {:ok, struct} -> "Soft restore with success" {:error, changeset} -> "Something went wrong" end """ - @callback restore(struct :: Ecto.Schema.t()) :: + @callback soft_restore(struct :: Ecto.Schema.t()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()} @doc """ - Same as `c:restore/1` but returns the struct or raises if the changeset is invalid. + Same as `c:soft_restore/1` but returns the struct or raises if the changeset is invalid. """ - @callback restore!(struct :: Ecto.Schema.t()) :: + @callback soft_restore!(struct :: Ecto.Schema.t()) :: Ecto.Schema.t() defmacro __using__(_opts) do @@ -111,7 +111,7 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def restore_all(struct, repo \\ :context) do + def soft_restore_all(struct, repo \\ :context) do source = Ecto.get_meta(struct, :source) context = @@ -136,7 +136,7 @@ defmodule Ecto.SoftDelete.Repo do {num_rows, rows} end - def restore(struct, repo \\ :context, key \\ "id") do + def soft_restore(struct, repo \\ :context, key \\ "id") do value = Map.from_struct(struct) |> Map.get(String.to_atom(key)) diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 5dde9f0..1c34c90 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -90,18 +90,18 @@ defmodule Ecto.SoftDelete.Repo.Test do end end - describe "restore/1" do + describe "soft_restore/1" do test "should soft restore the queryable" do user = Repo.insert!(%User{email: "test0@example.com"}) Repo.soft_delete(user) - Repo.restore(user, Repo) + Repo.soft_restore(user, Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == nil end end - describe "restore_all/1" do + describe "soft_restore_all/1" do test "soft deleted the query" do Repo.insert!(%User{email: "test0@example.com"}) Repo.insert!(%User{email: "test1@example.com"}) @@ -120,7 +120,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert %DateTime{} = Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.restore_all(%User{}, Repo) == {3, nil} + assert Repo.soft_restore_all(%User{}, Repo) == {3, nil} assert User |> Repo.all(with_deleted: true) |> length() == 3 From 360f42776f8a0f84b1c55db17bbe99b23bc13508 Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 11 Feb 2024 02:20:26 -0700 Subject: [PATCH 58/61] fix soft_restore functions --- lib/ecto/soft_delete_repo.ex | 63 +++++++----------------------------- 1 file changed, 12 insertions(+), 51 deletions(-) diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index 71841db..ae7f809 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -111,59 +111,20 @@ defmodule Ecto.SoftDelete.Repo do |> update!() end - def soft_restore_all(struct, repo \\ :context) do - source = Ecto.get_meta(struct, :source) - - context = - case repo do - :context -> Ecto.get_meta(struct, :context) - _ -> repo - end - - %{ - columns: _, - command: _, - connection_id: _, - messages: _, - num_rows: num_rows, - rows: rows - } = - Ecto.Adapters.SQL.query!( - context, - "UPDATE #{source} SET deleted_at = NULL" - ) - - {num_rows, rows} + def soft_restore_all(queryable) do + update_all(queryable, set: [deleted_at: nil]) end - def soft_restore(struct, repo \\ :context, key \\ "id") do - value = - Map.from_struct(struct) - |> Map.get(String.to_atom(key)) - - source = Ecto.get_meta(struct, :source) - - context = - case repo do - :context -> Ecto.get_meta(struct, :context) - _ -> repo - end - - %{ - columns: _, - command: _, - connection_id: _, - messages: _, - num_rows: num_rows, - rows: rows - } = - Ecto.Adapters.SQL.query!( - context, - "UPDATE #{source} SET deleted_at = NULL WHERE #{key} = $1", - [value] - ) - - {num_rows, rows} + def soft_restore(struct_or_changeset) do + struct_or_changeset + |> Ecto.Changeset.change(deleted_at: nil) + |> update() + end + + def soft_restore!(struct_or_changeset) do + struct_or_changeset + |> Ecto.Changeset.change(deleted_at: nil) + |> update!() end @doc """ From 7dff0d4d3e3c960226c685fe0257738ebb9be71d Mon Sep 17 00:00:00 2001 From: mithereal Date: Sun, 11 Feb 2024 02:24:40 -0700 Subject: [PATCH 59/61] fix tests --- lib/ecto/soft_delete_migration.ex | 2 +- test/soft_delete_repo_test.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ecto/soft_delete_migration.ex b/lib/ecto/soft_delete_migration.ex index a329c10..7d0b504 100644 --- a/lib/ecto/soft_delete_migration.ex +++ b/lib/ecto/soft_delete_migration.ex @@ -29,6 +29,6 @@ defmodule Ecto.SoftDelete.Migration do end def soft_delete_index(table) do - create index(table, [:deleted_at]) + create(index(table, [:deleted_at])) end end diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 1c34c90..310daa8 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -93,7 +93,7 @@ defmodule Ecto.SoftDelete.Repo.Test do describe "soft_restore/1" do test "should soft restore the queryable" do user = Repo.insert!(%User{email: "test0@example.com"}) - Repo.soft_delete(user) + user = Repo.soft_delete!(user) Repo.soft_restore(user, Repo) assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == From 512081cc11d93dcceda42d38ce345eb7ea7ae19b Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Mon, 12 Feb 2024 12:39:31 -0700 Subject: [PATCH 60/61] Apply suggestions from code review Co-authored-by: Alexandre Lepretre --- .formatter.exs | 3 ++- lib/ecto/soft_delete_repo.ex | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.formatter.exs b/.formatter.exs index d2cda26..970afd1 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,4 +1,5 @@ # Used by "mix format" [ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], + import_deps: [:ecto], ] diff --git a/lib/ecto/soft_delete_repo.ex b/lib/ecto/soft_delete_repo.ex index ae7f809..499d765 100644 --- a/lib/ecto/soft_delete_repo.ex +++ b/lib/ecto/soft_delete_repo.ex @@ -39,7 +39,7 @@ defmodule Ecto.SoftDelete.Repo do """ - @callback soft_restore_all(struct :: Ecto.Schema.t()) :: {integer, nil | [term]} + @callback soft_restore_all(struct :: Ecto.Queryable.t()) :: {integer, nil | [term]} @doc """ Soft deletes a struct. From 4821a61ab9c68fb033bf504f831c447e4675a056 Mon Sep 17 00:00:00 2001 From: mithereal Date: Mon, 12 Feb 2024 12:50:30 -0700 Subject: [PATCH 61/61] remove index and fix test --- .formatter.exs | 2 +- lib/ecto/soft_delete_migration.ex | 5 ----- test/soft_delete_repo_test.exs | 22 ---------------------- 3 files changed, 1 insertion(+), 28 deletions(-) diff --git a/.formatter.exs b/.formatter.exs index 970afd1..90c80fe 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,5 +1,5 @@ # Used by "mix format" [ inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], - import_deps: [:ecto], + import_deps: [:ecto] ] diff --git a/lib/ecto/soft_delete_migration.ex b/lib/ecto/soft_delete_migration.ex index 7d0b504..5545012 100644 --- a/lib/ecto/soft_delete_migration.ex +++ b/lib/ecto/soft_delete_migration.ex @@ -18,7 +18,6 @@ defmodule Ecto.SoftDelete.Migration do add :password, :string timestamps() soft_delete_columns() - soft_delete_index(:users) end end end @@ -27,8 +26,4 @@ defmodule Ecto.SoftDelete.Migration do def soft_delete_columns do add(:deleted_at, :utc_datetime_usec, []) end - - def soft_delete_index(table) do - create(index(table, [:deleted_at])) - end end diff --git a/test/soft_delete_repo_test.exs b/test/soft_delete_repo_test.exs index 310daa8..0a1e403 100644 --- a/test/soft_delete_repo_test.exs +++ b/test/soft_delete_repo_test.exs @@ -109,29 +109,7 @@ defmodule Ecto.SoftDelete.Repo.Test do assert Repo.soft_delete_all(User) == {3, nil} - assert User |> Repo.all(with_deleted: true) |> length() == 3 - - assert %DateTime{} = - Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at - - assert %DateTime{} = - Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at - - assert %DateTime{} = - Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at - assert Repo.soft_restore_all(%User{}, Repo) == {3, nil} - - assert User |> Repo.all(with_deleted: true) |> length() == 3 - - assert Repo.get_by!(User, [email: "test0@example.com"], with_deleted: true).deleted_at == - nil - - assert Repo.get_by!(User, [email: "test1@example.com"], with_deleted: true).deleted_at == - nil - - assert Repo.get_by!(User, [email: "test2@example.com"], with_deleted: true).deleted_at == - nil end test "when no results are found" do