[R hooks] optmize insertion by using direct repository methods when possible
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 31 Jul 2009 23:44:16 +0200
changeset 2603 e47d63351891
parent 2602 7bfa83772d90
child 2604 6b55a2a81fd8
[R hooks] optmize insertion by using direct repository methods when possible
server/hooks.py
server/session.py
--- a/server/hooks.py	Fri Jul 31 23:39:50 2009 +0200
+++ b/server/hooks.py	Fri Jul 31 23:44:16 2009 +0200
@@ -21,65 +21,76 @@
     session.transaction_data.setdefault('pendingrelations', []).append(
         (eidfrom, rtype, eidto))
 
+def eschema_type_eid(session, etype):
+    """get eid of the CWEType entity for the given yams type"""
+    eschema = session.repo.schema.eschema(etype)
+    # eschema.eid is None if schema has been readen from the filesystem, not
+    # from the database (eg during tests)
+    if eschema.eid is None:
+        eschema.eid = session.unsafe_execute(
+            'Any X WHERE X is CWEType, X name %(name)s', {'name': etype})[0][0]
+    return eschema.eid
 
-# base meta-data handling #####################################################
+
+# base meta-data handling ######################################################
 
 def setctime_before_add_entity(session, entity):
     """before create a new entity -> set creation and modification date
 
     this is a conveniency hook, you shouldn't have to disable it
     """
-    if not 'creation_date' in entity:
-        entity['creation_date'] = datetime.now()
-    if not 'modification_date' in entity:
-        entity['modification_date'] = datetime.now()
-    if not 'cwuri' in entity:
-        if not session.get_shared_data('do-not-insert-cwuri'):
-            entity['cwuri'] = session.base_url() + u'eid/%s' % entity.eid
+    timestamp = datetime.now()
+    entity.setdefault('creation_date', timestamp)
+    entity.setdefault('modification_date', timestamp)
+    if not session.get_shared_data('do-not-insert-cwuri'):
+        entity.setdefault('cwuri', u'%seid/%s' % (session.base_url(), entity.eid))
+
 
 def setmtime_before_update_entity(session, entity):
     """update an entity -> set modification date"""
-    if not 'modification_date' in entity:
-        entity['modification_date'] = datetime.now()
+    entity.setdefault('modification_date', datetime.now())
+
 
 class SetCreatorOp(PreCommitOperation):
 
     def precommit_event(self):
-        if self.eid in self.session.transaction_data.get('pendingeids', ()):
+        session = self.session
+        if self.entity.eid in session.transaction_data.get('pendingeids', ()):
             # entity have been created and deleted in the same transaction
             return
-        ueid = self.session.user.eid
-        execute = self.session.unsafe_execute
-        if not execute('Any X WHERE X created_by U, X eid %(x)s',
-                       {'x': self.eid}, 'x'):
-            execute('SET X created_by U WHERE X eid %(x)s, U eid %(u)s',
-                    {'x': self.eid, 'u': ueid}, 'x')
+        if not self.entity.created_by:
+            session.add_relation(self.entity.eid, 'created_by', session.user.eid)
+
 
 def setowner_after_add_entity(session, entity):
     """create a new entity -> set owner and creator metadata"""
     asession = session.actual_session()
     if not asession.is_internal_session:
-        session.unsafe_execute('SET X owned_by U WHERE X eid %(x)s, U eid %(u)s',
-                               {'x': entity.eid, 'u': asession.user.eid}, 'x')
-        SetCreatorOp(asession, eid=entity.eid)
+        session.add_relation(entity.eid, 'owned_by', asession.user.eid)
+        SetCreatorOp(asession, entity=entity)
+
 
 def setis_after_add_entity(session, entity):
     """create a new entity -> set is relation"""
     if hasattr(entity, '_cw_recreating'):
         return
-    session.unsafe_execute('SET X is E WHERE X eid %(x)s, E name %(name)s',
-                           {'x': entity.eid, 'name': entity.id}, 'x')
+    try:
+        session.add_relation(entity.eid, 'is',
+                             eschema_type_eid(session, entity.id))
+    except IndexError:
+        # during schema serialization, skip
+        return
     # XXX < 2.50 bw compat
     if not session.get_shared_data('do-not-insert-is_instance_of'):
-        basetypes = entity.e_schema.ancestors() + [entity.e_schema]
-        session.unsafe_execute('SET X is_instance_of E WHERE X eid %%(x)s, E name IN (%s)' %
-                               ','.join("'%s'" % str(etype) for etype in basetypes),
-                               {'x': entity.eid}, 'x')
+        for etype in entity.e_schema.ancestors() + [entity.e_schema]:
+            session.add_relation(entity.eid, 'is_instance_of',
+                                 eschema_type_eid(session, etype))
+
 
 def setowner_after_add_user(session, entity):
     """when a user has been created, add owned_by relation on itself"""
