512 |
512 |
513 You can also set relations where the entity has 'object' role by |
513 You can also set relations where the entity has 'object' role by |
514 prefixing the relation name by 'reverse_'. Also, relation values may be |
514 prefixing the relation name by 'reverse_'. Also, relation values may be |
515 an entity or eid, a list of entities or eids. |
515 an entity or eid, a list of entities or eids. |
516 """ |
516 """ |
517 rql, qargs, pendingrels, attrcache = cls._cw_build_entity_query(kwargs) |
517 rql, qargs, pendingrels, _attrcache = cls._cw_build_entity_query(kwargs) |
518 if rql: |
518 if rql: |
519 rql = 'INSERT %s X: %s' % (cls.__regid__, rql) |
519 rql = 'INSERT %s X: %s' % (cls.__regid__, rql) |
520 else: |
520 else: |
521 rql = 'INSERT %s X' % (cls.__regid__) |
521 rql = 'INSERT %s X' % (cls.__regid__) |
522 try: |
522 try: |
523 created = execute(rql, qargs).get_entity(0, 0) |
523 created = execute(rql, qargs).get_entity(0, 0) |
524 except IndexError: |
524 except IndexError: |
525 raise Exception('could not create a %r with %r (%r)' % |
525 raise Exception('could not create a %r with %r (%r)' % |
526 (cls.__regid__, rql, qargs)) |
526 (cls.__regid__, rql, qargs)) |
527 created._cw_update_attr_cache(attrcache) |
|
528 cls._cw_handle_pending_relations(created.eid, pendingrels, execute) |
527 cls._cw_handle_pending_relations(created.eid, pendingrels, execute) |
529 return created |
528 return created |
530 |
529 |
531 def __init__(self, req, rset=None, row=None, col=0): |
530 def __init__(self, req, rset=None, row=None, col=0): |
532 AppObject.__init__(self, req, rset=rset, row=row, col=col) |
531 AppObject.__init__(self, req, rset=rset, row=row, col=col) |
554 if isinstance(self.eid, (int, long)): |
553 if isinstance(self.eid, (int, long)): |
555 return self.eid |
554 return self.eid |
556 return super(Entity, self).__hash__() |
555 return super(Entity, self).__hash__() |
557 |
556 |
558 def _cw_update_attr_cache(self, attrcache): |
557 def _cw_update_attr_cache(self, attrcache): |
559 # if context is a repository session, don't consider dont-cache-attrs as |
|
560 # the instance already holds modified values and loosing them could |
|
561 # introduce severe problems |
|
562 trdata = self._cw.transaction_data |
558 trdata = self._cw.transaction_data |
563 uncached_attrs = trdata.get('%s.storage-special-process-attrs' % self.eid, set()) |
559 uncached_attrs = trdata.get('%s.storage-special-process-attrs' % self.eid, set()) |
564 if self._cw.is_request: |
|
565 uncached_attrs.update(trdata.get('%s.dont-cache-attrs' % self.eid, set())) |
|
566 for attr in uncached_attrs: |
560 for attr in uncached_attrs: |
567 attrcache.pop(attr, None) |
561 attrcache.pop(attr, None) |
568 self.cw_attr_cache.pop(attr, None) |
562 self.cw_attr_cache.pop(attr, None) |
569 self.cw_attr_cache.update(attrcache) |
563 self.cw_attr_cache.update(attrcache) |
570 |
564 |
571 def _cw_dont_cache_attribute(self, attr, repo_side=False): |
565 def _cw_dont_cache_attribute(self, attr, repo_side=False): |
572 """Repository side method called when some attribute has been |
566 """Called when some attribute has been transformed by a *storage*, |
573 transformed by a hook, hence original value should not be cached by |
567 hence the original value should not be cached **by anyone**. |
574 the client. |
|
575 |
|
576 If repo_side is True, this means that the attribute has been |
|
577 transformed by a *storage*, hence the original value should |
|
578 not be cached **by anyone**. |
|
579 |
|
580 This only applies to a storage special case where the value |
|
581 specified in creation or update is **not** the value that will |
|
582 be transparently exposed later. |
|
583 |
568 |
584 For example we have a special "fs_importing" mode in BFSS |
569 For example we have a special "fs_importing" mode in BFSS |
585 where a file path is given as attribute value and stored as is |
570 where a file path is given as attribute value and stored as is |
586 in the data base. Later access to the attribute will provide |
571 in the data base. Later access to the attribute will provide |
587 the content of the file at the specified path. We do not want |
572 the content of the file at the specified path. We do not want |
588 the "filepath" value to be cached. |
573 the "filepath" value to be cached. |
589 """ |
574 |
590 self._cw.transaction_data.setdefault('%s.dont-cache-attrs' % self.eid, set()).add(attr) |
575 """ |
591 if repo_side: |
576 trdata = self._cw.transaction_data |
592 trdata = self._cw.transaction_data |
577 trdata.setdefault('%s.storage-special-process-attrs' % self.eid, set()).add(attr) |
593 trdata.setdefault('%s.storage-special-process-attrs' % self.eid, set()).add(attr) |
|
594 |
578 |
595 def __json_encode__(self): |
579 def __json_encode__(self): |
596 """custom json dumps hook to dump the entity's eid |
580 """custom json dumps hook to dump the entity's eid |
597 which is not part of dict structure itself |
581 which is not part of dict structure itself |
598 """ |
582 """ |
834 execute(rql, {'x': self.eid, 'y': ceid}) |
818 execute(rql, {'x': self.eid, 'y': ceid}) |
835 self.cw_clear_relation_cache(rschema.type, 'object') |
819 self.cw_clear_relation_cache(rschema.type, 'object') |
836 |
820 |
837 # data fetching methods ################################################### |
821 # data fetching methods ################################################### |
838 |
822 |
839 @cached |
|
840 def as_rset(self): # XXX .cw_as_rset |
823 def as_rset(self): # XXX .cw_as_rset |
841 """returns a resultset containing `self` information""" |
824 """returns a resultset containing `self` information""" |
842 rset = ResultSet([(self.eid,)], 'Any X WHERE X eid %(x)s', |
825 rset = ResultSet([(self.eid,)], 'Any X WHERE X eid %(x)s', |
843 {'x': self.eid}, [(self.cw_etype,)]) |
826 {'x': self.eid}, [(self.cw_etype,)]) |
844 rset.req = self._cw |
827 rset.req = self._cw |
1327 if ' WHERE ' in rql: |
1310 if ' WHERE ' in rql: |
1328 rql += ', X eid %(x)s' |
1311 rql += ', X eid %(x)s' |
1329 else: |
1312 else: |
1330 rql += ' WHERE X eid %(x)s' |
1313 rql += ' WHERE X eid %(x)s' |
1331 self._cw.execute(rql, qargs) |
1314 self._cw.execute(rql, qargs) |
1332 # update current local object _after_ the rql query to avoid |
|
1333 # interferences between the query execution itself and the cw_edited / |
|
1334 # skip_security machinery |
|
1335 self._cw_update_attr_cache(attrcache) |
|
1336 self._cw_handle_pending_relations(self.eid, pendingrels, self._cw.execute) |
1315 self._cw_handle_pending_relations(self.eid, pendingrels, self._cw.execute) |
1337 # XXX update relation cache |
1316 # XXX update relation cache |
1338 |
1317 |
1339 def cw_delete(self, **kwargs): |
1318 def cw_delete(self, **kwargs): |
1340 assert self.has_eid(), self.eid |
1319 assert self.has_eid(), self.eid |