Commit 48319105 authored by Alexandre Fayolle's avatar Alexandre Fayolle
Browse files

nicer error reporting for unique together constraints

--HG--
branch : stable
parent d36104de8459
......@@ -80,6 +80,8 @@ class ETypeNotSupportedBySources(RepositoryError, InternalError):
class MultiSourcesError(RepositoryError, InternalError):
"""usually due to bad multisources configuration or rql query"""
class UniqueTogetherError(RepositoryError):
"""raised when a unique_together constraint caused an IntegrityError"""
# security exceptions #########################################################
......
......@@ -50,12 +50,12 @@ from cubicweb import (CW_SOFTWARE_ROOT, CW_MIGRATION_MAP, QueryError,
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
_ = unicode
def del_existing_rel_if_needed(session, eidfrom, rtype, eidto):
"""delete existing relation when adding a new one if card is 1 or ?
......@@ -1062,7 +1062,14 @@ class Repository(object):
entity._cw_set_defaults()
if session.is_hook_category_activated('integrity'):
entity._cw_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] = _('violates unique_together constraints (%s)') % (','.join(rtypes))
raise ValidationError(entity.eid, problems)
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
......@@ -1133,14 +1140,22 @@ class Repository(object):
relations.append((attr, entity[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'):
entity._cw_check()
source.update_entity(session, entity)
try:
source.update_entity(session, entity)
except UniqueTogetherError, exc:
etype, rtypes = exc.args
problems = {}
for col in rtypes:
problems[col] = _('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:
......
......@@ -34,6 +34,7 @@ from datetime import datetime
from base64 import b64decode, b64encode
from contextlib import contextmanager
from os.path import abspath
import re
from logilab.common.compat import any
from logilab.common.cache import Cache
......@@ -44,7 +45,7 @@ from logilab.database import get_db_helper
from yams import schema2sql as y2sql
from cubicweb import UnknownEid, AuthenticationError, ValidationError, Binary
from cubicweb import UnknownEid, AuthenticationError, ValidationError, Binary, UniqueTogetherError
from cubicweb import transaction as tx, server, neg_role
from cubicweb.schema import VIRTUAL_RTYPES
from cubicweb.cwconfig import CubicWebNoAppConfiguration
......@@ -666,6 +667,16 @@ class NativeSQLSource(SQLAdapterMixIn, AbstractSource):
self.critical('transaction has been rollbacked')
except:
pass
if ex.__class__.__name__ == 'IntegrityError':
# need string comparison because of various backends
for arg in ex.args:
mo = re.search('unique_cw_[^ ]+_idx', arg)
if mo is not None:
index_name = mo.group(0)
elements = index_name.rstrip('_idx').split('_cw_')[1:]
etype = elements[0]
rtypes = elements[1:]
raise UniqueTogetherError(etype, rtypes)
raise
return cursor
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment