Repository Context with Convertors
Convertor Context Passing
Context data flows naturally through Convertor input parameters and subscription context.
Repository Context with Convertors
Section titled âRepository Context with ConvertorsâOverview
Section titled âOverviewâIn the Convertor pattern, context data (user IDs, chat IDs, filters) flows naturally through typed input parameters. There is no separate âRequestContextâ object - the Convertorâs input parameter carries all needed context.
Passing Context Through Parameters
Section titled âPassing Context Through ParametersâFilter Context
Section titled âFilter ContextâStream<List<NotificationModel>> queryList({ required String eventId, NotificationFilterCriteria? additionalFilter,}) { final filter = NotificationFilterCriteria( systemParentId: eventId, // Context: current event ...additionalFilter, );
final params = ListRequestParams<GnotificationFilters, GnotificationOrder>( filter: filterConvertor.mightExecute(filter), );
return listDatasource.thenEach(modelConvertor).execute(params);}Subscription Context
Section titled âSubscription ContextâFor subscriptions that need filtering context (e.g., chat messages for a specific chat):
Stream<ChatMessageModel> subscribeToMessages({ required String chatId, required String currentUserId,}) { final context = ChatMessageSubscriptionContext( chatId: chatId, currentUserId: currentUserId, );
final params = SubscriptionRequestParams(context: context); return subscriptionDatasource.thenMap(modelConvertor).execute(params);}The subscription context is serialized to JSON and passed via Ferryâs updateCacheHandlerContext:
@riverpodConvertor<GSubscribeToChatMessagesReq, SubscriptionRequestParams<ChatMessageSubscriptionContext>>chatMessageSubscriptionConvertor(Ref ref) { return Convertor((params) { return GSubscribeToChatMessagesReq((builder) { builder ..requestId = 'chat_message_subscription' ..updateCacheHandlerKey = 'messageSubscriptionCacheHandler' ..updateCacheHandlerContext = params.context?.toJson(); }); });}Using Interceptors for Cross-Cutting Context
Section titled âUsing Interceptors for Cross-Cutting ContextâAdd logging or analytics without modifying the data flow:
final loggedDatasource = datasource.intercept( onInput: (params) => log('Fetching with context: ${params.filter}'), onOutput: (data) => log('Received ${data.length} items'),);Using Decorators for Conditional Logic
Section titled âUsing Decorators for Conditional LogicâApply context-dependent behavior:
final withErrorHandling = datasource.decorate((convertor, input) { try { return convertor.execute(input); } catch (e, st) { analytics.trackError('datasource_error', error: e); return Stream.error(DomainException('Failed to fetch data'), st); }});