468 entity.eid = self.rows[row][col] |
468 entity.eid = self.rows[row][col] |
469 # cache entity |
469 # cache entity |
470 self.req.set_entity_cache(entity) |
470 self.req.set_entity_cache(entity) |
471 return entity |
471 return entity |
472 |
472 |
473 def _build_entity(self, row, col): |
473 def _build_entity(self, row, col, seen=None): |
474 """internal method to get a single entity, returns a partially |
474 """internal method to get a single entity, returns a partially |
475 initialized Entity instance. |
475 initialized Entity instance. |
476 |
476 |
477 partially means that only attributes selected in the RQL query will be |
477 partially means that only attributes selected in the RQL query will be |
478 directly assigned to the entity. |
478 directly assigned to the entity. |
482 row and col numbers localizing the entity among the result's table |
482 row and col numbers localizing the entity among the result's table |
483 |
483 |
484 :return: the partially initialized `Entity` instance |
484 :return: the partially initialized `Entity` instance |
485 """ |
485 """ |
486 req = self.req |
486 req = self.req |
487 if req is None: |
487 assert req is not None, 'do not call get_entity with no req on the result set' |
488 raise AssertionError('dont call get_entity with no req on the result set') |
488 |
489 rowvalues = self.rows[row] |
489 rowvalues = self.rows[row] |
490 eid = rowvalues[col] |
490 eid = rowvalues[col] |
491 assert eid is not None |
491 assert eid is not None |
492 try: |
492 try: |
493 entity = req.entity_cache(eid) |
493 entity = req.entity_cache(eid) |
494 if entity.cw_rset is self: |
|
495 # return entity as is, avoiding recursion |
|
496 return entity |
|
497 except KeyError: |
494 except KeyError: |
498 entity = self._make_entity(row, col) |
495 entity = self._make_entity(row, col) |
499 else: |
496 else: |
500 if entity.cw_rset is None: |
497 if entity.cw_rset is None: |
501 # entity has no rset set, this means entity has been created by |
498 # entity has no rset set, this means entity has been created by |
502 # the querier (req is a repository session) and so has no rset |
499 # the querier (req is a repository session) and so has no rset |
503 # info. Add it. |
500 # info. Add it. |
504 entity.cw_rset = self |
501 entity.cw_rset = self |
505 entity.cw_row = row |
502 entity.cw_row = row |
506 entity.cw_col = col |
503 entity.cw_col = col |
|
504 # avoid recursion |
|
505 if seen is None: |
|
506 seen = set() |
|
507 if col in seen: |
|
508 return entity |
|
509 seen.add(col) |
507 # try to complete the entity if there are some additional columns |
510 # try to complete the entity if there are some additional columns |
508 if len(rowvalues) > 1: |
511 if len(rowvalues) > 1: |
509 eschema = entity.e_schema |
512 eschema = entity.e_schema |
510 eid_col, attr_cols, rel_cols = self._rset_structure(eschema, col) |
513 eid_col, attr_cols, rel_cols = self._rset_structure(eschema, col) |
511 entity.eid = rowvalues[eid_col] |
514 entity.eid = rowvalues[eid_col] |
519 else: |
522 else: |
520 rql = 'Any Y WHERE Y %s X, X eid %s' |
523 rql = 'Any Y WHERE Y %s X, X eid %s' |
521 rrset = ResultSet([], rql % (rtype, entity.eid)) |
524 rrset = ResultSet([], rql % (rtype, entity.eid)) |
522 rrset.req = req |
525 rrset.req = req |
523 else: |
526 else: |
524 rrset = self._build_entity(row, col_idx).as_rset() |
527 rrset = self._build_entity(row, col_idx, seen).as_rset() |
525 entity.cw_set_relation_cache(rtype, role, rrset) |
528 entity.cw_set_relation_cache(rtype, role, rrset) |
526 return entity |
529 return entity |
527 |
530 |
528 @cached |
531 @cached |
529 def _rset_structure(self, eschema, entity_col): |
532 def _rset_structure(self, eschema, entity_col): |