author | Erica Marco <erica.marco@logilab.fr> |
Mon, 23 Mar 2015 11:08:04 +0100 | |
changeset 10281 | cc9eb88377f4 |
parent 10192 | 365e5a0287d6 |
child 10395 | 7e311ee8b5b0 |
permissions | -rw-r--r-- |
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 |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
46 |
rql = formula.replace('Any ', 'Any X, ', 1) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
47 |
kwargs = None |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
48 |
# add constraint on X to the formula |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
49 |
if None in eids : # recompute for all etype if None is found |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
50 |
rql += ', X is %s' % computed_attribute_rdef.subject |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
51 |
elif len(eids) == 1: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
52 |
rql += ', X eid %(x)s' |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
53 |
kwargs = {'x': eids.pop()} |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
54 |
else: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
55 |
rql += ', X eid IN (%s)' % ', '.join((str(eid) for eid in eids)) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
56 |
update_rql = 'SET X %s %%(value)s WHERE X eid %%(x)s' % attr |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
57 |
for eid, value in self.cnx.execute(rql, kwargs): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
58 |
self.cnx.execute(update_rql, {'value': value, 'x': eid}) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
59 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
60 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
61 |
class EntityWithCACreatedHook(hook.Hook): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
62 |
"""When creating an entity that has some computed attribute, those |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
63 |
attributes have to be computed. |
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 |
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
|
66 |
introspecting the schema. |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
67 |
""" |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
68 |
__abstract__ = True |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
69 |
events = ('after_add_entity',) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
70 |
# list of computed attribute rdefs that have to be recomputed |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
71 |
computed_attributes = None |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
72 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
73 |
def __call__(self): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
74 |
for rdef in self.computed_attributes: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
75 |
RecomputeAttributeOperation.get_instance(self._cw).add_data( |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
76 |
rdef, self.entity.eid) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
77 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
78 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
79 |
class RelationInvolvedInCAModifiedHook(hook.Hook): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
80 |
"""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
|
81 |
attributes have to be recomputed. |
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 |
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
|
84 |
introspecting the schema. |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
85 |
""" |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
86 |
__abstract__ = True |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
87 |
events = ('after_add_relation', 'before_delete_relation') |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
88 |
# 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
|
89 |
optimized_computed_attributes = None |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
90 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
91 |
def __call__(self): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
92 |
for rdef, optimize_on in self.optimized_computed_attributes: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
93 |
if optimize_on is None: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
94 |
eid = None |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
95 |
else: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
96 |
eid = getattr(self, optimize_on) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
97 |
RecomputeAttributeOperation.get_instance(self._cw).add_data(rdef, eid) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
98 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
99 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
100 |
class AttributeInvolvedInCAModifiedHook(hook.Hook): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
101 |
"""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
|
102 |
attributes have to be recomputed. |
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 |
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
|
105 |
introspecting the schema. |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
106 |
""" |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
107 |
__abstract__ = True |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
108 |
events = ('after_update_entity',) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
109 |
# 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
|
110 |
# that may have to be recomputed |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
111 |
attributes_computed_attributes = None |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
112 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
113 |
def __call__(self): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
114 |
edited_attributes = frozenset(self.entity.cw_edited) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
115 |
for rdef, used_attributes in self.attributes_computed_attributes.iteritems(): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
116 |
if edited_attributes.intersection(used_attributes): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
117 |
# XXX optimize if the modified attributes belong to the same |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
118 |
# entity as the computed attribute |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
119 |
RecomputeAttributeOperation.get_instance(self._cw).add_data(rdef) |
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 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
122 |
# code generation at registration time ######################################### |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
123 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
124 |
def _optimize_on(formula_select, rtype): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
125 |
"""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
|
126 |
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
|
127 |
('eidfrom' returned), object ('eidto' returned) or None. |
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 |
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
|
130 |
relation, else we may miss some necessary update. |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
131 |
""" |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
132 |
for rel in formula_select.get_nodes(nodes.Relation): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
133 |
if rel.r_type == rtype: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
134 |
sub = rel.get_variable_parts()[0] |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
135 |
obj = rel.get_variable_parts()[1] |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
136 |
if sub.name == 'X': |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
137 |
return 'eidfrom' |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
138 |
elif obj.name == 'X': |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
139 |
return 'eidto' |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
140 |
else: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
141 |
return None |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
142 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
143 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
144 |
class _FormulaDependenciesMatrix(object): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
145 |
"""This class computes and represents the dependencies of computed attributes |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
146 |
towards relations and attributes |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
147 |
""" |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
148 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
149 |
def __init__(self, schema): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
150 |
"""Analyzes the schema to compute the dependencies""" |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
151 |
# entity types holding some computed attribute {etype: [computed rdefs]} |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
152 |
self.computed_attribute_by_etype = defaultdict(list) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
153 |
# depending entity types {dep. etype: {computed rdef: dep. etype attributes}} |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
154 |
self.computed_attribute_by_etype_attrs = defaultdict(lambda: defaultdict(set)) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
155 |
# depending relations def {dep. rdef: [computed rdefs] |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
156 |
self.computed_attribute_by_relation = defaultdict(list) # by rdef |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
157 |
# Walk through all attributes definitions |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
158 |
for rdef in schema.iter_computed_attributes(): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
159 |
self.computed_attribute_by_etype[rdef.subject.type].append(rdef) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
160 |
# extract the relations it depends upon - `rdef.formula_select` is |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
161 |
# expected to have been set by finalize_computed_attributes |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
162 |
select = rdef.formula_select |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
163 |
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
|
164 |
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
|
165 |
continue |
9967
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
166 |
rschema = schema.rschema(rel_node.r_type) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
167 |
lhs, rhs = rel_node.get_variable_parts() |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
168 |
for sol in select.solutions: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
169 |
subject_etype = sol[lhs.name] |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
170 |
if isinstance(rhs, nodes.VariableRef): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
171 |
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
|
172 |
else: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
173 |
object_etypes = rschema.objects(subject_etype) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
174 |
for object_etype in object_etypes: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
175 |
if rschema.final: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
176 |
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
|
177 |
attr_for_computations[rdef].add(rschema.type) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
178 |
else: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
179 |
depend_on_rdef = rschema.rdefs[subject_etype, object_etype] |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
180 |
self.computed_attribute_by_relation[depend_on_rdef].append(rdef) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
181 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
182 |
def generate_entity_creation_hooks(self): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
183 |
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
|
184 |
regid = 'computed_attribute.%s_created' % etype |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
185 |
selector = hook.is_instance(etype) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
186 |
yield type('%sCreatedHook' % etype, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
187 |
(EntityWithCACreatedHook,), |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
188 |
{'__regid__': regid, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
189 |
'__select__': hook.Hook.__select__ & selector, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
190 |
'computed_attributes': computed_attributes}) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
191 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
192 |
def generate_relation_change_hooks(self): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
193 |
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
|
194 |
regid = 'computed_attribute.%s_modified' % rdef.rtype |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
195 |
selector = hook.match_rtype(rdef.rtype.type, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
196 |
frometypes=(rdef.subject.type,), |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
197 |
toetypes=(rdef.object.type,)) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
198 |
optimized_computed_attributes = [] |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
199 |
for computed_rdef in computed_attributes: |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
200 |
optimized_computed_attributes.append( |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
201 |
(computed_rdef, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
202 |
_optimize_on(computed_rdef.formula_select, rdef.rtype)) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
203 |
) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
204 |
yield type('%sModifiedHook' % rdef.rtype, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
205 |
(RelationInvolvedInCAModifiedHook,), |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
206 |
{'__regid__': regid, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
207 |
'__select__': hook.Hook.__select__ & selector, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
208 |
'optimized_computed_attributes': optimized_computed_attributes}) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
209 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
210 |
def generate_entity_update_hooks(self): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
211 |
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
|
212 |
regid = 'computed_attribute.%s_updated' % etype |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
213 |
selector = hook.is_instance(etype) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
214 |
yield type('%sModifiedHook' % etype, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
215 |
(AttributeInvolvedInCAModifiedHook,), |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
216 |
{'__regid__': regid, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
217 |
'__select__': hook.Hook.__select__ & selector, |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
218 |
'attributes_computed_attributes': attributes_computed_attributes}) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
219 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
220 |
|
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
221 |
def registration_callback(vreg): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
222 |
vreg.register_all(globals().values(), __name__) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
223 |
dependencies = _FormulaDependenciesMatrix(vreg.schema) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
224 |
for hook_class in dependencies.generate_entity_creation_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_relation_change_hooks(): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
227 |
vreg.register(hook_class) |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
228 |
for hook_class in dependencies.generate_entity_update_hooks(): |
e65873ad0371
[CWEP002] Add support for computed attribute synchronization
Sylvain Thénault
parents:
diff
changeset
|
229 |
vreg.register(hook_class) |