<s> from datetime import datetime <EOL> from jsonmapping import SchemaVisitor <EOL> from jsonmapping . value import convert_value <EOL> from aleph . core import db <EOL> from aleph . util import find_subclasses <EOL> from aleph . model . common import DatedModel <EOL> from aleph . model . validation import resolver , validate <EOL> class SchemaModel ( object ) : <EOL> """<STR_LIT>""" <EOL> _schema = None <EOL> _schema_recurse = False <EOL> @ property <EOL> def schema_data ( self ) : <EOL> if self . _schema is None : <EOL> raise NotImplementedError ( '<STR_LIT>' % self ) <EOL> _ , schema = resolver . resolve ( self . _schema ) <EOL> return schema <EOL> @ classmethod <EOL> def get_schema_class ( cls , schema ) : <EOL> for subcls in find_subclasses ( cls ) : <EOL> if subcls . _schema == schema : <EOL> return subcls <EOL> return cls <EOL> @ property <EOL> def schema_visitor ( self ) : <EOL> return SchemaVisitor ( self . schema_data , resolver ) <EOL> def schema_update ( self , data , merge = False ) : <EOL> """<STR_LIT>""" <EOL> validate ( data , self . _schema ) <EOL> db . session . add ( self ) <EOL> for prop in self . schema_visitor . properties : <EOL> if prop . name == '<STR_LIT:id>' : <EOL> continue <EOL> if prop . name not in data : <EOL> continue <EOL> prop_data = data [ prop . name ] <EOL> if prop . is_value : <EOL> self . _schema_update_value ( prop , prop_data ) <EOL> elif prop . is_object and self . _schema_recurse : <EOL> self . _schema_update_object ( prop , prop_data ) <EOL> elif prop . is_array and self . _schema_recurse : <EOL> self . _schema_update_array ( prop , prop_data , merge = merge ) <EOL> if isinstance ( self , DatedModel ) : <EOL> self . updated_at = datetime . utcnow ( ) <EOL> def _schema_update_value ( self , prop , data ) : <EOL> value = convert_value ( prop , data ) <EOL> setattr ( self , prop . name , value ) <EOL> def _get_property_by_column ( self , column ) : <EOL> """<STR_LIT>""" <EOL> for prop in self . __mapper__ . iterate_properties : <EOL> if hasattr ( prop , '<STR_LIT>' ) : <EOL> if column in prop . columns : <EOL> return prop . key <EOL> def _get_associations ( self , obj , rel ) : <EOL> """<STR_LIT>""" <EOL> for local_col , remote_col in rel . prop . local_remote_pairs : <EOL> local = self . _get_property_by_column ( local_col ) <EOL> remote = obj . _get_property_by_column ( remote_col ) <EOL> yield local , remote <EOL> def _get_relationship ( self , name , direction ) : <EOL> """<STR_LIT>""" <EOL> rel = getattr ( type ( self ) , name ) <EOL> if rel . prop . direction . name != direction : <EOL> raise TypeError ( "<STR_LIT>" % direction ) <EOL> if not issubclass ( rel . mapper . class_ , SchemaModel ) : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> return rel <EOL> def _schema_update_object ( self , prop , data ) : <EOL> """<STR_LIT>""" <EOL> rel = self . _get_relationship ( prop . name , '<STR_LIT>' ) <EOL> obj = getattr ( self , prop . name ) <EOL> if obj is None : <EOL> if data is None : <EOL> return <EOL> obj = rel . mapper . class_ ( ) <EOL> if data is not None : <EOL> obj . update ( data ) <EOL> db . session . flush ( ) <EOL> else : <EOL> obj . delete ( ) <EOL> for local , remote in self . _get_associations ( obj , rel ) : <EOL> value = getattr ( obj , remote ) <EOL> if data is None : <EOL> value = None <EOL> setattr ( self , local , value ) <EOL> return obj <EOL> def _schema_update_array ( self , prop , data , merge = False ) : <EOL> """<STR_LIT>""" <EOL> rel = self . _get_relationship ( prop . name , '<STR_LIT>' ) <EOL> cls = rel . mapper . class_ <EOL> existing = list ( getattr ( self , prop . name ) ) <EOL> ids = set ( ) <EOL> for item in data or [ ] : <EOL> if item is None : <EOL> continue <EOL> obj = cls ( ) <EOL> for cand in existing : <EOL> if item . get ( '<STR_LIT:id>' ) and cand . id == item . get ( '<STR_LIT:id>' ) : <EOL> obj = cand <EOL> elif merge and cand . _merge_compare ( item ) : <EOL> obj = cand <EOL> obj . update ( item ) <EOL> ids . add ( obj . id ) <EOL> existing . append ( obj ) <EOL> for obj in existing : <EOL> if obj . id not in ids and not merge : <EOL> obj . delete ( ) <EOL> continue <EOL> for local , remote in self . _get_associations ( obj , rel ) : <EOL> setattr ( obj , remote , getattr ( self , local ) ) <EOL> setattr ( self , prop . name , existing ) <EOL> return existing <EOL> def _merge_compare ( self , data ) : <EOL> for prop in self . schema_visitor . properties : <EOL> if not prop . is_value : <EOL> continue <EOL> if prop . name == '<STR_LIT:id>' : <EOL> continue <EOL> value = getattr ( self , prop . name ) <EOL> if value is None : <EOL> continue <EOL> if value != data . get ( prop . name ) : <EOL> return False <EOL> return True <EOL> def delete ( self ) : <EOL> for prop in self . schema_visitor . properties : <EOL> if prop . is_value : <EOL> continue <EOL> if prop . is_array and prop . items . inline : <EOL> for item in getattr ( self , prop . name ) : <EOL> item . delete ( ) <EOL> if prop . is_object and prop . inline : <EOL> value = getattr ( self , prop . name ) <EOL> if value is not None : <EOL> value . delete ( ) <EOL> super ( SchemaModel , self ) . delete ( ) <EOL> def to_dict ( self ) : <EOL> parent = super ( SchemaModel , self ) <EOL> data = parent . to_dict ( ) if hasattr ( parent , '<STR_LIT>' ) else { } <EOL> data [ '<STR_LIT>' ] = self . _schema <EOL> for prop in self . schema_visitor . properties : <EOL> if prop . is_value or prop . inline : <EOL> value = getattr ( self , prop . name ) <EOL> if value is not None : <EOL> data [ prop . name ] = value <EOL> if prop . is_array and prop . items . inline : <EOL> value = getattr ( self , prop . name ) <EOL> data [ prop . name ] = list ( value ) <EOL> return data </s>
