First create a function to handle the soft delete
defmodule MyApp.Repo.Migrations.SoftDeletes do
use Ecto.Migration
def up do
execute """
CREATE FUNCTION soft_delete() RETURNS TRIGGER AS $$
DECLARE
command text := ' SET deleted_at = current_timestamp where id = $1';
BEGIN
EXECUTE 'UPDATE ' || TG_TABLE_NAME || command USING OLD.id;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
"""
end
def down do
execute """
DROP FUNCTION soft_delete();
"""
end
end
Then create the migration for you table & view
defmodule MyApp.Repo.Migrations.CreateWidgets do
use Ecto.Migration
def up do
create table("all_widgets") do
add :name, :string
add :deleted_at, :utc_datetime
timestamps(type: :utc_datetime)
end
create index("all_widgets", [:deleted_at], where: "deleted_at IS NULL", name: :widgets_deleted_at_idx)
execute """
CREATE VIEW widgets AS
SELECT * FROM all_widgets WHERE deleted_at IS NULL;
"""
execute """
CREATE TRIGGER widgets_soft_delete_tg
INSTEAD OF DELETE ON widgets
FOR EACH ROW EXECUTE PROCEDURE soft_delete();
"""
end
def down do
execute "DROP VIEW widgets;"
drop table("all_widgets")
end
end
The Ecto schema doesn't change for this. You just create a schema as you would for the widgets
view. Inserts, updates, and deletes all work against the view and your Elixir code is none the wiser