docs: def _facts(self, pk, pk_att, target, visited=set(), parent_table='', parent_pk=''):
          '''
          Returns the facts for the given entity with pk in `target`.
          '''
          facts = []
          cols = self.db.cols[target]
          if target != self.db.target_table:
  
              # Skip the class attribute
              if self.db.target_att in cols:
                  cols.remove(self.db.target_att)
  
              # All rows matching `pk`
              for row in self.db.select_where(target, cols, pk_att, pk):
                  row_pk = self._row_pk(target, cols, row)
                  row_pk_name = '%s%s' % (target, str(row_pk))
                  parent_pk_name = '%s%s' % (parent_table, str(parent_pk))
  
                  # Each attr-value becomes one fact
                  for idx, col in enumerate(row):
                      attr_name = cols[idx]
  
                      # We give pks/fks a symbolic name based on the table and id
                      if attr_name in self.db.fkeys[target]:
                          origin_table = self.db.reverse_fkeys[(target, attr_name)]
                          if origin_table != self.db.target_table:
                              col = '%s%s' % (origin_table, str(col))
                          else:
                              continue
                      elif attr_name == self.db.pkeys[target]:
                          if parent_table and parent_table != self.db.target_table:
                              predicate = '%s_has_%s' % (parent_table, target)
                              predicate_template = '%s(+%s, -%s)' % (predicate,
                                                                     parent_table,
                                                                     target)
                              facts.append('%s(%s, %s)' % (predicate,
                                                           parent_pk_name,
                                                           row_pk_name))
                          else:
                              predicate = 'has_%s' % (target)
                              predicate_template = '%s(-%s)' % (predicate,
                                                                target)
                              facts.append('%s(%s)' % (predicate, row_pk_name))
  
                          output_type = '-%s' % target
                          if predicate_template not in self._predicates and \
                                          output_type not in self._output_types:
                              self._output_types.add('-%s' % target)
                              self._predicates.add(predicate_template)
                              self._template.append(predicate_template)
  
                      # Constants
                      else:
                          predicate = 'has_%s' % attr_name
  
                          col = self._discretize_check(target, attr_name, col)
                          facts.append('%s(%s, %s)' % (predicate,
                                                       row_pk_name,
                                                       str(col)))
                          predicate_template = '%s(+%s, #%s)' % (predicate,
                                                                 target,
                                                                 attr_name)
  
                          if predicate_template not in self._predicates:
                              self._predicates.add(predicate_template)
                              self._template.append(predicate_template)
  
          # Recursively follow links to other tables
          for table in self.db.tables:
              if (target, table) not in self.db.connected:
                  continue
  
              for this_att, that_att in self.db.connected[(target, table)]:
                  if (target, table, this_att, that_att) not in visited:
                      visited.add((target, table, this_att, that_att))
  
                      # Link case 1: this_att = pk_att is a fk in another table
                      if this_att == pk_att:
                          facts.extend(self._facts(pk,
                                                   that_att,
                                                   table,
                                                   visited=visited,
                                                   parent_table=target,
                                                   parent_pk=pk))
  
                      # Link case 2: this_att is a fk of another table
                      else:
                          fk_list = []
                          for row in self.db.select_where(target, [this_att] + cols, pk_att, pk):
                              row_pk = self._row_pk(target, cols, row[1:])
                              fk_list.append((row[0], row_pk))
                          for fk, row_pk in fk_list:
                              facts.extend(self._facts(fk,
                                                       that_att,
                                                       table,
                                                       visited=visited,
                                                       parent_table=target,
                                                       parent_pk=row_pk))
          return facts