예제 #1
0
        /// <summary>
        /// Generates a result representing the list items 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 GenerateListItemResult(out IResponseItem result)
        {
            result = null;
            var includeResult = false;

            // this instance represents an array of children
            // create an output array of the generated data for each child
            if (_childListItems.Count == 0)
            {
                result        = new ResponseList();
                includeResult = true;
            }
            else
            {
                var list = new ResponseList();
                foreach (var child in _childListItems)
                {
                    var includeChildResult = child.GenerateResult(out var childResult);
                    includeResult = includeResult || includeChildResult;
                    if (includeChildResult)
                    {
                        list.Add(childResult);
                    }
                }

                if (includeResult)
                {
                    result = list;
                }
            }

            return(includeResult);
        }
예제 #2
0
        private void WriteResponseItem(Utf8JsonWriter writer, IResponseItem dataItem)
        {
            if (dataItem == null)
            {
                this.WriteLeafValue(writer, dataItem);
                return;
            }

            switch (dataItem)
            {
            case IResponseFieldSet fieldSet:
                this.WriteObjectCollection(writer, fieldSet);
                break;

            case IResponseList list:
                this.WriteList(writer, list);
                break;

            case IResponseSingleValue singleValue:
                this.WriteLeafValue(writer, singleValue.Value);
                break;

            default:
                throw new ArgumentOutOfRangeException(
                          $"Unknown {nameof(IResponseItem)} type. " +
                          $"Default writer is unable to write type '{dataItem.GetType().FriendlyName()}' to the output stream.");
            }
        }
예제 #3
0
        /// <summary>
        /// Generates the result for this data item.  Will correctly populate a list or key/value pait object
        /// according to the rules of the field this data item represents.
        /// </summary>
        /// <param name="result">The result object that was generated.</param>
        /// <returns><c>true</c> if the result was generated and should be included in any up stream responses. <c>false</c> if this result should be ignored
        /// and not included.</returns>
        public bool GenerateResult(out IResponseItem result)
        {
            result = null;

            // no data resolved? no children can exist
            // return indicating if the "null" is acceptable or not.
            if (this.ResultData == null || _resultsDiscarded)
            {
                return(this.Status.IncludeInOutput());
            }

            // total fail, womp womp
            if (!this.Status.IncludeInOutput())
            {
                return(false);
            }

            // leafs have nothing underneath  them, the resolved data IS the item value.
            if (this.FieldContext.Field.IsLeaf)
            {
                // List<SomeScalar> and List<SomeEnum> are leafs since there is no further
                // resolution to the data but its still must be projected
                // as a list response item when rendered
                // ----
                return(this.IsListField
                    ? this.GenerateListItemResult(out result)
                    : this.GenerateSingleValueResult(out result));
            }

            bool includeResult;

            if (_childFields != null)
            {
                includeResult = this.GenerateFieldListResult(out result);
            }
            else if (_childListItems != null)
            {
                includeResult = this.GenerateListItemResult(out result);
            }
            else
            {
                // no fields were resolved and no children containers were assigned
                // drop the item from the response. This can occur if a resolver returns
                // an object that is not scoped to the current query such as returning
                // Droids and Humans but the query is just a fragment spread for Humans
                // the droids would be dropped as they were not requested
                includeResult = false;
                result        = null;
            }

            return(includeResult);
        }
예제 #4
0
        /// <summary>
        /// Generates the single value result.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns><c>true</c> if the leaf value was successfully rendered, <c>false</c> otherwise.</returns>
        private bool GenerateSingleValueResult(out IResponseItem result)
        {
            result = null;
            var resultData = this.ResultData;

            if (resultData != null)
            {
                var type = resultData.GetType();
                if (GraphQLProviders.ScalarProvider.IsScalar(type))
                {
                    var graphType = GraphQLProviders.ScalarProvider.RetrieveScalar(type);
                    resultData = graphType.Serializer.Serialize(resultData);
                }
            }

            result = new ResponseSingleValue(resultData);
            return(true);
        }
예제 #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);
        }
 /// <summary>
 /// Adds a new response item to this field set with the specified name.
 /// </summary>
 /// <param name="name">The name of the item.</param>
 /// <param name="item">The item.</param>
 public void Add(string name, IResponseItem item)
 {
     _dictionary.Add(name, item);
 }
예제 #7
0
 /// <summary>
 /// Adds the specified item to the growing list.
 /// </summary>
 /// <param name="item">The item.</param>
 public void Add(IResponseItem item)
 {
     _list.Add(item);
 }