cubicweb/hooks/synccomputed.py
author Philippe Pepiot <ph@itsalwaysdns.eu>
Tue, 31 Mar 2020 19:15:03 +0200
changeset 12957 0c973204033a
parent 12227 dc333e9104c9
permissions -rw-r--r--
[server] prevent returning closed cursor to the database pool In since c8c6ad8 init_repository use repo.internal_cnx() instead of repo.system_source.get_connection() so it use the pool and we should not close cursors from the pool before returning it back. Otherwise we may have "connection already closed" error. This bug only trigger when connection-pool-size = 1. Since we are moving to use a dynamic pooler we need to get this fixed. This does not occur with sqlite since the connection wrapper instantiate new cursor everytime, but this occur with other databases.
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
11767
432f87a63057 flake8 and all
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
    20
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    21
from collections import defaultdict
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 rql import nodes
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 cubicweb.server import hook
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
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    28
class RecomputeAttributeOperation(hook.DataOperationMixIn, hook.Operation):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    29
    """Operation to recompute caches of computed attribute at commit time,
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    30
    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
    31
    recompute twice the same attribute
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    32
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    33
    containercls = dict
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
    34
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    35
    def add_data(self, computed_attribute, eid=None):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    36
        try:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    37
            self._container[computed_attribute].add(eid)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    38
        except KeyError:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    39
            self._container[computed_attribute] = set((eid,))
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    40
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    41
    def precommit_event(self):
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10395
diff changeset
    42
        for computed_attribute_rdef, eids in self.get_data().items():
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    43
            attr = computed_attribute_rdef.rtype
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
    44
            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
    45
            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
    46
            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
    47
            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
    48
            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
    49
            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
    50
                select.add_type_restriction(xvar, computed_attribute_rdef.subject)
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    51
            else:
10395
7e311ee8b5b0 [hooks] manhandle the parsed rql query, not its string representation
Julien Cristau <julien.cristau@logilab.fr>
parents: 10192
diff changeset
    52
                select.add_eid_restriction(xvar, eids)
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    53
            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
    54
            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
    55
                self.cnx.execute(update_rql, {'value': value, 'x': eid})
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    56
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
class EntityWithCACreatedHook(hook.Hook):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    59
    """When creating an entity that has some computed attribute, those
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    60
    attributes have to be computed.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    61
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    62
    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
    63
    introspecting the schema.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    64
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    65
    __abstract__ = True
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    66
    events = ('after_add_entity',)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    67
    # list of computed attribute rdefs that have to be recomputed
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    68
    computed_attributes = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    69
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    70
    def __call__(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    71
        for rdef in self.computed_attributes:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    72
            RecomputeAttributeOperation.get_instance(self._cw).add_data(
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    73
                rdef, self.entity.eid)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    74
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
class RelationInvolvedInCAModifiedHook(hook.Hook):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    77
    """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
    78
    attributes have to be recomputed.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    79
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    80
    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
    81
    introspecting the schema.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    82
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    83
    __abstract__ = True
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    84
    events = ('after_add_relation', 'before_delete_relation')
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    85
    # 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
    86
    optimized_computed_attributes = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    87
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    88
    def __call__(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    89
        for rdef, optimize_on in self.optimized_computed_attributes:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    90
            if optimize_on is None:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    91
                eid = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    92
            else:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    93
                eid = getattr(self, optimize_on)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    94
            RecomputeAttributeOperation.get_instance(self._cw).add_data(rdef, eid)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    95
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
class AttributeInvolvedInCAModifiedHook(hook.Hook):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
    98
    """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
    99
    attributes have to be recomputed.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   100
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   101
    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
   102
    introspecting the schema.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   103
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   104
    __abstract__ = True
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   105
    events = ('after_update_entity',)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   106
    # 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
   107
    # that may have to be recomputed
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   108
    attributes_computed_attributes = None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   109
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   110
    def __call__(self):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   111
        edited_attributes = frozenset(self.entity.cw_edited)
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10395
diff changeset
   112
        for rdef, used_attributes in self.attributes_computed_attributes.items():
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   113
            if edited_attributes.intersection(used_attributes):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   114
                # XXX optimize if the modified attributes belong to the same
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   115
                # entity as the computed attribute
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   116
                RecomputeAttributeOperation.get_instance(self._cw).add_data(rdef)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   117
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
# code generation at registration time #########################################
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   120
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   121
def _optimize_on(formula_select, rtype):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   122
    """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
   123
    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
   124
    ('eidfrom' returned), object ('eidto' returned) or None.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   125
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   126
    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
   127
    relation, else we may miss some necessary update.
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   128
    """
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   129
    for rel in formula_select.get_nodes(nodes.Relation):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   130
        if rel.r_type == rtype:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   131
            sub = rel.get_variable_parts()[0]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   132
            obj = rel.get_variable_parts()[1]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   133
            if sub.name == 'X':
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   134
                return 'eidfrom'
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   135
            elif obj.name == 'X':
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   136
                return 'eidto'
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   137
            else:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   138
                return None
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   139
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
class _FormulaDependenciesMatrix(object):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   142
    """This class computes and represents the dependencies of computed attributes
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   143
    towards relations and attributes
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   144
    """
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
    def __init__(self, schema):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   147
        """Analyzes the schema to compute the dependencies"""
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   148
        # entity types holding some computed attribute {etype: [computed rdefs]}
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   149
        self.computed_attribute_by_etype = defaultdict(list)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   150
        # depending entity types {dep. etype: {computed rdef: dep. etype attributes}}
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   151
        self.computed_attribute_by_etype_attrs = defaultdict(lambda: defaultdict(set))
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   152
        # depending relations def {dep. rdef: [computed rdefs]
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   153
        self.computed_attribute_by_relation = defaultdict(list)  # by rdef
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   154
        # Walk through all attributes definitions
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   155
        for rdef in schema.iter_computed_attributes():
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   156
            self.computed_attribute_by_etype[rdef.subject.type].append(rdef)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   157
            # extract the relations it depends upon - `rdef.formula_select` is
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   158
            # expected to have been set by finalize_computed_attributes
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   159
            select = rdef.formula_select
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   160
            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
   161
                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
   162
                    continue
9967
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   163
                rschema = schema.rschema(rel_node.r_type)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   164
                lhs, rhs = rel_node.get_variable_parts()
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   165
                for sol in select.solutions:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   166
                    subject_etype = sol[lhs.name]
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   167
                    if isinstance(rhs, nodes.VariableRef):
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   168
                        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
   169
                    else:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   170
                        object_etypes = rschema.objects(subject_etype)
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   171
                    for object_etype in object_etypes:
e65873ad0371 [CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff changeset
   172
                        if rschema.final:
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   173
                            attr_for_computations = self.computed_attribute_by_etype_attrs[
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   174
                                subject_etype]
9967
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):
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10395
diff changeset
   181
        for etype, computed_attributes in self.computed_attribute_by_etype.items():
9967
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,
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   187
                        '__select__': hook.Hook.__select__ & selector,
9967
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):
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10395
diff changeset
   191
        for rdef, computed_attributes in self.computed_attribute_by_relation.items():
9967
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))
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   201
                )
9967
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,
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   205
                        '__select__': hook.Hook.__select__ & selector,
9967
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):
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10395
diff changeset
   209
        for etype, attributes_computed_attributes in self.computed_attribute_by_etype_attrs.items():
9967
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,
12227
dc333e9104c9 [cleanup] Fix some flake8 errors
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   215
                        '__select__': hook.Hook.__select__ & selector,
9967
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)