-    session.unsafe_execute('SET X owned_by X WHERE X eid %(x)s',
-                           {'x': entity.eid}, 'x')
+    session.add_relation(entity.eid, 'owned_by', entity.eid)
+
 
 def fti_update_after_add_relation(session, eidfrom, rtype, eidto):
     """sync fulltext index when relevant relation is added. Reindexing the
@@ -91,6 +102,8 @@
         FTIndexEntityOp(session, entity=session.entity_from_eid(eidto))
     elif ftcontainer == 'object':
         FTIndexEntityOp(session, entity=session.entity_from_eid(eidfrom))
+
+
 def fti_update_after_delete_relation(session, eidfrom, rtype, eidto):
     """sync fulltext index when relevant relation is deleted. Reindexing both
     entities is necessary.
@@ -99,6 +112,7 @@
         FTIndexEntityOp(session, entity=session.entity_from_eid(eidto))
         FTIndexEntityOp(session, entity=session.entity_from_eid(eidfrom))
 
+
 class SyncOwnersOp(PreCommitOperation):
 
     def precommit_event(self):
@@ -107,12 +121,13 @@
                                     {'c': self.compositeeid, 'x': self.composedeid},
                                     ('c', 'x'))
 
+
 def sync_owner_after_add_composite_relation(session, eidfrom, rtype, eidto):
     """when adding composite relation, the composed should have the same owners
     has the composite
     """
     if rtype == 'wf_info_for':
-        # skip this special composite relation
+        # skip this special composite relation # XXX (syt) why?
         return
     composite = rproperty(session, rtype, eidfrom, eidto, 'composite')
     if composite == 'subject':
@@ -120,6 +135,7 @@
     elif composite == 'object':
         SyncOwnersOp(session, compositeeid=eidto, composedeid=eidfrom)
 
+
 def _register_metadata_hooks(hm):
     """register meta-data related hooks on the hooks manager"""
     hm.register_hook(setctime_before_add_entity, 'before_add_entity', '')
@@ -133,6 +149,7 @@
     if 'CWUser' in hm.schema:
         hm.register_hook(setowner_after_add_user, 'after_add_entity', 'CWUser')
 
+
 # core hooks ##################################################################
 
 class DelayedDeleteOp(PreCommitOperation):
@@ -148,6 +165,7 @@
                                    % (etype, self.relation),
                                    {'x': self.eid}, 'x')
 
+
 def handle_composite_before_del_relation(session, eidfrom, rtype, eidto):
     """delete the object of composite relation"""
     composite = rproperty(session, rtype, eidfrom, eidto, 'composite')
@@ -156,6 +174,7 @@
     elif composite == 'object':
         DelayedDeleteOp(session, eid=eidfrom, relation='X %s Y' % rtype)
 
+
 def before_del_group(session, eid):
     """check that we don't remove the owners group"""
     check_internal_entity(session, eid, ('owners',))
@@ -185,6 +204,7 @@
     def commit_event(self):
         pass
 
+
 def cstrcheck_after_add_relation(session, eidfrom, rtype, eidto):
     """check the relation satisfy its constraints
 
@@ -210,9 +230,6 @@
                 raise ValidationError(entity.eid, {attr: msg % val})
 
 
-
-
-
 class CheckRequiredRelationOperation(LateOperation):
     """checking relation cardinality has to be done after commit in
     case the relation is being replaced
@@ -227,9 +244,8 @@
             etype = self.session.describe(self.eid)[0]
             _ = self.session._
             msg = _('at least one relation %(rtype)s is required on %(etype)s (%(eid)s)')
-            raise ValidationError(self.eid, {self.rtype: msg % {'rtype': _(self.rtype),
-                                                                'etype': _(etype),
-                                                                'eid': self.eid}})
+            msg %= {'rtype': _(self.rtype), 'etype': _(etype), 'eid': self.eid}
+            raise ValidationError(self.eid, {self.rtype: msg})
 
     def commit_event(self):
         pass
@@ -237,16 +253,19 @@
     def _rql(self):
         raise NotImplementedError()
 
+
 class CheckSRelationOp(CheckRequiredRelationOperation):
     """check required subject relation"""
     def _rql(self):
         return 'Any O WHERE S eid %%(x)s, S %s O' % self.rtype, {'x': self.eid}, 'x'
 
+
 class CheckORelationOp(CheckRequiredRelationOperation):
     """check required object relation"""
     def _rql(self):
         return 'Any S WHERE O eid %%(x)s, S %s O' % self.rtype, {'x': self.eid}, 'x'
 
+
 def checkrel_if_necessary(session, opcls, rtype, eid):
     """check an equivalent operation has not already been added"""
     for op in session.pending_operations:
@@ -255,6 +274,7 @@
     else:
         opcls(session, rtype=rtype, eid=eid)
 
+
 def cardinalitycheck_after_add_entity(session, entity):
     """check cardinalities are satisfied"""
     eid = entity.eid
@@ -276,6 +296,7 @@
         if card[cardindex] in '1+':
             checkrel_if_necessary(session, opcls, rschema.type, eid)
 
