mutateAsync method

Future<T> mutateAsync(
  1. P params
)

Executes the mutation with params, returning the resolved data or rethrowing the caught error.

Useful when callers want standard try/catch error handling at the call site.

try {
  final task = await createTodo.mutateAsync('New Task');
  print('Created: ${task.id}');
} catch (e) {
  print('Failed: $e');
}

Implementation

Future<T> mutateAsync(P params) async {
  _status.value = MutationStatus.pending;
  _error.value = null;

  dynamic context;
  T? autoPreviousSnapshot;

  // 1. Automated Optimistic Update Snapshot & Application
  if (optimisticKey != null) {
    autoPreviousSnapshot = BloomData.getQueryData<T>(optimisticKey!);
    if (optimisticData != null) {
      BloomData.setQueryData<T>(
        optimisticKey!,
        (old) => optimisticData!(params, old) as T,
      );
    }
  }

  // 2. Custom onMutate hook
  if (onMutate != null) {
    try {
      context = await onMutate!(params);
    } catch (_) {
      // Swallow onMutate errors — don't block the mutation
    }
  }

  try {
    final result = await mutateFn(params);
    _data.value = result;
    _status.value = MutationStatus.success;
    _error.value = null;

    // 3. Automated Cache Invalidation
    for (final key in invalidateKeys) {
      BloomData.invalidateQueries(key);
    }

    if (onSuccess != null) {
      await onSuccess!(result, params, context);
    }
    if (onSettled != null) {
      await onSettled!(result, null, params, context);
    }

    return result;
  } catch (err) {
    _error.value = err;
    _status.value = MutationStatus.error;

    // 4. Automated Optimistic Rollback
    if (optimisticKey != null) {
      BloomData.setQueryData<T>(
          optimisticKey!, (_) => autoPreviousSnapshot as T);
    }

    if (onError != null) {
      await onError!(err, params, context);
    }
    if (onSettled != null) {
      await onSettled!(null, err, params, context);
    }

    rethrow;
  }
}