buildCascadeDeleteIndices method

Future<Map<int, Set<int>>> buildCascadeDeleteIndices(
  1. String sheetName,
  2. List<String> idsToDelete, {
  3. Set<String>? visited,
})

Constrói de forma recursiva todas as requisições de deleção para os filhos (e netos) caso o onDeleteCascade esteja ativado no ForeignKey. Retorna um Map agrupando por sheetId (GID) um Set de índices de linha únicos a deletar.

Implementation

Future<Map<int, Set<int>>> buildCascadeDeleteIndices(
  String sheetName,
  List<String> idsToDelete, {
  Set<String>? visited,
}) async {
  Map<int, Set<int>> indicesBySheet = {};
  if (idsToDelete.isEmpty) return indicesBySheet;

  visited ??= {};
  if (visited.contains(sheetName)) {
    return indicesBySheet; // Evita loop infinito em dependências circulares
  }
  visited.add(sheetName);

  final dependents =
      foreignKeys?.where(
        (fk) => fk.lookupTable == sheetName && fk.onDeleteCascade,
      ) ??
      [];

  for (final fk in dependents) {
    final childRepo = repo(fk.sourceTable);
    final rawRows = await childRepo.getRawRows();
    if (rawRows.isEmpty) continue;

    final headers = List<String>.from(rawRows[0]);
    int fkColIndex = headers.indexOf(fk.sourceKeyColumn);
    int idColIndex = headers.indexOf('id');

    if (fkColIndex == -1) continue;

    List<String> childIdsToDelete = [];
    Set<int> childRowIndices = {};

    for (int i = 1; i < rawRows.length; i++) {
      final row = rawRows[i];
      if (row.length <= fkColIndex) continue;

      final fkValue = row[fkColIndex]?.toString();

      if (fkValue != null && idsToDelete.contains(fkValue)) {
        if (idColIndex != -1 && row.length > idColIndex) {
          final idVal = row[idColIndex]?.toString();
          if (idVal != null && idVal.isNotEmpty) {
            childIdsToDelete.add(idVal);
          }
        }
        childRowIndices.add(i);
      }
    }

    if (childRowIndices.isNotEmpty) {
      final childGid = await childRepo.getGid();
      indicesBySheet.putIfAbsent(childGid, () => {}).addAll(childRowIndices);
    }

    if (childIdsToDelete.isNotEmpty) {
      final cascadeIndices = await buildCascadeDeleteIndices(
        fk.sourceTable,
        childIdsToDelete,
        visited: Set.from(visited), // Passa cópia do Set para a ramificação
      );

      // Faz o merge dos resultados
      cascadeIndices.forEach((gid, indices) {
        indicesBySheet.putIfAbsent(gid, () => {}).addAll(indices);
      });
    }
  }
  return indicesBySheet;
}