コード例 #1
0
        /// <summary>
        /// Runs the creation mutation
        /// </summary>
        /// <param name="connection">The connection</param>
        /// <param name="request">The request</param>
        /// <param name="field">
        /// The connection field
        /// </param>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="argumentsSerializer">
        /// The arguments serializer.
        /// </param>
        /// <param name="onErrorCallback">
        /// The on error callback.
        /// </param>
        /// <returns>The resolved data</returns>
        private async Task <JObject> MutationCreate(
            INodeConnection <T> connection,
            ApiRequest request,
            ApiField field,
            RequestContext context,
            JsonSerializer argumentsSerializer,
            Action <Exception> onErrorCallback)
        {
            var serializedData = ((JObject)request.Arguments)?.Property("newNode")?.Value as JObject;
            var newNode        = serializedData?.ToObject <T>();
            var result         = await connection.Create(newNode);

            var mutationCreate =
                (JObject)
                await mutationResultResolver.ResolveQuery(
                    result,
                    request,
                    field,
                    context,
                    argumentsSerializer,
                    onErrorCallback);

            SetLog(request, field, context, EnConnectionAction.Create);
            return(mutationCreate);
        }
コード例 #2
0
        /// <summary>
        /// Adds a new filter condition
        /// </summary>
        /// <param name="name">The name of condition</param>
        /// <param name="expression">The expression generator</param>
        /// <param name="field">The field to check</param>
        /// <param name="description">The filter description</param>
        private static void AddFilterExpression(
            string name,
            Func <JProperty, Expression> expression,
            ApiField field,
            string description)
        {
            FilterChecks[name] = expression;

            description = string.Format(description, field.Name);
            var filterDescription = !string.IsNullOrWhiteSpace(field.Description)
                                        ? $"{description}, {field.Name}: {field.Description}"
                                        : description;

            if (field.ScalarType != EnScalarType.None)
            {
                FilterType.Fields.Add(
                    ApiField.Scalar(
                        name,
                        field.ScalarType,
                        EnFieldFlags.Queryable | EnFieldFlags.CanBeUsedInInput,
                        description: filterDescription));
            }
            else
            {
                FilterType.Fields.Add(
                    ApiField.Object(
                        name,
                        field.TypeName,
                        EnFieldFlags.Queryable | EnFieldFlags.CanBeUsedInInput,
                        description: filterDescription));
            }
        }
コード例 #3
0
        protected virtual void Process(HierarchyObject parent, ApiField field)
        {
            var hierarchyField = CreateHierarchyElementInternal <HierarchyField> (parent);

            hierarchyField.Init(field);
            AddLocationComment(field, hierarchyField);
            parent.AddMember(hierarchyField);
        }
コード例 #4
0
        public FieldModel(ApiField field)
        {
            if (field == null)
            {
                throw new ArgumentNullException(nameof(field));
            }

            _field = field;
        }
コード例 #5
0
 /// <inheritdoc />
 public Task <JToken> ResolveQuery(
     object source,
     ApiRequest request,
     ApiField apiField,
     RequestContext context,
     JsonSerializer argumentsSerializer,
     Action <Exception> onErrorCallback)
 {
     return(Task.FromResult <JToken>(null));
 }
コード例 #6
0
        public override void Init(ApiElement apiElement)
        {
            base.Init(apiElement);

            apiField         = EnsureApiElementType <ApiField> (apiElement);
            Transient        = apiField.Transient;
            Type             = apiField.Type;
            TypeGenericAware = apiField.TypeGenericAware;
            Value            = apiField.Value;
            Volatile         = apiField.Volatile;
        }
コード例 #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MergedUntypedMutationResult"/> class.
 /// </summary>
 /// <param name="originalReturnType">
 /// The original mutation return type.
 /// </param>
 /// <param name="root">
 /// The root.
 /// </param>
 /// <param name="provider">
 /// The provider.
 /// </param>
 /// <param name="field">
 /// The original field description
 /// </param>
 public MergedUntypedMutationResult(
     MergedType originalReturnType,
     MergedApiRoot root,
     ApiProvider provider,
     ApiField field)
     : base(originalReturnType.OriginalTypeName)
 {
     this.OriginalReturnType = originalReturnType;
     this.root     = root;
     this.field    = field;
     this.Provider = provider;
 }
