findAll method

Future<List<T>> findAll({
  1. DataLoadPolicy? loadPolicy,
  2. QueryParams? queryParams,
  3. Map<String, dynamic>? extra,
  4. Map<String, String>? headers,
})

Finds all items of this type.

This may return cached data if the policy is DataLoadPolicy.localOnly.

loadPolicy Controls whether to load from local storage, remote API, or both. queryParams Query parameters for filtering, sorting, and pagination.

Implementation

Future<List<T>> findAll({
  DataLoadPolicy? loadPolicy,
  QueryParams? queryParams,
  Map<String, dynamic>? extra,
  Map<String, String>? headers,
}) async {
  loadPolicy ??= defaultLoadPolicy;
  queryParams ??= QueryParams.empty;
  log.info(
    'Finding all $T using policy ${loadPolicy.name} and params: $queryParams',
  );

  List<T> results = [];

  switch (loadPolicy) {
    case DataLoadPolicy.localOnly:
      log.info('Policy: localOnly. Getting all $T from local database');
      results = await fetchAllFromLocal(queryParams: queryParams);
      break;
    case DataLoadPolicy.remoteFirst:
      log.info('Policy: remoteFirst. Fetching all $T from remote API');
      try {
        // Create a NetworkTask for remoteFirst findAll operation
        // and route through foreground queue for immediate execution
        final remoteFirstFetchAllTask = NetworkTask<List<T>>(
          exec: () => fetchAllFromRemote(
            queryParams: queryParams,
            extra: extra,
            headers: headers,
          ),
          idempotencyKey: 'all-remoteFirst-fetch-'
              '${cuid()}',
          operation: SyncOperation.read,
          modelType: T.toString(),
          modelId: 'all',
          taskName: 'remoteFirst_fetchAll_$T',
        );

        // Execute via foreground queue
        final List<T> remoteItems = await queueManager.enqueueTask(
          remoteFirstFetchAllTask,
          queueType: QueueType.foreground,
        );

        // Unlike findOne, an empty list from fetchAllFromRemote is
        // a valid response.
        // It means no items match the query on the remote.
        log.fine(
          'Remote fetch successful. Got ${remoteItems.length} items. '
          'Updating local cache.',
        );
        await updateLocalCache(remoteItems); // Handles empty list correctly
        // Fetch from local to get filtered results (excluding items with
        // pending sync operations)

        results = await fetchAllFromLocalWithoutPendingSyncOps(
          queryParams: queryParams,
        );
      } on ApiExceptionGone catch (e, stackTrace) {
        // 204 for a list endpoint implies no items match the query.
        log.fine(
          'No content for query in remote API (410). '
          'Clearing relevant local cache.',
          e,
          stackTrace,
        );
        await updateLocalCache([]);
        results = [];
      } catch (e, stackTrace) {
        log.warning(
          'Failed to get all $T from API, or API error. Falling back to '
          'local.',
          e,
          stackTrace,
        );
        results = await fetchAllFromLocal(queryParams: queryParams);
      }
      break;
    case DataLoadPolicy.localThenRemote:
      log.info(
        'Policy: localThenRemote. Getting all $T from local database first.',
      );
      try {
        results = await fetchAllFromLocal(queryParams: queryParams);
        log.fine(
          'Got ${results.length} items locally. Async refreshing from '
          'remote.',
        );
        // Async remote refresh using load queue instead of unawaited
        _enqueueRemoteFetchAllTask(
          queryParams: queryParams,
          extra: extra,
          headers: headers,
        );
      } catch (localError, localStackTrace) {
        log.warning(
          'Failed to get all $T from local database, trying remote',
          localError,
          localStackTrace,
        );
        try {
          final List<T> remoteItems = await fetchAllFromRemote(
            queryParams: queryParams,
            extra: extra,
            headers: headers,
          );
          log.fine(
            'Remote fetch successful after local failure. '
            'Got ${remoteItems.length} items. Updating local cache.',
          );
          await updateLocalCache(remoteItems);
          results = remoteItems;
        } on ApiExceptionGone catch (e, stackTrace) {
          log.fine(
            'No content for query in remote API (410) after local failure.',
            e,
            stackTrace,
          );
          results = [];
        } catch (remoteError, remoteStackTrace) {
          log.warning(
            'Both local and remote fetch failed for all $T',
            remoteError,
            remoteStackTrace,
          );
          results = [];
        }
      }
      break;
  }
  return results;
}