feat(api): setup database migrations

This commit is contained in:
minhtrannhat 2024-02-04 16:42:42 -05:00
parent 627f104101
commit b80883bec0
Signed by: minhtrannhat
GPG Key ID: E13CFA85C53F8062
4 changed files with 92 additions and 2 deletions

View File

@ -64,5 +64,6 @@ start = {cmd = "uvicorn --workers 2 neo_neo_todo.main:app", env_file = "developm
dev = {cmd = "uvicorn neo_neo_todo.main:app --reload", env_file = "development.env"}
recreate-db-base = "python3 src/neo_neo_todo/utils/database.py"
recreate-db = {composite = ["recreate-db-base"], env_file = "development.env"}
migration-base = "python3 src/neo_neo_todo/migrations/0.py"
recreate-db = {composite = ["recreate-db-base", "migration-base"], env_file = "development.env"}
test = {composite = ["recreate-db-base", "pytest tests/"], env_file = "testing.env"}

View File

@ -0,0 +1,71 @@
import os
from urllib.parse import urlparse
import psycopg
from psycopg import sql
def migrate() -> None:
"""
Migrate the PostgreSQL database
Watch for PostgreSQL version changes
"""
url_parts = urlparse(os.environ["TODO_DB_DATABASE_URL"])
# Extract connection parameters
dbname = url_parts.path[1:]
user_name = url_parts.username
password = url_parts.password
host = url_parts.hostname
port = url_parts.port
print(
f"The database name is {dbname}, the username is {user_name}, the password is {password}, the host is {host}, the port is {port}"
)
with psycopg.connect(
dbname=dbname, user=user_name, password=password, host=host, port=port
) as conn:
with conn.cursor() as cur:
# create the members table
cur.execute(
sql.SQL(
"""CREATE TABLE members (
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
created TIMESTAMP NOT NULL DEFAULT now(),
email TEXT NOT NULL,
email_verified TIMESTAMP,
password_hash TEXT NOT NULL
)"""
)
)
cur.execute(
sql.SQL(
"""CREATE UNIQUE INDEX members_unique_email_idx
ON members (LOWER(email)
)"""
)
)
cur.execute(
sql.SQL(
"""CREATE TABLE todos (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
complete BOOLEAN NOT NULL DEFAULT FALSE,
due TIMESTAMPTZ,
member_id INT NOT NULL REFERENCES members(id),
task TEXT NOT NULL
)"""
)
)
# Commit the changes
conn.commit()
print("Finished PostgreSQL migration number 0")
if __name__ == "__main__":
migrate()

View File

@ -0,0 +1,11 @@
from dataclasses import dataclass
from datetime import datetime
@dataclass
class Member:
id: int
email: str
password_hash: str
created: datetime
email_verified: datetime | None

View File

@ -58,7 +58,7 @@ def recreate_db() -> None:
# Create a new user
cur.execute(
sql.SQL("CREATE USER {} WITH PASSWORD {}").format(
sql.SQL("CREATE USER {} WITH PASSWORD {} CREATEDB").format(
sql.Identifier(user_name), password # type: ignore
)
)
@ -73,6 +73,13 @@ def recreate_db() -> None:
)
)
cur.execute(
sql.SQL("ALTER DATABASE {} OWNER TO {}").format(
sql.Identifier(dbname),
sql.Identifier(user_name), # type: ignore
)
)
# Commit the changes
conn.commit()