--- 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: