Functions-example-usage
Example Function Usage
///
/// This file demonstrates how to use the refactored AppFunction
/// with Either pattern for type-safe error handling.
import 'package:flutter/foundation.dart';
import 'package:services/function/search/search_function.dart';
import 'package:store/function/schema/error_schema.dart';
import 'package:store/function/schema/search/search_response_schema.dart';
import 'package:store/function/shared/function/search_function_type.dart';
import 'package:store/function/shared/search/search_sort_type.dart';
import 'package:store/function/shared/stripe/stripe_account_type.dart';
/// Example 1: Search Function Usage
///
/// The search function now returns `Either<ErrorSchema, SearchResponseSchema>`
/// instead of nullable GeneralSearchResults
Future<void> exampleSearchUsage() async {
// Create search function
final searchFn = SearchFunction.general(
searchType: SearchFunctionType.generalSearch,
sortType: SearchSortType.recent,
);
// Execute search
final result = await searchFn.search(
queryStr: 'flutter',
pageNum: 1,
);
// Handle result with fold
result.fold(
(error) {
// Left: Error occurred
debugPrint('Search failed:');
debugPrint(' Code: ${error.code}');
debugPrint(' Title: ${error.title}');
debugPrint(' Message: ${error.message}');
debugPrint(' Category: ${error.category}');
// Check if retryable
if (error.code.name == 'TIMEOUT' || error.code.name == 'SERVICE_UNAVAILABLE') {
debugPrint(' → Error is retryable, will retry...');
}
},
(data) {
// Right: Success
debugPrint('Search succeeded:');
debugPrint(' Query: ${data.q}');
debugPrint(' Found: ${data.found} results');
debugPrint(' Page: ${data.page}/${data.outOf}');
debugPrint(' Collection: ${data.collectionName}');
debugPrint(' Results: ${data.results.length} items');
// Process results
for (final result in data.results) {
print(' - ${result['title']}');
}
},
);
// Alternative: Check type explicitly
if (result.isLeft()) {
final error = result.fold((e) => e, (_) => null)!;
handleError(error);
} else {
final data = result.fold((_) => null, (d) => d)!;
handleSearchResults(data);
}
// Alternative: Use pattern matching (Dart 3.0+)
switch (result) {
case Left(value: final error):
debugPrint('Error: ${error.message}');
case Right(value: final data):
debugPrint('Success: ${data.found} results');
}
}
/// Example 2: Stripe Function Usage
///
/// Demonstrates how to use typed Stripe functions with Either pattern
Future<void> exampleStripeUsage() async {
final stripeFunction = StripeRefreshAccountFunction();
final result = await stripeFunction.refresh(
uid: 'user_123',
stripeAccountId: 'acct_stripe123',
accountType: StripeAccountType.express,
);
result.fold(
(error) {
// Handle different error types
if (error.category.name == 'stripe') {
debugPrint('Stripe-specific error: ${error.message}');
// Maybe redirect to account setup
} else if (error.code.name == 'unauthenticated') {
debugPrint('User needs to login again');
// Redirect to login
} else {
debugPrint('Generic error: ${error.message}');
}
},
(data) {
debugPrint('Stripe account refreshed successfully');
// Update UI with new account data
},
);
}
/// Example 3: Error-first handling
///
/// Shows how to handle errors first and early-return
Future<List<Map<String, dynamic>>> exampleErrorFirstHandling(String query) async {
final searchFn = SearchFunction.general(
searchType: SearchFunctionType.generalSearch,
sortType: SearchSortType.recent,
);
final result = await searchFn.search(queryStr: query);
// Handle error case first
if (result.isLeft()) {
final error = result.getLeft().toNullable()!;
print('Search error: ${error.message}');
return []; // Return empty list on error
}
// Success case
final data = result.getRight().toNullable()!;
return data.results;
}
/// Example 4: Chaining operations with Either
///
/// Shows how to chain multiple function calls
Future<void> exampleChainingOperations() async {
// Search for dares
final searchResult = await SearchFunction.general(
searchType: SearchFunctionType.generalSearch,
sortType: SearchSortType.recent,
).search(queryStr: 'test');
// Chain: only proceed if search succeeded
final processingResult = searchResult.flatMap((searchData) async {
// Process search results...
if (searchData.results.isEmpty) {
return Either.left(ErrorSchema(
endpoint: 'processing',
code: AppErrorCode.serverError,
category: AppErrorCategory.processing,
title: 'No Results',
message: 'No search results to process',
));
}
// Do something with results...
return Either.right('Processed ${searchData.results.length} items');
});
// Handle final result
processingResult.fold(
(error) => debugPrint('Failed: ${error.message}'),
(success) => debugPrint('Success: $success'),
);
}
/// Example 5: Async error recovery
///
/// Shows how to recover from errors with fallback logic
Future<void> exampleErrorRecovery() async {
final searchFn = SearchFunction.general(
searchType: SearchFunctionType.generalSearch,
sortType: SearchSortType.recent,
);
final result = await searchFn.search(queryStr: 'test');
final finalResult = result.fold(
(error) async {
// Try to recover from error
if (error.code.name == 'timeout') {
debugPrint('Timeout detected, retrying with longer timeout...');
// Retry logic here
return <Map<String, dynamic>>[];
}
debugPrint('Unrecoverable error: ${error.message}');
return <Map<String, dynamic>>[];
},
(data) async => data.results,
);
debugPrint('Final result: ${await finalResult}');
}
// Helper functions for examples
void handleError(ErrorSchema error) {
debugPrint('Handling error: ${error.message}');
}
void handleSearchResults(SearchResponseSchema data) {
debugPrint('Handling ${data.results.length} results');
}
// Needed imports that would be in actual usage:
// import 'package:store/function/schema/error_schema.dart';
// import 'package:store/function/schema/search/search_response_schema.dart';
// import 'package:store/function/shared/app_error_code.dart';
// import 'package:store/function/shared/app_error_category.dart';