コード例 #8
0
        public async Task EnumApiTest()
        {
            var enumType = new ApiEnumType("EnumType", new[] { "item1", "item2" });

            var api = new ApiDescription(
                "TestApi1",
                "0.0.0.1",
                new ApiType[] { enumType },
                new[] { ApiField.Object("enumField", enumType.TypeName) });

            var provider = new MoqProvider {
                Description = api, Data = "{\"enumField\": \"item2\"}"
            };

            var schema = SchemaGenerator.Generate(new List <ApiProvider> {
                provider
            });

            using (var printer = new SchemaPrinter(schema))
            {
                var description = printer.Print();
                this.output.WriteLine("-------- Schema -----------");
                this.output.WriteLine(description);
                Assert.False(string.IsNullOrWhiteSpace(description));
            }

            Assert.NotNull(schema.Query);
            Assert.Equal(3, schema.Query.Fields.Count());
            Assert.True(schema.Query.HasField("api"));

            var result = await new DocumentExecuter().ExecuteAsync(
                r =>
            {
                r.Schema = schema;
                r.Query  = "query { api { enumField } } ";
            }).ConfigureAwait(true);

            this.output.WriteLine("-------- Response -----------");
            var response = new DocumentWriter(true).Write(result);

            this.output.WriteLine(response);

            var expectedResponse = @"{
                                      ""data"": {
                                        ""api"": {
                                            ""enumField"": ""item2"" 
                                        }
                                     }                                      
                                    }";

            Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response));
        }
コード例 #9
0
 /// <summary>
 /// Resolves query
 /// </summary>
 /// <param name="requests">
 /// The query request
 /// </param>
 /// <param name="context">
 /// The request context.
 /// </param>
 /// <param name="onErrorCallback">
 /// The method that will be called in case of errors
 /// </param>
 /// <returns>
 /// Resolved query
 /// </returns>
 public virtual Task <JToken> ResolveQuery(
     List <ApiRequest> requests,
     RequestContext context,
     Action <Exception> onErrorCallback)
 {
     return(this.resolver.ResolveQuery(
                this,
                new ApiRequest {
         Fields = requests
     },
                ApiField.Object("root", this.ApiDescription.ApiName),
                context,
                this.argumentsSerializer,
                onErrorCallback));
 }
コード例 #10
0
        /// <inheritdoc />
        public Task <JObject> ResolveMutation(
            object nodeConnection,
            ApiRequest request,
            ApiField field,
            RequestContext context,
            JsonSerializer argumentsSerializer,
            Action <Exception> onErrorCallback)
        {
            var connection = nodeConnection as INodeConnection <T>;

            if (connection == null)
            {
                return(Task.FromResult <JObject>(null));
            }

            switch (request.FieldName)
            {
            case "create":
                return(this.MutationCreate(
                           connection,
                           request,
                           field,
                           context,
                           argumentsSerializer,
                           onErrorCallback));

            case "update":
                return(this.MutationUpdate(
                           connection,
                           request,
                           field,
                           context,
                           argumentsSerializer,
                           onErrorCallback));

            case "delete":
                return(this.MutationDelete(
                           connection,
                           request,
                           field,
                           context,
                           argumentsSerializer,
                           onErrorCallback));

            default:
                return(Task.FromResult <JObject>(null));
            }
        }
コード例 #11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MergedField"/> class.
 /// </summary>
 /// <param name="name">
 /// The field name.
 /// </param>
 /// <param name="type">
 /// The type.
 /// </param>
 /// <param name="provider">
 /// The api provider for the field
 /// </param>
 /// <param name="field">The original field description</param>
 /// <param name="flags">
 /// The flags.
 /// </param>
 /// <param name="arguments">
 /// The field arguments (in case the field is method).
 /// </param>
 /// <param name="description">
 /// The field description
 /// </param>
 public MergedField(
     string name,
     MergedType type,
     ApiProvider provider,
     ApiField field,
     EnFieldFlags flags = EnFieldFlags.None,
     IReadOnlyDictionary <string, MergedField> arguments = null,
     string description = null)
 {
     this.FieldName   = name;
     this.Type        = type;
     this.Flags       = flags;
     this.Arguments   = (arguments ?? new Dictionary <string, MergedField>()).ToImmutableDictionary();
     this.Description = description;
     this.AddProvider(provider, field);
 }
