fix: unique violations

Directly using Psycopg error instead of the error code.

Also, raise all other IntegrityErrors instead of silently dropping them.
This commit is contained in:
Chris Milne 2026-06-15 14:38:14 +01:00
parent 3433ba39ee
commit 3e4f68dd9b
3 changed files with 12 additions and 5 deletions

View file

@ -20,6 +20,7 @@ Endpoints:
from fastapi import APIRouter, status, BackgroundTasks from fastapi import APIRouter, status, BackgroundTasks
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from psycopg.errors import UniqueViolation
from src.iam.exceptions import GroupNotFoundException from src.iam.exceptions import GroupNotFoundException
from src.organisation.exceptions import OrgNotFoundException from src.organisation.exceptions import OrgNotFoundException
@ -283,10 +284,11 @@ async def create_group(
db.flush() db.flush()
except IntegrityError as e: except IntegrityError as e:
if ( if (
getattr(e.orig, "pgcode", None) == "23505" # Postgres unique violation isinstance(e.orig, UniqueViolation) # Postgres unique violation
or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation
): ):
raise ConflictException("Group with this name already exists") raise ConflictException("Group with this name already exists")
raise
group_response = GroupSummary(**group_model.__dict__) group_response = GroupSummary(**group_model.__dict__)
org_response = OrgSummary(**org_model.__dict__) org_response = OrgSummary(**org_model.__dict__)
db.commit() db.commit()
@ -500,10 +502,11 @@ async def create_new_permission(
db.flush() db.flush()
except IntegrityError as e: except IntegrityError as e:
if ( if (
getattr(e.orig, "pgcode", None) == "23505" # Postgres unique violation isinstance(e.orig, UniqueViolation) # Postgres unique violation
or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation
): ):
raise ConflictException(message="Permission already exists") raise ConflictException(message="Permission already exists")
raise
response = { response = {
"id": perm_model.id, "id": perm_model.id,
"service_name": perm_model.service_name, "service_name": perm_model.service_name,

View file

@ -18,10 +18,11 @@ Endpoints:
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Annotated from typing import Annotated
from sqlalchemy.exc import IntegrityError
from psycopg.errors import UniqueViolation
from fastapi import APIRouter, status from fastapi import APIRouter, status
from fastapi.params import Query from fastapi.params import Query
from sqlalchemy.exc import IntegrityError
from src.contact.schemas import ContactModel from src.contact.schemas import ContactModel
from src.exceptions import ( from src.exceptions import (
@ -175,12 +176,13 @@ async def create_org(
db.flush() db.flush()
except IntegrityError as e: except IntegrityError as e:
if ( if (
getattr(e.orig, "pgcode", None) == "23505" # Postgres unique violation isinstance(e.orig, UniqueViolation) # Postgres unique violation
or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation
): ):
raise ConflictException( raise ConflictException(
message="Organisation with this name already exists" message="Organisation with this name already exists"
) )
raise
# Adds currently logged-in user to org users list and sets them as root_user # Adds currently logged-in user to org users list and sets them as root_user
org_model.user_rel.append(user_model) org_model.user_rel.append(user_model)
org_model.root_user_rel = user_model org_model.root_user_rel = user_model

View file

@ -10,6 +10,7 @@ Endpoints:
from fastapi import APIRouter, status from fastapi import APIRouter, status
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from psycopg.errors import UniqueViolation
from src.exceptions import ConflictException from src.exceptions import ConflictException
from src.database import db_dependency from src.database import db_dependency
@ -110,10 +111,11 @@ async def register_service(
db.flush() db.flush()
except IntegrityError as e: except IntegrityError as e:
if ( if (
getattr(e.orig, "pgcode", None) == "23505" # Postgres unique violation isinstance(e.orig, UniqueViolation) # Postgres unique violation
or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation or "UNIQUE constraint failed" in str(e.orig) # SQLite unique violation
): ):
raise ConflictException(message="Service with this name already exists") raise ConflictException(message="Service with this name already exists")
raise
response = ServiceWithKeySchema(**service_model.__dict__) response = ServiceWithKeySchema(**service_model.__dict__)
db.commit() db.commit()
return {"service": response} return {"service": response}