473 entity = self.req.vreg['etypes'].etype_class(etype)(req, rset=self, |
473 entity = self.req.vreg['etypes'].etype_class(etype)(req, rset=self, |
474 row=row, col=col) |
474 row=row, col=col) |
475 entity.eid = eid |
475 entity.eid = eid |
476 # cache entity |
476 # cache entity |
477 req.set_entity_cache(entity) |
477 req.set_entity_cache(entity) |
478 eschema = entity.e_schema |
|
479 # try to complete the entity if there are some additional columns |
478 # try to complete the entity if there are some additional columns |
480 if len(rowvalues) > 1: |
479 if len(rowvalues) > 1: |
481 rqlst = self.syntax_tree() |
480 eschema = entity.e_schema |
482 if rqlst.TYPE == 'select': |
481 eid_col, attr_cols, rel_cols = self._rset_structure(eschema, col) |
483 # UNION query, find the subquery from which this entity has been |
482 entity.eid = rowvalues[eid_col] |
484 # found |
483 for attr, col_idx in attr_cols.items(): |
485 select, col = rqlst.locate_subquery(col, etype, self.args) |
484 entity.cw_attr_cache[attr] = rowvalues[col_idx] |
|
485 for (rtype, role), col_idx in rel_cols.items(): |
|
486 value = rowvalues[col_idx] |
|
487 if value is None: |
|
488 if role == 'subject': |
|
489 rql = 'Any Y WHERE X %s Y, X eid %s' |
|
490 else: |
|
491 rql = 'Any Y WHERE Y %s X, X eid %s' |
|
492 rrset = ResultSet([], rql % (rtype, entity.eid)) |
|
493 rrset.req = req |
|
494 else: |
|
495 rrset = self._build_entity(row, col_idx).as_rset() |
|
496 entity.cw_set_relation_cache(rtype, role, rrset) |
|
497 return entity |
|
498 |
|
499 @cached |
|
500 def _rset_structure(self, eschema, entity_col): |
|
501 eid_col = col = entity_col |
|
502 rqlst = self.syntax_tree() |
|
503 attr_cols = {} |
|
504 rel_cols = {} |
|
505 if rqlst.TYPE == 'select': |
|
506 # UNION query, find the subquery from which this entity has been |
|
507 # found |
|
508 select, col = rqlst.locate_subquery(entity_col, eschema.type, self.args) |
|
509 else: |
|
510 select = rqlst |
|
511 # take care, due to outer join support, we may find None |
|
512 # values for non final relation |
|
513 for i, attr, role in attr_desc_iterator(select, col, entity_col): |
|
514 if role == 'subject': |
|
515 rschema = eschema.subjrels[attr] |
486 else: |
516 else: |
487 select = rqlst |
517 rschema = eschema.objrels[attr] |
488 # take care, due to outer join support, we may find None |
518 if rschema.final: |
489 # values for non final relation |
519 if attr == 'eid': |
490 for i, attr, role in attr_desc_iterator(select, col, entity.cw_col): |
520 eid_col = i |
491 if role == 'subject': |
|
492 rschema = eschema.subjrels[attr] |
|
493 if rschema.final: |
|
494 if attr == 'eid': |
|
495 entity.eid = rowvalues[i] |
|
496 else: |
|
497 entity.cw_attr_cache[attr] = rowvalues[i] |
|
498 continue |
|
499 else: |
521 else: |
500 rschema = eschema.objrels[attr] |
522 attr_cols[attr] = i |
|
523 else: |
501 rdef = eschema.rdef(attr, role) |
524 rdef = eschema.rdef(attr, role) |
502 # only keep value if it can't be multivalued |
525 # only keep value if it can't be multivalued |
503 if rdef.role_cardinality(role) in '1?': |
526 if rdef.role_cardinality(role) in '1?': |
504 if rowvalues[i] is None: |
527 rel_cols[(attr, role)] = i |
505 if role == 'subject': |
528 return eid_col, attr_cols, rel_cols |
506 rql = 'Any Y WHERE X %s Y, X eid %s' |
|
507 else: |
|
508 rql = 'Any Y WHERE Y %s X, X eid %s' |
|
509 rrset = ResultSet([], rql % (attr, entity.eid)) |
|
510 rrset.req = req |
|
511 else: |
|
512 rrset = self._build_entity(row, i).as_rset() |
|
513 entity.cw_set_relation_cache(attr, role, rrset) |
|
514 return entity |
|
515 |
529 |
516 @cached |
530 @cached |
517 def syntax_tree(self): |
531 def syntax_tree(self): |
518 """get the syntax tree for the source query. |
532 """get the syntax tree for the source query. |
519 |
533 |