From 627f104101417c620a8c69448ce176fe1e1510af Mon Sep 17 00:00:00 2001 From: minhtrannhat Date: Sat, 3 Feb 2024 20:45:00 -0500 Subject: [PATCH] feat(testing): (re)create postgresql database for test and dev --- backend/development.env | 1 + backend/pdm.lock | 71 +++++++++++++++++- backend/pyproject.toml | 9 ++- backend/src/neo_neo_todo/utils/database.py | 83 ++++++++++++++++++++++ backend/testing.env | 1 + 5 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 backend/src/neo_neo_todo/utils/database.py diff --git a/backend/development.env b/backend/development.env index c2895e0..df2bd3d 100644 --- a/backend/development.env +++ b/backend/development.env @@ -1,3 +1,4 @@ UVICORN_PORT="5050" TODO_DEBUG=true TODO_SECRET_KEY="secret key" +TODO_DB_DATABASE_URL="postgresql://todo:todo@0.0.0.0:5432/todo" diff --git a/backend/pdm.lock b/backend/pdm.lock index a515609..9493eb5 100644 --- a/backend/pdm.lock +++ b/backend/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev"] strategy = ["cross_platform"] lock_version = "4.4.1" -content_hash = "sha256:a15732e99160a9c0463d7809d12e0405520e386b75c8cabcf9ce911abd4c1001" +content_hash = "sha256:d4750005194c2cd648e90c5535f88ca18e5bdc84a4c94d9f7e998e3ebc37d2f7" [[package]] name = "annotated-types" @@ -362,6 +362,65 @@ files = [ {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] +[[package]] +name = "psycopg" +version = "3.1.17" +requires_python = ">=3.7" +summary = "PostgreSQL database adapter for Python" +dependencies = [ + "typing-extensions>=4.1", + "tzdata; sys_platform == \"win32\"", +] +files = [ + {file = "psycopg-3.1.17-py3-none-any.whl", hash = "sha256:96b7b13af6d5a514118b759a66b2799a8a4aa78675fa6bb0d3f7d52d67eff002"}, + {file = "psycopg-3.1.17.tar.gz", hash = "sha256:437e7d7925459f21de570383e2e10542aceb3b9cb972ce957fdd3826ca47edc6"}, +] + +[[package]] +name = "psycopg-binary" +version = "3.1.17" +requires_python = ">=3.7" +summary = "PostgreSQL database adapter for Python -- C optimisation distribution" +files = [ + {file = "psycopg_binary-3.1.17-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0227885686c2cc0104ceb22d6eebc732766e9ad48710408cb0123237432e5435"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9124b6db07e8d8b11f4512b8b56cbe136bf1b7d0417d1280e62291a9dcad4408"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a46f77ba0ca7c5a5449b777170a518fa7820e1710edb40e777c9798f00d033"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f5f5bcbb772d8c243d605fc7151beec760dd27532d42145a58fb74ef9c5fbf2"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:267a82548c21476120e43dc72b961f1af52c380c0b4c951bdb34cf14cb26bd35"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b20013051f1fd7d02b8d0766cfe8d009e8078babc00a6d39bc7e2d50a7b96af"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c5c38129cc79d7e3ba553035b9962a442171e9f97bb1b8795c0885213f206f3"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d01c4faae66de60fcd3afd3720dcc8ffa03bc2087f898106da127774db12aac5"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e6ae27b0617ad3809449964b5e901b21acff8e306abacb8ba71d5ee7c8c47eeb"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:40af298b209dd77ca2f3e7eb3fbcfb87a25999fc015fcd14140bde030a164c7e"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-win_amd64.whl", hash = "sha256:7b4e4c2b05f3b431e9026e82590b217e87696e7a7548f512ae8059d59fa8af3b"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ea425a8dcd808a7232a5417d2633bfa543da583a2701b5228e9e29989a50deda"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3f1196d76860e72d338fab0d2b6722e8d47e2285d693e366ae36011c4a5898a"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1e867c2a729348df218a14ba1b862e627177fd57c7b4f3db0b4c708f6d03696"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0711e46361ea3047cd049868419d030c8236a9dea7e9ed1f053cbd61a853ec9"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1c0115bdf80cf6c8c9109cb10cf6f650fd1a8d841f884925e8cb12f34eb5371"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d0d154c780cc7b28a3a0886e8a4b18689202a1dbb522b3c771eb3a1289cf7c3"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f4028443bf25c1e04ecffdc552c0a98d826903dec76a1568dfddf5ebbbb03db7"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf424d92dd7e94705b31625b02d396297a7c8fab4b6f7de8dba6388323a7b71c"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:00377f6963ee7e4bf71cab17c2c235ef0624df9483f3b615d86aa24cde889d42"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9690a535d9ccd361bbc3590bfce7fe679e847f44fa7cc97f3b885f4744ca8a2c"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-win_amd64.whl", hash = "sha256:6b2ae342d69684555bfe77aed5546d125b4a99012e0b83a8b3da68c8829f0935"}, +] + +[[package]] +name = "psycopg" +version = "3.1.17" +extras = ["binary"] +requires_python = ">=3.7" +summary = "PostgreSQL database adapter for Python" +dependencies = [ + "psycopg-binary==3.1.17; implementation_name != \"pypy\"", + "psycopg==3.1.17", +] +files = [ + {file = "psycopg-3.1.17-py3-none-any.whl", hash = "sha256:96b7b13af6d5a514118b759a66b2799a8a4aa78675fa6bb0d3f7d52d67eff002"}, + {file = "psycopg-3.1.17.tar.gz", hash = "sha256:437e7d7925459f21de570383e2e10542aceb3b9cb972ce957fdd3826ca47edc6"}, +] + [[package]] name = "pydantic" version = "2.5.3" @@ -629,6 +688,16 @@ files = [ {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] +[[package]] +name = "tzdata" +version = "2023.4" +requires_python = ">=2" +summary = "Provider of IANA time zone data" +files = [ + {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, + {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, +] + [[package]] name = "uvicorn" version = "0.27.0" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 8868334..f9d7142 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -15,6 +15,7 @@ dependencies = [ "itsdangerous>=2.1.2", # signing user tokens "slowapi>=0.1.8", "redis>=5.0.1", + "psycopg[binary]>=3.1.17", ] requires-python = ">=3.11" readme = "README.md" @@ -58,8 +59,10 @@ format = {composite = ["format-black"]} lint = {composite = ["lint-ruff"]} -test = {cmd = "pytest tests/", env_file = "testing.env" } - -# start = {cmd = "uvicorn --workers 2 neo_neo_todo.main:app", env_file = "development.env"} +start = {cmd = "uvicorn --workers 2 neo_neo_todo.main:app", env_file = "development.env"} 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"} +test = {composite = ["recreate-db-base", "pytest tests/"], env_file = "testing.env"} diff --git a/backend/src/neo_neo_todo/utils/database.py b/backend/src/neo_neo_todo/utils/database.py new file mode 100644 index 0000000..2330f2d --- /dev/null +++ b/backend/src/neo_neo_todo/utils/database.py @@ -0,0 +1,83 @@ +import os +from urllib.parse import urlparse + +import psycopg +from psycopg import sql + + +def recreate_db() -> None: + """ + (Re)create 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="postgres", user="postgres", password=password, host=host, port=port + ) as conn: + with conn.cursor() as cur: + conn._set_autocommit(True) + + cur.execute( + sql.SQL("DROP OWNED BY {}").format( + sql.Identifier(user_name) # type: ignore + ) + ) + + # drop the database if exists + cur.execute( + sql.SQL("DROP DATABASE IF EXISTS {dbname}").format( + dbname=sql.Identifier(dbname), + ) + ) + # Drop the user if it exists + cur.execute( + sql.SQL("DROP USER IF EXISTS {}").format( + sql.Identifier(user_name), # type: ignore + ) + ) + + # Create a new database + cur.execute( + sql.SQL("CREATE DATABASE {dbname}").format( + dbname=sql.Identifier(dbname), + ) + ) + + # Create a new user + cur.execute( + sql.SQL("CREATE USER {} WITH PASSWORD {}").format( + sql.Identifier(user_name), password # type: ignore + ) + ) + + # Grant necessary privileges to the new user + cur.execute( + sql.SQL( + "GRANT ALL PRIVILEGES ON DATABASE {dbname} TO {user_name}" + ).format( + dbname=sql.Identifier(dbname), + user_name=sql.Identifier(user_name), # type: ignore + ) + ) + + # Commit the changes + conn.commit() + + print("Finished PostgreSQL (re)creatation") + + +if __name__ == "__main__": + recreate_db() diff --git a/backend/testing.env b/backend/testing.env index a04091e..e04212b 100644 --- a/backend/testing.env +++ b/backend/testing.env @@ -2,3 +2,4 @@ UVICORN_PORT="5050" TODO_DEBUG=true TODO_SECRET_KEY="secret key" TODO_TESTING=true +TODO_DB_DATABASE_URL="postgresql://todo:todo@0.0.0.0:5432/todo_test"