From 17ebcc5ae358107e305938ec6b9d5681fe99b8dc Mon Sep 17 00:00:00 2001 From: Jakub Miazek Date: Sat, 23 Mar 2024 21:04:35 +0100 Subject: [PATCH 1/3] wip: setting refactor --- .env | 9 +++++++++ app/api/nonsense.py | 41 +++++++++++++++++++++++++++++++++++++++++ app/config.py | 41 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 01bd42c..e1825a6 100644 --- a/.env +++ b/.env @@ -8,6 +8,15 @@ SQL_USER=user SQL_PASS=secret SQL_URL=postgresql+asyncpg://${SQL_USER}:${SQL_PASS}@${SQL_HOST}/${SQL_DB} +# Postgres +POSTGRES_SERVER=db +POSTGRES_PORT=5432 +POSTGRES_DB=devdb +POSTGRES_TEST_DB=testdb +POSTGRES_USER=user +POSTGRES_PASSWORD=secret + +# Redis REDIS_HOST=redis REDIS_PORT=6379 REDIS_DB=2 diff --git a/app/api/nonsense.py b/app/api/nonsense.py index 49422db..3cf8116 100644 --- a/app/api/nonsense.py +++ b/app/api/nonsense.py @@ -107,3 +107,44 @@ async def import_nonsense( finally: # Ensure that the database session is closed, regardless of whether an error occurred or not await db_session.close() + + +# TODO: add websocket to full text search postgres database for nonsense description + +# To add a WebSocket to full text search a PostgreSQL database for the `nonsense` description, you can use the `websockets` library in Python. Here's a step-by-step plan: +# +# 1. Install the `websockets` library if you haven't done so already. +# 2. Create a new WebSocket route in your FastAPI application. +# 3. In the WebSocket route, accept a search query from the client. +# 4. Use the search query to perform a full text search on the `nonsense` table in your PostgreSQL database. +# 5. Send the search results back to the client through the WebSocket connection. +# +# Here's how you can implement this: +# +# ```python +# import websockets +# from fastapi import WebSocket +# from sqlalchemy import text +# +# router = APIRouter() +# +# @router.websocket("/ws/nonsense") +# async def websocket_endpoint(websocket: WebSocket): +# await websocket.accept() +# while True: +# data = await websocket.receive_text() +# query = text(f""" +# SELECT * FROM nonsense +# WHERE to_tsvector('english', description) @@ plainto_tsquery('english', :q) +# """) +# result = await db_session.execute(query, {"q": data}) +# await websocket.send_json(result.fetchall()) +# # ``` +# +# This code creates a new WebSocket route at `/ws/nonsense`. When a client connects to this route and sends a message, the message is used as a search query in a full text search on the `nonsense` table. The search results are then sent back to the client through the WebSocket connection. +# +# Please note that this is a basic implementation and might need adjustments based on your specific needs. For example, you might want to add error handling, handle disconnections, or format the search results before sending them back to the client. +# + +# TODO: https://medium.com/@amitosh/full-text-search-fts-with-postgresql-and-sqlalchemy-edc436330a0c +# TODO: https://www.postgresql.org/docs/13/textsearch-intro.html \ No newline at end of file diff --git a/app/config.py b/app/config.py index 9bb7fee..32f709b 100644 --- a/app/config.py +++ b/app/config.py @@ -1,14 +1,49 @@ import os -from pydantic import PostgresDsn, RedisDsn -from pydantic_settings import BaseSettings +from pydantic import PostgresDsn, RedisDsn, computed_field +from pydantic_core import MultiHostUrl +from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): - asyncpg_url: PostgresDsn = os.getenv("SQL_URL") + model_config = SettingsConfigDict( + env_file=".env", + env_ignore_empty=True, + extra="ignore" + ) + # asyncpg_url: PostgresDsn = os.getenv("SQL_URL") redis_url: RedisDsn = os.getenv("REDIS_URL") jwt_algorithm: str = os.getenv("JWT_ALGORITHM") jwt_expire: int = os.getenv("JWT_EXPIRE") + SQL_USER: str + SQL_PASS: str + SQL_HOST: str + SQL_DB: str + + @computed_field + @property + def asyncpg_url(self) -> PostgresDsn: + """ + This is a computed field that generates a PostgresDsn URL for asyncpg. + + The URL is built using the MultiHostUrl.build method, which takes the following parameters: + - scheme: The scheme of the URL. In this case, it is "postgresql+asyncpg". + - username: The username for the SQL database, retrieved from the SQL_USER environment variable. + - password: The password for the SQL database, retrieved from the SQL_PASS environment variable. + - host: The host of the SQL database, retrieved from the SQL_HOST environment variable. + - path: The path of the SQL database, retrieved from the SQL_DB environment variable. + + Returns: + PostgresDsn: The constructed PostgresDsn URL for asyncpg. + """ + return MultiHostUrl.build( + scheme="postgresql+asyncpg", + username=self.SQL_USER, + password=self.SQL_PASS, + host=self.SQL_HOST, + path=self.SQL_DB, + ) + settings = Settings() From b50b3c9d4371fd68e080c454b4f90bc4f1e8c81c Mon Sep 17 00:00:00 2001 From: Jakub Miazek Date: Sun, 24 Mar 2024 10:33:15 +0100 Subject: [PATCH 2/3] refactor db init sql script --- db/create.sql | 2 -- 1 file changed, 2 deletions(-) diff --git a/db/create.sql b/db/create.sql index 95421a5..35d64d4 100644 --- a/db/create.sql +++ b/db/create.sql @@ -1,5 +1,3 @@ -DROP DATABASE IF EXISTS devdb; -CREATE DATABASE devdb; \connect devdb; CREATE SCHEMA shakespeare; CREATE SCHEMA happy_hog; From 053fbe00ced35bed53fdf616436b8f4149dbbddc Mon Sep 17 00:00:00 2001 From: Jakub Miazek Date: Sun, 24 Mar 2024 10:51:35 +0100 Subject: [PATCH 3/3] drop SQL_URL --- .env | 2 +- .github/workflows/build-and-test.yml | 2 +- app/config.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.env b/.env index e1825a6..bb7151b 100644 --- a/.env +++ b/.env @@ -6,7 +6,7 @@ SQL_TEST_DB=testdb SQL_HOST=db SQL_USER=user SQL_PASS=secret -SQL_URL=postgresql+asyncpg://${SQL_USER}:${SQL_PASS}@${SQL_HOST}/${SQL_DB} +#SQL_URL=postgresql+asyncpg://${SQL_USER}:${SQL_PASS}@${SQL_HOST}/${SQL_DB} # Postgres POSTGRES_SERVER=db diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 575df60..5e141af 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -23,7 +23,7 @@ jobs: SQL_USER: app-user POSTGRES_PASSWORD: secret PGPASSWORD: secret - SQL_URL: postgresql+asyncpg://app-user:secret@localhost:5432/testdb +# SQL_URL: postgresql+asyncpg://app-user:secret@localhost:5432/testdb REDIS_HOST: 127.0.0.1 REDIS_PORT: 6379 REDIS_DB: 2 diff --git a/app/config.py b/app/config.py index 32f709b..25d0c70 100644 --- a/app/config.py +++ b/app/config.py @@ -11,7 +11,6 @@ class Settings(BaseSettings): env_ignore_empty=True, extra="ignore" ) - # asyncpg_url: PostgresDsn = os.getenv("SQL_URL") redis_url: RedisDsn = os.getenv("REDIS_URL") jwt_algorithm: str = os.getenv("JWT_ALGORITHM") jwt_expire: int = os.getenv("JWT_EXPIRE")