processQuery static method

void processQuery(
  1. AFStateTestContext context,
  2. AFAsyncQuery query,
  3. AFStore store,
  4. AFDispatcher dispatcher,
)

Process a query by looking up the results we have for that query, and then feeding them to its testAsyncResponse method.

Implementation

static void processQuery(AFStateTestContext context, AFAsyncQuery query, AFStore store, AFDispatcher dispatcher) {

  final key = AFStateTest.specifierToId(query);
  final results = context.test.results;

  if(query is AFTimeUpdateListenerQuery) {
    if(AFibF.g.testOnlyIsInWorkflowTest) {
      query.startAsyncAF(dispatcher, store, completer: null);
      return;
    }
  }

  if(query is AFNavigateUnimplementedQuery) {
    query.startAsyncAF(dispatcher, store, completer: null);
    return;
  }



  var h = results[key];
  if(h == null) {
    /// Ummm, this might be a good place to admit that sometimes the type system
    /// in Dart vexes me.
    if(key.toString().startsWith("AFAlwaysFailQuery")) {
      h = results["AFAlwaysFailQuery<AFAppStateAreaUnused>"];
    }
  }

  if(h == null) {
    /// deferred queries don't have any results.
    if(query is AFDeferredQuery) {
      final successContext = query.createSuccessContext(
        dispatcher: dispatcher,
        state: store.state,
        isPreExecute: false,
      );

      // when we are in a state test in the interactive UI, it is important to actually do the delay,
      // as sometimes an animation must complete before it is safe to execute the deferred action.
      _simulateLatencyIfAppropriate(() => query.finishAsyncExecute(successContext), delay: query.delay, factor: 1, onSuccess: () {
        dispatcher.dispatch(AFShutdownDeferredQueryAction(query.key));
      });

      return;
    }

    if(query is AFPeriodicQuery) {
      // TODO: This seems to work, but I think you want something more nuanced here.  You really
      // want to be synchronous in command-line tests, and also in state tests executed within prototype mode
      // but in the background.   Then, you want to add asynchronous waits in prototype mode once the UI
      // is actually displayed, and the user is interacting with it.
      if(AFibF.g.isPrototypeMode) {
        Timer.periodic(query.delay, (timer) {

          final successContext = query.createSuccessContext(
            dispatcher: dispatcher,
            state: store.state,
            isPreExecute: false,
          );
          final keepGoing = query.finishAsyncExecute(successContext);
          if(!keepGoing) {
            timer.cancel();
            dispatcher.dispatch(AFShutdownPeriodicQueryAction(query.key));
          }
        });
      } else {
        var keepGoing = true;
        while(keepGoing) {
          final successContext = query.createSuccessContext(
            dispatcher: dispatcher,
            state: store.state,
            isPreExecute: false,
          );
          keepGoing = query.finishAsyncExecute(successContext);
          if(!keepGoing) {
            query.shutdown();
            dispatcher.dispatch(AFShutdownPeriodicQueryAction(query.key));
          }
        }
      }

      return;
    }

    if(query is AFCompositeQuery) {
      final successContext = AFFinishQuerySuccessContext<AFCompositeQueryResponse>(
        conceptualStore: AFibF.g.activeConceptualStore,
        response: query.queryResponses,
        isPreExecute: false,
      );
      for(final consolidatedQueries in query.queryResponses.responses) {
        final consolidatedQuery = consolidatedQueries.query;
        final consolidatedKey = AFStateTest.specifierToId(consolidatedQuery);
        final consolidatedHandler = results[consolidatedKey];
        if(consolidatedHandler != null) {
          consolidatedQueries.result = consolidatedHandler.handler?.call(context, consolidatedQuery);
        } else {
          throw AFException("No results specified for query $consolidatedKey in composite query.  Note that you can use defineQueryResponseNone if you intend to have no results.");
        }
      }
      _simulateLatencyIfAppropriate(() => query.finishAsyncWithResponseAF(successContext), factor: query.simulatedLatencyFactor ?? 1);
      return;
    }

    if(key == AFUIQueryID.time.code) {
      throw AFException("Please call defineInitialTime in your state tests if you use AFTimeUpdateListenerQuery to listen to the time");
    }

    throw AFException("No results specified for query ${AFStateTest.specifierToId(query)}");
  }

  final handler = h.handler;
  if(handler != null) {
    final pre = query.onPreExecuteResponse;
    if(pre != null) {
      final preResponse = pre();
      final successContext = query.createSuccessContextForResponse(
        dispatcher: dispatcher,
        state: store.state,
        response: preResponse,
        isPreExecute: true,
      );
      query.finishAsyncWithResponseAF(successContext);
    }

    _simulateLatencyIfAppropriate(() => handler(context, query), factor: query.simulatedLatencyFactor ?? 1);
  }
}