+
 def cardinalitycheck_before_del_relation(session, eidfrom, rtype, eidto):
     """check cardinalities are satisfied"""
     card = rproperty(session, rtype, eidfrom, eidto, 'cardinality')
@@ -314,6 +335,7 @@
         Operation.__init__(self, session, *args, **kwargs)
         self.group = result[0][0]
 
+
 class DeleteGroupOp(GroupOperation):
     """synchronize user when a in_group relation has been deleted"""
     def commit_event(self):
@@ -325,6 +347,7 @@
             self.error('user %s not in group %s',  self.cnxuser, self.group)
             return
 
+
 def after_del_in_group(session, fromeid, rtype, toeid):
     """modify user permission, need to update users"""
     for session_ in get_user_sessions(session.repo, fromeid):
@@ -342,6 +365,7 @@
             return
         groups.add(self.group)
 
+
 def after_add_in_group(session, fromeid, rtype, toeid):
     """modify user permission, need to update users"""
     for session_ in get_user_sessions(session.repo, fromeid):
@@ -361,11 +385,13 @@
         except BadConnectionId:
             pass # already closed
 
+
 def after_del_user(session, eid):
     """modify user permission, need to update users"""
     for session_ in get_user_sessions(session.repo, eid):
         DelUserOp(session, session_.id)
 
+
 def _register_usergroup_hooks(hm):
     """register user/group related hooks on the hooks manager"""
     hm.register_hook(after_del_user, 'after_delete_entity', 'CWUser')
@@ -437,6 +463,7 @@
 def set_initial_state_after_add(session, entity):
     SetInitialStateOp(session, entity=entity)
 
+
 def _register_wf_hooks(hm):
     """register workflow related hooks on the hooks manager"""
     if 'in_state' in hm.schema:
@@ -461,6 +488,7 @@
         except KeyError:
             self.error('%s has no associated value', self.key)
 
+
 class ChangeCWPropertyOp(Operation):
     """a user's custom properties has been added/changed"""
 
@@ -468,6 +496,7 @@
         """the observed connections pool has been commited"""
         self.epropdict[self.key] = self.value
 
+
 class AddCWPropertyOp(Operation):
     """a user's custom properties has been added/changed"""
 
@@ -478,6 +507,7 @@
             self.repo.vreg.eprop_values[eprop.pkey] = eprop.value
         # if for_user is set, update is handled by a ChangeCWPropertyOp operation
 
+
 def after_add_eproperty(session, entity):
     key, value = entity.pkey, entity.value
     try:
@@ -487,11 +517,11 @@
     except ValueError, ex:
         raise ValidationError(entity.eid, {'value': session._(str(ex))})
     if not session.user.matching_groups('managers'):
-        session.unsafe_execute('SET P for_user U WHERE P eid %(x)s,U eid %(u)s',
-                               {'x': entity.eid, 'u': session.user.eid}, 'x')
+        session.add_relation(entity.eid, 'for_user', session.user.eid)
     else:
         AddCWPropertyOp(session, eprop=entity)
 
+
 def after_update_eproperty(session, entity):
     key, value = entity.pkey, entity.value
     try:
@@ -509,6 +539,7 @@
         ChangeCWPropertyOp(session, epropdict=session.vreg.eprop_values,
                           key=key, value=value)
 
+
 def before_del_eproperty(session, eid):
     for eidfrom, rtype, eidto in session.transaction_data.get('pendingrelations', ()):
         if rtype == 'for_user' and eidfrom == eid:
@@ -519,6 +550,7 @@
                               {'x': eid}, 'x')[0][0]
         DelCWPropertyOp(session, epropdict=session.vreg.eprop_values, key=key)
 
+
 def after_add_for_user(session, fromeid, rtype, toeid):
     if not session.describe(fromeid)[0] == 'CWProperty':
         return
@@ -531,6 +563,7 @@
         ChangeCWPropertyOp(session, epropdict=session_.user.properties,
                           key=key, value=value)
 
+
 def before_del_for_user(session, fromeid, rtype, toeid):
     key = session.execute('Any K WHERE P eid %(x)s, P pkey K',
                           {'x': fromeid}, 'x')[0][0]
@@ -538,6 +571,7 @@
     for session_ in get_user_sessions(session.repo, toeid):
         DelCWPropertyOp(session, epropdict=session_.user.properties, key=key)
 
+
 def _register_eproperty_hooks(hm):
     """register workflow related hooks on the hooks manager"""
     hm.register_hook(after_add_eproperty, 'after_add_entity', 'CWProperty')
--- a/server/session.py	Fri Jul 31 23:39:50 2009 +0200
+++ b/server/session.py	Fri Jul 31 23:44:16 2009 +0200
@@ -40,8 +40,6 @@
         description.append(term.get_type(solution, args))
     return description
 
-from rql import stmts
-assert hasattr(stmts.Union, 'get_variable_variables'), "You need RQL > 0.18.3"
 
 class Session(RequestSessionMixIn):
     """tie session id, user, connections pool and other session data all