コード例 #12
0
        public static string ToCSharpPropertyName(this ApiField subject, string?containingType)
        {
            var propertyName = CSharpIdentifier.ForClassOrNamespace(subject.Name);

            return(subject.Type switch
            {
                ApiFieldType.Primitive primitive when primitive.ToCSharpPrimitiveType() == CSharpType.Bool &&
                !propertyName.StartsWith("Is") &&
                !propertyName.StartsWith("Can")
                => $"Is{propertyName}",

                // Resolve CS0542 - Member names cannot be the same as their enclosing type by adding prefix/suffix
                ApiFieldType.Array _ when string.Equals(propertyName, containingType, StringComparison.OrdinalIgnoreCase)
                => $"{propertyName}Items",

                _ => propertyName
            });
コード例 #13
0
        /// <summary>
        /// Gets the generated arguments
        /// </summary>
        /// <returns>The list of arguments</returns>
        public static IEnumerable <ApiField> GetArguments()
        {
            if (FilterType.Fields.Count > 2)
            {
                yield return
                    (FilterType.CreateField(
                         "filter",
                         EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument));
            }

            if (SortType.Values.Any())
            {
                const EnFieldFlags SortFlags =
                    EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument
                    | EnFieldFlags.IsArray;
                yield return(ApiField.Object("sort", SortType.TypeName, SortFlags));
            }

            if (NodeMetaData.KeyProperty != null)
            {
                var keyMetadata = TypeMetadata.GenerateTypeMetadata(
                    NodeMetaData.KeyProperty.PropertyType,
                    NodeMetaData.KeyProperty.GetCustomAttribute <PublishToApiAttribute>());
                if (keyMetadata.ScalarType != EnScalarType.None)
                {
                    yield return
                        (ApiField.Scalar(
                             "id",
                             keyMetadata.ScalarType,
                             EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument));
                }
            }

            yield return
                (ApiField.Scalar(
                     "limit",
                     EnScalarType.Integer,
                     EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument));

            yield return
                (ApiField.Scalar(
                     "offset",
                     EnScalarType.Integer,
                     EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument));
        }
コード例 #14
0
        private string GenerateExtensionMethodsFor(
            string currentDtoType,
            string currentPartialType,
            ApiField apiField)
        {
            var indent  = new Indent();
            var builder = new StringBuilder();

            var propertyName = apiField.ToCSharpPropertyName(currentDtoType);
            var apiFieldName = apiField.Name;

            // Field
            builder.AppendLine($"{indent}public static {currentPartialType} With{propertyName}(this {currentPartialType} it)");
            indent.Increment();
            builder.AppendLine($"{indent}=> it.AddFieldName(\"{apiFieldName}\");");
            indent.Decrement();
            builder.AppendLine($"{indent}");

            var currentFieldInnerType = GenerateCSharpTypeFrom(apiField.Type);

            var isPrimitiveOrObject = apiField.Type is ApiFieldType.Primitive || apiField.Type is ApiFieldType.Object;
            var isArrayOfPrimitive  = apiField.Type is ApiFieldType.Array arrayField && arrayField.ElementType is ApiFieldType.Primitive;

            if (!isPrimitiveOrObject && !isArrayOfPrimitive && !string.IsNullOrEmpty(currentFieldInnerType))
            {
                // Recursive field?
                if (currentDtoType == currentFieldInnerType)
                {
                    builder.AppendLine($"{indent}public static {currentPartialType} With{propertyName}Recursive(this {currentPartialType} it)");
                    indent.Increment();
                    builder.AppendLine($"{indent}=> it.AddFieldName(\"{apiFieldName}!\");");
                    indent.Decrement();
                    builder.AppendLine($"{indent}");
                }

                // Field with partial builder
                builder.AppendLine($"{indent}public static {currentPartialType} With{propertyName}(this {currentPartialType} it, Func<Partial<{currentFieldInnerType}>, Partial<{currentFieldInnerType}>> partialBuilder)");
                indent.Increment();
                builder.AppendLine($"{indent}=> it.AddFieldName(\"{apiFieldName}\", partialBuilder(new Partial<{currentFieldInnerType}>(it)));");
                indent.Decrement();
                builder.AppendLine($"{indent}");
            }

            return(builder.ToString());
        }
コード例 #15
0
        /// <summary>
        /// Sets the operation log
        /// </summary>
        /// <param name="request">
        /// The initial request
        /// </param>
        /// <param name="apiField">
        /// The connection field
        /// </param>
        /// <param name="context">
        /// The request context
        /// </param>
        /// <param name="action">
        /// The action performed
        /// </param>
        protected static void SetLog(
            ApiRequest request,
            ApiField apiField,
            RequestContext context,
            EnConnectionAction action)
        {
            if (apiField.LogAccessRules == null || !apiField.LogAccessRules.Any())
            {
                return;
            }

            var rule =
                apiField.LogAccessRules.OrderByDescending(r => r.Severity)
                .FirstOrDefault(r => r.ConnectionActions.HasFlag(action));

            if (rule == null)
            {
                return;
            }

            var operationGranted = EnSecurityLogType.OperationGranted;

            switch (action)
            {
            case EnConnectionAction.Create:
                operationGranted = EnSecurityLogType.DataCreateGranted;
                break;

            case EnConnectionAction.Update:
                operationGranted = EnSecurityLogType.DataUpdateGranted;
                break;

            case EnConnectionAction.Delete:
                operationGranted = EnSecurityLogType.DataDeleteGranted;
                break;
            }

            SecurityLog.CreateRecord(
                operationGranted,
                rule.Severity,
                context,
                rule.LogMessage,
                ((JObject)request.Arguments).ToString(Formatting.None));
        }
コード例 #16
0
        /// <summary>
        /// Runs the creation mutation
        /// </summary>
        /// <param name="connection">The connection</param>
        /// <param name="request">The request</param>
        /// <param name="field">
        /// The connection field
        /// </param>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="argumentsSerializer">
        /// The arguments serializer.
        /// </param>
        /// <param name="onErrorCallback">
        /// The on error callback.
        /// </param>
        /// <returns>The resolved data</returns>
        private async Task <JObject> MutationUpdate(
            INodeConnection <T> connection,
            ApiRequest request,
            ApiField field,
            RequestContext context,
            JsonSerializer argumentsSerializer,
            Action <Exception> onErrorCallback)
        {
            var serializedData = ((JObject)request.Arguments)?.Property("newNode")?.Value as JObject;
            var serializedId   = ((JObject)request.Arguments)?.Property("id")?.Value;
            var id             = serializedId?.ToObject(NodeMetaData.KeyProperty.PropertyType);

            if (id == null)
            {
                return(null);
            }

            var newNode = serializedData?.ToObject <T>();
            var result  = await connection.Update(id, newNode, request);

            var mutationUpdate =
                (JObject)
                await mutationResultResolver.ResolveQuery(
                    result,
                    request,
                    field,
                    context,
                    argumentsSerializer,
                    onErrorCallback);

            if (result.Result != null)
            {
                if (!id.Equals(GetIdValue(result.Result)))
                {
                    mutationUpdate.Add("__deletedId", JToken.FromObject(id));
                }
            }

            SetLog(request, field, context, EnConnectionAction.Update);
            return(mutationUpdate);
        }
コード例 #17
0
        /// <inheritdoc />
        public async Task <JToken> ResolveQuery(object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback)
        {
            if (source == null)
            {
                return(JValue.CreateNull());
            }

            var collection = source as IEnumerable;

            if (collection == null)
            {
                onErrorCallback?.Invoke(new InvalidOperationException($"{source.GetType().FullName} is not a collection"));
                return(JValue.CreateNull());
            }

            var result = new JArray();

            foreach (var value in collection)
            {
                result.Add(await this.elementResolver.ResolveQuery(value, request, apiField, context, argumentsSerializer, onErrorCallback));
            }

            return(result);
        }
コード例 #18
0
        public async Task ArraysApiTest()
        {
            var viewerFields = new[]
            {
                ApiField.Scalar("id", EnScalarType.Guid, EnFieldFlags.Queryable | EnFieldFlags.IsKey),
                ApiField.Scalar("name", EnScalarType.String),
                ApiField.Scalar("numbers", EnScalarType.Integer, EnFieldFlags.IsArray | EnFieldFlags.Queryable)
            };
            var viewerType = new ApiObjectType("viewer", viewerFields);

            var objectFields = new[]
            {
                ApiField.Scalar("id", EnScalarType.Integer, EnFieldFlags.IsKey | EnFieldFlags.Queryable),
                ApiField.Scalar("name", EnScalarType.String)
            };

            var objectType = new ApiObjectType("object", objectFields);

            var api = new ApiDescription(
                "TestApi1",
                "0.0.0.1",
                new[] { viewerType, objectType },
                new[] { viewerType.CreateField("viewer"), objectType.CreateField("object", EnFieldFlags.IsConnection | EnFieldFlags.Queryable) });

            var provider = new MoqProvider
            {
                Description = api,
                Data        = @"{
	                    ""viewer"": {
		                    ""__id"": ""FD73BAFB-3698-4FA1-81F5-27C8C83BB4F0"", 
		                    ""name"": ""test name"",
		                    ""numbers"": [1, 2, 3]
	                    }, 
	                    ""object"": {
		                    ""count"": 2, 
		                    ""edges"": [
			                    {""__id"": 10, ""node___id"": 10}, 
			                    {""__id"": 20, ""node___id"": 20}
		                    ]
	                    }
                    }"
            };

            var schema = SchemaGenerator.Generate(new List <ApiProvider> {
                provider
            });

            using (var printer = new SchemaPrinter(schema))
            {
                var description = printer.Print();
                this.output.WriteLine("-------- Schema -----------");
                this.output.WriteLine(description);
                Assert.False(string.IsNullOrWhiteSpace(description));
            }

            Assert.NotNull(schema.Query);
            Assert.Equal(3, schema.Query.Fields.Count());
            Assert.True(schema.Query.HasField("api"));

            var result = await new DocumentExecuter().ExecuteAsync(
                r =>
            {
                r.Schema = schema;
                r.Query  = @"
                                query {
                                    api {
                                        viewer {
                                            __id,
                                            name,
                                            numbers
                                        },
                                        object {
                                            count,
                                            edges {
                                                cursor,                                                
                                                node {
                                                    __id
                                                }
                                            }
                                        }
                                    }
                                }            
                                ";
            }).ConfigureAwait(true);

            this.output.WriteLine("-------- Response -----------");
            var response = new DocumentWriter(true).Write(result);

            this.output.WriteLine(response);

            var expectedResponse = @"{
                                      ""data"": {
                                        ""api"": {
                                          ""viewer"": {
                                            ""__id"": ""fd73bafb-3698-4fa1-81f5-27c8c83bb4f0"",
                                            ""name"": ""test name"",
		                                    ""numbers"": [1, 2, 3]
                                          },
                                          ""object"": {
                                            ""count"": 2,
                                            ""edges"": [
                                              {
                                                ""cursor"": 10,
                                                ""node"": {
                                                  ""__id"": 10
                                                }
                                              },
                                              {
                                                ""cursor"": 20,
                                                ""node"": {
                                                  ""__id"": 20
                                                }
                                              }
                                            ]
                                          }
                                        }
                                      }
                                    }";

            Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response));
        }
