スキル一覧に戻る
pretodev

manageproviderquery

by pretodev

0🍴 0📅 2026年1月21日
GitHubで見るManusで実行

SKILL.md


name: ManageProviderQuery description: Guidelines for creating and maintaining query providers, which abstract data fetching for UI consumption in Flutter/Riverpod.

Query providers are pre-customized data sources that abstract access to certain data, making it ready to be consumed by the UI. They fetch data and provide reactive streams or async values.

When to Use Query Providers

Use a Query Provider when you need to:

  • Fetch data for UI consumption
  • Create reactive data streams
  • Abstract data access with pre-configured parameters
  • Provide one-time async data fetches
  • Combine or transform data from repositories

Location

Query providers are located within feature directories:

Path: lib/features/<feature>/providers/<name>_query.dart

lib/features/<feature>/providers/
├── providers.dart              # Service providers
├── <name>_query.dart           # Query providers (pre-customized data sources)
├── <action>_command.dart       # Command providers
└── *.g.dart                    # Generated files

Structure

Query providers are simple functions that fetch and return data:

// lib/features/trainning/providers/training_from_id_query.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../data/training.dart';
import 'providers.dart';

part 'training_from_id_query.g.dart';

@riverpod
Stream<DailyTraining> trainingFromId(Ref ref, String id) {
  return ref.read(trainingRepositoryProvider).fromId(id);
}

Naming Conventions

ElementConventionExample
File name*_query.darttraining_from_id_query.dart
Function nameDescriptive of data being fetchedtrainingFromId, usersByRole
Provider nameGenerated from functiontrainingFromIdProvider
ParametersDescriptive namesString id, UserRole role

Return Types

Stream for Real-Time Data

Use Stream<T> for data that updates in real-time:

@riverpod
Stream<DailyTraining> trainingFromId(Ref ref, String id) {
  return ref.read(trainingRepositoryProvider).fromId(id);
}

Future for One-Time Fetches

Use Future<T> for data fetched once:

@riverpod
Future<UserProfile> userProfile(Ref ref, String userId) {
  return ref.read(userRepositoryProvider).getProfile(userId);
}

Best Practices

PracticeDescription
Return Stream<T> for real-time dataSubscriptions that update automatically
Return Future<T> for one-time fetchesData that doesn't need live updates
Use ref.read() to access repositoriesAvoid ref.watch() in query functions
Keep queries simpleJust fetch and return data
No business logicQueries abstract data access, not business rules
Name files with *_query.dartClear identification of query providers
Use descriptive parameter namesMakes usage clear at call site

Examples

Stream Query with Parameter

// lib/features/trainning/providers/training_from_id_query.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../data/training.dart';
import 'providers.dart';

part 'training_from_id_query.g.dart';

@riverpod
Stream<DailyTraining> trainingFromId(Ref ref, String id) {
  return ref.read(trainingRepositoryProvider).fromId(id);
}

Future Query with Multiple Parameters

// lib/features/users/providers/users_by_role_query.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../data/user.dart';
import 'providers.dart';

part 'users_by_role_query.g.dart';

@riverpod
Future<List<User>> usersByRole(Ref ref, UserRole role, {int limit = 10}) {
  return ref.read(userRepositoryProvider).findByRole(role, limit: limit);
}

Stream Query for Collections

// lib/features/trainning/providers/all_trainings_query.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../data/training.dart';
import 'providers.dart';

part 'all_trainings_query.g.dart';

@riverpod
Stream<List<DailyTraining>> allTrainings(Ref ref) {
  return ref.read(trainingRepositoryProvider).watchAll();
}

Query with Date Range

// lib/features/analytics/providers/metrics_in_range_query.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../data/metric.dart';
import 'providers.dart';

part 'metrics_in_range_query.g.dart';

@riverpod
Future<List<Metric>> metricsInRange(
  Ref ref,
  DateTime startDate,
  DateTime endDate,
) {
  return ref.read(analyticsRepositoryProvider).getMetrics(startDate, endDate);
}

Maintenance and Modification

When modifying existing queries:

  1. Parameter Updates: If adding parameters, update all call sites. Consider using named parameters for optional filters.
  2. Performance Check: Ensure new logic doesn't introduce blocking operations. Queries should be lightweight.
  3. No Side Effects: Verify that no side effects (like API writes or state mutations) are added.
  4. Refactor: If a query becomes complex, consider moving logic to the repository or creating a specific repository method.

Consuming Queries in UI

Watching Queries

Use ref.watch() for reactive data subscriptions:

@override
Widget build(BuildContext context) {
  final training = ref.watch(trainingFromIdProvider('training-123'));

  return training.when(
    data: (data) => TrainingView(training: data),
    loading: () => const CircularProgressIndicator(),
    error: (error, stack) => ErrorWidget(error),
  );
}

Watching with Parameters

@override
Widget build(BuildContext context) {
  final users = ref.watch(usersByRoleProvider(UserRole.admin, limit: 20));

  return users.when(
    data: (userList) => UserListView(users: userList),
    loading: () => const LoadingIndicator(),
    error: (error, stack) => ErrorView(error: error),
  );
}

Anti-Patterns to Avoid

❌ DON'T: Business Logic in Query

// BAD: Business logic doesn't belong in queries
@riverpod
Stream<DailyTraining> trainingFromId(Ref ref, String id) {
  return ref.read(trainingRepositoryProvider)
      .fromId(id)
      .map((training) {
        // BAD: Business logic in query
        if (training.exercises.isEmpty) {
          training.addDefaultExercise();
        }
        return training;
      });
}

❌ DON'T: Mutations in Query

// BAD: Queries should not mutate data
@riverpod
Future<User> userProfile(Ref ref, String userId) async {
  final user = await ref.read(userRepositoryProvider).getProfile(userId);

  // BAD: Don't mutate in queries
  user.lastAccessed = DateTime.now();
  await ref.read(userRepositoryProvider).save(user);

  return user;
}

❌ DON'T: Complex Transformations

// BAD: Complex logic should be in the entity or a use case
@riverpod
Future<TrainingSummary> trainingSummary(Ref ref, String id) async {
  final training = await ref.read(trainingRepositoryProvider).fromId(id).first;

  // BAD: This logic belongs in the entity
  final totalVolume = training.exercises.fold(0, (sum, e) => sum + e.volume);
  final avgIntensity = training.exercises.map((e) => e.intensity).average;
  final muscleGroups = training.exercises.map((e) => e.muscleGroup).toSet();

  return TrainingSummary(
    totalVolume: totalVolume,
    avgIntensity: avgIntensity,
    muscleGroups: muscleGroups,
  );
}

❌ DON'T: Use ref.watch() Inside Query

// BAD: Don't use ref.watch() in query functions
@riverpod
Stream<DailyTraining> trainingFromId(Ref ref, String id) {
  // BAD: Use ref.read() instead
  final repo = ref.watch(trainingRepositoryProvider);
  return repo.fromId(id);
}

Code Smells

SmellProblemSolution
Business logic in queryBreaks separation of concernsMove logic to entity domain methods
Mutations in queryQueries should be read-onlyUse a command for mutations
Complex transformationsQuery doing too muchMove to entity methods or use case
Using ref.watch()Unnecessary reactivity in providerUse ref.read() in queries
Missing file suffixHard to identify query providersName files with *_query.dart
Non-descriptive namesUnclear what data is fetchedUse descriptive function names

Code Generation

Always include the part directive and run code generation after changes:

import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'your_query.g.dart';
dart run build_runner build -d

Note: The -d flag is short for --delete-conflicting-outputs.

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です