defmodule Mix.Tasks.SetUpTestDatabase do
use Mix.Task
alias Mix.Tasks.Helpers
@test_database "todos_test"
@shortdoc "Set up test database and tables"
def run(_) do
Mix.Task.run("app.start")
setup_test_database()
end
defp setup_test_database do
Helpers.create_database(@test_database)
{:ok, pid} =
Postgrex.start_link(
hostname: "localhost",
username: "postgres",
password: "postgres",
database: @test_database
)
create_database_logic(pid)
create_database_tables(pid)
seed_database_tables(pid)
set_up_logical_replication(pid)
end
defp create_database_logic(pid) do
Helpers.create_extension(pid, "citext")
Helpers.create_extension(pid, "uuid-ossp")
create_updated_at_function(pid)
end
defp create_database_tables(pid) do
create_user_table(pid)
create_updated_at_trigger(pid, "user")
create_todo_table(pid)
create_updated_at_trigger(pid, "todo")
end
defp set_up_logical_replication(pid) do
set_wal_level_to_logical(pid)
set_event_publications(pid)
set_replica_identity(pid, "user")
set_replica_identity(pid, "todo")
end
defp set_wal_level_to_logical(pid) do
set_wal_level = "ALTER SYSTEM SET wal_level = \'logical\';"
Postgrex.query!(pid, set_wal_level, [])
end
defp set_event_publications(pid) do
event_publications = "CREATE PUBLICATION events FOR TABLE \"user\", \"todo\";"
Postgrex.query!(pid, event_publications, [])
end
defp set_replica_identity(pid, table_name) do
replica_identity = "ALTER TABLE \"#{table_name}\" REPLICA IDENTITY FULL;"
Postgrex.query!(pid, replica_identity, [])
end
defp create_updated_at_function(pid) do
create_updated_at_function_statement = """
CREATE OR REPLACE FUNCTION set_current_timestamp_updated_at()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
"""
Postgrex.query!(pid, create_updated_at_function_statement, [])
end
defp create_updated_at_trigger(pid, table_name) do
create_updated_at_trigger_statement = """
CREATE TRIGGER set_#{table_name}_updated_at
BEFORE UPDATE ON \"#{table_name}\"
FOR EACH ROW
EXECUTE PROCEDURE set_current_timestamp_updated_at();
"""
Postgrex.query!(pid, create_updated_at_trigger_statement, [])
end
defp create_user_table(pid) do
create_user_table_statement = """
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
email citext UNIQUE NOT NULL,
name VARCHAR NOT NULL,
age INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
"""
Postgrex.query!(pid, create_user_table_statement, [])
end
defp create_todo_table(pid) do
create_table_statement = """
CREATE TABLE todo (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
user_id INTEGER REFERENCES "user"(id) ON DELETE CASCADE,
description TEXT NOT NULL,
due_date DATE,
is_completed BOOLEAN DEFAULT FALSE,
priority INTEGER DEFAULT 0,
tags VARCHAR[] DEFAULT '{}'::VARCHAR[],
rules JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
"""
Postgrex.query!(pid, create_table_statement, [])
end
defp seed_database_tables(pid) do
seed_users(pid)
seed_todos(pid)
end
defp seed_users(pid) do
users = """
INSERT INTO \"user\" (email, name, age)
VALUES
('john.doe@example.com', 'John Doe', 28),
('jane.smith@example.com', 'Jane Smith', 32),
('bob.jones@example.com', 'Bob Jones', 25),
('alice.davis@example.com', 'Alice Davis', 34),
('charlie.brown@example.com', 'Charlie Brown', 30);
"""
Postgrex.query!(pid, users, [])
end
defp seed_todos(pid) do
todos = """
INSERT INTO todo (user_id, description, due_date, is_completed, priority, tags, rules)
VALUES
-- User 1 todos
(1, 'Buy groceries', '2023-01-10', false, 2, ARRAY['groceries', 'shopping'], '{\"reminder\": true, \"repeat\": \"weekly\"}'::JSONB),
(1, 'Finish work project', '2023-01-15', true, 1, ARRAY['work', 'project'], '{\"priority\": \"high\"}'::JSONB),
(1, 'Exercise', NULL, false, 3, ARRAY['health', 'fitness'], '{}'::JSONB),
-- User 2 todos
(2, 'Read a book', '2023-02-01', true, 2, ARRAY['reading', 'books'], '{\"genre\": \"mystery\"}'::JSONB),
(2, 'Write a blog post', '2023-02-10', false, 1, ARRAY['writing', 'blog'], '{\"format\": \"tutorial\"}'::JSONB),
(2, 'Plan vacation', '2023-03-01', false, 3, ARRAY['travel', 'vacation'], '{\"destination\": \"beach\"}'::JSONB),
-- User 3 todos
(3, 'Learn a new programming language', '2023-01-20', false, 2, ARRAY['coding', 'programming'], '{\"level\": \"intermediate\"}'::JSONB),
(3, 'Cook a new recipe', '2023-02-05', false, 1, ARRAY['cooking', 'recipe'], '{\"cuisine\": \"Italian\"}'::JSONB),
(3, 'Study for exams', '2023-02-28', true, 3, ARRAY['education', 'exams'], '{\"subject\": \"math\"}'::JSONB),
-- User 4 todos
(4, 'Explore hiking trails', NULL, true, 2, ARRAY['outdoors', 'hiking'], '{}'::JSONB),
(4, 'Complete home improvement projects', '2023-03-15', true, 1, ARRAY['home', 'projects'], '{\"room\": \"kitchen\"}'::JSONB),
(4, 'Attend a music concert', '2023-04-01', false, 3, ARRAY['music', 'concert'], '{\"genre\": \"rock\"}'::JSONB),
-- User 5 todos
(5, 'Volunteer at local community center', '2023-02-10', false, 2, ARRAY['community', 'volunteer'], '{\"activity\": \"food drive\"}'::JSONB),
(5, 'Practice mindfulness', NULL, false, 1, ARRAY['mindfulness', 'meditation'], '{}'::JSONB),
(5, 'Attend a language exchange meetup', '2023-03-05', true, 3, ARRAY['language', 'meetup'], '{\"languages\": [\"Spanish\", \"French\"]}'::JSONB)
;
"""
Postgrex.query!(pid, todos, [])
end
end