async_result 1.1.2 copy "async_result: ^1.1.2" to clipboard
async_result: ^1.1.2 copied to clipboard

A Dart package that provides a type-safe way to handle different states of asynchronous operations.

example/async_result_example.dart

import 'dart:async';
import 'dart:math';

import 'package:async_result/async_result.dart';

void main() async {
  print('=== AsyncResult Comprehensive Example ===\n');

  // Basic usage example
  await basicUsageExample();

  // Error handling example
  await errorHandlingExample();

  // Transformation examples
  transformationExamples();

  // Combination examples
  combinationExamples();

  // New utility methods examples
  utilityMethodsExamples();

  // Real-world example
  await realWorldExample();
}

/// Demonstrates basic usage of AsyncResult states
Future<void> basicUsageExample() async {
  print('--- Basic Usage Example ---');

  // Simulate a data fetching operation
  final result = await fetchUserData(userId: 123);

  // Handle the result using when()
  final message = result.when(
    initial: () => 'Operation not started',
    loading: () => 'Fetching user data...',
    data: (user) => 'User loaded: ${user.name} (${user.email})',
    error: (error) => 'Failed to load user: $error',
  );
  print('Result: $message');

  // Alternative: Handle only specific states
  result.whenData((user) {
    print('Success! User ID: ${user.id}');
  });

  result.whenError((error) {
    print('Error occurred: $error');
  });

  print('');
}

/// Demonstrates error handling patterns
Future<void> errorHandlingExample() async {
  print('--- Error Handling Example ---');

  final result = await fetchUserData(userId: -1); // This will fail

  // Safe data access
  final userData = result.dataOrNull;
  if (userData != null) {
    print('User: ${userData.name}');
  } else {
    print('No user data available');
  }

  // Using getDataOrElse for default values
  final defaultUser = result.getDataOrElse(User(
    id: 0,
    name: 'Anonymous',
    email: 'anonymous@example.com',
  ));
  print('User (with default): ${defaultUser.name}');

  // Recovery from errors
  final recovered = result.recover((error) => User(
        id: -1,
        name: 'Error User',
        email: 'error@example.com',
      ));
  print('Recovered user: ${recovered.dataOrThrow.name}');
  print('');
}

/// Demonstrates transformation methods
void transformationExamples() {
  print('--- Transformation Examples ---');

  final userResult = AsyncResult<User, String>.data(User(
    id: 123,
    name: 'John Doe',
    email: 'john@example.com',
  ));

  // Transform data
  final nameResult = userResult.map((user) => user.name.toUpperCase());
  print('Uppercase name: ${nameResult.dataOrThrow}');

  // Transform errors
  final errorResult = AsyncResult<User, String>.error('network_timeout');
  final mappedError = errorResult.mapError((err) => 'Connection Error: $err');
  print('Mapped error: ${mappedError.errorOrThrow}');

  // Conditional transformations
  final conditionalResult = userResult.mapWhere(
    (user) => user.name.length > 5,
    (user) => user.copyWith(name: '${user.name} (Long Name)'),
  );
  print('Conditional transform: ${conditionalResult.dataOrThrow.name}');

  // Validation
  final validatedResult = userResult.validate(
    (user) => user.email.contains('@'),
    (user) => 'Invalid email: ${user.email}',
  );
  print('Validation result: ${validatedResult.isSuccess}');

  // Chain operations with flatMap
  final chainedResult = userResult.flatMap((user) {
    if (user.id > 0) {
      return AsyncResult.data('Valid user: ${user.name}');
    }
    return AsyncResult.error('Invalid user ID');
  });
  print('Chained result: ${chainedResult.dataOrThrow}');

  print('');
}

/// Demonstrates combination methods
void combinationExamples() {
  print('--- Combination Examples ---');

  final user = AsyncResult<User, String>.data(User(
    id: 1,
    name: 'Alice',
    email: 'alice@example.com',
  ));

  final profile = AsyncResult<UserProfile, String>.data(UserProfile(
    bio: 'Software Developer',
    location: 'San Francisco',
  ));

  // Combine two results
  final combined = AsyncResult.combine2(user, profile);
  if (combined.isSuccess) {
    final data = combined.dataOrThrow;
    print('Combined: ${data.first.name} - ${data.second.bio}');
  }

  // Combine multiple results
  final results = [
    AsyncResult<int, String>.data(1),
    AsyncResult<int, String>.data(2),
    AsyncResult<int, String>.data(3),
  ];

  final combinedList = AsyncResult.combineIterable(results);
  print('Combined list: ${combinedList.dataOrThrow}');

  // Static utility methods
  print('All success: ${AsyncResult.allSuccess(results)}');
  print('Any error: ${AsyncResult.anyError(results)}');
  print('All data: ${AsyncResult.getAllData(results).toList()}');

  print('');
}

