private async Task ExecuteMappedSelectionSubsetAsync(MappedSelectionSubSet mappedSubSet, IList <ObjectTypeDef> possibleTypes,
                                                             IList <OutputObjectScope> parentScopes)
        {
            foreach (var mappedItem in mappedSubSet.MappedItems)
            {
                if (mappedItem.Item.OnExecuting(_requestContext, out var args) && args.Skip)
                {
                    continue;
                }

                // if it is a fragment spread, make recursive call to process fragment fields
                if (mappedItem.Item.Kind == SelectionItemKind.FragmentSpread)
                {
                    var mappedSpread      = (MappedFragmentSpread)mappedItem;
                    var objTypeDef        = mappedSubSet.Mapping.TypeDef;
                    var fragmSelSubset    = mappedSpread.Spread.Fragment.SelectionSubset;
                    var entType           = mappedSubSet.Mapping.EntityType;
                    var mappedFragmSubset = GetMappedSubset(fragmSelSubset, possibleTypes, entType, mappedSpread.Spread);
                    await ExecuteMappedSelectionSubsetAsync(mappedFragmSubset, possibleTypes, parentScopes); //call self recursively

                    continue;
                }

                // It is a plain field
                var mappedField  = (MappedSelectionField)mappedItem;
                var fieldContext = new FieldContext(_requestContext, this, mappedField, parentScopes);
                var selFieldKey  = mappedField.Field.Key;

                // Process each scope for the field
                foreach (var scope in parentScopes)
                {
                    if (fieldContext.BatchResultWasSet && scope.ContainsKey(selFieldKey))
                    {
                        continue;
                    }
                    fieldContext.SetCurrentParentScope(scope);
                    var    fldDef = fieldContext.FieldDef;
                    object result = await InvokeResolverAsync(fieldContext);

                    // if batched result was not set, save value in scope
                    if (!fieldContext.BatchResultWasSet)
                    {
                        scope.SetValue(selFieldKey, result);
                    }
                } //foreach scope
                // if there are any non-null object-type results, add this field context to this special list
                //   to execute selection subsets in the next round.
                if (mappedField.Field.SelectionSubset != null && fieldContext.AllResultScopes.Count > 0)
                {
                    _executedObjectFieldContexts.Add(fieldContext);
                }
            } //foreach mappedItem
        }     //method
        public async Task ExecuteOperationFieldAsync()
        {
            try {
                if (_mappedOpField.Field.OnExecuting(_requestContext, out var args) && args.Skip)
                {
                    Result = DBNull.Value; // it's a signal to skip value in output
                    return;
                }
                var opFieldContext = new FieldContext(_requestContext, this, _mappedOpField);
                opFieldContext.SetCurrentParentScope(_parentScope);
                // We do not save result in parent top-level context: we maybe executing in parallel with other top-level fields;
                // we need synchronization(lock), and also op fields might finish out of order. So we save result in a field, and
                //  RequestHandler will save all results from executers in proper order.
                //_parentScope.SetValue(_mappedOpField.Field.Key, opOutValue); -- do not do this
                this.Result = await InvokeResolverAsync(opFieldContext);

                // for fields returning objects, save for further processing of results
                if (opFieldContext.MappedField.Field.SelectionSubset != null)
                {
                    _executedObjectFieldContexts.Add(opFieldContext);
                }

                // process object field results until no more
                while (_executedObjectFieldContexts.Count > 0)
                {
                    if (_requestContext.CancellationToken.IsCancellationRequested)
                    {
                        opFieldContext.ThrowRequestCancelled();
                    }
                    // save current list, create new one in the field
                    var oldFieldContexts = _executedObjectFieldContexts;
                    _executedObjectFieldContexts = new List <FieldContext>();
                    foreach (var fldCtx in oldFieldContexts)
                    {
                        await ExecuteFieldSelectionSubsetAsync(fldCtx);
                    }
                }//while
            } finally {
                // notify resolvers about end request
                if (_resolverInstances.Count > 0)
                {
                    foreach (var resObj in _resolverInstances)
                    {
                        (resObj as IResolverClass)?.EndRequest(_requestContext);
                    }
                }
            }
        }