From 5df6cb75fbc2a34c9b6a67cef2e8407b171822c9 Mon Sep 17 00:00:00 2001 From: HII Date: Mon, 4 Jun 2018 17:40:25 +0200 Subject: [PATCH] GraphQL fixed --- .../Contents/GraphQL/GraphQLModel.cs | 2 +- .../Contents/GraphQL/IGraphModel.cs | 3 +- .../GraphQL/Types/ContentDataGraphType.cs | 14 ++++- .../GraphQL/Types/NestedObjectGraphType.cs | 15 ++++- .../GraphQL/Types/QueryGraphTypeVisitor.cs | 63 +++++++++---------- .../Contents/GraphQL/GraphQLQueriesTests.cs | 22 +++++++ .../Contents/GraphQL/GraphQLTestBase.cs | 16 ++++- 7 files changed, 94 insertions(+), 41 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs index 742a66805..56caec708 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs @@ -135,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return partitionResolver(key); } - public (IGraphType ResolveType, IFieldResolver Resolver) GetGraphType(ISchemaEntity schema, IField field) + public (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field) { return field.Accept(new QueryGraphTypeVisitor(schema, GetContentType, this, assetListType)); } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs index 0e155b65b..54ab6d109 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs @@ -10,6 +10,7 @@ using GraphQL.Resolvers; using GraphQL.Types; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Schemas; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL @@ -36,6 +37,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL IGraphType GetInputGraphType(IField field); - (IGraphType ResolveType, IFieldResolver Resolver) GetGraphType(ISchemaEntity schema, IField field); + (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs index 1ee1d48b9..2400dab3b 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs @@ -43,10 +43,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types foreach (var partitionItem in partition) { + var resolver = new FuncFieldResolver(c => + { + if (((ContentFieldData)c.Source).TryGetValue(c.FieldName, out var value)) + { + return fieldInfo.Resolver(value, c); + } + else + { + return fieldInfo; + } + }); + fieldGraphType.AddField(new FieldType { Name = partitionItem.Key, - Resolver = fieldInfo.Resolver, + Resolver = resolver, ResolvedType = fieldInfo.ResolveType, Description = field.RawProperties.Hints }); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedObjectGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedObjectGraphType.cs index 455d91ac4..dc9428fa5 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedObjectGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedObjectGraphType.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Linq; +using GraphQL.Resolvers; using GraphQL.Types; using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Core.Schemas; @@ -32,10 +33,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types if (fieldInfo.ResolveType != null) { + var resolver = new FuncFieldResolver(c => + { + if (((JObject)c.Source).TryGetValue(nestedField.Name, out var value)) + { + return fieldInfo.Resolver(value, c); + } + else + { + return fieldInfo; + } + }); + AddField(new FieldType { Name = nestedField.Name.ToCamelCase(), - Resolver = fieldInfo.Resolver, + Resolver = resolver, ResolvedType = fieldInfo.ResolveType, Description = $"The {fieldName}/{nestedField.DisplayName()} nested field." }); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs index 91cee6505..3cb56c0a3 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs @@ -6,18 +6,18 @@ // ========================================================================== using System; -using System.Collections.Generic; -using GraphQL.Resolvers; using GraphQL.Types; using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types { - public sealed class QueryGraphTypeVisitor : IFieldVisitor<(IGraphType ResolveType, IFieldResolver Resolver)> + public delegate object ValueResolver(JToken value, ResolveFieldContext context); + + public sealed class QueryGraphTypeVisitor : IFieldVisitor<(IGraphType ResolveType, ValueResolver Resolver)> { + private static readonly ValueResolver NoopResolver = new ValueResolver((value, c) => value); private readonly ISchemaEntity schema; private readonly Func schemaResolver; private readonly IGraphModel model; @@ -31,87 +31,81 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types this.schemaResolver = schemaResolver; } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IArrayField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IArrayField field) { return ResolveNested(field); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveAssets(assetListType); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveDefault(AllTypes.NoopBoolean); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveDefault(AllTypes.NoopDate); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveDefault(AllTypes.NoopGeolocation); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveDefault(AllTypes.NoopJson); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveDefault(AllTypes.NoopFloat); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveReferences(field); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveDefault(AllTypes.NoopString); } - public (IGraphType ResolveType, IFieldResolver Resolver) Visit(IField field) + public (IGraphType ResolveType, ValueResolver Resolver) Visit(IField field) { return ResolveDefault(AllTypes.NoopTags); } - private static (IGraphType ResolveType, IFieldResolver Resolver) ResolveDefault(IGraphType type) + private static (IGraphType ResolveType, ValueResolver Resolver) ResolveDefault(IGraphType type) { - return (type, new FuncFieldResolver, object>(c => c.Source.GetOrDefault(c.FieldName))); + return (type, NoopResolver); } - private static ValueTuple ResolveAssets(IGraphType assetListType) + private (IGraphType ResolveType, ValueResolver Resolver) ResolveNested(IArrayField field) { - var resolver = new FuncFieldResolver, object>(c => - { - var context = (GraphQLExecutionContext)c.UserContext; - var contentIds = c.Source.GetOrDefault(c.FieldName); - - return context.GetReferencedAssetsAsync(contentIds); - }); + var schemaFieldType = new ListGraphType(new NonNullGraphType(new NestedObjectGraphType(model, schema, field))); - return (assetListType, resolver); + return (schemaFieldType, NoopResolver); } - private ValueTuple ResolveNested(IArrayField field) + private (IGraphType ResolveType, ValueResolver Resolver) ResolveAssets(IGraphType assetListType) { - var resolver = new FuncFieldResolver, object>(c => + var resolver = new ValueResolver((value, c) => { - return c.Source.GetOrDefault(c.FieldName); - }); + var context = (GraphQLExecutionContext)c.UserContext; - var schemaFieldType = new ListGraphType(new NonNullGraphType(new NestedObjectGraphType(model, schema, field))); + return context.GetReferencedAssetsAsync(value); + }); - return (schemaFieldType, resolver); + return (assetListType, resolver); } - private ValueTuple ResolveReferences(IField field) + private (IGraphType ResolveType, ValueResolver Resolver) ResolveReferences(IField field) { var schemaId = ((ReferencesFieldProperties)field.RawProperties).SchemaId; @@ -122,12 +116,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types return (null, null); } - var resolver = new FuncFieldResolver, object>(c => + var resolver = new ValueResolver((value, c) => { var context = (GraphQLExecutionContext)c.UserContext; - var contentIds = c.Source.GetOrDefault(c.FieldName); - return context.GetReferencedContentsAsync(schemaId, contentIds); + return context.GetReferencedContentsAsync(schemaId, value); }); var schemaFieldType = new ListGraphType(new NonNullGraphType(contentType)); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs index 8b75b5cf5..03d7d7fac 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs @@ -273,6 +273,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL myTags { iv } + myArray { + iv { + nestedNumber + nestedBoolean + } + } } } }"; @@ -342,6 +348,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL "tag1", "tag2" } + }, + myArray = new + { + iv = new[] + { + new + { + nestedNumber = 1, + nestedBoolean = true + }, + new + { + nestedNumber = 2, + nestedBoolean = false + } + } } } } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs index 652e23f6e..56e9fe31a 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -72,7 +72,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL .AddGeolocation(10, "my-geolocation", Partitioning.Invariant, new GeolocationFieldProperties()) .AddTags(11, "my-tags", Partitioning.Invariant, - new TagsFieldProperties()); + new TagsFieldProperties()) + .AddArray(12, "my-array", Partitioning.Invariant, f => f + .AddBoolean(121, "nested-boolean") + .AddNumber(122, "nested-number")); A.CallTo(() => app.Id).Returns(appId); A.CallTo(() => app.Name).Returns(appName); @@ -122,7 +125,16 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL .AddValue("iv", JToken.FromObject(new[] { refId }))) .AddField("my-geolocation", new ContentFieldData() - .AddValue("iv", JToken.FromObject(new { latitude = 10, longitude = 20 }))); + .AddValue("iv", JToken.FromObject(new { latitude = 10, longitude = 20 }))) + .AddField("my-array", + new ContentFieldData() + .AddValue("iv", new JArray( + new JObject( + new JProperty("nested-boolean", true), + new JProperty("nested-number", 1)), + new JObject( + new JProperty("nested-boolean", false), + new JProperty("nested-number", 2))))); if (!noJson) {