merge method

  1. @override
Future<bool> merge(
  1. List<Map<String, dynamic>> sourceData, {
  2. required List<String> matchOn,
  3. ConflictAction whenMatched = ConflictAction.update,
  4. ConflictAction whenNotMatched = ConflictAction.ignore,
  5. ConflictAction? whenNotMatchedBySource,
  6. List<String>? updateColumns,
  7. List<String>? insertColumns,
  8. Map<String, dynamic>? additionalValues,
})
inherited

Implementation

@override
Future<bool> merge(
  List<Map<String, dynamic>> sourceData, {
  required List<String> matchOn,
  ConflictAction whenMatched = ConflictAction.update,
  ConflictAction whenNotMatched = ConflictAction.ignore,
  ConflictAction? whenNotMatchedBySource,
  List<String>? updateColumns,
  List<String>? insertColumns,
  Map<String, dynamic>? additionalValues,
}) async {
  if (sourceData.isEmpty) {
    throw InvalidArgumentException(
        'Source data cannot be empty for merge operation');
  }

  if (matchOn.isEmpty) {
    throw InvalidArgumentException(
        'Match columns cannot be empty for merge operation');
  }

  try {
    final conn = await getConnection();
    final paramBindings = <String, dynamic>{};

    final sourceColumns = sourceData.first.keys.toList();
    final valueGroups = <String>[];

    for (var row in sourceData) {
      final placeholders = sourceColumns.map((column) {
        final paramName = _nextParamName();
        paramBindings[paramName] = row[column];
        return ":$paramName";
      }).join(", ");
      valueGroups.add("($placeholders)");
    }

    final sourceClause =
        "(VALUES ${valueGroups.join(', ')}) AS source(${sourceColumns.join(', ')})";

    final matchConditions =
        matchOn.map((col) => "$getTable.$col = source.$col").join(' AND ');

    String mergeSQL =
        "MERGE INTO $getTable USING $sourceClause ON $matchConditions";

    if (whenMatched == ConflictAction.update) {
      final columnsToUpdate = updateColumns ??
          sourceColumns.where((col) => !matchOn.contains(col)).toList();
      final updateSets =
          columnsToUpdate.map((col) => "$col = source.$col").join(', ');
      mergeSQL += " WHEN MATCHED THEN UPDATE SET $updateSets";
    } else if (whenMatched == ConflictAction.delete) {
      mergeSQL += " WHEN MATCHED THEN DELETE";
    }

    if (whenNotMatched != ConflictAction.ignore) {
      final columnsToInsert = insertColumns ?? sourceColumns;
      final insertValues =
          columnsToInsert.map((col) => "source.$col").join(', ');
      mergeSQL +=
          " WHEN NOT MATCHED THEN INSERT (${columnsToInsert.join(', ')}) VALUES ($insertValues)";
    }

    if (whenNotMatchedBySource == ConflictAction.delete) {
      mergeSQL += " WHEN NOT MATCHED BY SOURCE THEN DELETE";
    }

    await conn.execute(mergeSQL, paramBindings);
    return true;
  } catch (e) {
    rethrow;
  }
}