hooks/synccomputed.py
author Julien Cristau <julien.cristau@logilab.fr>
Tue, 28 Jul 2015 09:25:26 +0200
changeset 10553 1d824df4f2bd
parent 10395 7e311ee8b5b0
child 10662 10942ed172de
permissions -rw-r--r--
Fix (de)serialization of ComputedRelation read permissions For normal relation types, permissions don't need to be stored since they're just default values for the relation definitions. However, computed relations are serialized (as CWComputedRType), while their relation definitions are added at schema finalization time, and are only in memory. So add the 'read_permission' relation to CWComputedRType, and the appropriate hooks to save and restore those permissions. To avoid having to touch yams, we drop the 'add' and 'delete' permissions from the default computed relation permissions; this should probably be backported there. The actual permissions (set on the relation definitions) are hardcoded in finalize_computed_relations anyway. In deserialize_schema, the CWComputedRType handling needs to be delayed a little bit, until after we've called deserialize_ertype_permissions. The rql2sql test is adjusted because CWComputedRType has a 'name' attribute and the 'read_permission' relation, which generates ambiguity vs CWEType. We add an explicit CubicWebRelationSchema.check_permission_definitions, since we need to check both that computed and non-computed rtypes are defined properly. Based on report and initial patch from Christophe de Vienne (thanks!). Closes #5706307
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     1
# copyright 2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     3
#
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     4
# This file is part of CubicWeb.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     5
#
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
     9
