Пример #1
0
 private void CalcVariableDefaultValues(GraphQLOperation op)
 {
     foreach (var varDef in op.Variables)
     {
         if (varDef.ParsedDefaultValue == null)
         {
             continue;
         }
         var inpDef  = varDef.InputDef;
         var typeRef = inpDef.TypeRef;
         var eval    = GetInputValueEvaluator(inpDef, varDef.ParsedDefaultValue, typeRef);
         if (!eval.IsConst())
         {
             // somewhere inside there's reference to variable, this is not allowed
             AddError($"Default value cannot reference variables.", varDef);
             continue;
         }
         var value = eval.GetValue(_requestContext);
         if (value != null && value.GetType() != typeRef.TypeDef.ClrType)
         {
             // TODO: add valid coersion rules; for ex, spec allows auto convert like  int => int[]
             AddError($"Detected type mismatch for default value '{value}' of variable {varDef.Name} of type {typeRef.Name}", varDef);
         }
         inpDef.DefaultValue    = value;
         inpDef.HasDefaultValue = true;
     } // foreach varDef
 }
Пример #2
0
        private async Task ExecuteOperationAsync(GraphQLOperation op, OutputObjectScope topScope)
        {
            var opOutItemSet = op.SelectionSubset.MappedItemSets.FirstOrDefault(fi => fi.ObjectTypeDef == op.OperationTypeDef);
            var topFields    = _requestContext.GetIncludedMappedFields(opOutItemSet);

            topScope.Init(op.OperationTypeDef, topFields);
            var parallel = _parallelQuery && op.OperationType == OperationType.Query && topFields.Count > 1;

            // Note: if we go parallel here, note that the topScope is safe for concurrent thread access;
            //   it is only used to save op result value (SetValue method)
            var executers = new List <OperationFieldExecuter>();

            for (int fieldIndex = 0; fieldIndex < topFields.Count; fieldIndex++)
            {
                var opExecuter = new OperationFieldExecuter(_requestContext, topScope, fieldIndex);
                executers.Add(opExecuter);
            }

            _requestContext.Metrics.ExecutionThreadCount = executers.Count;
            if (parallel)
            {
                await ExecuteAllParallel(executers);
            }
            else
            {
                await ExecuteAllNonParallel(executers);
            }
        }
Пример #3
0
 private void CalcVariableDefaultValues(GraphQLOperation op)
 {
     foreach (var varDef in op.Variables)
     {
         if (varDef.ParsedDefaultValue == null)
         {
             continue;
         }
         var inpDef  = varDef.InputDef;
         var typeRef = inpDef.TypeRef;
         var eval    = GetInputValueEvaluator(inpDef, varDef.ParsedDefaultValue, typeRef);
         if (!eval.IsConst())
         {
             // somewhere inside there's reference to variable, this is not allowed
             AddError($"Default value cannot reference variables.", varDef);
             continue;
         }
         var value = eval.GetValue(_requestContext);
         if (value != null && value.GetType() != typeRef.TypeDef.ClrType)
         {
             // TODO: fix that, add type conversion, for now throwing exception; or maybe it's not needed, value will be converted at time of use
             // but spec also allows auto casting like  int => int[]
             AddError($"Detected type mismatch for default value '{value}' of variable {varDef.Name} of type {typeRef.Name}", varDef);
         }
         inpDef.DefaultValue    = value;
         inpDef.HasDefaultValue = true;
     } // foreach varDef
 }
Пример #4
0
        public void MapAndValidateRequest()
        {
            var fragmAnalyzer = new FragmentAnalyzer(_requestContext);

            fragmAnalyzer.Analyze();
            if (_requestContext.Failed)
            {
                return;
            }
            foreach (var fragm in _requestContext.ParsedRequest.Fragments)
            {
                if (!fragm.IsInline)
                {
                    MapFragment(fragm);
                }
            }

            foreach (var op in _requestContext.ParsedRequest.Operations)
            {
                if (!AssignOperationDef(op))
                {
                    continue;
                }
                MapOperation(op);
                CalcVariableDefaultValues(op);
            }
            _currentOp = null;
        }
Пример #5
0
 private void MapOperation(GraphQLOperation op)
 {
     MapSelectionSubSet(op.SelectionSubset, op.OperationTypeDef, op.Directives);
     if (_pendingSelectionSets.Count > 0)
     {
         MapPendingSelectionSubsets();
     }
 }
