entity.py
changeset 8493 25da1e5c7c50
parent 8483 4ba11607d84a
child 8494 1527b012802f
equal deleted inserted replaced
8492:8ec7cc28b501 8493:25da1e5c7c50
   453 
   453 
   454     @classmethod
   454     @classmethod
   455     def _cw_build_entity_query(cls, kwargs):
   455     def _cw_build_entity_query(cls, kwargs):
   456         relations = []
   456         relations = []
   457         restrictions = set()
   457         restrictions = set()
   458         pending_relations = []
   458         pendingrels = []
   459         eschema = cls.e_schema
   459         eschema = cls.e_schema
   460         qargs = {}
   460         qargs = {}
   461         attrcache = {}
   461         attrcache = {}
   462         for attr, value in kwargs.items():
   462         for attr, value in kwargs.items():
   463             if attr.startswith('reverse_'):
   463             if attr.startswith('reverse_'):
   472                     continue # avoid crash with empty IN clause
   472                     continue # avoid crash with empty IN clause
   473                 elif len(value) == 1:
   473                 elif len(value) == 1:
   474                     value = iter(value).next()
   474                     value = iter(value).next()
   475                 else:
   475                 else:
   476                     # prepare IN clause
   476                     # prepare IN clause
   477                     pending_relations.append( (attr, role, value) )
   477                     pendingrels.append( (attr, role, value) )
   478                     continue
   478                     continue
   479             if rschema.final: # attribute
   479             if rschema.final: # attribute
   480                 relations.append('X %s %%(%s)s' % (attr, attr))
   480                 relations.append('X %s %%(%s)s' % (attr, attr))
   481                 attrcache[attr] = value
   481                 attrcache[attr] = value
   482             elif value is None:
   482             elif value is None:
   483                 pending_relations.append( (attr, role, value) )
   483                 pendingrels.append( (attr, role, value) )
   484             else:
   484             else:
   485                 rvar = attr.upper()
   485                 rvar = attr.upper()
   486                 if role == 'object':
   486                 if role == 'object':
   487                     relations.append('%s %s X' % (rvar, attr))
   487                     relations.append('%s %s X' % (rvar, attr))
   488                 else:
   488                 else:
   496         rql = u''
   496         rql = u''
   497         if relations:
   497         if relations:
   498             rql += ', '.join(relations)
   498             rql += ', '.join(relations)
   499         if restrictions:
   499         if restrictions:
   500             rql += ' WHERE %s' % ', '.join(restrictions)
   500             rql += ' WHERE %s' % ', '.join(restrictions)
   501         return rql, qargs, pending_relations, attrcache
   501         return rql, qargs, pendingrels, attrcache
   502 
   502 
   503     @classmethod
   503     @classmethod
   504     def _cw_handle_pending_relations(cls, eid, pending_relations, execute):
   504     def _cw_handle_pending_relations(cls, eid, pendingrels, execute):
   505         for attr, role, values in pending_relations:
   505         for attr, role, values in pendingrels:
   506             if role == 'object':
   506             if role == 'object':
   507                 restr = 'Y %s X' % attr
   507                 restr = 'Y %s X' % attr
   508             else:
   508             else:
   509                 restr = 'X %s Y' % attr
   509                 restr = 'X %s Y' % attr
   510             if values is None:
   510             if values is None:
   528 
   528 
   529         You can also set relations where the entity has 'object' role by
   529         You can also set relations where the entity has 'object' role by
   530         prefixing the relation name by 'reverse_'. Also, relation values may be
   530         prefixing the relation name by 'reverse_'. Also, relation values may be
   531         an entity or eid, a list of entities or eids.
   531         an entity or eid, a list of entities or eids.
   532         """
   532         """
   533         rql, qargs, pending_relations, attrcache = cls._cw_build_entity_query(kwargs)
   533         rql, qargs, pendingrels, attrcache = cls._cw_build_entity_query(kwargs)
   534         if rql:
   534         if rql:
   535             rql = 'INSERT %s X: %s' % (cls.__regid__, rql)
   535             rql = 'INSERT %s X: %s' % (cls.__regid__, rql)
   536         else:
   536         else:
   537             rql = 'INSERT %s X' % (cls.__regid__)
   537             rql = 'INSERT %s X' % (cls.__regid__)
   538         created = execute(rql, qargs).get_entity(0, 0)
   538         created = execute(rql, qargs).get_entity(0, 0)
       
   539         created._cw_update_attr_cache(attrcache)
   539         created.cw_attr_cache.update(attrcache)
   540         created.cw_attr_cache.update(attrcache)
   540         cls._cw_handle_pending_relations(created.eid, pending_relations, execute)
   541         cls._cw_handle_pending_relations(created.eid, pendingrels, execute)
   541         return created
   542         return created
   542 
   543 
   543     def __init__(self, req, rset=None, row=None, col=0):
   544     def __init__(self, req, rset=None, row=None, col=0):
   544         AppObject.__init__(self, req, rset=rset, row=row, col=col)
   545         AppObject.__init__(self, req, rset=rset, row=row, col=col)
   545         self._cw_related_cache = {}
   546         self._cw_related_cache = {}
   554         return '<Entity %s %s %s at %s>' % (
   555         return '<Entity %s %s %s at %s>' % (
   555             self.e_schema, self.eid, self.cw_attr_cache.keys(), id(self))
   556             self.e_schema, self.eid, self.cw_attr_cache.keys(), id(self))
   556 
   557 
   557     def __cmp__(self, other):
   558     def __cmp__(self, other):
   558         raise NotImplementedError('comparison not implemented for %s' % self.__class__)
   559         raise NotImplementedError('comparison not implemented for %s' % self.__class__)
       
   560 
       
   561     def _cw_update_attr_cache(self, attrcache):
       
   562         for key in self._cw.get_shared_data('%s.dont-cache-attrs' % self.eid,
       
   563                                             default=(), txdata=True, pop=True):
       
   564             attrcache.pop(key, None)
       
   565         self.cw_attr_cache.update(attrcache)
       
   566 
       
   567     def _cw_dont_cache_attribute(self, attr):
       
   568         """repository side method called when some attribute have been
       
   569         transformed by a hook, hence original value should not be cached by
       
   570         client
       
   571         """
       
   572         self._cw.transaction_data.setdefault('%s.dont-cache-attrs' % self.eid, set()).add(attr)
   559 
   573 
   560     def __json_encode__(self):
   574     def __json_encode__(self):
   561         """custom json dumps hook to dump the entity's eid
   575         """custom json dumps hook to dump the entity's eid
   562         which is not part of dict structure itself
   576         which is not part of dict structure itself
   563         """
   577         """
  1252         """
  1266         """
  1253         _check_cw_unsafe(kwargs)
  1267         _check_cw_unsafe(kwargs)
  1254         assert kwargs
  1268         assert kwargs
  1255         assert self.cw_is_saved(), "should not call set_attributes while entity "\
  1269         assert self.cw_is_saved(), "should not call set_attributes while entity "\
  1256                "hasn't been saved yet"
  1270                "hasn't been saved yet"
  1257         rql, qargs, pending_relations, attrcache = self._cw_build_entity_query(kwargs)
  1271         rql, qargs, pendingrels, attrcache = self._cw_build_entity_query(kwargs)
  1258         if rql:
  1272         if rql:
  1259             rql = 'SET ' + rql
  1273             rql = 'SET ' + rql
  1260             qargs['x'] = self.eid
  1274             qargs['x'] = self.eid
  1261             if ' WHERE ' in rql:
  1275             if ' WHERE ' in rql:
  1262                 rql += ', X eid %(x)s'
  1276                 rql += ', X eid %(x)s'
  1264                 rql += ' WHERE X eid %(x)s'
  1278                 rql += ' WHERE X eid %(x)s'
  1265             self._cw.execute(rql, qargs)
  1279             self._cw.execute(rql, qargs)
  1266         # update current local object _after_ the rql query to avoid
  1280         # update current local object _after_ the rql query to avoid
  1267         # interferences between the query execution itself and the cw_edited /
  1281         # interferences between the query execution itself and the cw_edited /
  1268         # skip_security machinery
  1282         # skip_security machinery
  1269         self.cw_attr_cache.update(attrcache)
  1283         self._cw_update_attr_cache(attrcache)
  1270         self._cw_handle_pending_relations(self.eid, pending_relations, self._cw.execute)
  1284         self._cw_handle_pending_relations(self.eid, pendingrels, self._cw.execute)
  1271         # XXX update relation cache
  1285         # XXX update relation cache
  1272 
  1286 
  1273     def cw_delete(self, **kwargs):
  1287     def cw_delete(self, **kwargs):
  1274         assert self.has_eid(), self.eid
  1288         assert self.has_eid(), self.eid
  1275         self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema,
  1289         self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema,