Skip to content

Instantly share code, notes, and snippets.

@rockwood
Last active November 27, 2018 07:24
Show Gist options
  • Save rockwood/78150119d8736234d048b98227423b26 to your computer and use it in GitHub Desktop.
Save rockwood/78150119d8736234d048b98227423b26 to your computer and use it in GitHub Desktop.
Ecto Soft-Delete Pattern
defmodule MyApp.ArchivePostScenario do
alias MyApp.Repo
alias Ecto.Multi
alias __MODULE__.Query
def run(options) do
post = Keyword.fetch!(options, :post)
archive_and_delete([
comments: Query.comments(post),
views: Query.views(post),
posts: Query.posts(post),
])
end
defp archive_and_delete(queries) do
Multi.new()
|> archive(queries)
|> delete(queries)
|> Repo.transaction()
|> case do
{:ok, result} -> {:ok, result}
{:error, step, _result, _changes_so_far} -> {:error, step}
end
end
defp archive(multi, queries) do
Enum.reduce(queries, multi, fn({name, query}, acc) ->
record_maps = query |> Query.select_plain_map() |> Repo.all()
Multi.insert_all(acc, "archive_#{name}", name, record_maps, prefix: :archive)
end)
end
defp delete(multi, queries) do
Enum.reduce(queries, multi, fn({name, query}, acc) ->
Multi.delete_all(acc, "delete_#{name}", query)
end)
end
defmodule Query do
import Ecto.Query
alias MyApp.{Blog}
def posts(post) do
from Blog.Post, where: [id: ^post.id]
end
def views(post) do
from Blog.View, where: [post_id: ^post.id]
end
def comments(post) do
from Blog.Comment, where: [post_id: ^post.id]
end
def select_plain_map(query = %{from: %{source: {_name, schema}}}) do
fields = schema.__schema__(:fields)
from record in query, select: map(record, ^fields)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment