Skip to content

Commit

Permalink
Rewrite get_or_create function NOT to bypass the ORM
Browse files Browse the repository at this point in the history
  • Loading branch information
nadzyah committed Aug 9, 2023
1 parent de32f0c commit 3406251
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,37 +42,6 @@ def upgrade() -> None:
),
{"source": source_data, "id": artefact.id},
)
# Create the trigger function
op.execute(
"""
CREATE OR REPLACE FUNCTION ensure_store_key_for_snap() RETURNS TRIGGER AS $$
BEGIN
IF (EXISTS (
SELECT 1
FROM stage s
JOIN family f ON s.family_id = f.id
WHERE s.id = NEW.stage_id AND f.name = 'snap'
) AND NOT NEW.source ? 'store') THEN
RAISE EXCEPTION
'The "store" key is required in source for artefacts with the snap family';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
"""
)

# Attach the trigger to the artefact table
op.execute(
"""
CREATE TRIGGER trigger_ensure_store_key_for_snap
BEFORE INSERT OR UPDATE
ON artefact
FOR EACH ROW
EXECUTE FUNCTION ensure_store_key_for_snap();
"""
)


def downgrade() -> None:
Expand All @@ -99,5 +68,3 @@ def downgrade() -> None:
),
{"source": source_data, "id": artefact.id},
)
op.execute("DROP TRIGGER IF EXISTS trigger_ensure_store_key_for_snap ON artefact")
op.execute("DROP FUNCTION IF EXISTS ensure_store_key_for_snap()")
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# Nadzeya Hutsko <[email protected]>


from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session

from test_observer.data_access.models import (
Expand Down Expand Up @@ -51,45 +51,48 @@ def start_test_execution(
.one()
)

artefact = get_or_create(
db,
Artefact,
filter_kwargs={
"name": request.name,
"version": request.version,
"source": request.source,
},
creation_kwargs={"stage_id": stage.id},
)
try:
artefact = get_or_create(
db,
Artefact,
filter_kwargs={
"name": request.name,
"version": request.version,
"source": request.source,
},
creation_kwargs={"stage_id": stage.id},
)

environment = get_or_create(
db,
Environment,
filter_kwargs={"name": request.environment, "architecture": request.arch},
)
environment = get_or_create(
db,
Environment,
filter_kwargs={"name": request.environment, "architecture": request.arch},
)

artefact_build = get_or_create(
db,
ArtefactBuild,
filter_kwargs={
"architecture": request.arch,
"revision": request.revision,
"artefact_id": artefact.id,
},
)
artefact_build = get_or_create(
db,
ArtefactBuild,
filter_kwargs={
"architecture": request.arch,
"revision": request.revision,
"artefact_id": artefact.id,
},
)

test_execution = get_or_create(
db,
TestExecution,
filter_kwargs={
"environment_id": environment.id,
"artefact_build_id": artefact_build.id,
},
creation_kwargs={
"status": TestExecutionStatus.IN_PROGRESS,
},
)
return {"id": test_execution.id}
test_execution = get_or_create(
db,
TestExecution,
filter_kwargs={
"environment_id": environment.id,
"artefact_build_id": artefact_build.id,
},
creation_kwargs={
"status": TestExecutionStatus.IN_PROGRESS,
},
)
return {"id": test_execution.id}
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.patch("/{id}")
Expand Down
30 changes: 14 additions & 16 deletions backend/test_observer/data_access/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from sqlalchemy import and_, func
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.orm import Session, joinedload

from sqlalchemy.exc import IntegrityError

from .models_enums import FamilyName
from .models import DataModel, Family, Stage, Artefact
Expand Down Expand Up @@ -115,18 +115,16 @@ def get_or_create(
"""
# Try to create first to avoid race conditions
creation_kwargs = creation_kwargs or {}
stmt = (
insert(model)
.values([{**filter_kwargs, **creation_kwargs}])
.on_conflict_do_nothing()
.returning(model)
)

result = db.execute(stmt).scalar_one_or_none()
db.commit()

if result is None:
# If the object already existed, we need to query it
result = db.query(model).filter_by(**filter_kwargs).one()

return result
instance = model(**filter_kwargs, **creation_kwargs)

try:
# Attempt to add and commit the new instance
db.add(instance)
db.commit()
return instance
except IntegrityError:
# In case of unique constraint violation, rollback the session
db.rollback()

# Query and return the existing instance
return db.query(model).filter_by(**filter_kwargs).one()

0 comments on commit 3406251

Please sign in to comment.