Skip to content

Commit 25830dd

Browse files
authored
fix sqlalchemy events (hopefully) (#207)
* remove unwanted orm model init override * fix: event listener conn/session usage * fix: event listener conn/session usage MAYBE
1 parent b7275b9 commit 25830dd

File tree

1 file changed

+58
-37
lines changed

1 file changed

+58
-37
lines changed

colandr/models.py

Lines changed: 58 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -746,12 +746,6 @@ class DataExtraction(db.Model):
746746
lazy="select",
747747
)
748748

749-
# TODO: remove this custom init when able to test data extraction workflows
750-
def __init__(self, study_id, review_id, extracted_items=None):
751-
self.study_id = study_id
752-
self.review_id = review_id
753-
self.extracted_items = extracted_items
754-
755749
def __repr__(self):
756750
return f"<DataExtraction(id={self.id}, study_id={self.study_id})>"
757751

@@ -768,19 +762,19 @@ def __repr__(self):
768762

769763

770764
@sa_event.listens_for(Review, "after_insert")
771-
def insert_review_plan(mapper, connection, target):
765+
def insert_review_plan(mapper, connection: sa.Connection, target):
772766
review_plan = ReviewPlan(id=target.id)
773767
connection.execute(sa.insert(ReviewPlan).values(id=target.id))
774768
LOGGER.info("inserted %s and %s", target, review_plan)
775769

776770