コード例 #19
0
 /// <summary>
 /// Adds a provider to the provider list
 /// </summary>
 /// <param name="provider">The provider</param>
 /// <param name="field">The original field description</param>
 public void AddProvider(ApiProvider provider, ApiField field)
 {
     this.providers.Add(provider);
     this.OriginalFields[provider.Description.ApiName] = field;
 }
コード例 #20
0
        private string GenerateDtoFieldDefinition(string typeNameForDto, ApiField apiField)
        {
            var indent  = new Indent();
            var builder = new StringBuilder();

            var propertyNameForField     = apiField.ToCSharpPropertyName(typeNameForDto);
            var backingFieldNameForField = apiField.ToCSharpBackingFieldName();

            // Backing field
            builder.Append($"{indent}private PropertyValue<");
            builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
            if (apiField.Type.Nullable)
            {
                builder.Append("?");
            }

            builder.Append("> ");
            builder.Append($"{backingFieldNameForField} = new PropertyValue<");
            builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
            if (apiField.Type.Nullable)
            {
                builder.Append("?");
            }

            builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}));");
            builder.AppendLine($"{indent}");

            // Property
            if (!apiField.Optional && !apiField.Type.Nullable)
            {
                builder.AppendLine($"{indent}[Required]");
            }
            if (apiField.Deprecation != null)
            {
                builder.AppendLine(apiField.Deprecation.ToCSharpDeprecation());
            }
            builder.AppendLine($"{indent}[JsonPropertyName(\"{apiField.Name}\")]");

            if (apiField.Type is ApiFieldType.Primitive apiFieldTypePrimitive)
            {
                var csharpType = apiFieldTypePrimitive.ToCSharpPrimitiveType();
                if (csharpType.JsonConverter != null)
                {
                    builder.AppendLine($"{indent}[JsonConverter(typeof({csharpType.JsonConverter.Name}))]");
                }
            }

            builder.Append($"{indent}public ");
            builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
            if (apiField.Type.Nullable)
            {
                builder.Append("?");
            }
            builder.Append(" ");
            builder.AppendLine($"{indent}{propertyNameForField}");

            builder.AppendLine($"{indent}{{");
            indent.Increment();

            builder.AppendLine($"{indent}get => {backingFieldNameForField}.GetValue();");
            builder.AppendLine($"{indent}set => {backingFieldNameForField}.SetValue(value);");

            indent.Decrement();
            builder.AppendLine($"{indent}}}");

            return(builder.ToString());
        }
