run method

  1. @override
Future<int> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<int> run() async {
  final collectionPath = argResults!['collection'] as String;
  final filePath = argResults!['file'] as String;
  final idField = argResults!['id-field'] as String?;
  final merge = argResults!['merge'] as bool;
  final apply = argResults!['apply'] as bool;
  final verbose = argResults!['verbose'] as bool;

  final result = OperationResult();

  try {
    stdout.writeln('Loading JSON from $filePath...');
    final json = await JsonValidator.loadJsonFile(filePath);
    final array = JsonValidator.validateArray(json, 'Root JSON');
    final documents = JsonValidator.validateArrayOfObjects(
      array,
      'Documents',
    );

    final collection = PathValidator.validateCollectionPath(collectionPath);

    stdout
      ..writeln('\n=== Operation Plan ===')
      ..writeln('Collection: $collectionPath')
      ..writeln('Documents: ${documents.length}')
      ..writeln('Mode: ${merge ? 'Merge' : 'Replace'}');

    final preview = _analyzeDocuments(documents, idField);
    stdout.writeln(
      'ID Strategy: ${preview.withId} with ID field, ${preview.autoId} auto-ID',
    );

    if (verbose) {
      stdout.writeln('\nDocument preview:');
      for (
        var i = 0;
        i < (documents.length < 5 ? documents.length : 5);
        i++
      ) {
        final doc = documents[i];
        final docId = idField != null ? doc[idField]?.toString() : null;
        stdout.writeln(
          '  [${i + 1}] ${docId ?? '(auto-ID)'}: ${doc.length} fields',
        );
      }
      if (documents.length > 5) {
        stdout.writeln('  ... and ${documents.length - 5} more');
      }
    }

    if (!apply) {
      stdout
        ..writeln('\n⚠️  DRY RUN MODE - No changes will be made')
        ..writeln('Use --apply to execute the operation');
      return 0;
    }

    stdout.writeln('\nConnecting to Firestore...');
    final client = await FirestoreClient.fromEnvironment();

    stdout.writeln('Writing ${documents.length} documents...');

    for (var i = 0; i < documents.length; i++) {
      final doc = documents[i];
      String? docId;

      if (idField != null && doc.containsKey(idField)) {
        docId = doc[idField]?.toString();
      }

      await _writeDocument(
        client: client,
        collection: collection,
        documentId: docId,
        data: doc,
        merge: merge,
        result: result,
        index: i,
      );

      if ((i + 1) % 10 == 0 || i == documents.length - 1) {
        stdout.write('\rProgress: ${i + 1}/${documents.length}');
      }
    }

    stdout.writeln();
    result.printSummary(verbose: verbose);
    return result.hasErrors ? 1 : 0;
  } on Exception catch (e) {
    stderr.writeln('Error: $e');
    return 2;
  }
}