561 results = self.process_result(cursor, cnx, cbs) |
561 results = self.process_result(cursor, cnx, cbs) |
562 assert dbg_results(results) |
562 assert dbg_results(results) |
563 return results |
563 return results |
564 |
564 |
565 @contextmanager |
565 @contextmanager |
566 def _storage_handler(self, entity, event): |
566 def _fixup_cw(self, cnx, entity): |
|
567 _cw = entity._cw |
|
568 entity._cw = cnx |
|
569 try: |
|
570 yield |
|
571 finally: |
|
572 entity._cw = _cw |
|
573 |
|
574 @contextmanager |
|
575 def _storage_handler(self, cnx, entity, event): |
567 # 1/ memorize values as they are before the storage is called. |
576 # 1/ memorize values as they are before the storage is called. |
568 # For instance, the BFSStorage will replace the `data` |
577 # For instance, the BFSStorage will replace the `data` |
569 # binary value with a Binary containing the destination path |
578 # binary value with a Binary containing the destination path |
570 # on the filesystem. To make the entity.data usage absolutely |
579 # on the filesystem. To make the entity.data usage absolutely |
571 # transparent, we'll have to reset entity.data to its binary |
580 # transparent, we'll have to reset entity.data to its binary |
576 else: |
585 else: |
577 entities = [entity] |
586 entities = [entity] |
578 etype = entities[0].__regid__ |
587 etype = entities[0].__regid__ |
579 for attr, storage in self._storages.get(etype, {}).items(): |
588 for attr, storage in self._storages.get(etype, {}).items(): |
580 for entity in entities: |
589 for entity in entities: |
581 if event == 'deleted': |
590 with self._fixup_cw(cnx, entity): |
582 storage.entity_deleted(entity, attr) |
591 if event == 'deleted': |
583 else: |
592 storage.entity_deleted(entity, attr) |
584 edited = entity.cw_edited |
593 else: |
585 if attr in edited: |
594 edited = entity.cw_edited |
586 handler = getattr(storage, 'entity_%s' % event) |
595 if attr in edited: |
587 to_restore = handler(entity, attr) |
596 handler = getattr(storage, 'entity_%s' % event) |
588 restore_values.append((entity, attr, to_restore)) |
597 to_restore = handler(entity, attr) |
|
598 restore_values.append((entity, attr, to_restore)) |
589 try: |
599 try: |
590 yield # 2/ execute the source's instructions |
600 yield # 2/ execute the source's instructions |
591 finally: |
601 finally: |
592 # 3/ restore original values |
602 # 3/ restore original values |
593 for entity, attr, value in restore_values: |
603 for entity, attr, value in restore_values: |
594 entity.cw_edited.edited_attribute(attr, value) |
604 entity.cw_edited.edited_attribute(attr, value) |
595 |
605 |
596 def add_entity(self, cnx, entity): |
606 def add_entity(self, cnx, entity): |
597 """add a new entity to the source""" |
607 """add a new entity to the source""" |
598 with self._storage_handler(entity, 'added'): |
608 with self._storage_handler(cnx, entity, 'added'): |
599 attrs = self.preprocess_entity(entity) |
609 attrs = self.preprocess_entity(entity) |
600 sql = self.sqlgen.insert(SQL_PREFIX + entity.cw_etype, attrs) |
610 sql = self.sqlgen.insert(SQL_PREFIX + entity.cw_etype, attrs) |
601 self.doexec(cnx, sql, attrs) |
611 self.doexec(cnx, sql, attrs) |
602 if cnx.ertype_supports_undo(entity.cw_etype): |
612 if cnx.ertype_supports_undo(entity.cw_etype): |
603 self._record_tx_action(cnx, 'tx_entity_actions', u'C', |
613 self._record_tx_action(cnx, 'tx_entity_actions', u'C', |
604 etype=unicode(entity.cw_etype), eid=entity.eid) |
614 etype=unicode(entity.cw_etype), eid=entity.eid) |
605 |
615 |
606 def update_entity(self, cnx, entity): |
616 def update_entity(self, cnx, entity): |
607 """replace an entity in the source""" |
617 """replace an entity in the source""" |
608 with self._storage_handler(entity, 'updated'): |
618 with self._storage_handler(cnx, entity, 'updated'): |
609 attrs = self.preprocess_entity(entity) |
619 attrs = self.preprocess_entity(entity) |
610 if cnx.ertype_supports_undo(entity.cw_etype): |
620 if cnx.ertype_supports_undo(entity.cw_etype): |
611 changes = self._save_attrs(cnx, entity, attrs) |
621 changes = self._save_attrs(cnx, entity, attrs) |
612 self._record_tx_action(cnx, 'tx_entity_actions', u'U', |
622 self._record_tx_action(cnx, 'tx_entity_actions', u'U', |
613 etype=unicode(entity.cw_etype), eid=entity.eid, |
623 etype=unicode(entity.cw_etype), eid=entity.eid, |
616 ['cw_eid']) |
626 ['cw_eid']) |
617 self.doexec(cnx, sql, attrs) |
627 self.doexec(cnx, sql, attrs) |
618 |
628 |
619 def delete_entity(self, cnx, entity): |
629 def delete_entity(self, cnx, entity): |
620 """delete an entity from the source""" |
630 """delete an entity from the source""" |
621 with self._storage_handler(entity, 'deleted'): |
631 with self._storage_handler(cnx, entity, 'deleted'): |
622 if cnx.ertype_supports_undo(entity.cw_etype): |
632 if cnx.ertype_supports_undo(entity.cw_etype): |
623 attrs = [SQL_PREFIX + r.type |
633 attrs = [SQL_PREFIX + r.type |
624 for r in entity.e_schema.subject_relations() |
634 for r in entity.e_schema.subject_relations() |
625 if (r.final or r.inlined) and not r in VIRTUAL_RTYPES] |
635 if (r.final or r.inlined) and not r in VIRTUAL_RTYPES] |
626 changes = self._save_attrs(cnx, entity, attrs) |
636 changes = self._save_attrs(cnx, entity, attrs) |