コード例 #21
0
        /// <inheritdoc />
        public async Task <JToken> ResolveQuery(
            object source,
            ApiRequest request,
            ApiField apiField,
            RequestContext context,
            JsonSerializer argumentsSerializer,
            Action <Exception> onErrorCallback)
        {
            var arguments      = (JObject)request.Arguments;
            var id             = arguments?.Property("id");
            var filterArgument = arguments?.Property("filter")?.Value as JObject;
            var sortArgument   = arguments?.Property("sort")?.Value as JArray;
            var limit          = (int?)(arguments?.Property("limit")?.Value as JValue);
            var offset         = (int?)(arguments?.Property("offset")?.Value as JValue);

            var filter = CreateFilter(filterArgument, id);
            var sort   = sortArgument != null?this.CreateSort(sortArgument) : null;

            var items = await this.GetQueryResult(source, request, filter, sort, limit, offset);

            if (items == null)
            {
                onErrorCallback?.Invoke(new Exception("Source is not a node connection"));
                return(JValue.CreateNull());
            }

            SetLog(request, apiField, context, EnConnectionAction.Query);

            var result = new JObject();
            var fields = request.Fields.GroupBy(f => f.Alias ?? f.FieldName).Select(
                g =>
            {
                var f = g.First();
                if (f.Fields == null)
                {
                    return(f);
                }

                return(new ApiRequest
                {
                    Alias = f.Alias,
                    Arguments = f.Arguments,
                    FieldName = f.FieldName,
                    Fields = g.SelectMany(sr => sr.Fields).ToList()
                });
            });

            foreach (var requestField in fields)
            {
                switch (requestField.FieldName)
                {
                case "count":
                    result.Add(requestField.Alias ?? requestField.FieldName, new JValue(items.Count));
                    break;

                case "items":
                {
                    var itemsValue =
                        await new SimpleCollectionResolver(this.NodeResolver).ResolveQuery(
                            items.Items,
                            requestField,
                            apiField,
                            context,
                            argumentsSerializer,
                            onErrorCallback);
                    result.Add(requestField.Alias ?? requestField.FieldName, itemsValue);
                }

                break;
                }
            }

            return(result);
        }
