From f2fc921bc579e43519da5b78e2f2e168132de7c0 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 21 Aug 2023 11:32:50 +0100 Subject: [PATCH] optimised api speed, good enough for now --- .../app/db/functions/portfolio_functions.py | 2 +- .../app/db/functions/property_functions.py | 12 +++++----- .../db/functions/recommendations_functions.py | 22 +++++++++---------- backend/app/plan/router.py | 15 ++++++++++++- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/backend/app/db/functions/portfolio_functions.py b/backend/app/db/functions/portfolio_functions.py index e3ca001a..37b6bf37 100644 --- a/backend/app/db/functions/portfolio_functions.py +++ b/backend/app/db/functions/portfolio_functions.py @@ -32,4 +32,4 @@ def aggregate_portfolio_recommendations(session, portfolio_id: int): # Merge the updated portfolio back into the session session.merge(portfolio) - session.commit() + session.flush() diff --git a/backend/app/db/functions/property_functions.py b/backend/app/db/functions/property_functions.py index 9fe7c5d5..ecad3ab7 100644 --- a/backend/app/db/functions/property_functions.py +++ b/backend/app/db/functions/property_functions.py @@ -31,7 +31,7 @@ def create_property(session, portfolio_id: int, address: str, postcode: str) -> # Merge the updated property back into the session session.merge(existing_property) - session.commit() + session.flush() return existing_property.id, False @@ -50,7 +50,7 @@ def create_property(session, portfolio_id: int, address: str, postcode: str) -> # Add the new property to the session session.add(new_property) - session.commit() + session.flush() return new_property.id, True @@ -73,7 +73,7 @@ def create_property_targets(session, property_id: int, portfolio_id: int, epc_ta heat_demand=heat_demand_target ) session.add(new_target) - session.commit() + session.flush() return True @@ -93,9 +93,9 @@ def update_property_data(session, property_id: int, portfolio_id: int, property_ existing_property.updated_at = now - # Merge the updated property back into the session and commit + # Merge the updated property back into the session and flush session.merge(existing_property) - session.commit() + session.flush() except NoResultFound: raise Exception(f"Property with property_id {property_id} and portfolio_id {portfolio_id} not found") @@ -125,6 +125,6 @@ def create_property_details_epc(session, property_details_epc: dict): new_property_details_epc = PropertyDetailsEpcModel(**property_details_epc) session.add(new_property_details_epc) - session.commit() + session.flush() return True diff --git a/backend/app/db/functions/recommendations_functions.py b/backend/app/db/functions/recommendations_functions.py index ec90557a..84f2f967 100644 --- a/backend/app/db/functions/recommendations_functions.py +++ b/backend/app/db/functions/recommendations_functions.py @@ -1,5 +1,5 @@ -from sqlalchemy import text -from backend.app.db.models.recommendations import Plan, Recommendation, RecommendationMaterials +from sqlalchemy import insert +from backend.app.db.models.recommendations import Plan, Recommendation, RecommendationMaterials, PlanRecommendations def create_plan(session, plan): @@ -24,7 +24,7 @@ def create_recommendation(session, recommendation): new_recommendation = Recommendation(**recommendation) session.add(new_recommendation) - session.commit() + session.flush() return new_recommendation.id @@ -44,25 +44,23 @@ def create_recommendation_material(session, recommendation_id, material_id, dept depth=depth ) session.add(new_recommendation_material) - session.commit() + session.flush() return new_recommendation_material.id def create_plan_recommendations(session, plan_id, recommendation_ids): """ - This function will create a record for the plan_recommendation in the database if it does not exist. + This function will create records for the plan_recommendation in the database. :param plan_id: ID of the plan :param recommendation_ids: list of recommendation IDs """ - for recommendation_id in recommendation_ids: - session.execute( - text( - 'INSERT INTO plan_recommendations (plan_id, recommendation_id) VALUES (:plan_id, ' - ':recommendation_id)'), - {'plan_id': plan_id, 'recommendation_id': recommendation_id} - ) + # Prepare a list of dictionaries for bulk insert + data = [{"plan_id": plan_id, "recommendation_id": rid} for rid in recommendation_ids] + + # Bulk insert using SQLAlchemy's core API + session.execute(insert(PlanRecommendations).values(data)) def upload_recommendations(session, recommendations_to_upload, property_id): diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py index acaf4160..70b1ad19 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -14,6 +14,7 @@ from utils.uvalue_estimates import classify_decile_newvalues from backend.app.db.utils import row2dict from starlette.responses import Response from sqlalchemy.orm import sessionmaker +from sqlalchemy.exc import IntegrityError, OperationalError # database interaction functions from backend.app.db.functions.property_functions import ( @@ -135,7 +136,7 @@ async def trigger_plan(body: PlanTriggerRequest): session = Session() try: - + session.begin() logger.info("Getting the inputs") # Read in the trigger file from s3 bucket_name = get_settings().PLAN_TRIGGER_BUCKET @@ -373,6 +374,18 @@ async def trigger_plan(body: PlanTriggerRequest): # Commit all changes at once session.commit() + except IntegrityError: + logger.error("Database integrity error occurred", exc_info=True) + session.rollback() + return Response(status_code=500, content="Database integrity error.") + except OperationalError: + logger.error("Database operational error occurred", exc_info=True) + session.rollback() + return Response(status_code=500, content="Database operational error.") + except ValueError: + logger.error("Value error - possibly due to malformed data", exc_info=True) + session.rollback() + return Response(status_code=400, content="Bad request: malformed data.") except Exception as e: # General exception handling logger.error(f"An error occurred: {e}") session.rollback()