loadReferences<C, P> method

Future<Map<EntityEntry<C>, P?>> loadReferences<C, P>(
  1. ForeignKey<C, P> relation,
  2. Iterable<EntityEntry<C>> children
)

Loads parents for children in batches.

Implementation

Future<Map<EntityEntry<C>, P?>> loadReferences<C, P>(
    ForeignKey<C, P> relation, Iterable<EntityEntry<C>> children) {
  final entries = List<EntityEntry<C>>.of(children);
  _checkRegisteredRelationship(this, relation);
  for (final entry in entries) {
    _checkRelationshipEntry(entry, relation.child);
    if (!identical(entry.context, this)) {
      throw const OrmStateException(
          'Relationship entries belong to different contexts');
    }
  }
  return _serialize(() async {
    final result = Map<EntityEntry<C>, P?>.identity();
    final wanted = <EntityKey, List<EntityEntry<C>>>{};
    for (final entry in entries) {
      _checkRelationshipEntry(entry, relation.child);
      final links = _relationshipLinks[entry];
      if (links != null && links.containsKey(relation)) {
        _validateRelationshipLinks(entry);
        final parent = links[relation];
        if (parent != null) {
          _checkRelationshipEntry(parent, relation.parent);
        }
        result[entry] = parent?.entity as P?;
        continue;
      }
      final key = _relationshipEntityKey(relation.columns, entry.entity);
      if (key == null) {
        result[entry] = null;
      } else {
        (wanted[key] ??= []).add(entry);
      }
    }
    final parents = <EntityKey, P>{};
    for (final chunk
        in _relationshipChunks(wanted.keys, relation.targetColumns.length)) {
      final predicate = _relationshipPredicate(relation.targetColumns, chunk);
      final rows = await connection.query(
          'SELECT ${_relationshipProjection(relation.parent)} '
          'FROM ${quoteIdentifier(relation.parent.tableName)} '
          'WHERE ${predicate.$1}',
          predicate.$2);
      for (final values in rows.rows) {
        final reader = _relationshipReader(rows.columns, values);
        final key = _relationshipReaderKey(relation.targetColumns, reader);
        if (key == null || parents.containsKey(key)) {
          throw const OrmStateException(
              'Relationship target is not unique in the store');
        }
        parents[key] = _materialize(relation.parent, reader);
      }
    }
    final required = relation.columns.every((column) => !column.nullable);
    for (final request in wanted.entries) {
      final parent = parents[request.key];
      if (parent == null && required) {
        throw OrmStateException(
            'Required parent for ${relation.name} is missing');
      }
      for (final entry in request.value) {
        result[entry] = parent;
      }
    }
    return Map<EntityEntry<C>, P?>.unmodifiable(result);
  });
}