From bf98fd098b465c54e98fc66394c5f11decb28526 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 7 Jun 2018 18:42:29 +0200 Subject: [PATCH] Mutations removed. --- .../Contents/GraphQL/CachingGraphQLService.cs | 7 +- .../GraphQL/GraphQLExecutionContext.cs | 6 - .../Contents/GraphQL/GraphQLModel.cs | 11 +- .../Contents/GraphQL/GraphQLQuery.cs | 2 +- .../Contents/GraphQL/IGraphModel.cs | 2 - .../Contents/GraphQL/Types/AllTypes.cs | 10 +- .../GraphQL/Types/AppMutationsGraphType.cs | 344 ------------- .../GraphQL/Types/CommandVersionGraphType.cs | 44 -- .../ContentDataChangedResultGraphType.cs | 44 -- .../Types/ContentDataGraphInputType.cs | 70 --- .../GraphQL/Types/ContentDataGraphType.cs | 4 +- .../Types/GeolocationInputGraphType.cs | 31 -- .../GraphQL/Types/InputFieldExtensions.cs | 20 - .../GraphQL/Types/InputFieldVisitor.cs | 71 --- .../Contents/GraphQL/Types/NestedGraphType.cs | 2 +- .../GraphQL/Types/NestedInputGraphType.cs | 47 -- .../Types/{ => Utils}/GuidGraphType.cs | 2 +- .../GraphQL/Types/Utils/InputConverter.cs | 73 --- .../Contents/GraphQL/GraphQLMutationTests.cs | 487 ------------------ .../Contents/GraphQL/GraphQLTestBase.cs | 4 +- 20 files changed, 13 insertions(+), 1268 deletions(-) delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppMutationsGraphType.cs delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/CommandVersionGraphType.cs delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataChangedResultGraphType.cs delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphInputType.cs delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GeolocationInputGraphType.cs delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldExtensions.cs delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldVisitor.cs delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedInputGraphType.cs rename src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/{ => Utils}/GuidGraphType.cs (95%) delete mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/InputConverter.cs delete mode 100644 tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs index 56f8bf48c..68bad5840 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs @@ -12,7 +12,6 @@ using Microsoft.Extensions.Caching.Memory; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { @@ -20,7 +19,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10); private readonly IContentQueryService contentQuery; - private readonly ICommandBus commandBus; private readonly IGraphQLUrlGenerator urlGenerator; private readonly IAssetRepository assetRepository; private readonly IAppProvider appProvider; @@ -28,20 +26,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL public CachingGraphQLService(IMemoryCache cache, IAppProvider appProvider, IAssetRepository assetRepository, - ICommandBus commandBus, IContentQueryService contentQuery, IGraphQLUrlGenerator urlGenerator) : base(cache) { Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(assetRepository, nameof(assetRepository)); - Guard.NotNull(commandBus, nameof(commandBus)); Guard.NotNull(contentQuery, nameof(contentQuery)); Guard.NotNull(urlGenerator, nameof(urlGenerator)); this.appProvider = appProvider; this.assetRepository = assetRepository; - this.commandBus = commandBus; this.contentQuery = contentQuery; this.urlGenerator = urlGenerator; } @@ -58,7 +53,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL var modelContext = await GetModelAsync(context.App); - var ctx = new GraphQLExecutionContext(context, assetRepository, commandBus, contentQuery, urlGenerator); + var ctx = new GraphQLExecutionContext(context, assetRepository, contentQuery, urlGenerator); return await modelContext.ExecuteAsync(ctx, query); } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs index 8456884eb..31acd1523 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs @@ -11,25 +11,19 @@ using System.Threading.Tasks; using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets.Repositories; -using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { public sealed class GraphQLExecutionContext : QueryExecutionContext { - public ICommandBus CommandBus { get; } - public IGraphQLUrlGenerator UrlGenerator { get; } public GraphQLExecutionContext(QueryContext context, IAssetRepository assetRepository, - ICommandBus commandBus, IContentQueryService contentQuery, IGraphQLUrlGenerator urlGenerator) : base(context, assetRepository, contentQuery) { - CommandBus = commandBus; - UrlGenerator = urlGenerator; } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs index d449c0364..2b8daf4e6 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs @@ -63,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { var schemas = model.schemasById.Values; - return new GraphQLSchema { Query = new AppQueriesGraphType(model, schemas), Mutation = new AppMutationsGraphType(model, schemas) }; + return new GraphQLSchema { Query = new AppQueriesGraphType(model, schemas) }; } private void InitializeContentTypes() @@ -142,11 +142,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return field.Accept(new QueryGraphTypeVisitor(schema, GetContentType, this, assetListType)); } - public IGraphType GetInputGraphType(IField field) - { - return field.GetInputGraphType(); - } - public IGraphType GetAssetType() { return assetType; @@ -173,6 +168,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return null; } + contentDataTypes.GetOrAdd(schema, s => new ContentDataGraphType()); + return contentTypes.GetOrAdd(schema, s => new ContentGraphType()); } @@ -180,7 +177,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { Guard.NotNull(context, nameof(context)); - var inputs = InputConverter.ToInputs(query.Variables); + var inputs = query.Variables?.ToInputs(); var result = await new DocumentExecuter().ExecuteAsync(options => { diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLQuery.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLQuery.cs index db45e3672..91d17ec15 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLQuery.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLQuery.cs @@ -9,7 +9,7 @@ using Newtonsoft.Json.Linq; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { - public class GraphQLQuery + public sealed class GraphQLQuery { public string OperationName { get; set; } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs index 54ab6d109..f44c36b58 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs @@ -35,8 +35,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL IGraphType GetContentDataType(Guid schemaId); - IGraphType GetInputGraphType(IField field); - (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs index 70b3c14e2..f9f25ad41 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs @@ -36,8 +36,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types public static readonly IGraphType References = new ListGraphType>(); - public static readonly IGraphType GeolocationInput = new GeolocationInputGraphType(); - public static readonly IGraphType NonNullInt = new NonNullGraphType(Int); public static readonly IGraphType NonNullGuid = new NonNullGraphType(Guid); @@ -52,22 +50,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types public static readonly IGraphType NonNullStatusType = new NonNullGraphType(Status); - public static readonly IGraphType NoopArray = new NoopGraphType("Array"); - public static readonly IGraphType NoopDate = new NoopGraphType(Date); public static readonly IGraphType NoopJson = new NoopGraphType(Json); - public static readonly IGraphType NoopTags = new NoopGraphType(Tags); - public static readonly IGraphType NoopFloat = new NoopGraphType(Float); public static readonly IGraphType NoopString = new NoopGraphType(String); public static readonly IGraphType NoopBoolean = new NoopGraphType(Boolean); - public static readonly IGraphType NoopGeolocation = new NoopGraphType(GeolocationInput); + public static readonly IGraphType NoopTags = new NoopGraphType("Tags"); - public static readonly IGraphType CommandVersion = new CommandVersionGraphType(); + public static readonly IGraphType NoopGeolocation = new NoopGraphType("Geolocation"); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppMutationsGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppMutationsGraphType.cs deleted file mode 100644 index 0da986ba6..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppMutationsGraphType.cs +++ /dev/null @@ -1,344 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using GraphQL; -using GraphQL.Resolvers; -using GraphQL.Types; -using Newtonsoft.Json.Linq; -using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Entities.Contents.Commands; -using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types -{ - public sealed class AppMutationsGraphType : ObjectGraphType - { - public AppMutationsGraphType(IGraphModel model, IEnumerable schemas) - { - foreach (var schema in schemas) - { - var schemaId = schema.NamedId(); - var schemaType = schema.TypeName(); - var schemaName = schema.DisplayName(); - - var contentType = model.GetContentType(schema.Id); - var contentDataType = model.GetContentDataType(schema.Id); - - var resultType = new ContentDataChangedResultGraphType(schemaType, schemaName, contentDataType); - - var inputType = new ContentDataGraphInputType(model, schema); - - AddContentCreate(schemaId, schemaType, schemaName, inputType, contentDataType, contentType); - AddContentUpdate(schemaType, schemaName, inputType, resultType); - AddContentPatch(schemaType, schemaName, inputType, resultType); - AddContentPublish(schemaType, schemaName); - AddContentUnpublish(schemaType, schemaName); - AddContentArchive(schemaType, schemaName); - AddContentRestore(schemaType, schemaName); - AddContentDelete(schemaType, schemaName); - } - - Description = "The app mutations."; - } - - private void AddContentCreate(NamedId schemaId, string schemaType, string schemaName, ContentDataGraphInputType inputType, IGraphType contentDataType, IGraphType contentType) - { - AddField(new FieldType - { - Name = $"create{schemaType}Content", - Arguments = new QueryArguments - { - new QueryArgument(AllTypes.None) - { - Name = "data", - Description = $"The data for the {schemaName} content.", - DefaultValue = null, - ResolvedType = new NonNullGraphType(inputType), - }, - new QueryArgument(AllTypes.None) - { - Name = "publish", - Description = "Set to true to autopublish content.", - DefaultValue = false, - ResolvedType = AllTypes.Boolean - }, - new QueryArgument(AllTypes.None) - { - Name = "expectedVersion", - Description = "The expected version", - DefaultValue = EtagVersion.Any, - ResolvedType = AllTypes.Int - } - }, - ResolvedType = new NonNullGraphType(contentType), - Resolver = ResolveAsync(async (c, publish) => - { - var argPublish = c.GetArgument("publish"); - - var contentData = GetContentData(c); - - var command = new CreateContent { SchemaId = schemaId, Data = contentData, Publish = argPublish }; - var commandContext = await publish(command); - - var result = commandContext.Result>(); - var response = ContentEntity.Create(command, result); - - return (IContentEntity)ContentEntity.Create(command, result); - }), - Description = $"Creates an {schemaName} content." - }); - } - - private void AddContentUpdate(string schemaType, string schemaName, ContentDataGraphInputType inputType, IGraphType resultType) - { - AddField(new FieldType - { - Name = $"update{schemaType}Content", - Arguments = new QueryArguments - { - new QueryArgument(AllTypes.None) - { - Name = "id", - Description = $"The id of the {schemaName} content (GUID)", - DefaultValue = string.Empty, - ResolvedType = AllTypes.NonNullGuid - }, - new QueryArgument(AllTypes.None) - { - Name = "data", - Description = $"The data for the {schemaName} content.", - DefaultValue = null, - ResolvedType = new NonNullGraphType(inputType), - }, - new QueryArgument(AllTypes.None) - { - Name = "expectedVersion", - Description = "The expected version", - DefaultValue = EtagVersion.Any, - ResolvedType = AllTypes.Int - } - }, - ResolvedType = new NonNullGraphType(resultType), - Resolver = ResolveAsync(async (c, publish) => - { - var contentId = c.GetArgument("id"); - var contentData = GetContentData(c); - - var command = new UpdateContent { ContentId = contentId, Data = contentData }; - var commandContext = await publish(command); - - var result = commandContext.Result(); - - return result; - }), - Description = $"Update an {schemaName} content by id." - }); - } - - private void AddContentPatch(string schemaType, string schemaName, ContentDataGraphInputType inputType, IGraphType resultType) - { - AddField(new FieldType - { - Name = $"patch{schemaType}Content", - Arguments = new QueryArguments - { - new QueryArgument(AllTypes.None) - { - Name = "id", - Description = $"The id of the {schemaName} content (GUID)", - DefaultValue = string.Empty, - ResolvedType = AllTypes.NonNullGuid - }, - new QueryArgument(AllTypes.None) - { - Name = "data", - Description = $"The data for the {schemaName} content.", - DefaultValue = null, - ResolvedType = new NonNullGraphType(inputType), - }, - new QueryArgument(AllTypes.None) - { - Name = "expectedVersion", - Description = "The expected version", - DefaultValue = EtagVersion.Any, - ResolvedType = AllTypes.Int - } - }, - ResolvedType = new NonNullGraphType(resultType), - Resolver = ResolveAsync(async (c, publish) => - { - var contentId = c.GetArgument("id"); - var contentData = GetContentData(c); - - var command = new PatchContent { ContentId = contentId, Data = contentData }; - var commandContext = await publish(command); - - var result = commandContext.Result(); - - return result; - }), - Description = $"Patch a {schemaName} content." - }); - } - - private void AddContentPublish(string schemaType, string schemaName) - { - AddField(new FieldType - { - Name = $"publish{schemaType}Content", - Arguments = CreateIdArguments(schemaName), - ResolvedType = AllTypes.CommandVersion, - Resolver = ResolveAsync((c, publish) => - { - var contentId = c.GetArgument("id"); - - var command = new ChangeContentStatus { ContentId = contentId, Status = Status.Published }; - - return publish(command); - }), - Description = $"Publish a {schemaName} content." - }); - } - - private void AddContentUnpublish(string schemaType, string schemaName) - { - AddField(new FieldType - { - Name = $"unpublish{schemaType}Content", - Arguments = CreateIdArguments(schemaName), - ResolvedType = AllTypes.CommandVersion, - Resolver = ResolveAsync((c, publish) => - { - var contentId = c.GetArgument("id"); - - var command = new ChangeContentStatus { ContentId = contentId, Status = Status.Draft }; - - return publish(command); - }), - Description = $"Unpublish a {schemaName} content." - }); - } - - private void AddContentArchive(string schemaType, string schemaName) - { - AddField(new FieldType - { - Name = $"archive{schemaType}Content", - Arguments = CreateIdArguments(schemaName), - ResolvedType = AllTypes.CommandVersion, - Resolver = ResolveAsync((c, publish) => - { - var contentId = c.GetArgument("id"); - - var command = new ChangeContentStatus { ContentId = contentId, Status = Status.Archived }; - - return publish(command); - }), - Description = $"Archive a {schemaName} content." - }); - } - - private void AddContentRestore(string schemaType, string schemaName) - { - AddField(new FieldType - { - Name = $"restore{schemaType}Content", - Arguments = CreateIdArguments(schemaName), - ResolvedType = AllTypes.CommandVersion, - Resolver = ResolveAsync((c, publish) => - { - var contentId = c.GetArgument("id"); - - var command = new ChangeContentStatus { ContentId = contentId, Status = Status.Draft }; - - return publish(command); - }), - Description = $"Restore a {schemaName} content." - }); - } - - private void AddContentDelete(string schemaType, string schemaName) - { - AddField(new FieldType - { - Name = $"delete{schemaType}Content", - Arguments = CreateIdArguments(schemaName), - ResolvedType = AllTypes.CommandVersion, - Resolver = ResolveAsync((c, publish) => - { - var contentId = c.GetArgument("id"); - - var command = new DeleteContent { ContentId = contentId }; - - return publish(command); - }), - Description = $"Delete an {schemaName} content." - }); - } - - private static QueryArguments CreateIdArguments(string schemaName) - { - return new QueryArguments - { - new QueryArgument(AllTypes.None) - { - Name = "id", - Description = $"The id of the {schemaName} content (GUID)", - DefaultValue = string.Empty, - ResolvedType = AllTypes.NonNullGuid - }, - new QueryArgument(AllTypes.None) - { - Name = "expectedVersion", - Description = "The expected version", - DefaultValue = EtagVersion.Any, - ResolvedType = AllTypes.Int - } - }; - } - - private static IFieldResolver ResolveAsync(Func>, Task> action) - { - return new FuncFieldResolver>(async c => - { - var e = (GraphQLExecutionContext)c.UserContext; - - try - { - return await action(c, command => - { - command.ExpectedVersion = c.GetArgument("expectedVersion", EtagVersion.Any); - - return e.CommandBus.PublishAsync(command); - }); - } - catch (ValidationException ex) - { - c.Errors.Add(new ExecutionError(ex.Message)); - - throw; - } - catch (DomainException ex) - { - c.Errors.Add(new ExecutionError(ex.Message)); - - throw; - } - }); - } - - private static NamedContentData GetContentData(ResolveFieldContext c) - { - return JObject.FromObject(c.GetArgument("data")).ToObject(); - } - } -} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/CommandVersionGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/CommandVersionGraphType.cs deleted file mode 100644 index 9fdc792f2..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/CommandVersionGraphType.cs +++ /dev/null @@ -1,44 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using GraphQL.Resolvers; -using GraphQL.Types; -using Squidex.Infrastructure.Commands; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types -{ - public sealed class CommandVersionGraphType : ObjectGraphType - { - public CommandVersionGraphType() - { - Name = "CommandVersionDto"; - - AddField(new FieldType - { - Name = "version", - ResolvedType = AllTypes.Int, - Resolver = ResolveVersion(), - Description = "The new version of the item." - }); - - Description = "The result of a mutation"; - } - - private static IFieldResolver ResolveVersion() - { - return new FuncFieldResolver(x => - { - if (x.Source.Result() is EntitySavedResult result) - { - return (int)result.Version; - } - - return null; - }); - } - } -} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataChangedResultGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataChangedResultGraphType.cs deleted file mode 100644 index d050c3696..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataChangedResultGraphType.cs +++ /dev/null @@ -1,44 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using GraphQL.Resolvers; -using GraphQL.Types; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types -{ - public sealed class ContentDataChangedResultGraphType : ObjectGraphType - { - public ContentDataChangedResultGraphType(string schemaType, string schemaName, IGraphType contentDataType) - { - Name = $"{schemaName}DataChangedResultDto"; - - AddField(new FieldType - { - Name = "version", - ResolvedType = AllTypes.Int, - Resolver = Resolve(x => x.Version), - Description = $"The new version of the {schemaName} content." - }); - - AddField(new FieldType - { - Name = "data", - ResolvedType = new NonNullGraphType(contentDataType), - Resolver = Resolve(x => x.Data), - Description = $"The new data of the {schemaName} content." - }); - - Description = $"The result of the {schemaName} mutation"; - } - - private static IFieldResolver Resolve(Func action) - { - return new FuncFieldResolver(c => action(c.Source)); - } - } -} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphInputType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphInputType.cs deleted file mode 100644 index 0186366a9..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphInputType.cs +++ /dev/null @@ -1,70 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Linq; -using GraphQL.Types; -using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Infrastructure; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types -{ - public sealed class ContentDataGraphInputType : InputObjectGraphType - { - public ContentDataGraphInputType(IGraphModel model, ISchemaEntity schema) - { - var schemaType = schema.TypeName(); - var schemaName = schema.DisplayName(); - - Name = $"{schemaType}InputDto"; - - foreach (var field in schema.SchemaDef.Fields.Where(x => !x.IsHidden)) - { - var inputType = model.GetInputGraphType(field); - - if (inputType != null) - { - if (field.RawProperties.IsRequired) - { - inputType = new NonNullGraphType(inputType); - } - - var fieldName = field.RawProperties.Label.WithFallback(field.Name); - - var fieldGraphType = new InputObjectGraphType - { - Name = $"{schemaType}Data{field.Name.ToPascalCase()}InputDto" - }; - - var partition = model.ResolvePartition(field.Partitioning); - - foreach (var partitionItem in partition) - { - fieldGraphType.AddField(new FieldType - { - Name = partitionItem.Key, - Resolver = null, - ResolvedType = inputType, - Description = field.RawProperties.Hints - }); - } - - fieldGraphType.Description = $"The input structure of the {fieldName} of a {schemaName} content type."; - - AddField(new FieldType - { - Name = field.Name.ToCamelCase(), - Resolver = null, - ResolvedType = fieldGraphType, - Description = $"The {fieldName} field." - }); - } - } - - Description = $"The structure of a {schemaName} content type."; - } - } -} 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 2400dab3b..ab748e37a 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs @@ -64,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types }); } - fieldGraphType.Description = $"The structure of the {fieldName} field of a {schemaName} content type."; + fieldGraphType.Description = $"The structure of the {fieldName} field of the {schemaName} content type."; var fieldResolver = new FuncFieldResolver>(c => { @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types } } - Description = $"The structure of a {schemaName} content type."; + Description = $"The structure of the {schemaName} content type."; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GeolocationInputGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GeolocationInputGraphType.cs deleted file mode 100644 index 73ba49b5c..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GeolocationInputGraphType.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using GraphQL.Types; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types -{ - public sealed class GeolocationInputGraphType : InputObjectGraphType - { - public GeolocationInputGraphType() - { - Name = "GeolocationInputDto"; - - AddField(new FieldType - { - Name = "latitude", - ResolvedType = AllTypes.NonNullFloat - }); - - AddField(new FieldType - { - Name = "longitude", - ResolvedType = AllTypes.NonNullFloat - }); - } - } -} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldExtensions.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldExtensions.cs deleted file mode 100644 index 84af9a8f0..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using GraphQL.Types; -using Squidex.Domain.Apps.Core.Schemas; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types -{ - public static class InputFieldExtensions - { - public static IGraphType GetInputGraphType(this IField field) - { - return field.Accept(InputFieldVisitor.Default); - } - } -} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldVisitor.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldVisitor.cs deleted file mode 100644 index e000e13e5..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/InputFieldVisitor.cs +++ /dev/null @@ -1,71 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using GraphQL.Types; -using Squidex.Domain.Apps.Core.Schemas; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types -{ - public sealed class InputFieldVisitor : IFieldVisitor - { - public static readonly InputFieldVisitor Default = new InputFieldVisitor(); - - private InputFieldVisitor() - { - } - - public IGraphType Visit(IArrayField field) - { - return AllTypes.NoopArray; - } - - public IGraphType Visit(IField field) - { - return AllTypes.References; - } - - public IGraphType Visit(IField field) - { - return AllTypes.Boolean; - } - - public IGraphType Visit(IField field) - { - return AllTypes.Date; - } - - public IGraphType Visit(IField field) - { - return AllTypes.GeolocationInput; - } - - public IGraphType Visit(IField field) - { - return AllTypes.Json; - } - - public IGraphType Visit(IField field) - { - return AllTypes.Float; - } - - public IGraphType Visit(IField field) - { - return AllTypes.References; - } - - public IGraphType Visit(IField field) - { - return AllTypes.String; - } - - public IGraphType Visit(IField field) - { - return AllTypes.Tags; - } - } -} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs index dfbb998f7..5bdc36b5d 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs @@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types } } - Description = $"The structure of a {schemaName}.{fieldName} child schema."; + Description = $"The structure of the {schemaName}.{fieldName} nested schema."; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedInputGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedInputGraphType.cs deleted file mode 100644 index 44434370d..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedInputGraphType.cs +++ /dev/null @@ -1,47 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Linq; -using GraphQL.Types; -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 NestedInputGraphType : InputObjectGraphType - { - public NestedInputGraphType(IGraphModel model, ISchemaEntity schema, IArrayField field) - { - var schemaType = schema.TypeName(); - var schemaName = schema.DisplayName(); - - var fieldType = field.TypeName(); - var fieldName = field.DisplayName(); - - Name = $"{schemaType}{fieldName}ChildDto"; - - foreach (var nestedField in field.Fields.Where(x => !x.IsHidden)) - { - var fieldInfo = model.GetGraphType(schema, nestedField); - - if (fieldInfo.ResolveType != null) - { - AddField(new FieldType - { - Name = nestedField.Name.ToCamelCase(), - Resolver = null, - ResolvedType = fieldInfo.ResolveType, - Description = $"The {fieldName}/{nestedField.DisplayName()} nested field." - }); - } - } - - Description = $"The structure of a {schemaName}.{fieldName} nested schema."; - } - } -} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GuidGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/GuidGraphType.cs similarity index 95% rename from src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GuidGraphType.cs rename to src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/GuidGraphType.cs index 196c8ed44..bbfc8ea5b 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GuidGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/GuidGraphType.cs @@ -9,7 +9,7 @@ using System; using GraphQL.Language.AST; using GraphQL.Types; -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types +namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Utils { public sealed class GuidGraphType : ScalarGraphType { diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/InputConverter.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/InputConverter.cs deleted file mode 100644 index 7e6d71ebd..000000000 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Utils/InputConverter.cs +++ /dev/null @@ -1,73 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Collections.Generic; -using GraphQL; -using Newtonsoft.Json.Linq; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Utils -{ - public static class InputConverter - { - public static Inputs ToInputs(JObject input) - { - var result = new Inputs(); - - if (input != null) - { - foreach (var kvp in input) - { - result.Add(kvp.Key, GetValue(kvp.Value, 1)); - } - } - - return result; - } - - private static object GetValue(object value, int level) - { - if (level == 3) - { - return value; - } - - switch (value) - { - case JObject jObject: - { - var result = new Dictionary(); - - foreach (var kvp in jObject) - { - result.Add(kvp.Key, GetValue(kvp.Value, level + 1)); - } - - return result; - } - - case JArray jArray: - { - var result = new List(); - - foreach (var item in jArray) - { - result.Add(GetValue(item, level + 1)); - } - - return result; - } - - case JValue jValue: - { - return jValue.Value; - } - } - - return value; - } - } -} diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs deleted file mode 100644 index 91660566c..000000000 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs +++ /dev/null @@ -1,487 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Threading.Tasks; -using FakeItEasy; -using Newtonsoft.Json.Linq; -using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Entities.Contents.Commands; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; -using Xunit; - -namespace Squidex.Domain.Apps.Entities.Contents.GraphQL -{ - public class GraphQLMutationTests : GraphQLTestBase - { - private readonly Guid contentId = Guid.NewGuid(); - private readonly IContentEntity content; - private readonly CommandContext commandContext = new CommandContext(new PatchContent(), A.Dummy()); - - public GraphQLMutationTests() - { - content = CreateContent(contentId, Guid.NewGuid(), Guid.NewGuid(), null); - - A.CallTo(() => commandBus.PublishAsync(A.Ignored)) - .Returns(commandContext); - } - - [Fact] - public async Task Should_return_single_content_when_creating_content() - { - var query = $@" - mutation OP($data: MySchemaInputDto!) {{ - createMySchemaContent(data: $data, expectedVersion: 10) {{ - version - data {{ - myString {{ - de - }} - myNumber {{ - iv - }} - myBoolean {{ - iv - }} - myDatetime {{ - iv - }} - myGeolocation {{ - iv - }} - myTags {{ - iv - }} - }} - }} - }}"; - - commandContext.Complete(new EntityCreatedResult(content.Data, 13)); - - var inputContent = GetInputContent(content); - - var variables = - new JObject( - new JProperty("data", inputContent)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query, Variables = variables }); - - var expected = new - { - data = new - { - createMySchemaContent = new - { - version = 13, - data = new - { - myString = new - { - de = "value" - }, - myNumber = new - { - iv = 1 - }, - myBoolean = new - { - iv = true - }, - myDatetime = new - { - iv = content.LastModified.ToDateTimeUtc() - }, - myGeolocation = new - { - iv = new - { - latitude = 10, - longitude = 20 - } - }, - myTags = new - { - iv = new[] - { - "tag1", - "tag2" - } - } - } - } - } - }; - - AssertResult(expected, result); - } - - [Fact] - public async Task Should_return_single_content_when_updating_content() - { - var query = $@" - mutation OP($data: MySchemaInputDto!) {{ - updateMySchemaContent(id: ""{contentId}"", data: $data, expectedVersion: 10) {{ - version - data {{ - myString {{ - de - }} - myNumber {{ - iv - }} - myBoolean {{ - iv - }} - myDatetime {{ - iv - }} - myGeolocation {{ - iv - }} - myTags {{ - iv - }} - }} - }} - }}"; - - commandContext.Complete(new ContentDataChangedResult(content.Data, 13)); - - var inputContent = GetInputContent(content); - - var variables = - new JObject( - new JProperty("data", inputContent)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query, Variables = variables }); - - var expected = new - { - data = new - { - updateMySchemaContent = new - { - version = 13, - data = new - { - myString = new - { - de = "value" - }, - myNumber = new - { - iv = 1 - }, - myBoolean = new - { - iv = true - }, - myDatetime = new - { - iv = content.LastModified.ToDateTimeUtc() - }, - myGeolocation = new - { - iv = new - { - latitude = 10, - longitude = 20 - } - }, - myTags = new - { - iv = new[] - { - "tag1", - "tag2" - } - } - } - } - } - }; - - AssertResult(expected, result); - } - - [Fact] - public async Task Should_return_single_content_when_patching_content() - { - var query = $@" - mutation OP($data: MySchemaInputDto!) {{ - patchMySchemaContent(id: ""{contentId}"", data: $data, expectedVersion: 10) {{ - version - data {{ - myString {{ - de - }} - myNumber {{ - iv - }} - myBoolean {{ - iv - }} - myDatetime {{ - iv - }} - myGeolocation {{ - iv - }} - myTags {{ - iv - }} - }} - }} - }}"; - - commandContext.Complete(new ContentDataChangedResult(content.Data, 13)); - - var inputContent = GetInputContent(content); - - var variables = - new JObject( - new JProperty("data", inputContent)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query, Variables = variables }); - - var expected = new - { - data = new - { - patchMySchemaContent = new - { - version = 13, - data = new - { - myString = new - { - de = "value" - }, - myNumber = new - { - iv = 1 - }, - myBoolean = new - { - iv = true - }, - myDatetime = new - { - iv = content.LastModified.ToDateTimeUtc() - }, - myGeolocation = new - { - iv = new - { - latitude = 10, - longitude = 20 - } - }, - myTags = new - { - iv = new[] - { - "tag1", - "tag2" - } - } - } - } - } - }; - - AssertResult(expected, result); - } - - [Fact] - public async Task Should_publish_command_for_publish() - { - var query = $@" - mutation {{ - publishMySchemaContent(id: ""{contentId}"", expectedVersion: 10) {{ - version - }} - }}"; - - commandContext.Complete(new EntitySavedResult(13)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query }); - - var expected = new - { - data = new - { - publishMySchemaContent = new - { - version = 13 - } - } - }; - - AssertResult(expected, result); - - A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => - x.ContentId == contentId && - x.Status == Status.Published && - x.ExpectedVersion == 10))) - .MustHaveHappened(); - } - - [Fact] - public async Task Should_publish_command_for_unpublish() - { - var query = $@" - mutation {{ - unpublishMySchemaContent(id: ""{contentId}"", expectedVersion: 10) {{ - version - }} - }}"; - - commandContext.Complete(new EntitySavedResult(13)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query }); - - var expected = new - { - data = new - { - unpublishMySchemaContent = new - { - version = 13 - } - } - }; - - AssertResult(expected, result); - - A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => - x.ContentId == contentId && - x.Status == Status.Draft && - x.ExpectedVersion == 10))) - .MustHaveHappened(); - } - - [Fact] - public async Task Should_publish_command_for_archive() - { - var query = $@" - mutation {{ - archiveMySchemaContent(id: ""{contentId}"", expectedVersion: 10) {{ - version - }} - }}"; - - commandContext.Complete(new EntitySavedResult(13)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query }); - - var expected = new - { - data = new - { - archiveMySchemaContent = new - { - version = 13 - } - } - }; - - AssertResult(expected, result); - - A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => - x.ContentId == contentId && - x.Status == Status.Archived && - x.ExpectedVersion == 10))) - .MustHaveHappened(); - } - - [Fact] - public async Task Should_publish_command_for_restore() - { - var query = $@" - mutation {{ - restoreMySchemaContent(id: ""{contentId}"", expectedVersion: 10) {{ - version - }} - }}"; - - commandContext.Complete(new EntitySavedResult(13)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query }); - - var expected = new - { - data = new - { - restoreMySchemaContent = new - { - version = 13 - } - } - }; - - AssertResult(expected, result); - - A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => - x.ContentId == contentId && - x.Status == Status.Draft && - x.ExpectedVersion == 10))) - .MustHaveHappened(); - } - - [Fact] - public async Task Should_publish_command_for_delete() - { - var query = $@" - mutation {{ - deleteMySchemaContent(id: ""{contentId}"", expectedVersion: 10) {{ - version - }} - }}"; - - commandContext.Complete(new EntitySavedResult(13)); - - var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query }); - - var expected = new - { - data = new - { - deleteMySchemaContent = new - { - version = 13 - } - } - }; - - AssertResult(expected, result); - - A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => - x.ContentId == contentId && - x.ExpectedVersion == 10))) - .MustHaveHappened(); - } - - private static JObject GetInputContent(IContentEntity content) - { - var camelContent = new NamedContentData(); - - foreach (var kvp in content.Data) - { - camelContent[kvp.Key.ToCamelCase()] = kvp.Value; - } - - return JObject.FromObject(camelContent); - } - } -} 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 e22d33f62..174f1f477 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -24,7 +24,6 @@ using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.TestData; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; using Xunit; #pragma warning disable SA1311 // Static readonly fields must begin with upper-case letter @@ -39,7 +38,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL protected static readonly string appName = "my-app"; protected readonly Schema schemaDef; protected readonly IContentQueryService contentQuery = A.Fake(); - protected readonly ICommandBus commandBus = A.Fake(); protected readonly IAssetRepository assetRepository = A.Fake(); protected readonly ISchemaEntity schema = A.Fake(); protected readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); @@ -93,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL A.CallTo(() => appProvider.GetSchemasAsync(appId)).Returns(allSchemas); - sut = new CachingGraphQLService(cache, appProvider, assetRepository, commandBus, contentQuery, new FakeUrlGenerator()); + sut = new CachingGraphQLService(cache, appProvider, assetRepository, contentQuery, new FakeUrlGenerator()); } protected static IContentEntity CreateContent(Guid id, Guid refId, Guid assetId, NamedContentData data = null)