feat(api): setup database migrations
This commit is contained in:
		
							
								
								
									
										71
									
								
								backend/src/neo_neo_todo/migrations/0.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								backend/src/neo_neo_todo/migrations/0.py
									
									
									
									
									
										Normal 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()
 | 
			
		||||
							
								
								
									
										11
									
								
								backend/src/neo_neo_todo/models/member.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								backend/src/neo_neo_todo/models/member.py
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user