コード例 #22
0
        /// <inheritdoc />
        public Task <JToken> ResolveQuery(object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback)
        {
            var result = source as JToken;

            return(Task.FromResult(result ?? JValue.CreateNull()));
        }
コード例 #23
0
 public static string ToCSharpVariableName(this ApiField subject)
 => CSharpIdentifier.ForVariable(subject.Name);
コード例 #24
0
 public static string ToCSharpBackingFieldName(this ApiField subject)
 => CSharpIdentifier.ForBackingField(subject.Name);
コード例 #25
0
        public async Task SchemaDescriptionTest()
        {
            var checkAttributeArguments = new[]
            {
                ApiField.Scalar(
                    "attribute",
                    EnScalarType.String,
                    description: "attribute to check")
            };

            var objectFields = new[]
            {
                ApiField.Scalar(
                    "uid",
                    EnScalarType.Guid,
                    description: "The object unique identifier"),
                ApiField.Scalar("name", EnScalarType.String, description: "The object name"),
                ApiField.Scalar(
                    "attributes",
                    EnScalarType.String,
                    EnFieldFlags.IsArray,
                    description: "The object attributes"),
                ApiField.Scalar(
                    "checkAttribute",
                    EnScalarType.Boolean,
                    arguments: checkAttributeArguments,
                    description: "checks the attribute")
            };

            var objectType = new ApiObjectType("object", objectFields)
            {
                Description = "Some abstract object"
            };
            var apiField = objectType.CreateField(
                "new",
                description: "The new object data");

            var mutations = new[]
            {
                ApiMutation.CreateFromField(
                    ApiField.Object(
                        "objects_create",
                        "object",
                        arguments: new[] { apiField },
                        description: "creates a new object"),
                    ApiMutation.EnType.ConnectionCreate,
                    new List <ApiRequest>())
            };

            var api = new ApiDescription(
                "TestApi",
                "0.0.0.1",
                new[] { objectType },
                new[] { objectType.CreateField("objects", EnFieldFlags.IsConnection, "The objects dataset") },
                mutations)
            {
                Description = "The test api"
            };

            var provider = new MoqProvider {
                Description = api
            };
            var schema = SchemaGenerator.Generate(new List <ApiProvider> {
                provider
            });

            var errors = SchemaGenerator.CheckSchema(schema).Select(e => $"Schema type error: {e}")
                         .Union(SchemaGenerator.CheckSchemaIntrospection(schema))
                         .Select(e => $"Schema introspection error: {e}");

            var hasErrors = false;

            foreach (var error in errors)
            {
                hasErrors = true;
                this.output.WriteLine(error);
            }

            using (var printer = new SchemaPrinter(schema))
            {
                var description = printer.Print();
                this.output.WriteLine("-------- Schema -----------");
                this.output.WriteLine(description);
                Assert.False(string.IsNullOrWhiteSpace(description));
            }

            Assert.False(hasErrors);
            var query = BaseInstaller.ReadTextResource(
                this.GetType().GetTypeInfo().Assembly,
                "KlusterKite.Web.Tests.GraphQL.Resources.IntrospectionQuery.txt");

            var result = await new DocumentExecuter().ExecuteAsync(
                r =>
            {
                r.Schema = schema;

                r.Query = query;
            }).ConfigureAwait(true);
            var response = new DocumentWriter(true).Write(result);

            this.output.WriteLine(response);

            var expectedResponse = BaseInstaller.ReadTextResource(
                this.GetType().GetTypeInfo().Assembly,
                "KlusterKite.Web.Tests.GraphQL.Resources.SchemaDescriptionTestSnapshot.txt");

            Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response));
        }
