schema.py
changeset 9952 0f3f965b6365
parent 9951 8cdcbf3f4fd0
child 9957 5def1d98fce7
--- a/schema.py	Fri Sep 12 14:10:03 2014 +0200
+++ b/schema.py	Fri Sep 12 14:46:11 2014 +0200
@@ -41,6 +41,7 @@
                          fill_schema_from_namespace)
 
 from rql import parse, nodes, RQLSyntaxError, TypeResolverException
+from rql.analyze import ETypeResolver
 
 import cubicweb
 from cubicweb import ETYPE_NAME_MAP, ValidationError, Unauthorized
@@ -1007,6 +1008,35 @@
     def schema_by_eid(self, eid):
         return self._eid_index[eid]
 
+    def iter_computed_relations(self):
+        for relation in self.relations():
+            if relation.rule:
+                yield relation
+
+    def finalize(self):
+        super(CubicWebSchema, self).finalize()
+        self.finalize_computed_relations()
+
+    def finalize_computed_relations(self):
+        """Build relation definitions for computed relations
+
+        The subject and object types are infered using rql analyzer.
+        """
+        analyzer = ETypeResolver(self)
+        for rschema in self.iter_computed_relations():
+            # XXX rule is valid if both S and O are defined and not in an exists
+            rqlexpr = RRQLExpression(rschema.rule)
+            rqlst = rqlexpr.snippet_rqlst
+            analyzer.visit(rqlst)
+            couples = set((sol['S'], sol['O']) for sol in rqlst.solutions)
+            for subjtype, objtype in couples:
+                if self[objtype].final:
+                    raise BadSchemaDefinition('computed relations cannot be final')
+                rdef = ybo.RelationDefinition(
+                    subjtype, rschema.type, objtype)
+                rdef.infered = True
+                self.add_relation_def(rdef)
+
 
 # additional cw specific constraints ###########################################