777771
@sa_event.listens_for(Review, "after_update")
778-
def update_study_num_reviewers(mapper, connection, target):
772+
def update_study_num_reviewers(mapper, connection: sa.Connection, target):
779773
review_id = target.id
780774
study_id_updates = collections.defaultdict(dict)
781775
# randomly assign num citation reviewers for unscreened studies
782776
citation_reviewer_num_pcts = target.citation_reviewer_num_pcts
783-
study_ids: list[int] = (
777+
study_ids: list[int] = list(
784778
connection.execute(
785779
sa.select(Study.id).filter_by(
786780
review_id=review_id, citation_status="not_screened"
@@ -799,7 +793,7 @@ def update_study_num_reviewers(mapper, connection, target):
799793
study_id_updates[id_]["num_citation_reviewers"] = num_citation_reviewers
800794
# randomly assign num fulltext reviewers for unscreened studies
801795
fulltext_reviewer_num_pcts = target.fulltext_reviewer_num_pcts
802-
study_ids: list[int] = (
796+
study_ids: list[int] = list(
803797
connection.execute(
804798
sa.select(Study.id).filter_by(
805799
review_id=review_id, fulltext_status="not_screened"
@@ -818,11 +812,13 @@ def update_study_num_reviewers(mapper, connection, target):
818812
study_id_updates[id_]["num_fulltext_reviewers"] = num_fulltext_reviewers
819813
# munge updates into form required for sqlalchemy bulk update, submit all together
820814
if study_id_updates:
815+
session = sa_orm.object_session(target)
816+
assert session is not None # type guard
821817
studies_to_update = [
822818
{"id": id_} | num_reviewers_updated
823819
for id_, num_reviewers_updated in study_id_updates.items()
824820
]
825-
_ = db.session.execute(sa.update(Study), studies_to_update)
821+
_ = session.execute(sa.update(Study), studies_to_update)
826822
LOGGER.info(
827823
"updated num reviewer counts on %s studies for %s",
828824
len(studies_to_update),
@@ -833,18 +829,21 @@ def update_study_num_reviewers(mapper, connection, target):
833829
@sa_event.listens_for(Screening, "after_insert")
834830
@sa_event.listens_for(Screening, "after_delete")
835831
@sa_event.listens_for(Screening, "after_update")
836-
def update_study_status(mapper, connection, target):
832+
def update_study_status(mapper, connection: sa.Connection, target):
837833
review_id = target.review_id
838834
study_id = target.study_id
839835
study = target.study
840836
# TODO(burton): you added this so that conftest populate_db func would work
841837
# for reasons unknown, the target here didn't have a loaded citation object
842838
# but this is _probably_ a bad thing, and you should find a way to fix it
843839
if study is None:
844-
study = db.session.execute(
845-
sa.select(Study).filter_by(id=study_id)
846-
).scalar_one_or_none()
847-
assert isinstance(study, Study) # type guard
840+
study = connection.execute(
841+
sa.select(
842+
Study.num_citation_reviewers,
843+
Study.num_fulltext_reviewers,
844+
).filter_by(id=study_id)
845+
).one_or_none()
846+
assert study is not None # type guard
848847
# prep stage-specific variables
849848
stage = target.stage
850849
if stage == "citation":
@@ -855,12 +854,13 @@ def update_study_status(mapper, connection, target):
855854
study_status_col_str = "fulltext_status"
856855
# compute the new status, and update the study accordingly
857856
status = utils.assign_status(
858-
[
859-
screening.status
860-
for screening in db.session.execute(
861-
sa.select(Screening).filter_by(study_id=study_id, stage=stage)
862-
).scalars()
863-
],
857+
(
858+
connection.execute(
859+
sa.select(Screening.status).filter_by(study_id=study_id, stage=stage)
860+
)
861+
.scalars()
862+
.all()
863+
),
864864
num_reviewers,
865865
)
866866
connection.execute(
@@ -874,19 +874,30 @@ def update_study_status(mapper, connection, target):
874874
# get rid of any contrary fulltext screenings
875875
if status != "included":
876876
connection.execute(
877-
sa.delete(Screening)
878-
.where(Screening.study_id == study_id)
879-
.where(Screening.stage == "fulltext")
877+
sa.delete(Screening).where(
878+
Screening.study_id == study_id,
879+
Screening.stage == "fulltext",
880+
)
880881
)
881882
LOGGER.info(
882883
"deleted all <Screening(study_id=%s, stage='fulltext')>", study_id
883884
)
884-
review = (
885-
db.session.execute(sa.select(Review).filter_by(id=review_id))
886-
.scalars()
887-
.one()
888-
)
889-
status_counts = review.num_citations_by_status(["included", "excluded"])
885+
# review = (
886+
# db.session.execute(sa.select(Review).filter_by(id=review_id))
887+
# .scalars()
888+
# .one()
889+
# )
890+
# status_counts = review.num_citations_by_status(["included", "excluded"])
891+
status_counts = {"included": 0, "excluded": 0}
892+
status_counts |= {
893+
row.citation_status: row.count
894+
for row in connection.execute(
895+
sa.select(Study.citation_status, sa.func.count())
896+
.filter_by(review_id=review_id, dedupe_status="not_duplicate")
897+
.where(Study.citation_status.in_(["included", "excluded"]))
898+
.group_by(Study.citation_status)
899+
)
900+
}
890901
n_included = status_counts.get("included", 0)
891902
n_excluded = status_counts.get("excluded", 0)
892903
# if at least 25 citations have been included AND excluded
@@ -922,12 +933,22 @@ def update_study_status(mapper, connection, target):
922933
LOGGER.info("deleted <DataExtraction(study_id=%s)>", study_id)
923934
data_extraction_inserted_or_deleted = True
924935
if data_extraction_inserted_or_deleted is True:
925-
review = (
926-
db.session.execute(sa.select(Review).filter_by(id=review_id))
927-
.scalars()
928-
.one()
929-
)
930-
status_counts = review.num_fulltexts_by_status(["included", "excluded"])
936+
# review = (
937+
# db.session.execute(sa.select(Review).filter_by(id=review_id))
938+
# .scalars()
939+
# .one()
940+
# )
941+
# status_counts = review.num_fulltexts_by_status(["included", "excluded"])
942+
status_counts = {"included": 0, "excluded": 0}
943+
status_counts |= {
944+
row.fulltext_status: row.count
945+
for row in connection.execute(
946+
sa.select(Study.fulltext_status, sa.func.count())
947+
.filter_by(review_id=review_id, dedupe_status="not_duplicate")
948+
.where(Study.fulltext_status.in_(["included", "excluded"]))
949+
.group_by(Study.fulltext_status)
950+
)
951+
}
931952
n_incl_excl = status_counts.get("included", 0) + status_counts.get(
932953
"excluded", 0
933954
)

0 commit comments

Comments
 (0)