コード例 #26
0
        public async Task NonEmptyApiTest()
        {
            var viewerType = new ApiObjectType(
                "viewer",
                new[] { ApiField.Scalar("id", EnScalarType.Integer), ApiField.Scalar("name", EnScalarType.String) });

            var api = new ApiDescription(
                "TestApi1",
                "0.0.0.1",
                new[] { viewerType },
                new[] { viewerType.CreateField("viewer") });

            var provider = new MoqProvider
            {
                Description = api,
                Data        = "{\"viewer\": {\"__id\": 1, \"name\": \"test name\"}}"
            };

            var schema = SchemaGenerator.Generate(new List <ApiProvider> {
                provider
            });

            using (var printer = new SchemaPrinter(schema))
            {
                var description = printer.Print();
                this.output.WriteLine("-------- Schema -----------");
                this.output.WriteLine(description);
                Assert.False(string.IsNullOrWhiteSpace(description));
            }

            Assert.NotNull(schema.Query);
            Assert.Equal(3, schema.Query.Fields.Count());
            Assert.True(schema.Query.HasField("api"));

            var result = await new DocumentExecuter().ExecuteAsync(
                r =>
            {
                r.Schema = schema;
                r.Query  = @"
                                query {
                                    api {
                                        viewer {
                                            __id,
                                            name
                                        }
                                    }
                                }            
                                ";
            }).ConfigureAwait(true);

            this.output.WriteLine("-------- Response -----------");
            var response = new DocumentWriter(true).Write(result);

            this.output.WriteLine(response);
            var expectedResponse = @"{
                                      ""data"": {
                                        ""api"": {
                                          ""viewer"": {
                                            ""__id"": 1,
                                            ""name"": ""test name""
                                          }
                                        }
                                      }
                                    }";

            Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response));
        }
コード例 #27
0
        /// <inheritdoc />
        public Task <JToken> ResolveQuery(object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback)
        {
            var value = hasFlags ? new JValue((long)source) : new JValue(source.ToString());

            return(Task.FromResult <JToken>(value));
        }
コード例 #28
0
        /// <summary>
        /// Creates field from api description
        /// </summary>
        /// <param name="provider">The api provider</param>
        /// <param name="apiField">The api field description</param>
        /// <param name="complexField">The same field merged from previous api descriptions</param>
        /// <param name="path">The list of processed types</param>
        /// <param name="createAsInput">A value indicating that an input type is assembled</param>
        /// <param name="typesCreated">The list of already created types</param>
        /// <returns>The field description</returns>
        private static MergedType CreateMergedType(
            ApiProvider provider,
            ApiField apiField,
            MergedField complexField,
            ICollection <string> path,
            bool createAsInput,
            Dictionary <string, MergedType> typesCreated)
        {
            MergedType createdType;

            if (apiField.ScalarType != EnScalarType.None)
            {
                return(CreateScalarType(apiField.ScalarType, typesCreated));
            }

            var apiType = provider.Description.Types.FirstOrDefault(t => t.TypeName == apiField.TypeName);

            if (apiType == null)
            {
                throw new Exception("type was not found");
            }

            var apiEnumType = apiType as ApiEnumType;

            if (apiEnumType != null)
            {
                return(CreateEnumType(apiEnumType, provider, typesCreated));
            }

            var apiObjectType = (ApiObjectType)apiType;

            if (apiField.Flags.HasFlag(EnFieldFlags.IsConnection))
            {
                var typedArgumentNames =
                    apiField.Arguments.Where(a => a.Flags.HasFlag(EnFieldFlags.IsTypeArgument))
                    .Select(f => f.Name)
                    .ToList();
                return(CreateConnectionType(apiObjectType, provider, typesCreated, typedArgumentNames));
            }

            var objectType = (complexField?.Type as MergedObjectType)?.Clone()
                             ?? (createAsInput
                                     ? new MergedInputType($"{provider.Description.ApiName}_{apiField.TypeName}")
                                     : new MergedObjectType($"{provider.Description.ApiName}_{apiField.TypeName}"));

            objectType.AddProvider(new FieldProvider {
                FieldType = apiObjectType, Provider = provider
            });
            if (complexField != null)
            {
                objectType.Category = MergedObjectType.EnCategory.MultipleApiType;
            }

            if (typesCreated.TryGetValue(objectType.ComplexTypeName, out createdType))
            {
                return(createdType);
            }

            typesCreated[objectType.ComplexTypeName] = objectType;

            MergeFields(
                objectType,
                apiObjectType.Fields,
                provider,
                path.Union(new[] { apiObjectType.TypeName }).ToList(),
                createAsInput,
                typesCreated);

            objectType.Initialize();
            return(objectType);
        }
