server/repository.py
changeset 6225 a176e68b7d0d
parent 6142 8bc6eac1fac1
parent 6211 e9d125fd1465
child 6279 42079f752a9c
--- a/server/repository.py	Tue Sep 07 17:34:42 2010 +0200
+++ b/server/repository.py	Mon Sep 13 15:15:21 2010 +0200
@@ -50,14 +50,13 @@
                       UnknownEid, AuthenticationError, ExecutionError,
                       ETypeNotSupportedBySources, MultiSourcesError,
                       BadConnectionId, Unauthorized, ValidationError,
-                      RepositoryError, typed_eid, onevent)
+                      RepositoryError, UniqueTogetherError, typed_eid, onevent)
 from cubicweb import cwvreg, schema, server
 from cubicweb.server import utils, hook, pool, querier, sources
 from cubicweb.server.session import Session, InternalSession, InternalManager, \
      security_enabled
 from cubicweb.server.ssplanner import EditedEntity
 
-
 def del_existing_rel_if_needed(session, eidfrom, rtype, eidto):
     """delete existing relation when adding a new one if card is 1 or ?
 
@@ -82,14 +81,14 @@
     # not expected for this).  So: don't do it, we pretend to ensure repository
     # consistency.
     #
-    # XXX we don't want read permissions to be applied but we want delete
-    # permission to be checked
-    rschema = session.repo.schema.rschema(rtype)
-    if card[0] in '1?':
-        if not rschema.inlined: # inlined relations will be implicitly deleted
-            with security_enabled(session, read=False):
-                session.execute('DELETE X %s Y WHERE X eid %%(x)s, '
-                                'NOT Y eid %%(y)s' % rtype,
+    # notes:
+    # * inlined relations will be implicitly deleted for the subject entity
+    # * we don't want read permissions to be applied but we want delete
+    #   permission to be checked
+    if card[0] in '1?' and not session.repo.schema.rschema(rtype).inlined:
+        with security_enabled(session, read=False):
+            session.execute('DELETE X %s Y WHERE X eid %%(x)s, '
+                            'NOT Y eid %%(y)s' % rtype,
                                 {'x': eidfrom, 'y': eidto})
     if card[1] in '1?':
         with security_enabled(session, read=False):
@@ -1070,10 +1069,16 @@
         edited.set_defaults()
         if session.is_hook_category_activated('integrity'):
             edited.check(creation=True)
-        source.add_entity(session, entity)
+        try:
+            source.add_entity(session, entity)
+        except UniqueTogetherError, exc:
+            etype, rtypes = exc.args
+            problems = {}
+            for col in rtypes:
+                problems[col] = session._('violates unique_together constraints (%s)') % (','.join(rtypes))
+            raise ValidationError(entity.eid, problems)
+        self.add_info(session, entity, source, extid, complete=False)
         edited.saved = True
-        self.add_info(session, entity, source, extid, complete=False)
-        entity._cw_is_saved = True # entity has an eid and is saved
         # prefill entity relation caches
         for rschema in eschema.subject_relations():
             rtype = str(rschema)
@@ -1089,9 +1094,10 @@
             if rtype in schema.VIRTUAL_RTYPES:
                 continue
             entity.cw_set_relation_cache(rtype, 'object', session.empty_rset())
-        # set inline relation cache before call to after_add_entity
+        # set inlined relation cache before call to after_add_entity
         for attr, value in relations:
             session.update_rel_cache_add(entity.eid, attr, value)
+            del_existing_rel_if_needed(session, entity.eid, attr, value)
         # trigger after_add_entity after after_add_relation
         if source.should_call_hooks:
             self.hm.call_hooks('after_add_entity', session, entity=entity)
@@ -1142,15 +1148,22 @@
                     relations.append((attr, edited[attr], previous_value))
             if source.should_call_hooks:
                 # call hooks for inlined relations
-                for attr, value, _ in relations:
+                for attr, value, _t in relations:
                     hm.call_hooks('before_add_relation', session,
                                   eidfrom=entity.eid, rtype=attr, eidto=value)
                 if not only_inline_rels:
                     hm.call_hooks('before_update_entity', session, entity=entity)
             if session.is_hook_category_activated('integrity'):
                 edited.check()
-            source.update_entity(session, entity)
-            edited.saved = True
+            try:
+                source.update_entity(session, entity)
+                edited.saved = True
+            except UniqueTogetherError, exc:
+                etype, rtypes = exc.args
+                problems = {}
+                for col in rtypes:
+                    problems[col] = session._('violates unique_together constraints (%s)') % (','.join(rtypes))
+                raise ValidationError(entity.eid, problems)
             self.system_source.update_info(session, entity, need_fti_update)
             if source.should_call_hooks:
                 if not only_inline_rels: