cubicweb/hooks/integrity.py
author Philippe Pepiot <ph@itsalwaysdns.eu>
Tue, 31 Mar 2020 18:22:05 +0200
changeset 12966 6cd938c29ca3
parent 12567 26744ad37953
permissions -rw-r--r--
[server] Make connection pooler configurable and set better default values Drop the configuration connections-pool-size and add new configurations options: * connections-pool-min-size. Set to 0 by default so we open connections only when needed. This avoid opening min-size*processes connections at startup, which is, it think, a good default. * connections-pool-max-size. Set to 0 (unlimited) by default, so we move the bottleneck to postgresql. * connections-idle-timeout. Set to 10 minutes. I don't have arguments about this except that this is the default in pgbouncer.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11767
432f87a63057 flake8 and all
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11765
diff changeset
     1
# copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     3
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     4
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     5
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
     9
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    10
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    14
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    15
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5060
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    18
"""Core hooks: check for data integrity according to the instance'schema
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    19
validity
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    20
"""
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    21
10666
7f6b5f023884 [py3k] replace '_ = unicode' in global scope (closes #7589459)
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10662
diff changeset
    22
from cubicweb import _
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    23
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    24
from threading import Lock
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    25
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
    26
from cubicweb import validation_error, neg_role
6375
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    27
from cubicweb.schema import (META_RTYPES, WORKFLOW_RTYPES,
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    28
                             RQLConstraint, RQLUniqueConstraint)
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
    29
from cubicweb.predicates import is_instance, composite_etype
4023
eae23c40627a drop common subpackage
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4003
diff changeset
    30
from cubicweb.uilib import soup2xhtml
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    31
from cubicweb.server import hook
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    32
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    33
# special relations that don't have to be checked for integrity, usually
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    34
# because they are handled internally by hooks (so we trust ourselves)
6375
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    35
DONT_CHECK_RTYPES_ON_ADD = META_RTYPES | WORKFLOW_RTYPES
df4fd2a1b0e7 [schema] introduce new WORKFLOW_RTYPES set and use it to build SYSTEM_RTYPES/DONT_CHECK_RTYPES_ON_ADD/DONT_CHECK_RTYPES_ON_DEL sets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
    36
DONT_CHECK_RTYPES_ON_DEL = META_RTYPES | WORKFLOW_RTYPES
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    37
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    38
_UNIQUE_CONSTRAINTS_LOCK = Lock()
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    39
_UNIQUE_CONSTRAINTS_HOLDER = None
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    40
4517
0f3c10fc42b2 backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4498
diff changeset
    41
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    42
def _acquire_unique_cstr_lock(cnx):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    43
    """acquire the _UNIQUE_CONSTRAINTS_LOCK for the cnx.
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    44
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    45
    This lock used to avoid potential integrity pb when checking
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    46
    RQLUniqueConstraint in two different transactions, as explained in
10893
351c82df25be [hooks] update internal URL in doc string
Julien Cristau <julien.cristau@logilab.fr>
parents: 10689
diff changeset
    47
    https://extranet.logilab.fr/3577926
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    48
    """
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    49
    if 'uniquecstrholder' in cnx.transaction_data:
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    50
        return
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    51
    _UNIQUE_CONSTRAINTS_LOCK.acquire()
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    52
    cnx.transaction_data['uniquecstrholder'] = True
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    53
    # register operation responsible to release the lock on commit/rollback
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    54
    _ReleaseUniqueConstraintsOperation(cnx)
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    55
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    56
def _release_unique_cstr_lock(cnx):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    57
    if 'uniquecstrholder' in cnx.transaction_data:
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    58
        del cnx.transaction_data['uniquecstrholder']
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    59
        _UNIQUE_CONSTRAINTS_LOCK.release()
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    60
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    61
class _ReleaseUniqueConstraintsOperation(hook.Operation):
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    62
    def postcommit_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    63
        _release_unique_cstr_lock(self.cnx)
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    64
    def rollback_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    65
        _release_unique_cstr_lock(self.cnx)
4490
d45cde54d464 backport stable branch and some vreg cleanups:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
    66
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    67
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    68
class _CheckRequiredRelationOperation(hook.DataOperationMixIn,
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    69
                                      hook.LateOperation):
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    70
    """checking relation cardinality has to be done after commit in case the
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    71
    relation is being replaced
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    72
    """
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    73
    containercls = list
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    74
    role = key = base_rql = None
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    75
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    76
    def precommit_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    77
        cnx = self.cnx
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    78
        pendingeids = cnx.transaction_data.get('pendingeids', ())
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    79
        pendingrtypes = cnx.transaction_data.get('pendingrtypes', ())
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
    80
        for eid, rtype in self.get_data():
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    81
            # recheck pending eids / relation types
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    82
            if eid in pendingeids:
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    83
                continue
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    84
            if rtype in pendingrtypes:
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    85
                continue
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
    86
            if not cnx.execute(self.base_rql % rtype, {'x': eid}):
11765
9cb215e833b0 [cnx] Use entity_type instead of entity_metas()['type']
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11366
diff changeset
    87
                etype = cnx.entity_type(eid)
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    88
                msg = _('at least one relation %(rtype)s is required on '
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    89
                        '%(etype)s (%(eid)s)')
8556
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
    90
                raise validation_error(eid, {(rtype, self.role): msg},
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
    91
                                       {'rtype': rtype, 'etype': etype, 'eid': eid},
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
    92
                                       ['rtype', 'etype'])
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    93
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    94
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    95
class _CheckSRelationOp(_CheckRequiredRelationOperation):
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    96
    """check required subject relation"""
5030
5238d9a8dfee [form] put qualified name on validation error, should fix #784299
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5007
diff changeset
    97
    role = 'subject'
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
    98
    base_rql = 'Any O WHERE S eid %%(x)s, S %s O'
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    99
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   100
class _CheckORelationOp(_CheckRequiredRelationOperation):
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   101
    """check required object relation"""
5030
5238d9a8dfee [form] put qualified name on validation error, should fix #784299
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5007
diff changeset
   102
    role = 'object'
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
   103
    base_rql = 'Any S WHERE O eid %%(x)s, S %s O'
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   104
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   105
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   106
class IntegrityHook(hook.Hook):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   107
    __abstract__ = True
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   108
    category = 'integrity'
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   109
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   110
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   111
class _EnsureSymmetricRelationsAdd(hook.Hook):
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   112
    """ ensure X r Y => Y r X iff r is symmetric """
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   113
    __regid__ = 'cw.add_ensure_symmetry'
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   114
    __abstract__ = True
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   115
    category = 'activeintegrity'
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   116
    events = ('after_add_relation',)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   117
    # __select__ is set in the registration callback
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   118
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   119
    def __call__(self):
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   120
        self._cw.repo.system_source.add_relation(self._cw, self.eidto,
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   121
                                                 self.rtype, self.eidfrom)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   122
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   123
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   124
class _EnsureSymmetricRelationsDelete(hook.Hook):
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   125
    """ ensure X r Y => Y r X iff r is symmetric """
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   126
    __regid__ = 'cw.delete_ensure_symmetry'
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   127
    __abstract__ = True
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   128
    category = 'activeintegrity'
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   129
    events = ('after_delete_relation',)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   130
    # __select__ is set in the registration callback
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   131
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   132
    def __call__(self):
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   133
        self._cw.repo.system_source.delete_relation(self._cw, self.eidto,
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   134
                                                    self.rtype, self.eidfrom)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   135
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   136
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   137
class CheckCardinalityHookBeforeDeleteRelation(IntegrityHook):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   138
    """check cardinalities are satisfied"""
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   139
    __regid__ = 'checkcard_before_delete_relation'
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   140
    events = ('before_delete_relation',)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   141
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   142
    def __call__(self):
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   143
        rtype = self.rtype
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   144
        if rtype in DONT_CHECK_RTYPES_ON_DEL:
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   145
            return
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   146
        cnx = self._cw
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   147
        eidfrom, eidto = self.eidfrom, self.eidto
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   148
        rdef = cnx.rtype_eids_rdef(rtype, eidfrom, eidto)
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   149
        if (rdef.subject, rtype, rdef.object) in cnx.transaction_data.get('pendingrdefs', ()):
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   150
            return
7502
e7190f7e850e [session] deprecates schema_rproperty in favor of more optimized rtype_eids_rdef which return the rdef (so reusable to gather other data)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7495
diff changeset
   151
        card = rdef.cardinality
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   152
        if card[0] in '1+' and not cnx.deleted_in_transaction(eidfrom):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   153
            _CheckSRelationOp.get_instance(cnx).add_data((eidfrom, rtype))
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   154
        if card[1] in '1+' and not cnx.deleted_in_transaction(eidto):
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   155
            _CheckORelationOp.get_instance(cnx).add_data((eidto, rtype))
7495
09d245a9bf5f [hooks] use local variable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7494
diff changeset
   156
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   157
6889
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   158
class CheckCardinalityHookAfterAddEntity(IntegrityHook):
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   159
    """check cardinalities are satisfied"""
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   160
    __regid__ = 'checkcard_after_add_entity'
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   161
    events = ('after_add_entity',)
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   162
37668bf302f5 improve massive deletion performance
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6838
diff changeset
   163
    def __call__(self):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   164
        eid = self.entity.eid
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   165
        eschema = self.entity.e_schema
3890
d7a270f50f54 backport stable branch (one more time painfully)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3731
diff changeset
   166
        for rschema, targetschemas, role in eschema.relation_definitions():
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   167
            # skip automatically handled relations
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   168
            if rschema.type in DONT_CHECK_RTYPES_ON_ADD:
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   169
                continue
3890
d7a270f50f54 backport stable branch (one more time painfully)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3731
diff changeset
   170
            rdef = rschema.role_rdef(eschema, targetschemas[0], role)
d7a270f50f54 backport stable branch (one more time painfully)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3731
diff changeset
   171
            if rdef.role_cardinality(role) in '1+':
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
   172
                if role == 'subject':
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   173
                    op = _CheckSRelationOp.get_instance(self._cw)
5060
ee3b856e1406 [repo] optimize massive insertion/deletion by using the new set_operation function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5030
diff changeset
   174
                else:
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   175
                    op = _CheckORelationOp.get_instance(self._cw)
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   176
                op.add_data((eid, rschema.type))
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   177
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   178
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   179
class _CheckConstraintsOp(hook.DataOperationMixIn, hook.LateOperation):
5450
269dcd14b92c [hooks/integrity & tests/entities] fix test to check for sibling error (set_operations yields a different order for constraints)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5449
diff changeset
   180
    """ check a new relation satisfy its constraints """
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   181
    containercls = list
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   182
    def precommit_event(self):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   183
        cnx = self.cnx
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   184
        for values in self.get_data():
5450
269dcd14b92c [hooks/integrity & tests/entities] fix test to check for sibling error (set_operations yields a different order for constraints)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5449
diff changeset
   185
            eidfrom, rtype, eidto, constraints = values
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   186
            # first check related entities have not been deleted in the same
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   187
            # transaction
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   188
            if cnx.deleted_in_transaction(eidfrom):
6894
ba3f7e655414 we must check constraint for all concerned entities and not stop at the first deleted one
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6889
diff changeset
   189
                continue
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   190
            if cnx.deleted_in_transaction(eidto):
6894
ba3f7e655414 we must check constraint for all concerned entities and not stop at the first deleted one
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 6889
diff changeset
   191
                continue
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   192
            for constraint in constraints:
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   193
                # XXX
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   194
                # * lock RQLConstraint as well?
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   195
                # * use a constraint id to use per constraint lock and avoid
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   196
                #   unnecessary commit serialization ?
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   197
                if isinstance(constraint, RQLUniqueConstraint):
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   198
                    _acquire_unique_cstr_lock(cnx)
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   199
                try:
9613
45370ea9f495 [hooks/integrity] use a cnx not a session
Julien Cristau <julien.cristau@logilab.fr>
parents: 9548
diff changeset
   200
                    constraint.repo_check(cnx, eidfrom, rtype, eidto)
5448
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   201
                except NotImplementedError:
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   202
                    self.critical('can\'t check constraint %s, not supported',
9bf648d678cd [hooks/operations] use set_operations for three ops (huge gains for massive imports)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5426
diff changeset
   203
                                  constraint)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   204
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   205
4835
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4530
diff changeset
   206
class CheckConstraintHook(IntegrityHook):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   207
    """check the relation satisfy its constraints
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   208
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   209
    this is delayed to a precommit time operation since other relation which
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   210
    will make constraint satisfied (or unsatisfied) may be added later.
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   211
    """
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   212
    __regid__ = 'checkconstraint'
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   213
    events = ('after_add_relation',)
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   214
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   215
    def __call__(self):
3998
94cc7cad3d2d backport stable into default
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3894
diff changeset
   216
        # XXX get only RQL[Unique]Constraints?
7502
e7190f7e850e [session] deprecates schema_rproperty in favor of more optimized rtype_eids_rdef which return the rdef (so reusable to gather other data)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7495
diff changeset
   217
        rdef = self._cw.rtype_eids_rdef(self.rtype, self.eidfrom, self.eidto)
e7190f7e850e [session] deprecates schema_rproperty in favor of more optimized rtype_eids_rdef which return the rdef (so reusable to gather other data)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7495
diff changeset
   218
        constraints = rdef.constraints
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   219
        if constraints:
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   220
            _CheckConstraintsOp.get_instance(self._cw).add_data(
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   221
                (self.eidfrom, self.rtype, self.eidto, constraints))
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   222
4027
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4024
diff changeset
   223
4835
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4530
diff changeset
   224
class CheckAttributeConstraintHook(IntegrityHook):
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   225
    """check the attribute relation satisfy its constraints
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   226
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   227
    this is delayed to a precommit time operation since other relation which
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   228
    will make constraint satisfied (or unsatisfied) may be added later.
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   229
    """
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   230
    __regid__ = 'checkattrconstraint'
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   231
    events = ('after_add_entity', 'after_update_entity')
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   232
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   233
    def __call__(self):
4190
742e3eb16f81 fix bad merge
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4181
diff changeset
   234
        eschema = self.entity.e_schema
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   235
        for attr in self.entity.cw_edited:
4181
c79135c217df backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4075
diff changeset
   236
            if eschema.subjrels[attr].final:
c79135c217df backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4075
diff changeset
   237
                constraints = [c for c in eschema.rdef(attr).constraints
3998
94cc7cad3d2d backport stable into default
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3894
diff changeset
   238
                               if isinstance(c, (RQLUniqueConstraint, RQLConstraint))]
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   239
                if constraints:
6426
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   240
                    _CheckConstraintsOp.get_instance(self._cw).add_data(
541659c39f6a [hook/operation] nicer api to achieve same result as set_operation, as described in #1253630
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6376
diff changeset
   241
                        (self.entity.eid, attr, None, constraints))
3630
275feb5370c9 oops, feature killed by merge...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3590
diff changeset
   242
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   243
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   244
class DontRemoveOwnersGroupHook(IntegrityHook):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   245
    """delete the composed of a composite relation when this relation is deleted
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   246
    """
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   247
    __regid__ = 'checkownersgroup'
5877
0c7b7b76a84f [selectors] provide a new, optimized, is_instance selector that should at some point replace implements (along with the adaptable selector)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5538
diff changeset
   248
    __select__ = IntegrityHook.__select__ & is_instance('CWGroup')
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   249
    events = ('before_delete_entity', 'before_update_entity')
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   250
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   251
    def __call__(self):
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   252
        entity = self.entity
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   253
        if self.event == 'before_delete_entity' and entity.name == 'owners':
8556
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
   254
            raise validation_error(entity, {None: _("can't be deleted")})
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   255
        elif self.event == 'before_update_entity' \
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   256
                 and 'name' in entity.cw_edited:
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   257
            oldname, newname = entity.cw_edited.oldnewvalue('name')
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   258
            if oldname == 'owners' and newname != oldname:
8556
bbe0d6985e59 [validation error] refactor validation error handling so translation is done on the web side
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8508
diff changeset
   259
                raise validation_error(entity, {('name', 'subject'): _("can't be changed")})
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   260
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   261
4835
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4530
diff changeset
   262
class TidyHtmlFields(IntegrityHook):
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   263
    """tidy HTML in rich text strings"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   264
    __regid__ = 'htmltidy'
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   265
    events = ('before_add_entity', 'before_update_entity')
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   266
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   267
    def __call__(self):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   268
        entity = self.entity
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   269
        metaattrs = entity.e_schema.meta_attributes()
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   270
        edited = entity.cw_edited
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 9680
diff changeset
   271
        for metaattr, (metadata, attr) in metaattrs.items():
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   272
            if metadata == 'format' and attr in edited:
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   273
                try:
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   274
                    value = edited[attr]
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   275
                except KeyError:
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   276
                    continue # no text to tidy
12567
26744ad37953 Drop python2 support
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11767
diff changeset
   277
                if isinstance(value, str): # filter out None and Binary
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   278
                    if getattr(entity, str(metaattr)) == 'text/html':
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   279
                        edited[attr] = soup2xhtml(value, self._cw.encoding)
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   280
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   281
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   282
class StripCWUserLoginHook(IntegrityHook):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   283
    """ensure user logins are stripped"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3086
diff changeset
   284
    __regid__ = 'stripuserlogin'
5877
0c7b7b76a84f [selectors] provide a new, optimized, is_instance selector that should at some point replace implements (along with the adaptable selector)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5538
diff changeset
   285
    __select__ = IntegrityHook.__select__ & is_instance('CWUser')
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   286
    events = ('before_add_entity', 'before_update_entity',)
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   287
2900
9d65e0350aa1 api update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2896
diff changeset
   288
    def __call__(self):
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   289
        login = self.entity.cw_edited.get('login')
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   290
        if login:
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5877
diff changeset
   291
            self.entity.cw_edited['login'] = login.strip()
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   292
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   293
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   294
class DeleteCompositeOrphanHook(hook.Hook):
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   295
    """Delete the composed of a composite relation when the composite is
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   296
    deleted (this is similar to the cascading ON DELETE CASCADE
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   297
    semantics of sql).
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   298
    """
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   299
    __regid__ = 'deletecomposite'
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   300
    __select__ = hook.Hook.__select__ & composite_etype()
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   301
    events = ('before_delete_entity',)
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   302
    category = 'activeintegrity'
9680
8fb8f001f4e2 [hooks] run cascading delete hook later
Julien Cristau <julien.cristau@logilab.fr>
parents: 9613
diff changeset
   303
    # give the application's before_delete_entity hooks a chance to run before we cascade
8fb8f001f4e2 [hooks] run cascading delete hook later
Julien Cristau <julien.cristau@logilab.fr>
parents: 9613
diff changeset
   304
    order = 99
5007
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   305
bc0a67a95b69 don't put hooks deleting orphan composites into the 'integrity' category, we usually want it when integrity is deactivated
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
   306
    def __call__(self):
9548
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   307
        eid = self.entity.eid
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   308
        for rdef, role in self.entity.e_schema.composite_rdef_roles:
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   309
            rtype = rdef.rtype.type
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   310
            target = getattr(rdef, neg_role(role))
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   311
            expr = ('C %s X' % rtype) if role == 'subject' else ('X %s C' % rtype)
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   312
            self._cw.execute('DELETE %s X WHERE C eid %%(c)s, %s' % (target, expr),
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   313
                             {'c': eid})
be001628edad [schema] fix composite deletion handling
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9469
diff changeset
   314
9361
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   315
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   316
def registration_callback(vreg):
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   317
    vreg.register_all(globals().values(), __name__)
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   318
    symmetric_rtypes = [rschema.type for rschema in vreg.schema.relations()
0542a85fe667 symmetric relations: replace bogus rql2sql translation by a hook
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 8556
diff changeset
   319
                        if rschema.symmetric]
10936
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   320
    class EnsureSymmetricRelationsAdd(_EnsureSymmetricRelationsAdd):
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   321
        __select__ = _EnsureSymmetricRelationsAdd.__select__ & hook.match_rtype(*symmetric_rtypes)
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   322
    vreg.register(EnsureSymmetricRelationsAdd)
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   323
    class EnsureSymmetricRelationsDelete(_EnsureSymmetricRelationsDelete):
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   324
        __select__ = _EnsureSymmetricRelationsDelete.__select__ & hook.match_rtype(*symmetric_rtypes)
c3606b52092c [hooks] build EnsureSymmetricRelations{Add,Delete} dynamically
Julien Cristau <julien.cristau@logilab.fr>
parents: 10907
diff changeset
   325
    vreg.register(EnsureSymmetricRelationsDelete)