Skip to content

Commit

Permalink
wip: add attributes to base study
Browse files Browse the repository at this point in the history
  • Loading branch information
jdkent committed Aug 23, 2023
1 parent 6b63a63 commit f720eab
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 165 deletions.
29 changes: 29 additions & 0 deletions store/neurostore/models/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ class BaseStudy(BaseMixin, db.Model):
"Study", backref=backref("base_study"), cascade="all, delete-orphan"
)

def update_has_images_and_points(self):
# Calculate has_images and has_coordinates for the BaseStudy
self.has_images = any([version.has_images for version in self.versions])
self.has_coordinates = any(
[version.has_coordinates for version in self.versions]
)

__table_args__ = (
db.CheckConstraint(level.in_(["group", "meta"])),
db.UniqueConstraint("doi", "pmid", name="doi_pmid"),
Expand Down Expand Up @@ -185,6 +192,14 @@ class Study(BaseMixin, db.Model):
cascade="all, delete, delete-orphan",
)

@property
def has_images(self):
return any([analysis.has_images for analysis in self.analyses])

@property
def has_coordinates(self):
return any([analysis.has_coordinates for analysis in self.analyses])

__table_args__ = (
db.CheckConstraint(level.in_(["group", "meta"])),
sa.Index("ix_study___ts_vector__", __ts_vector__, postgresql_using="gin"),
Expand Down Expand Up @@ -246,6 +261,20 @@ class Analysis(BaseMixin, db.Model):
cascade="all, delete-orphan",
)

@property
def has_images(self):
deleted_images = {
image for image in db.session.deleted if isinstance(image, Image)
}
return bool(set(self.images) - deleted_images)

@property
def has_coordinates(self):
deleted_points = {
point for point in db.session.deleted if isinstance(point, Point)
}
return bool(set(self.points) - deleted_points)


class Condition(BaseMixin, db.Model):
__tablename__ = "conditions"
Expand Down
75 changes: 40 additions & 35 deletions store/neurostore/models/event_listeners.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from sqlalchemy.exc import SQLAlchemyError
from flask_sqlalchemy.session import Session
from sqlalchemy import event
from .data import (
AnnotationAnalysis,
Annotation,
Studyset,
BaseStudy,
Study,
Analysis,
Point,
Expand Down Expand Up @@ -130,38 +132,41 @@ def add_annotation_analyses_study(study, analyses, collection_adapter):
event.listen(Study.analyses, "bulk_replace", add_annotation_analyses_study)


# Define an event listener to update Base-Study flags
# @event.listens_for(Analysis.points, 'append')
# @event.listens_for(Analysis.points, 'remove')
# @event.listens_for(Analysis.images, 'append')
# @event.listens_for(Analysis.images, 'remove')
# def update_base_study_flags(target, value, initiator):
# base_study = getattr(getattr(target, 'study', None), 'base_study', None)
# updated = False
# if base_study is not None:
# base_study.has_coordinates = isinstance(value, Point) or any(
# analysis.points for study in base_study.versions for analysis in study.analyses
# )
# base_study.has_images = isinstance(value, Image) or any(
# analysis.images for study in base_study.versions for analysis in study.analyses
# )
# db.session.add(base_study)
# updated = True

# return updated


# @event.listens_for(db.session, 'after_flush')
# def update_base_study_flags_item_delete(session, flush_context):
# any_updates = False
# for obj in session.deleted:
# if isinstance(obj, (Point, Image)):
# target = obj.analysis_id
# value = obj
# initiator = "DELETE"
# res = update_base_study_flags(target, value, initiator)
# if not any_updates and res:
# any_updates = True

# if any_updates:
# db.session.commit()
@event.listens_for(Session, "before_flush")
def before_flush(session, flush_context, instances):
"""Update the base study attributes has_coordinates and has_images"""

changed_objects = set(session.dirty) | set(session.new) | set(session.deleted)

# Find unique BaseStudies affected by the changes
def get_nested_attr(obj, nested_attr):
attrs = nested_attr.split(".")
result = obj
for attr in attrs:
result = getattr(result, attr, None)
if result is None:
return
return result

def get_base_study(obj):
base_study = None
if isinstance(obj, (Point, Image)):
base_study = get_nested_attr(obj, "analysis.study.base_study")
if isinstance(obj, Analysis):
base_study = get_nested_attr(obj, "study.base_study")
if isinstance(obj, Study):
base_study = obj.base_study
if isinstance(obj, BaseStudy):
base_study = obj

return base_study

unique_base_studies = {
base_study
for base_study in [get_base_study(obj) for obj in changed_objects]
if base_study is not None
}

# Update the has_images and has_points for each unique BaseStudy
for base_study in unique_base_studies:
base_study.update_has_images_and_points()
17 changes: 13 additions & 4 deletions store/neurostore/resources/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,16 @@ class BaseView(MethodView):
_linked = {}
_composite_key = {}

def custom_record_update(record):
"""Custom processing of a record (defined in specific classes)"""
def pre_nested_record_update(record):
"""
Processing of a record before updating nested components (defined in specific classes).
"""
return record

def post_nested_record_update(record):
"""
Processing of a record after updating nested components (defined in specific classes).
"""
return record

@classmethod
Expand Down Expand Up @@ -159,7 +167,7 @@ def update_or_create(cls, data, id=None, commit=True):
print(k)
raise AttributeError

record = cls.custom_record_update(record)
record = cls.pre_nested_record_update(record)

to_commit.append(record)

Expand All @@ -180,6 +188,7 @@ def update_or_create(cls, data, id=None, commit=True):
setattr(record, field, nested)

# add other custom update after the nested attributes are handled...
record = cls.post_nested_record_update(record)
if commit:
db.session.add_all(to_commit)
try:
Expand Down Expand Up @@ -336,7 +345,7 @@ def delete(self, id):
def insert_data(self, id, data):
return data

def post_delete(record):
def post_delete(self, record):
pass


Expand Down
Loading

0 comments on commit f720eab

Please sign in to comment.