Browse Source

Finalized

pull/630/head
Sebastian 5 years ago
parent
commit
9fe052bd0d
  1. 133
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs
  2. 29
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs
  3. 10
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs
  4. 9
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppMutationsGraphType.cs
  5. 18
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs
  6. 3
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs
  7. 143
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs
  8. 14
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs
  9. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentUnionGraphType.cs
  10. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataFlatGraphType.cs
  11. 9
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataGraphType.cs
  12. 7
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs
  13. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedGraphType.cs
  14. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs
  15. 16
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GraphQLFieldInputVisitor.cs
  16. 16
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GraphQLFieldVisitor.cs
  17. 7
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs

133
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs

@ -5,22 +5,14 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using GraphQL; using GraphQL;
using GraphQL.Resolvers;
using GraphQL.Types;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Log; using Squidex.Log;
using GraphQLSchema = GraphQL.Types.Schema; using GraphQLSchema = GraphQL.Types.Schema;
@ -29,137 +21,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
public sealed class GraphQLModel public sealed class GraphQLModel
{ {
private static readonly IDocumentExecuter Executor = new DocumentExecuter(); private static readonly IDocumentExecuter Executor = new DocumentExecuter();
private readonly Dictionary<SchemaInfo, ContentGraphType> contentTypes = new Dictionary<SchemaInfo, ContentGraphType>(ReferenceEqualityComparer.Instance);
private readonly Dictionary<SchemaInfo, ContentResultGraphType> contentResultTypes = new Dictionary<SchemaInfo, ContentResultGraphType>(ReferenceEqualityComparer.Instance);
private readonly GraphQLSchema schema; private readonly GraphQLSchema schema;
private readonly GraphQLTypeFactory typeFactory;
private readonly ISemanticLog log; private readonly ISemanticLog log;
#pragma warning disable IDE0044 // Add readonly modifier
private GraphQLFieldVisitor fieldVisitor;
private GraphQLFieldInputVisitor fieldInputVisitor;
private PartitionResolver partitionResolver;
#pragma warning restore IDE0044 // Add readonly modifier
static GraphQLModel()
{
ValueConverter.Register<JsonBoolean, bool>(x => x.Value);
ValueConverter.Register<JsonNumber, double>(x => x.Value);
ValueConverter.Register<JsonString, string>(x => x.Value);
ValueConverter.Register<JsonString, DateTimeOffset>(x => DateTimeOffset.Parse(x.Value, CultureInfo.InvariantCulture));
ValueConverter.Register<string, DomainId>(DomainId.Create);
}
public GraphQLTypeFactory TypeFactory
{
get { return typeFactory; }
}
public GraphQLModel(IAppEntity app, IEnumerable<ISchemaEntity> schemas, GraphQLTypeFactory typeFactory, ISemanticLog log) public GraphQLModel(IAppEntity app, IEnumerable<ISchemaEntity> schemas, GraphQLTypeFactory typeFactory, ISemanticLog log)
{ {
this.typeFactory = typeFactory;
this.log = log; this.log = log;
partitionResolver = app.PartitionResolver(); schema = new Builder(app, typeFactory).BuildSchema(schemas);
fieldVisitor = new GraphQLFieldVisitor(this);
fieldInputVisitor = new GraphQLFieldInputVisitor(this);
var allSchemas = schemas.Where(x => x.SchemaDef.IsPublished).Select(SchemaInfo.Build).ToList();
BuildSchemas(allSchemas);
schema = BuildSchema(allSchemas);
schema.RegisterValueConverter(JsonConverter.Instance);
schema.RegisterValueConverter(InstantConverter.Instance);
InitializeContentTypes(allSchemas);
partitionResolver = null!;
fieldVisitor = null!;
fieldInputVisitor = null!;
}
private void BuildSchemas(List<SchemaInfo> allSchemas)
{
foreach (var schemaInfo in allSchemas)
{
var contentType = new ContentGraphType(schemaInfo);
contentTypes[schemaInfo] = contentType;
contentResultTypes[schemaInfo] = new ContentResultGraphType(contentType, schemaInfo);
}
}
private void InitializeContentTypes(List<SchemaInfo> allSchemas)
{
foreach (var (schemaInfo, contentType) in contentTypes)
{
contentType.Initialize(this, schemaInfo, allSchemas);
}
foreach (var contentType in contentTypes.Values)
{
schema.RegisterType(contentType);
}
schema.Initialize();
schema.CleanupMetadata();
}
private GraphQLSchema BuildSchema(List<SchemaInfo> schemas)
{
var newSchema = new GraphQLSchema
{
Query = new AppQueriesGraphType(this, schemas)
};
newSchema.RegisterType(ContentInterfaceGraphType.Instance);
var schemasWithFields = schemas.Where(x => x.Fields.Count > 0);
if (schemasWithFields.Any())
{
newSchema.Mutation = new AppMutationsGraphType(this, schemasWithFields);
}
return newSchema;
}
internal IFieldPartitioning ResolvePartition(Partitioning key)
{
return partitionResolver(key);
}
internal IGraphType? GetInputGraphType(FieldInfo fieldInfo)
{
return fieldInfo.Field.Accept(fieldInputVisitor, fieldInfo);
}
internal (IGraphType?, IFieldResolver?, QueryArguments?) GetGraphType(FieldInfo fieldInfo)
{
return fieldInfo.Field.Accept(fieldVisitor, fieldInfo);
}
internal IObjectGraphType? GetContentType(DomainId schemaId)
{
return contentTypes.FirstOrDefault(x => x.Key.Schema.Id == schemaId).Value;
}
internal IObjectGraphType GetContentType(SchemaInfo schemaId)
{
return contentTypes.GetOrDefault(schemaId);
}
internal IObjectGraphType GetContentResultType(SchemaInfo schemaId)
{
return contentResultTypes.GetOrDefault(schemaId);
}
internal IEnumerable<KeyValuePair<SchemaInfo, ContentGraphType>> GetAllContentTypes()
{
return contentTypes;
} }
public async Task<(object Data, object[]? Errors)> ExecuteAsync(GraphQLExecutionContext context, GraphQLQuery query) public async Task<(object Data, object[]? Errors)> ExecuteAsync(GraphQLExecutionContext context, GraphQLQuery query)

29
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs

@ -1,29 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
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;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
public interface IGraphModel
{
IFieldPartitioning ResolvePartition(Partitioning key);
GraphQLTypeFactory TypeFactory { get; }
IGraphType GetContentType(DomainId schemaId);
IGraphType? GetInputGraphType(ISchemaEntity schema, IField field, string fieldName);
(IGraphType?, ValueResolver?, QueryArguments?) GetGraphType(ISchemaEntity schema, IField field, string fieldName);
}
}

10
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs

@ -16,8 +16,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
public static readonly Type None = typeof(NoopGraphType); public static readonly Type None = typeof(NoopGraphType);
public static readonly Type NonNullTagsType = typeof(NonNullGraphType<ListGraphType<NonNullGraphType<StringGraphType>>>);
public static readonly IGraphType Int = new IntGraphType(); public static readonly IGraphType Int = new IntGraphType();
public static readonly IGraphType DomainId = new StringGraphType(); public static readonly IGraphType DomainId = new StringGraphType();
@ -28,20 +26,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
public static readonly IGraphType Date = new InstantGraphType(); public static readonly IGraphType Date = new InstantGraphType();
public static readonly IGraphType Tags = new ListGraphType(new NonNullGraphType(new StringGraphType()));
public static readonly IGraphType Json = new JsonGraphType(); public static readonly IGraphType Json = new JsonGraphType();
public static readonly IGraphType Float = new FloatGraphType(); public static readonly IGraphType Float = new FloatGraphType();
public static readonly IGraphType String = new StringGraphType(); public static readonly IGraphType String = new StringGraphType();
public static readonly IGraphType Strings = new ListGraphType(new NonNullGraphType(new StringGraphType()));
public static readonly IGraphType Boolean = new BooleanGraphType(); public static readonly IGraphType Boolean = new BooleanGraphType();
public static readonly IGraphType AssetType = new EnumerationGraphType<AssetType>(); public static readonly IGraphType AssetType = new EnumerationGraphType<AssetType>();
public static readonly IGraphType References = new ListGraphType(new NonNullGraphType(new StringGraphType()));
public static readonly IGraphType NonNullInt = new NonNullGraphType(Int); public static readonly IGraphType NonNullInt = new NonNullGraphType(Int);
public static readonly IGraphType NonNullDomainId = new NonNullGraphType(DomainId); public static readonly IGraphType NonNullDomainId = new NonNullGraphType(DomainId);
@ -56,6 +52,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
public static readonly IGraphType NonNullString = new NonNullGraphType(String); public static readonly IGraphType NonNullString = new NonNullGraphType(String);
public static readonly IGraphType NonNullStrings = new NonNullGraphType(Strings);
public static readonly IGraphType NonNullBoolean = new NonNullGraphType(Boolean); public static readonly IGraphType NonNullBoolean = new NonNullGraphType(Boolean);
public static readonly IGraphType NonNullAssetType = new NonNullGraphType(AssetType); public static readonly IGraphType NonNullAssetType = new NonNullGraphType(AssetType);

9
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppMutationsGraphType.cs

@ -10,19 +10,18 @@ using System.Linq;
using GraphQL.Types; using GraphQL.Types;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Utils; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Utils;
using Squidex.Domain.Apps.Entities.Schemas;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
public sealed class AppMutationsGraphType : ObjectGraphType internal sealed class AppMutationsGraphType : ObjectGraphType
{ {
public AppMutationsGraphType(GraphQLModel model, IEnumerable<SchemaInfo> schemas) public AppMutationsGraphType(Builder builder, IEnumerable<SchemaInfo> schemas)
{ {
foreach (var schemaInfo in schemas.Where(x => x.Fields.Count > 0)) foreach (var schemaInfo in schemas.Where(x => x.Fields.Count > 0))
{ {
var contentType = model.GetContentType(schemaInfo); var contentType = builder.GetContentType(schemaInfo);
var inputType = new DataInputGraphType(model, schemaInfo); var inputType = new DataInputGraphType(builder, schemaInfo);
AddField(new FieldType AddField(new FieldType
{ {

18
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs

@ -11,20 +11,20 @@ using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
public sealed class AppQueriesGraphType : ObjectGraphType internal sealed class AppQueriesGraphType : ObjectGraphType
{ {
public AppQueriesGraphType(GraphQLModel model, IEnumerable<SchemaInfo> schemaInfos) public AppQueriesGraphType(Builder builder, IEnumerable<SchemaInfo> schemaInfos)
{ {
AddField(model.TypeFactory.FindAsset); AddField(builder.TypeFactory.FindAsset);
AddField(model.TypeFactory.QueryAssets); AddField(builder.TypeFactory.QueryAssets);
AddField(model.TypeFactory.QueryAssetsWithTotal); AddField(builder.TypeFactory.QueryAssetsWithTotal);
foreach (var schemaInfo in schemaInfos) foreach (var schemaInfo in schemaInfos)
{ {
var contentType = model.GetContentType(schemaInfo); var contentType = builder.GetContentType(schemaInfo);
AddContentFind(schemaInfo, contentType); AddContentFind(schemaInfo, contentType);
AddContentQueries(model, schemaInfo, contentType); AddContentQueries(builder, schemaInfo, contentType);
} }
Description = "The app queries."; Description = "The app queries.";
@ -42,7 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
}).WithSchemaId(schemaInfo); }).WithSchemaId(schemaInfo);
} }
private void AddContentQueries(GraphQLModel model, SchemaInfo schemaInfo, IGraphType contentType) private void AddContentQueries(Builder builder, SchemaInfo schemaInfo, IGraphType contentType)
{ {
AddField(new FieldType AddField(new FieldType
{ {
@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
Description = $"Query {schemaInfo.DisplayName} content items." Description = $"Query {schemaInfo.DisplayName} content items."
}).WithSchemaId(schemaInfo); }).WithSchemaId(schemaInfo);
var resultType = model.GetContentResultType(schemaInfo); var resultType = builder.GetContentResultType(schemaInfo);
AddField(new FieldType AddField(new FieldType
{ {

3
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs

@ -196,10 +196,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
AddField(new FieldType AddField(new FieldType
{ {
Name = "tags", Name = "tags",
ResolvedType = null, ResolvedType = AllTypes.NonNullStrings,
Resolver = Resolve(x => x.TagNames), Resolver = Resolve(x => x.TagNames),
Description = "The asset tags.", Description = "The asset tags.",
Type = AllTypes.NonNullTagsType
}); });
AddField(new FieldType AddField(new FieldType

143
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs

@ -0,0 +1,143 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using GraphQL;
using GraphQL.Resolvers;
using GraphQL.Types;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
using GraphQLSchema = GraphQL.Types.Schema;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{
internal sealed class Builder
{
private readonly Dictionary<SchemaInfo, ContentGraphType> contentTypes = new Dictionary<SchemaInfo, ContentGraphType>(ReferenceEqualityComparer.Instance);
private readonly Dictionary<SchemaInfo, ContentResultGraphType> contentResultTypes = new Dictionary<SchemaInfo, ContentResultGraphType>(ReferenceEqualityComparer.Instance);
private readonly GraphQLTypeFactory typeFactory;
private readonly GraphQLFieldVisitor fieldVisitor;
private readonly GraphQLFieldInputVisitor fieldInputVisitor;
private readonly PartitionResolver partitionResolver;
public GraphQLTypeFactory TypeFactory
{
get { return typeFactory; }
}
static Builder()
{
ValueConverter.Register<JsonBoolean, bool>(x => x.Value);
ValueConverter.Register<JsonNumber, double>(x => x.Value);
ValueConverter.Register<JsonString, string>(x => x.Value);
ValueConverter.Register<JsonString, DateTimeOffset>(x => DateTimeOffset.Parse(x.Value, CultureInfo.InvariantCulture));
ValueConverter.Register<string, DomainId>(DomainId.Create);
ValueConverter.Register<string, Status>(x => new Status(x));
}
public Builder(IAppEntity app, GraphQLTypeFactory typeFactory)
{
this.typeFactory = typeFactory;
partitionResolver = app.PartitionResolver();
fieldVisitor = new GraphQLFieldVisitor(this);
fieldInputVisitor = new GraphQLFieldInputVisitor(this);
}
public GraphQLSchema BuildSchema(IEnumerable<ISchemaEntity> schemas)
{
var schemaInfos =
schemas
.Where(x => x.SchemaDef.IsPublished).Select(SchemaInfo.Build)
.Where(x => x.Fields.Count > 0)
.ToList();
foreach (var schemaInfo in schemaInfos)
{
var contentType = new ContentGraphType(schemaInfo);
contentTypes[schemaInfo] = contentType;
contentResultTypes[schemaInfo] = new ContentResultGraphType(contentType, schemaInfo);
}
var newSchema = new GraphQLSchema
{
Query = new AppQueriesGraphType(this, schemaInfos)
};
newSchema.RegisterValueConverter(JsonConverter.Instance);
newSchema.RegisterValueConverter(InstantConverter.Instance);
newSchema.RegisterType(ContentInterfaceGraphType.Instance);
if (schemas.Any())
{
newSchema.Mutation = new AppMutationsGraphType(this, schemaInfos);
}
foreach (var (schemaInfo, contentType) in contentTypes)
{
contentType.Initialize(this, schemaInfo, schemaInfos);
}
foreach (var contentType in contentTypes.Values)
{
newSchema.RegisterType(contentType);
}
newSchema.Initialize();
newSchema.CleanupMetadata();
return newSchema;
}
public IFieldPartitioning ResolvePartition(Partitioning key)
{
return partitionResolver(key);
}
public IGraphType? GetInputGraphType(FieldInfo fieldInfo)
{
return fieldInfo.Field.Accept(fieldInputVisitor, fieldInfo);
}
public (IGraphType?, IFieldResolver?, QueryArguments?) GetGraphType(FieldInfo fieldInfo)
{
return fieldInfo.Field.Accept(fieldVisitor, fieldInfo);
}
public IObjectGraphType? GetContentType(DomainId schemaId)
{
return contentTypes.FirstOrDefault(x => x.Key.Schema.Id == schemaId).Value;
}
public IObjectGraphType GetContentType(SchemaInfo schemaId)
{
return contentTypes.GetOrDefault(schemaId);
}
public IObjectGraphType GetContentResultType(SchemaInfo schemaId)
{
return contentResultTypes.GetOrDefault(schemaId);
}
public IEnumerable<KeyValuePair<SchemaInfo, ContentGraphType>> GetAllContentTypes()
{
return contentTypes;
}
}
}

14
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs

@ -44,7 +44,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
return value is IContentEntity content && content.SchemaId?.Id == schemaId; return value is IContentEntity content && content.SchemaId?.Id == schemaId;
} }
public void Initialize(GraphQLModel model, SchemaInfo schemaInfo, IEnumerable<SchemaInfo> all) public void Initialize(Builder builder, SchemaInfo schemaInfo, IEnumerable<SchemaInfo> all)
{ {
AddField(new FieldType AddField(new FieldType
{ {
@ -54,7 +54,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Description = $"The url to the content." Description = $"The url to the content."
}); });
var contentDataType = new DataGraphType(model, schemaInfo); var contentDataType = new DataGraphType(builder, schemaInfo);
if (contentDataType.Fields.Any()) if (contentDataType.Fields.Any())
{ {
@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
}); });
} }
var contentDataTypeFlat = new DataFlatGraphType(model, schemaInfo); var contentDataTypeFlat = new DataFlatGraphType(builder, schemaInfo);
if (contentDataTypeFlat.Fields.Any()) if (contentDataTypeFlat.Fields.Any())
{ {
@ -82,13 +82,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
foreach (var other in all.Where(x => References(x, schemaInfo))) foreach (var other in all.Where(x => References(x, schemaInfo)))
{ {
AddReferencingQueries(model, other); AddReferencingQueries(builder, other);
} }
} }
private void AddReferencingQueries(GraphQLModel model, SchemaInfo referencingSchemaInfo) private void AddReferencingQueries(Builder builder, SchemaInfo referencingSchemaInfo)
{ {
var contentType = model.GetContentType(referencingSchemaInfo); var contentType = builder.GetContentType(referencingSchemaInfo);
AddField(new FieldType AddField(new FieldType
{ {
@ -99,7 +99,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Description = $"Query {referencingSchemaInfo.DisplayName} content items." Description = $"Query {referencingSchemaInfo.DisplayName} content items."
}).WithSchemaId(referencingSchemaInfo); }).WithSchemaId(referencingSchemaInfo);
var contentResultsTyp = model.GetContentResultType(referencingSchemaInfo); var contentResultsTyp = builder.GetContentResultType(referencingSchemaInfo);
AddField(new FieldType AddField(new FieldType
{ {

8
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentUnionGraphType.cs

@ -13,11 +13,11 @@ using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public sealed class ContentUnionGraphType : UnionGraphType internal sealed class ContentUnionGraphType : UnionGraphType
{ {
private readonly Dictionary<DomainId, IObjectGraphType> types = new Dictionary<DomainId, IObjectGraphType>(); private readonly Dictionary<DomainId, IObjectGraphType> types = new Dictionary<DomainId, IObjectGraphType>();
public ContentUnionGraphType(GraphQLModel model, FieldInfo fieldInfo, ReferencesFieldProperties properties) public ContentUnionGraphType(Builder builder, FieldInfo fieldInfo, ReferencesFieldProperties properties)
{ {
Name = fieldInfo.UnionType; Name = fieldInfo.UnionType;
@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
foreach (var schemaId in properties.SchemaIds) foreach (var schemaId in properties.SchemaIds)
{ {
var contentType = model.GetContentType(schemaId); var contentType = builder.GetContentType(schemaId);
if (contentType != null) if (contentType != null)
{ {
@ -35,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
} }
else else
{ {
foreach (var (key, value) in model.GetAllContentTypes()) foreach (var (key, value) in builder.GetAllContentTypes())
{ {
types[key.Schema.Id] = value; types[key.Schema.Id] = value;
} }

6
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataFlatGraphType.cs

@ -10,15 +10,15 @@ using Squidex.Domain.Apps.Core.Contents;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public sealed class DataFlatGraphType : ObjectGraphType<FlatContentData> internal sealed class DataFlatGraphType : ObjectGraphType<FlatContentData>
{ {
public DataFlatGraphType(GraphQLModel model, SchemaInfo schemaInfo) public DataFlatGraphType(Builder builder, SchemaInfo schemaInfo)
{ {
Name = schemaInfo.DataFlatType; Name = schemaInfo.DataFlatType;
foreach (var fieldInfo in schemaInfo.Fields) foreach (var fieldInfo in schemaInfo.Fields)
{ {
var (resolvedType, resolver, args) = model.GetGraphType(fieldInfo); var (resolvedType, resolver, args) = builder.GetGraphType(fieldInfo);
if (resolver != null) if (resolver != null)
{ {

9
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataGraphType.cs

@ -14,13 +14,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
internal sealed class DataGraphType : ObjectGraphType<ContentData> internal sealed class DataGraphType : ObjectGraphType<ContentData>
{ {
public DataGraphType(GraphQLModel model, SchemaInfo schemaInfo) public DataGraphType(Builder builder, SchemaInfo schemaInfo)
{ {
Name = schemaInfo.DataType; Name = schemaInfo.DataType;
foreach (var fieldInfo in schemaInfo.Fields) foreach (var fieldInfo in schemaInfo.Fields)
{ {
var (resolvedType, resolver, args) = model.GetGraphType(fieldInfo); var (resolvedType, resolver, args) = builder.GetGraphType(fieldInfo);
if (resolver != null) if (resolver != null)
{ {
@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Name = fieldInfo.TypeName Name = fieldInfo.TypeName
}; };
var partitioning = model.ResolvePartition(((RootField)fieldInfo.Field).Partitioning); var partitioning = builder.ResolvePartition(((RootField)fieldInfo.Field).Partitioning);
foreach (var partitionKey in partitioning.AllKeys) foreach (var partitionKey in partitioning.AllKeys)
{ {
@ -49,8 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
Name = fieldInfo.FieldName, Name = fieldInfo.FieldName,
ResolvedType = fieldGraphType, ResolvedType = fieldGraphType,
Resolver = ContentResolvers.Field, Resolver = ContentResolvers.Field
Description = $"The {fieldInfo.DisplayName} field."
}).WithSourceName(fieldInfo); }).WithSourceName(fieldInfo);
} }
} }

7
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs

@ -13,13 +13,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
internal sealed class DataInputGraphType : InputObjectGraphType internal sealed class DataInputGraphType : InputObjectGraphType
{ {
public DataInputGraphType(GraphQLModel model, SchemaInfo schemaInfo) public DataInputGraphType(Builder builder, SchemaInfo schemaInfo)
{ {
Name = schemaInfo.DataInputType; Name = schemaInfo.DataInputType;
foreach (var fieldInfo in schemaInfo.Fields) foreach (var fieldInfo in schemaInfo.Fields)
{ {
var resolvedType = model.GetInputGraphType(fieldInfo); var resolvedType = builder.GetInputGraphType(fieldInfo);
if (resolvedType != null) if (resolvedType != null)
{ {
@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Name = fieldInfo.LocalizedInputType Name = fieldInfo.LocalizedInputType
}; };
var partitioning = model.ResolvePartition(((RootField)fieldInfo.Field).Partitioning); var partitioning = builder.ResolvePartition(((RootField)fieldInfo.Field).Partitioning);
foreach (var partitionKey in partitioning.AllKeys) foreach (var partitionKey in partitioning.AllKeys)
{ {
@ -48,7 +48,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Name = fieldInfo.FieldName, Name = fieldInfo.FieldName,
ResolvedType = fieldGraphType, ResolvedType = fieldGraphType,
Resolver = null, Resolver = null,
Description = $"The {fieldInfo.DisplayName} field."
}).WithSourceName(fieldInfo); }).WithSourceName(fieldInfo);
} }
} }

8
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedGraphType.cs

@ -10,15 +10,15 @@ using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public sealed class NestedGraphType : ObjectGraphType<JsonObject> internal sealed class NestedGraphType : ObjectGraphType<JsonObject>
{ {
public NestedGraphType(GraphQLModel model, FieldInfo fieldInfo) public NestedGraphType(Builder builder, FieldInfo fieldInfo)
{ {
Name = fieldInfo.NestedType; Name = fieldInfo.NestedType;
foreach (var nestedFieldInfo in fieldInfo.Fields) foreach (var nestedFieldInfo in fieldInfo.Fields)
{ {
var (resolvedType, resolver, args) = model.GetGraphType(nestedFieldInfo); var (resolvedType, resolver, args) = builder.GetGraphType(nestedFieldInfo);
if (resolvedType != null && resolver != null) if (resolvedType != null && resolver != null)
{ {
@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Arguments = args, Arguments = args,
ResolvedType = resolvedType, ResolvedType = resolvedType,
Resolver = resolver, Resolver = resolver,
Description = $"The {fieldInfo.DisplayName}/{nestedFieldInfo.DisplayName} nested field." Description = nestedFieldInfo.Field.RawProperties.Hints
}).WithSourceName(nestedFieldInfo); }).WithSourceName(nestedFieldInfo);
} }
} }

6
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs

@ -11,13 +11,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
internal sealed class NestedInputGraphType : InputObjectGraphType internal sealed class NestedInputGraphType : InputObjectGraphType
{ {
public NestedInputGraphType(GraphQLModel model, FieldInfo fieldInfo) public NestedInputGraphType(Builder builder, FieldInfo fieldInfo)
{ {
Name = fieldInfo.NestedInputType; Name = fieldInfo.NestedInputType;
foreach (var nestedFieldInfo in fieldInfo.Fields) foreach (var nestedFieldInfo in fieldInfo.Fields)
{ {
var resolvedType = model.GetInputGraphType(nestedFieldInfo); var resolvedType = builder.GetInputGraphType(nestedFieldInfo);
if (resolvedType != null) if (resolvedType != null)
{ {
@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Name = nestedFieldInfo.FieldName, Name = nestedFieldInfo.FieldName,
ResolvedType = resolvedType, ResolvedType = resolvedType,
Resolver = null, Resolver = null,
Description = $"The {fieldInfo.DisplayName}/{nestedFieldInfo.DisplayName} nested field." Description = nestedFieldInfo.Field.RawProperties.Hints
}).WithSourceName(nestedFieldInfo); }).WithSourceName(nestedFieldInfo);
} }
} }

16
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GraphQLFieldInputVisitor.cs

@ -11,13 +11,13 @@ using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
public sealed class GraphQLFieldInputVisitor : IFieldVisitor<IGraphType?, FieldInfo> internal sealed class GraphQLFieldInputVisitor : IFieldVisitor<IGraphType?, FieldInfo>
{ {
private readonly GraphQLModel model; private readonly Builder builder;
public GraphQLFieldInputVisitor(GraphQLModel model) public GraphQLFieldInputVisitor(Builder builder)
{ {
this.model = model; this.builder = builder;
} }
public IGraphType? Visit(IArrayField field, FieldInfo args) public IGraphType? Visit(IArrayField field, FieldInfo args)
@ -25,14 +25,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
var schemaFieldType = var schemaFieldType =
new ListGraphType( new ListGraphType(
new NonNullGraphType( new NonNullGraphType(
new NestedInputGraphType(model, args))); new NestedInputGraphType(builder, args)));
return schemaFieldType; return schemaFieldType;
} }
public IGraphType? Visit(IField<AssetsFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<AssetsFieldProperties> field, FieldInfo args)
{ {
return AllTypes.References; return AllTypes.Strings;
} }
public IGraphType? Visit(IField<BooleanFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<BooleanFieldProperties> field, FieldInfo args)
@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
public IGraphType? Visit(IField<ReferencesFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<ReferencesFieldProperties> field, FieldInfo args)
{ {
return AllTypes.Json; return AllTypes.Strings;
} }
public IGraphType? Visit(IField<StringFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<StringFieldProperties> field, FieldInfo args)
@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
public IGraphType? Visit(IField<TagsFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<TagsFieldProperties> field, FieldInfo args)
{ {
return AllTypes.Tags; return AllTypes.Strings;
} }
public IGraphType? Visit(IField<UIFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<UIFieldProperties> field, FieldInfo args)

16
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/GraphQLFieldVisitor.cs

@ -33,11 +33,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
return context.GetReferencedContentsAsync(value); return context.GetReferencedContentsAsync(value);
}); });
private readonly GraphQLModel model; private readonly Builder builder;
public GraphQLFieldVisitor(GraphQLModel model) public GraphQLFieldVisitor(Builder builder)
{ {
this.model = model; this.builder = builder;
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IArrayField field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IArrayField field, FieldInfo args)
@ -45,14 +45,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
var schemaFieldType = var schemaFieldType =
new ListGraphType( new ListGraphType(
new NonNullGraphType( new NonNullGraphType(
new NestedGraphType(model, args))); new NestedGraphType(builder, args)));
return (schemaFieldType, Noop, null); return (schemaFieldType, Noop, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<AssetsFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<AssetsFieldProperties> field, FieldInfo args)
{ {
return (model.TypeFactory.AssetsList, Assets, null); return (builder.TypeFactory.AssetsList, Assets, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<BooleanFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<BooleanFieldProperties> field, FieldInfo args)
@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<TagsFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<TagsFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.Tags, Noop, null); return (AllTypes.Strings, Noop, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<UIFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<UIFieldProperties> field, FieldInfo args)
@ -102,11 +102,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
private (IGraphType?, IFieldResolver?, QueryArguments?) ResolveReferences(IField<ReferencesFieldProperties> field, FieldInfo args) private (IGraphType?, IFieldResolver?, QueryArguments?) ResolveReferences(IField<ReferencesFieldProperties> field, FieldInfo args)
{ {
IGraphType? contentType = model.GetContentType(field.Properties.SingleId()); IGraphType? contentType = builder.GetContentType(field.Properties.SingleId());
if (contentType == null) if (contentType == null)
{ {
var union = new ContentUnionGraphType(model, args, field.Properties); var union = new ContentUnionGraphType(builder, args, field.Properties);
if (!union.PossibleTypes.Any()) if (!union.PossibleTypes.Any())
{ {

7
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using GraphQL; using GraphQL;
using GraphQL.NewtonsoftJson; using GraphQL.NewtonsoftJson;
using GraphQL.Types;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NodaTime; using NodaTime;
@ -38,6 +39,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
[Fact] [Fact]
public async Task Should_return_single_content_when_creating_content() public async Task Should_return_single_content_when_creating_content()
{ {
var f = new FloatGraphType().ParseValue("12.0");
var query = @" var query = @"
mutation { mutation {
createMySchemaContent(data: <DATA>, publish: true) { createMySchemaContent(data: <DATA>, publish: true) {
@ -478,9 +481,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{ {
var data = TestContent.Data(content, schemaRefId1.Id, schemaRefId2.Id); var data = TestContent.Data(content, schemaRefId1.Id, schemaRefId2.Id);
var json = JsonConvert.SerializeObject(data); var json = JsonConvert.SerializeObject(data, Formatting.Indented);
return Regex.Replace(json, "\"([^\"]+)\":", x => x.Groups[1].Value + ":"); return Regex.Replace(json, "\"([^\"]+)\":", x => x.Groups[1].Value + ":").Replace(".0", string.Empty);
} }
} }
} }

Loading…
Cancel
Save