Пример #6
0
        private void BuildDefaultQuery(Node qNode)
        {
            var query = new GraphQLOperation()
            {
                Name = null, OperationType = OperationType.Query
            };

            CompleteBuildOperation(query, qNode);
        }
Пример #7
0
 public void MapAndValidateRequest()
 {
     Fragments_MapValidate();
     if (_requestContext.Failed)
     {
         return;
     }
     foreach (var op in _requestContext.ParsedRequest.Operations)
     {
         op.OperationTypeDef = _model.GetOperationDef(op.OperationType);
         _currentOp          = op;
         CalcVariableDefaultValues(op);
         MapOperation(op);
     }
     _currentOp = null;
 }
Пример #8
0
 private void BuildOperations(IList <Node> opNodes)
 {
     foreach (var opNode in opNodes)
     {
         var    nameNode   = opNode.FindChild(TermNames.Name);
         string name       = nameNode?.GetText() ?? null;
         var    opTypeNode = opNode.FindChild(TermNames.OpType);
         var    opTypeStr  = opTypeNode.GetText();
         if (!Enum.TryParse <OperationType>(opTypeStr, true, out var opType))
         {
             AddError($"Invalid operation type '{opTypeStr}'.", opTypeNode);
             continue;
         }
         var op = new GraphQLOperation()
         {
             Name = name, OperationType = opType
         };
         CompleteBuildOperation(op, opNode);
     }
 }
Пример #9
0
        private bool AssignOperationDef(GraphQLOperation op)
        {
            ObjectTypeDef opDef = null;

            switch (op.OperationType)
            {
            case OperationType.Query: opDef = _model.QueryType; break;

            case OperationType.Mutation: opDef = _model.MutationType; break;

            case OperationType.Subscription: opDef = _model.SubscriptionType; break;
            }
            if (opDef == null)
            {
                AddError($"Operation '{op.OperationType}' is not defined in schema. Operation: '{op.Name}'.", op);
                return(false);
            }
            op.OperationTypeDef = opDef;
            return(true);
        }
Пример #10
0
 private void CompleteBuildOperation(GraphQLOperation op, Node opNode)
 {
     try {
         if (op.Name != null)
         {
             _path.Push(op.Name);
         }
         var varDefsNode = opNode.FindChild(TermNames.VarDefList);
         op.Variables = BuildOperationVariables(varDefsNode);
         var selSetNode = opNode.FindChild(TermNames.SelSet);
         if (selSetNode != null)
         {
             var selItems = BuildSelectionItemsList(selSetNode, op);
             op.SelectionSubset = new SelectionSubset(op, selItems, selSetNode.GetLocation());
         }
         _requestContext.ParsedRequest.Operations.Add(op);
     } finally {
         // op.Name might have been assigned, so we don't check name, but just pop path
         _path.Clear();
     }
 }
Пример #11
0
        private async Task ExecuteOperationAsync(GraphQLOperation op, OutputObjectScope topScope)
        {
            var mappedTopSubset = op.SelectionSubset.MappedSubSets[0];
            var topMappedItems  = mappedTopSubset.MappedItems;
            var parallel        = _parallelQueryEnabled && op.OperationType == OperationType.Query &&
                                  op.SelectionSubset.Items.Count > 1;

            var executers = new List <OperationFieldExecuter>();

            foreach (var mappedItem in topMappedItems)
            {
                switch (mappedItem)
                {
                case MappedFragmentSpread mfs:
                    _requestContext.AddInputError($"Top selection items may not be fragments", mfs.Spread);
                    return;

                case MappedSelectionField mappedField:
                    var opExecuter = new OperationFieldExecuter(_requestContext, mappedField, topScope);
                    executers.Add(opExecuter);
                    break;
                }
            }

            if (parallel)
            {
                await ExecuteAllParallel(executers);
            }
            else
            {
                await ExecuteAllNonParallel(executers);
            }

            // Save results from op fields into top scope; we do it here, after all threads finished, to avoid concurrency issues
            // and preserve output field order
            foreach (var ex in executers)
            {
                topScope.SetValue(ex.ResultKey, ex.Result);
            }
        }
Пример #12
0
 private void MapOperation(GraphQLOperation op)
 {
     _currentOp = op;
     MapSelectionSubSet(op.SelectionSubset, op.OperationTypeDef);
 }