# any later version.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    10
#
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    14
# details.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    15
#
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    18
"""Hooks for synchronizing computed attributes"""
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    19
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    20
__docformat__ = "restructuredtext en"
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    21
_ = unicode
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    22
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    23
from collections import defaultdict
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    24
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    25
from rql import nodes
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    26
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    27
from cubicweb.server import hook
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    28
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    29
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    30
class RecomputeAttributeOperation(hook.DataOperationMixIn, hook.Operation):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    31
    """Operation to recompute caches of computed attribute at commit time,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    32
    depending on what's have been modified in the transaction and avoiding to
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    33
    recompute twice the same attribute
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    34
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    35
    containercls = dict
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    36
    def add_data(self, computed_attribute, eid=None):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    37
        try:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    38
            self._container[computed_attribute].add(eid)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    39
        except KeyError:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    40
            self._container[computed_attribute] = set((eid,))
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    41
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    42
    def precommit_event(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    43
        for computed_attribute_rdef, eids in self.get_data().iteritems():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    44
            attr = computed_attribute_rdef.rtype
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    45
            formula  = computed_attribute_rdef.formula
10395
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    46
            select = self.cnx.repo.vreg.rqlhelper.parse(formula).children[0]
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    47
            xvar = select.get_variable('X')
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    48
            select.add_selected(xvar, index=0)
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    49
            select.add_group_var(xvar, index=0)
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    50
            if None in eids:
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    51
                select.add_type_restriction(xvar, computed_attribute_rdef.subject)
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    52
            else:
10395
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    53
                select.add_eid_restriction(xvar, eids)
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    54
            update_rql = 'SET X %s %%(value)s WHERE X eid %%(x)s' % attr
10395
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    55
            for eid, value in self.cnx.execute(select.as_string()):
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    56
                self.cnx.execute(update_rql, {'value': value, 'x': eid})
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    57
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    58
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    59
class EntityWithCACreatedHook(hook.Hook):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    60
    """When creating an entity that has some computed attribute, those
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    61
    attributes have to be computed.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    62
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    63
    Concret class of this hook are generated at registration time by
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    64
    introspecting the schema.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    65
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    66
    __abstract__ = True
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    67
    events = ('after_add_entity',)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    68
    # list of computed attribute rdefs that have to be recomputed
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    69
    computed_attributes = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    70
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    71
    def __call__(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    72
        for rdef in self.computed_attributes:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    73
            RecomputeAttributeOperation.get_instance(self._cw).add_data(
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    74
                rdef, self.entity.eid)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    75
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    76
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    77
class RelationInvolvedInCAModifiedHook(hook.Hook):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    78
    """When some relation used in a computed attribute is updated, those
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    79
    attributes have to be recomputed.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    80
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    81
    Concret class of this hook are generated at registration time by
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    82
    introspecting the schema.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    83
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    84
    __abstract__ = True
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    85
    events = ('after_add_relation', 'before_delete_relation')
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    86
    # list of (computed attribute rdef, optimize_on) that have to be recomputed
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    87
    optimized_computed_attributes = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    88
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    89
    def __call__(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    90
        for rdef, optimize_on in self.optimized_computed_attributes:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    91
            if optimize_on is None:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    92
                eid = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    93
            else:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    94
                eid = getattr(self, optimize_on)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    95
            RecomputeAttributeOperation.get_instance(self._cw).add_data(rdef, eid)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    96
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    97
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    98
class AttributeInvolvedInCAModifiedHook(hook.Hook):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    99
    """When some attribute used in a computed attribute is updated, those
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   100
    attributes have to be recomputed.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   101
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   102
    Concret class of this hook are generated at registration time by
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   103
    introspecting the schema.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   104
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   105
    __abstract__ = True
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   106
    events = ('after_update_entity',)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   107
    # list of (computed attribute rdef, attributes of this entity type involved)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   108
    # that may have to be recomputed
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   109
    attributes_computed_attributes = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   110
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   111
    def __call__(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   112
        edited_attributes = frozenset(self.entity.cw_edited)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   113
        for rdef, used_attributes in self.attributes_computed_attributes.iteritems():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   114
            if edited_attributes.intersection(used_attributes):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   115
                # XXX optimize if the modified attributes belong to the same
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   116
                # entity as the computed attribute
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   117
                RecomputeAttributeOperation.get_instance(self._cw).add_data(rdef)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   118
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   119
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   120
# code generation at registration time #########################################
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   121
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   122
def _optimize_on(formula_select, rtype):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   123
    """Given a formula and some rtype, tells whether on update of the given
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   124
    relation, formula may be recomputed only for rhe relation's subject
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   125
    ('eidfrom' returned), object ('eidto' returned) or None.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   126
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   127
    Optimizing is only possible when X is used as direct subject/object of this
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   128
    relation, else we may miss some necessary update.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   129
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   130
    for rel in formula_select.get_nodes(nodes.Relation):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   131
        if rel.r_type == rtype:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   132
            sub = rel.get_variable_parts()[0]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   133
            obj = rel.get_variable_parts()[1]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   134
            if sub.name == 'X':
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   135
                return 'eidfrom'
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   136
            elif obj.name == 'X':
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   137
                return 'eidto'
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   138
            else:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   139
                return None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   140
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   141
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   142
class _FormulaDependenciesMatrix(object):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   143
    """This class computes and represents the dependencies of computed attributes
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   144
    towards relations and attributes
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   145
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   146
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   147
    def __init__(self, schema):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   148
        """Analyzes the schema to compute the dependencies"""
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   149
        # entity types holding some computed attribute {etype: [computed rdefs]}
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   150
        self.computed_attribute_by_etype = defaultdict(list)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   151
        # depending entity types {dep. etype: {computed rdef: dep. etype attributes}}
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   152
        self.computed_attribute_by_etype_attrs = defaultdict(lambda: defaultdict(set))
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   153
        # depending relations def {dep. rdef: [computed rdefs]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   154
        self.computed_attribute_by_relation = defaultdict(list) # by rdef
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   155
        # Walk through all attributes definitions
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   156
        for rdef in schema.iter_computed_attributes():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   157
            self.computed_attribute_by_etype[rdef.subject.type].append(rdef)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   158
            # extract the relations it depends upon - `rdef.formula_select` is
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   159
            # expected to have been set by finalize_computed_attributes
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   160
            select = rdef.formula_select
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   161
            for rel_node in select.get_nodes(nodes.Relation):
10192
365e5a0287d6 [computed attribute] ensure attribute's formula apply only to the correct type. Closes #4901163
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9967
diff changeset
   162
                if rel_node.is_types_restriction():
365e5a0287d6 [computed attribute] ensure attribute's formula apply only to the correct type. Closes #4901163
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9967
diff changeset
   163
                    continue
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   164
                rschema = schema.rschema(rel_node.r_type)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   165
                lhs, rhs = rel_node.get_variable_parts()
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   166
                for sol in select.solutions:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   167
                    subject_etype = sol[lhs.name]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   168
                    if isinstance(rhs, nodes.VariableRef):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   169
                        object_etypes = set(sol[rhs.name] for sol in select.solutions)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   170
                    else:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   171
                        object_etypes = rschema.objects(subject_etype)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   172
                    for object_etype in object_etypes:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   173
                        if rschema.final:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   174
                            attr_for_computations = self.computed_attribute_by_etype_attrs[subject_etype]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   175
                            attr_for_computations[rdef].add(rschema.type)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   176
                        else:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   177
                            depend_on_rdef = rschema.rdefs[subject_etype, object_etype]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   178
                            self.computed_attribute_by_relation[depend_on_rdef].append(rdef)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   179
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   180
    def generate_entity_creation_hooks(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   181
        for etype, computed_attributes in self.computed_attribute_by_etype.iteritems():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   182
            regid = 'computed_attribute.%s_created' % etype
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   183
            selector = hook.is_instance(etype)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   184
            yield type('%sCreatedHook' % etype,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   185
                       (EntityWithCACreatedHook,),
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   186
                       {'__regid__': regid,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   187
                        '__select__':  hook.Hook.__select__ & selector,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   188
                        'computed_attributes': computed_attributes})
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   189
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   190
    def generate_relation_change_hooks(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   191
        for rdef, computed_attributes in self.computed_attribute_by_relation.iteritems():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   192
            regid = 'computed_attribute.%s_modified' % rdef.rtype
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   193
            selector = hook.match_rtype(rdef.rtype.type,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   194
                                        frometypes=(rdef.subject.type,),
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   195
                                        toetypes=(rdef.object.type,))
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   196
            optimized_computed_attributes = []
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   197
            for computed_rdef in computed_attributes:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   198
                optimized_computed_attributes.append(
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   199
                    (computed_rdef,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   200
                     _optimize_on(computed_rdef.formula_select, rdef.rtype))
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   201
                     )
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   202
            yield type('%sModifiedHook' % rdef.rtype,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   203
                       (RelationInvolvedInCAModifiedHook,),
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   204
                       {'__regid__': regid,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   205
                        '__select__':  hook.Hook.__select__ & selector,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   206
                        'optimized_computed_attributes': optimized_computed_attributes})
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   207
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   208
    def generate_entity_update_hooks(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   209
        for etype, attributes_computed_attributes in self.computed_attribute_by_etype_attrs.iteritems():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   210
            regid = 'computed_attribute.%s_updated' % etype
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   211
            selector = hook.is_instance(etype)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   212
            yield type('%sModifiedHook' % etype,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   213
                       (AttributeInvolvedInCAModifiedHook,),
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   214
                       {'__regid__': regid,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   215
                        '__select__':  hook.Hook.__select__ & selector,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   216
                        'attributes_computed_attributes': attributes_computed_attributes})
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   217
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   218
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   219
def registration_callback(vreg):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   220
    vreg.register_all(globals().values(), __name__)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   221
    dependencies = _FormulaDependenciesMatrix(vreg.schema)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   222
    for hook_class in dependencies.generate_entity_creation_hooks():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   223
        vreg.register(hook_class)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   224
    for hook_class in dependencies.generate_relation_change_hooks():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   225
        vreg.register(hook_class)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   226
    for hook_class in dependencies.generate_entity_update_hooks():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   227
        vreg.register(hook_class)