// perform a query
        public override async Task QueryAsync(PartitionQueryEvent queryEvent, EffectTracker effectTracker)
        {
            try
            {
                var instanceQuery = queryEvent.InstanceQuery;

#if FASTER_SUPPORTS_PSF
                IAsyncEnumerable <OrchestrationState> queryPSFsAsync(ClientSession <Key, Value, EffectTracker, TrackedObject, PartitionReadEvent, Functions> session)
                {
                    // Issue the PSF query. Note that pending operations will be completed before this returns.
                    var querySpec = new List <(IPSF, IEnumerable <PSFKey>)>();

                    if (instanceQuery.HasRuntimeStatus)
                    {
                        querySpec.Add((this.RuntimeStatusPsf, instanceQuery.RuntimeStatus.Select(s => new PSFKey(s))));
                    }
                    if (instanceQuery.CreatedTimeFrom.HasValue || instanceQuery.CreatedTimeTo.HasValue)
                    {
                        IEnumerable <PSFKey> enumerateDateBinKeys()
                        {
                            var to   = instanceQuery.CreatedTimeTo ?? DateTime.UtcNow;
                            var from = instanceQuery.CreatedTimeFrom ?? to.AddDays(-7);   // TODO Some default so we don't have to iterate from the first possible date

                            for (var dt = from; dt <= to; dt += PSFKey.DateBinInterval)
                            {
                                yield return(new PSFKey(dt));
                            }
                        }
                        querySpec.Add((this.CreatedTimePsf, enumerateDateBinKeys()));
                    }
                    if (!string.IsNullOrWhiteSpace(instanceQuery.InstanceIdPrefix))
                    {
                        querySpec.Add((this.InstanceIdPrefixPsf, new[] { new PSFKey(instanceQuery.InstanceIdPrefix) }));
                    }
                    var querySettings = new PSFQuerySettings
                    {
                        // This is a match-all-PSFs enumeration so do not continue after any PSF has hit EOS
                        OnStreamEnded = (unusedPsf, unusedIndex) => false
                    };

                    OrchestrationState getOrchestrationState(ref Value v)
                    {
                        if (v.Val is byte[] serialized)
                        {
                            var result = ((InstanceState)Serializer.DeserializeTrackedObject(serialized))?.OrchestrationState;
                            if (result != null && !instanceQuery.FetchInput)
                            {
                                result.Input = null;
                            }
                            return(result);
                        }
                        else
                        {
                            var state  = ((InstanceState)((TrackedObject)v))?.OrchestrationState;
                            var result = state?.ClearFieldsImmutably(instanceQuery.FetchInput, true);
                            return(result);
                        }
                    }

                    return(session.QueryPSFAsync(querySpec, matches => matches.All(b => b), querySettings)
                           .Select(providerData => getOrchestrationState(ref providerData.GetValue()))
                           .Where(orchestrationState => orchestrationState != null));
                }
#else
                IAsyncEnumerable <OrchestrationState> queryPSFsAsync(ClientSession <Key, Value, EffectTracker, TrackedObject, object, IFunctions <Key, Value, EffectTracker, TrackedObject, object> > session)
                => this.ScanOrchestrationStates(effectTracker, queryEvent);
#endif
                // create an individual session for this query so the main session can be used
                // while the query is progressing.
                using (var session = this.CreateASession())
                {
                    var orchestrationStates = (this.partition.Settings.UsePSFQueries && instanceQuery.IsSet)
                        ? queryPSFsAsync(session)
                        : this.ScanOrchestrationStates(effectTracker, queryEvent);

                    await effectTracker.ProcessQueryResultAsync(queryEvent, orchestrationStates);
                }
            }
            catch (Exception exception)
                when(this.terminationToken.IsCancellationRequested && !Utils.IsFatal(exception))
                {
                    throw new OperationCanceledException("Partition was terminated.", exception, this.terminationToken);
                }
        }