1+
2+ from collections import ChainMap
13import pathlib
4+ from operator import itemgetter
25
36import connexion
47from flask import abort , request , jsonify , current_app
1316
1417from ..database import db
1518from ..models .analysis import ( # noqa E401
19+ Condition ,
20+ SpecificationCondition ,
1621 Studyset ,
1722 Annotation ,
1823 MetaAnalysis ,
2934from ..models .auth import User
3035
3136from ..schemas import ( # noqa E401
37+ ConditionSchema ,
38+ SpecificationConditionSchema ,
3239 MetaAnalysisSchema ,
3340 AnnotationSchema ,
3441 StudysetSchema ,
@@ -87,6 +94,7 @@ class ClassView(cls):
8794class BaseView (MethodView ):
8895 _model = None
8996 _nested = {}
97+ _attribute_name = None
9098
9199 @classmethod
92100 def _external_request (cls , data , record , id ):
@@ -110,6 +118,8 @@ def update_or_create(cls, data, id=None, commit=True):
110118
111119 only_ids = set (data .keys ()) - set (["id" ]) == set ()
112120
121+ if cls ._model is Condition :
122+ record = cls ._model .query .filter_by (name = data .get ('name' )).first () or cls ._model ()
113123 if id is None :
114124 record = cls ._model ()
115125 record .user = current_user
@@ -137,29 +147,44 @@ def update_or_create(cls, data, id=None, commit=True):
137147 # check if external request updated the data already
138148 committed = cls ._external_request (data , record , id )
139149
150+ # get nested attributes
151+ nested_keys = [
152+ item for key in cls ._nested .keys ()
153+ for item in (key if isinstance (key , tuple ) else (key ,))
154+ ]
155+
140156 # Update all non-nested attributes
141157 if not committed :
142158 for k , v in data .items ():
143- if k not in cls . _nested and k not in ["id" , "user" ]:
159+ if k not in nested_keys and k not in ["id" , "user" ]:
144160 setattr (record , k , v )
145161
146162 to_commit .append (record )
147163
148164 # Update nested attributes recursively
149165 for field , res_name in cls ._nested .items ():
166+ field = (field ,) if not isinstance (field , tuple ) else field
167+ try :
168+ rec_data = itemgetter (* field )(data )
169+ except KeyError :
170+ rec_data = None
171+
150172 ResCls = globals ()[res_name ]
151- if data .get (field ) is not None :
152- if isinstance (data .get (field ), list ):
173+ if rec_data is not None :
174+ if isinstance (rec_data , tuple ):
175+ rec_data = [dict (ChainMap (* rc )) for rc in zip (* rec_data )]
176+ if isinstance (rec_data , list ):
153177 nested = [
154178 ResCls .update_or_create (rec , commit = False )
155- for rec in data . get ( field )
179+ for rec in rec_data
156180 ]
157181 to_commit .extend (nested )
158182 else :
159- nested = ResCls .update_or_create (data . get ( field ) , commit = False )
183+ nested = ResCls .update_or_create (rec_data , commit = False )
160184 to_commit .append (nested )
161-
162- setattr (record , field , nested )
185+ update_field = field if len (field ) == 1 else (cls ._attribute_name ,)
186+ for f in update_field :
187+ setattr (record , f , nested )
163188
164189 if commit :
165190 db .session .add_all (to_commit )
@@ -374,7 +399,10 @@ class StudysetsView(ObjectView, ListView):
374399
375400@view_maker
376401class SpecificationsView (ObjectView , ListView ):
377- pass
402+ _nested = {
403+ ("conditions" , "weights" ): "SpecificationConditionsResource" ,
404+ }
405+ _attribute_name = "specification_conditions"
378406
379407
380408@view_maker
@@ -387,6 +415,16 @@ class AnnotationReferencesResource(ObjectView):
387415 pass
388416
389417
418+ @view_maker
419+ class ConditionsResource (ObjectView ):
420+ pass
421+
422+
423+ @view_maker
424+ class SpecificationConditionsResource (ObjectView ):
425+ _nested = {"condition" : "ConditionsResource" }
426+
427+
390428@view_maker
391429class MetaAnalysisResultsView (ObjectView , ListView ):
392430 _nested = {
0 commit comments