/// Demonstrates new utility methods
void utilityMethodsExamples() {
  print('--- Utility Methods Examples ---');

  final numbers = AsyncResult<List<int>, String>.data([1, 2, 3, 4, 5]);

  // Test predicate
  final hasEvenNumbers = numbers.any((list) => list.any((n) => n % 2 == 0));
  print('Has even numbers: $hasEvenNumbers');

  // Filter data
  final filtered = numbers.filter(
    (list) => list.length >= 3,
    () => 'List too short',
  );
  print('Filtered result: ${filtered.isSuccess}');

  // Swap data and error types
  final swapped = numbers.swap();
  print('Swapped (now error): ${swapped.isError}');

  // Side effects with tap
  final tapped = numbers.tap(
    onData: (data) => print('Tapped data length: ${data.length}'),
    onError: (error) => print('Tapped error: $error'),
  );
  print('Tap preserves original: ${identical(numbers, tapped)}');

  print('');
}

/// Real-world example demonstrating a complete flow
Future<void> realWorldExample() async {
  print('--- Real-World Example: User Management System ---');

  // Simulate user creation flow
  final userCreationFlow = await createUserWorkflow(
    name: 'Jane Smith',
    email: 'jane.smith@example.com',
  );

  userCreationFlow.when(
    initial: () => print('User creation not started'),
    loading: () => print('Creating user...'),
    data: (result) => print('✅ User created successfully: ${result.message}'),
    error: (error) => print('❌ User creation failed: $error'),
  );

  // Demonstrate error recovery in a pipeline
  final pipeline = await userDataPipeline(userId: 999); // Non-existent user

  pipeline.when(
    initial: () => print('Pipeline not started'),
    loading: () => print('Processing user data...'),
    data: (result) => print('✅ Pipeline completed: $result'),
    error: (error) => print('❌ Pipeline failed: $error'),
  );

  print('');
}

/// Simulates fetching user data with random success/failure
Future<AsyncResult<User, String>> fetchUserData({required int userId}) async {
  // Simulate network delay
  await Future.delayed(Duration(milliseconds: 100));

  if (userId <= 0) {
    return AsyncResult.error('Invalid user ID');
  }

  // Simulate random failure
  if (Random().nextBool()) {
    return AsyncResult.error('Network timeout');
  }

  return AsyncResult.data(User(
    id: userId,
    name: 'User $userId',
    email: 'user$userId@example.com',
  ));
}

/// Simulates user creation with validation
Future<AsyncResult<CreateUserResult, String>> createUserWorkflow({
  required String name,
  required String email,
}) async {
  // Validate input
  if (name.isEmpty) {
    return AsyncResult.error('Name cannot be empty');
  }

  if (!email.contains('@')) {
    return AsyncResult.error('Invalid email format');
  }

  // Simulate API call
  await Future.delayed(Duration(milliseconds: 200));

  return AsyncResult.data(CreateUserResult(
    userId: Random().nextInt(1000) + 1,
    message: 'User $name created successfully',
  ));
}

/// Demonstrates a complex pipeline with error handling
Future<AsyncResult<String, String>> userDataPipeline(
    {required int userId}) async {
  // Step 1: Fetch user
  final userResult = await fetchUserData(userId: userId);

  if (userResult.isError) {
    return AsyncResult.error(
        'Failed to fetch user: ${userResult.errorOrThrow}');
  }

  if (!userResult.isSuccess) {
    return AsyncResult.error('User fetch incomplete');
  }

  final user = userResult.dataOrThrow;

  // Step 2: Validate user
  if (user.email.isEmpty) {
    return AsyncResult.error('User has no email');
  }

  // Step 3: Fetch additional profile data
  await Future.delayed(Duration(milliseconds: 50));

  return AsyncResult.data('Complete profile for ${user.name}');
}

// Domain models
class User {
  final int id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  User copyWith({int? id, String? name, String? email}) {
    return User(
      id: id ?? this.id,
      name: name ?? this.name,
      email: email ?? this.email,
    );
  }
}

class UserProfile {
  final String bio;
  final String location;

  UserProfile({required this.bio, required this.location});
}

class CreateUserResult {
  final int userId;
  final String message;

  CreateUserResult({required this.userId, required this.message});
}
5
likes
160
points
175
downloads

Publisher

unverified uploader

Weekly Downloads

A Dart package that provides a type-safe way to handle different states of asynchronous operations.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

More

Packages that depend on async_result