コード例 #29
0
        private async void AddItemCommandHandler(object p)
        {
            // Prompt to create the new item
            var dialog = new AddItemDialog();

            // Show the dialog and wait for a response
            var result = await dialog.ShowAsync();

            if (result == ContentDialogResult.Primary)
            {
                try
                {
                    // Get the category
                    var category = p as ApiCategory;

                    // Create an item
                    var item = new ApiItem()
                    {
                        Name = dialog.ItemName
                    };

                    // Save the item to the api
                    var r = await KryptPadApi.SaveItemAsync(category.Id, item);

                    // Set the item
                    item.Id = r.Id;

                    // If a template was selected, create a couple of fields to start with
                    if (dialog.SelectedItemTemplate != null)
                    {
                        var templateFields = dialog.SelectedItemTemplate.Fields;

                        // A template was selected, add all the fields from the template
                        foreach (var templateField in templateFields)
                        {
                            // Create field
                            var field = new ApiField()
                            {
                                Name      = templateField.Name,
                                FieldType = templateField.FieldType
                            };

                            // Send to api
                            await KryptPadApi.SaveFieldAsync(category.Id, item.Id, field);
                        }
                    }


                    // Navigate to item edit page
                    NavigationHelper.Navigate(typeof(NewItemPage), new EditItemPageParams()
                    {
                        Category = category,
                        Item     = item
                    });
                }
                catch (WebException ex)
                {
                    // Something went wrong in the api
                    await DialogHelper.ShowMessageDialogAsync(ex.Message);
                }
                catch (Exception ex)
                {
                    // Failed
                    await DialogHelper.ShowGenericErrorDialogAsync(ex);
                }
            }
        }
コード例 #30
0
        private string GenerateDtoFieldDefinition(string typeNameForDto, ApiField apiField)
        {
            var indent  = new Indent();
            var builder = new StringBuilder();

            var propertyNameForField     = apiField.ToCSharpPropertyName(typeNameForDto);
            var backingFieldNameForField = apiField.ToCSharpBackingFieldName();

            // Backing field
            builder.Append($"{indent}private PropertyValue<");
            builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
            if (apiField.Type.Nullable)
            {
                builder.Append("?");
            }

            builder.Append("> ");
            builder.Append($"{backingFieldNameForField} = new PropertyValue<");
            builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
            if (apiField.Type.Nullable)
            {
                builder.Append("?");
            }

            // For non-nullable List<> and Dictionary<>, make sure the field is initialized.
            // We do this by setting a temporary default value for this pass.
            var overrideDefaultValue = !apiField.Type.Nullable && apiField.DefaultValue == null;

            if (overrideDefaultValue)
            {
                // TODO When switching to records (.NET 6 LTS), replace this construct to be immutable.
                apiField.DefaultValue = apiField.Type switch
                {
                    ApiFieldType.Array _ => new ApiDefaultValue.Collection(),
                                       ApiFieldType.Map _ => new ApiDefaultValue.Map(),
                                       _ => apiField.DefaultValue
                };
            }

            var initialValueForAssignment = apiField.ToCSharpDefaultValueForAssignment(_codeGenerationContext);

            if (initialValueForAssignment != null)
            {
                builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}), {initialValueForAssignment});");
            }
            else
            {
                builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}));");
            }
            builder.AppendLine($"{indent}");

            // Restore null default value
            if (overrideDefaultValue)
            {
                apiField.DefaultValue = null;
            }

            // Property
            if (!apiField.Optional && !apiField.Type.Nullable)
            {
                builder.AppendLine($"{indent}[Required]");
            }
            if (apiField.Deprecation != null)
            {
                builder.AppendLine(apiField.Deprecation.ToCSharpDeprecation());
            }
            builder.AppendLine($"{indent}[JsonPropertyName(\"{apiField.Name}\")]");

            if (apiField.Type is ApiFieldType.Primitive apiFieldTypePrimitive)
            {
                var csharpType = apiFieldTypePrimitive.ToCSharpPrimitiveType();
                if (csharpType.JsonConverter != null)
                {
                    builder.AppendLine($"{indent}[JsonConverter(typeof({csharpType.JsonConverter.Name}))]");
                }
            }

            builder.Append($"{indent}public ");
            builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
            if (apiField.Type.Nullable)
            {
                builder.Append("?");
            }
            builder.Append(" ");
            builder.AppendLine($"{indent}{propertyNameForField}");

            builder.AppendLine($"{indent}{{");
            indent.Increment();

            builder.AppendLine($"{indent}get => {backingFieldNameForField}.GetValue();");
            builder.AppendLine($"{indent}set => {backingFieldNameForField}.SetValue(value);");

            indent.Decrement();
            builder.AppendLine($"{indent}}}");

            return(builder.ToString());
        }