Exemple #1
0
        /// <summary>
        /// Generates the execution result, a list of individual results for each resolver tracked.
        /// </summary>
        /// <returns>IDictionary&lt;System.String, System.Object&gt;.</returns>
        private IResponseFieldSet GenerateExecutionResult()
        {
            // apollo tracing does not specifiy providing startOffset and duration keys for the execution
            // phase, just output the resolvers array
            var list = new ResponseList();

            foreach (var timeEntry in _resolverEntries.OrderBy(x => x.Value.StartOffsetTicks))
            {
                var resolverEntry = new ResponseFieldSet();
                resolverEntry.Add("path", new ResponseList(timeEntry
                                                           .Key
                                                           .Request
                                                           .Origin
                                                           .Path
                                                           .ToArray()
                                                           .Select(x => new ResponseSingleValue(x))));

                var parentType = _schema.KnownTypes.FindGraphType(timeEntry.Key.Request?.DataSource?.Value);
                if (parentType != null)
                {
                    resolverEntry.AddSingleValue("parentType", parentType.Name);
                }

                resolverEntry.AddSingleValue("fieldName", timeEntry.Key.Request.Field.Name);
                resolverEntry.AddSingleValue("returnType", timeEntry.Key.Request.Field.TypeExpression.ToString());
                resolverEntry.AddSingleValue("startOffset", timeEntry.Value.StartOffsetNanoseconds);
                resolverEntry.AddSingleValue("duration", timeEntry.Value.DurationNanoSeconds);
                list.Add(resolverEntry);
            }

            var dictionary = new ResponseFieldSet();

            dictionary.Add("resolvers", list);
            return(dictionary);
        }
Exemple #2
0
        /// <summary>
        /// Formats the output of the metrics into a set of nested key/value pairs that can be written to a graph
        /// ql data response. The keys returned will be written directly to the "extensions" section of the graphql response.
        /// It is recommended to return a single toplevel key containing the entirety of your metrics data.
        /// </summary>
        /// <returns>KeyValuePair&lt;System.String, System.Object&gt;.</returns>
        public virtual IResponseFieldSet GenerateResult()
        {
            var results = new ResponseFieldSet();

            results.AddSingleValue("version", VERSION);

            // the apollo tracing specification says the date MUST be in RFC3339 format
            // do not leave the formatting up to the serializer.
            results.AddSingleValue("startTime", this.StartDate);
            results.AddSingleValue("endTime", this.StartDate.AddTicks(this.TotalTicks));
            results.AddSingleValue("duration", this.TotalTicks);

            if (_phaseEntries.TryGetValue(ApolloExecutionPhase.PARSING, out var entry))
            {
                results.Add("parsing", this.GeneratePhaseResult(entry));
            }
            if (_phaseEntries.TryGetValue(ApolloExecutionPhase.VALIDATION, out entry))
            {
                results.Add("validation", this.GeneratePhaseResult(entry));
            }

            results.Add("execution", this.GenerateExecutionResult());

            var finalResult = new ResponseFieldSet();

            finalResult.Add("tracing", results);
            return(finalResult);
        }
Exemple #3
0
        /// <summary>
        /// Generates the phase metrics result for inclusion in the output json.
        /// </summary>
        /// <param name="entry">The entry.</param>
        /// <returns>System.Object.</returns>
        private IResponseItem GeneratePhaseResult(ApolloMetricsEntry entry)
        {
            var dictionary = new ResponseFieldSet();

            dictionary.AddSingleValue("startOffset", entry.StartOffsetNanoseconds);
            dictionary.AddSingleValue("duration", entry.DurationNanoSeconds);
            return(dictionary);
        }
Exemple #4
0
        /// <summary>
        /// Convert the data items that were generated pushing their results into a final top level dictionary
        /// to be returned as the graph projection. Takes care of an final messaging in case one of the tasks failed.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns>GraphQL.AspNet.Interfaces.Response.IResponseFieldSet.</returns>
        private IResponseFieldSet CreateFinalDictionary(GraphQueryExecutionContext context)
        {
            var topFieldResponses = new ResponseFieldSet();

            foreach (var fieldResult in context.FieldResults)
            {
                var generated = fieldResult.GenerateResult(out var result);
                if (generated)
                {
                    topFieldResponses.Add(fieldResult.Name, result);
                }
            }

            if (topFieldResponses.Fields.Count == 0 || topFieldResponses.Fields.All(x => x.Value == null))
            {
                topFieldResponses = null;
            }

            return(topFieldResponses);
        }
Exemple #5
0
        /// <summary>
        /// Generates a result representing the individual child fields of this instance. This result
        /// is built in a manner that can be easily serialized.
        /// </summary>
        /// <param name="result">The result that was generated.</param>
        /// <returns><c>true</c> if the result that was generated is valid and should
        /// be included in a final result, <c>false</c> otherwise.</returns>
        private bool GenerateFieldListResult(out IResponseItem result)
        {
            result = null;
            var includeResult = false;

            // this instance represents a set of key/value pair fields
            // create a dictionary of those kvps as the result
            var fieldSet = new ResponseFieldSet();

            foreach (var field in _childFields)
            {
                var includeChildResult = field.GenerateResult(out var childResult);
                includeResult = includeResult || includeChildResult;
                if (includeChildResult)
                {
                    if (fieldSet.Fields.ContainsKey(field.FieldContext.Name))
                    {
                        throw new GraphExecutionException(
                                  $"Duplicate field name. The field '{field.Name}'  at '{this.Origin.Path.DotString()}' was resolved " +
                                  $"more than once for a source object, unable to generate a valid output. " +
                                  $"Field collections require unique names. An attempt was made to add the field '{field.Name}', " +
                                  $"for target type '{field.FieldContext.ExpectedSourceType?.FriendlyName() ?? "-all-"}' when the field " +
                                  "name was already present in the output dictionary.",
                                  this.Origin,
                                  new InvalidOperationException($"The source object '{this.SourceData}' successfully resolved a field name of '{field.Name}' more than once when it shouldn't. This may occur if a source " +
                                                                "object type is referenced to to multiple target graph types in fragment references. Ensure that your source data uniquely maps to one fragment per field collection " +
                                                                "or that the fragments do not share property names."));
                    }

                    fieldSet.Add(field.FieldContext.Name, childResult);
                }
            }

            if (includeResult)
            {
                result = fieldSet;
            }

            return(includeResult);
        }
        public async Task EnsureProperStringEscapement(string testValue, string expectedValue)
        {
            var fixedDate = DateTimeOffset.UtcNow.UtcDateTime;

            var builder = new TestServerBuilder()
                          .AddGraphType <SimpleExecutionController>();

            builder.AddGraphQL(o =>
            {
                o.ResponseOptions.TimeStampLocalizer = (_) => fixedDate;
            });

            var server       = builder.Build();
            var queryBuilder = server.CreateQueryContextBuilder();

            var dic = new ResponseFieldSet();

            dic.Add("testKey", new ResponseSingleValue(testValue));

            var mockResult = new Mock <IGraphOperationResult>();

            mockResult.Setup(x => x.Data).Returns(dic);
            mockResult.Setup(x => x.Messages).Returns(new GraphMessageCollection());
            mockResult.Setup(x => x.Request).Returns(queryBuilder.OperationRequest);

            var writer = new DefaultResponseWriter <GraphSchema>(server.Schema);
            var result = await this.WriteResponse(writer, mockResult.Object);

            var expected = @"
                            {
                                ""data"" : {
                                    ""testKey"" : """ + expectedValue + @""",
                                }
                            }";

            CommonAssertions.AreEqualJsonStrings(expected, result);
        }