--- a/rset.py Fri Jan 28 15:12:13 2011 +0100
+++ b/rset.py Fri Jan 28 15:15:14 2011 +0100
@@ -487,24 +487,21 @@
select = rqlst
# take care, due to outer join support, we may find None
# values for non final relation
- for i, attr, role in attr_desc_iterator(select, col):
- outerselidx = rqlst.subquery_selection_index(select, i)
- if outerselidx is None:
- continue
+ for i, attr, role in attr_desc_iterator(select, col, entity.cw_col):
if role == 'subject':
rschema = eschema.subjrels[attr]
if rschema.final:
if attr == 'eid':
- entity.eid = rowvalues[outerselidx]
+ entity.eid = rowvalues[i]
else:
- entity.cw_attr_cache[attr] = rowvalues[outerselidx]
+ entity.cw_attr_cache[attr] = rowvalues[i]
continue
else:
rschema = eschema.objrels[attr]
rdef = eschema.rdef(attr, role)
# only keep value if it can't be multivalued
if rdef.role_cardinality(role) in '1?':
- if rowvalues[outerselidx] is None:
+ if rowvalues[i] is None:
if role == 'subject':
rql = 'Any Y WHERE X %s Y, X eid %s'
else:
@@ -512,7 +509,7 @@
rrset = ResultSet([], rql % (attr, entity.eid))
rrset.req = req
else:
- rrset = self._build_entity(row, outerselidx).as_rset()
+ rrset = self._build_entity(row, i).as_rset()
entity.cw_set_relation_cache(attr, role, rrset)
return entity
@@ -650,8 +647,13 @@
return rhs.eval(self.args)
return None
+def _get_variable(term):
+ # XXX rewritten const
+ # use iget_nodes for (hack) case where we have things like MAX(V)
+ for vref in term.iget_nodes(nodes.VariableRef):
+ return vref.variable
-def attr_desc_iterator(rqlst, index=0):
+def attr_desc_iterator(select, selectidx, rootidx):
"""return an iterator on a list of 2-uple (index, attr_relation)
localizing attribute relations of the main variable in a result's row
@@ -662,25 +664,33 @@
a generator on (index, relation, target) describing column being
attribute of the main variable
"""
- main = rqlst.selection[index]
- for i, term in enumerate(rqlst.selection):
- if i == index:
+ rootselect = select
+ while rootselect.parent.parent is not None:
+ rootselect = rootselect.parent.parent.parent
+ rootmain = rootselect.selection[selectidx]
+ rootmainvar = _get_variable(rootmain)
+ assert rootmainvar
+ root = rootselect.parent
+ selectmain = select.selection[selectidx]
+ for i, term in enumerate(rootselect.selection):
+ rootvar = _get_variable(term)
+ if rootvar is None:
continue
- # XXX rewritten const
- # use iget_nodes for (hack) case where we have things like MAX(V)
- for vref in term.iget_nodes(nodes.VariableRef):
- var = vref.variable
- break
- else:
+ if rootvar.name == rootmainvar.name:
+ continue
+ if select is not rootselect:
+ term = select.selection[root.subquery_selection_index(select, i)]
+ var = _get_variable(term)
+ if var is None:
continue
for ref in var.references():
rel = ref.relation()
if rel is None or rel.is_types_restriction():
continue
lhs, rhs = rel.get_variable_parts()
- if main.is_equivalent(lhs):
+ if selectmain.is_equivalent(lhs):
if rhs.is_equivalent(term):
yield (i, rel.r_type, 'subject')
- elif main.is_equivalent(rhs):
+ elif selectmain.is_equivalent(rhs):
if lhs.is_equivalent(term):
yield (i, rel.r_type, 'object')
--- a/test/unittest_rset.py Fri Jan 28 15:12:13 2011 +0100
+++ b/test/unittest_rset.py Fri Jan 28 15:15:14 2011 +0100
@@ -49,7 +49,7 @@
'Any C where C is Company, C employs P' : [],
}
for rql, relations in queries.items():
- result = list(attr_desc_iterator(parse(rql).children[0]))
+ result = list(attr_desc_iterator(parse(rql).children[0], 0, 0))
self.assertEqual((rql, result), (rql, relations))
def test_relations_description_indexed(self):
@@ -59,8 +59,8 @@
{0: [(2,'employs', 'subject')], 1: [(3,'login', 'subject'), (4,'mail', 'subject')]},
}
for rql, results in queries.items():
- for var_index, relations in results.items():
- result = list(attr_desc_iterator(parse(rql).children[0], var_index))
+ for idx, relations in results.items():
+ result = list(attr_desc_iterator(parse(rql).children[0], idx, idx))
self.assertEqual(result, relations)
@@ -328,7 +328,7 @@
self.assertEqual(entity, None)
self.assertEqual(rtype, None)
- def test_related_entity_union_subquery(self):
+ def test_related_entity_union_subquery_1(self):
e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path')
rset = self.execute('Any X,N ORDERBY N WITH X,N BEING '
'((Any X,N WHERE X is CWGroup, X name N)'
@@ -337,10 +337,14 @@
entity, rtype = rset.related_entity(0, 1)
self.assertEqual(entity.eid, e.eid)
self.assertEqual(rtype, 'title')
+ self.assertEqual(entity.title, 'aaaa')
entity, rtype = rset.related_entity(1, 1)
self.assertEqual(entity.__regid__, 'CWGroup')
self.assertEqual(rtype, 'name')
- #
+ self.assertEqual(entity.name, 'guests')
+
+ def test_related_entity_union_subquery_2(self):
+ e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path')
rset = self.execute('Any X,N ORDERBY N WHERE X is Bookmark WITH X,N BEING '
'((Any X,N WHERE X is CWGroup, X name N)'
' UNION '
@@ -348,7 +352,10 @@
entity, rtype = rset.related_entity(0, 1)
self.assertEqual(entity.eid, e.eid)
self.assertEqual(rtype, 'title')
- #
+ self.assertEqual(entity.title, 'aaaa')
+
+ def test_related_entity_union_subquery_3(self):
+ e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path')
rset = self.execute('Any X,N ORDERBY N WITH N,X BEING '
'((Any N,X WHERE X is CWGroup, X name N)'
' UNION '
@@ -356,6 +363,18 @@
entity, rtype = rset.related_entity(0, 1)
self.assertEqual(entity.eid, e.eid)
self.assertEqual(rtype, 'title')
+ self.assertEqual(entity.title, 'aaaa')
+
+ def test_related_entity_union_subquery_4(self):
+ e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path')
+ rset = self.execute('Any X,X, N ORDERBY N WITH X,N BEING '
+ '((Any X,N WHERE X is CWGroup, X name N)'
+ ' UNION '
+ ' (Any X,N WHERE X is Bookmark, X title N))')
+ entity, rtype = rset.related_entity(0, 2)
+ self.assertEqual(entity.eid, e.eid)
+ self.assertEqual(rtype, 'title')
+ self.assertEqual(entity.title, 'aaaa')
def test_related_entity_trap_subquery(self):
req = self.request()