Browse Source

Migration to graphql 4. (#676)

* Migration to graphql 4.

* Updated packages.
pull/679/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
096609a82f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj
  2. 2
      backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj
  3. 1
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsFluidExtension.cs
  4. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsJintExtension.cs
  5. 22
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AllTypes.cs
  6. 32
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetActions.cs
  7. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs
  8. 24
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs
  9. 167
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs
  10. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentFields.cs
  11. 52
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs
  12. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldInputVisitor.cs
  13. 84
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs
  14. 18
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs
  15. 101
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs
  16. 79
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/Converters.cs
  17. 10
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/EntityResolvers.cs
  18. 32
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/InstantConverter.cs
  19. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/InstantGraphType.cs
  20. 25
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/InstantValueNode.cs
  21. 72
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonConverter.cs
  22. 58
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs
  23. 20
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonNoopGraphType.cs
  24. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonValueNode.cs
  25. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Resolvers.cs
  26. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesFluidExtension.cs
  27. 5
      backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj
  28. 2
      backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj
  29. 4
      backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj
  30. 2
      backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj
  31. 4
      backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs
  32. 5
      backend/src/Squidex.Infrastructure/Json/Objects/JsonArray.cs
  33. 4
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  34. 3
      backend/src/Squidex.Web/GraphQL/GraphQLMiddleware.cs
  35. 4
      backend/src/Squidex.Web/Squidex.Web.csproj
  36. 10
      backend/src/Squidex/Config/Domain/QueryServices.cs
  37. 1
      backend/src/Squidex/Config/Domain/SerializationServices.cs
  38. 25
      backend/src/Squidex/Squidex.csproj
  39. 2
      backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj
  40. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs
  41. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLIntrospectionTests.cs
  42. 18
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs
  43. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs
  44. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj
  45. 2
      backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj
  46. 2
      backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj
  47. 6
      backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj

2
backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj

@ -10,7 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Algolia.Search" Version="6.9.1" /> <PackageReference Include="Algolia.Search" Version="6.9.1" />
<PackageReference Include="Confluent.Apache.Avro" Version="1.7.7.7" /> <PackageReference Include="Confluent.Apache.Avro" Version="1.7.7.7" />
<PackageReference Include="Confluent.Kafka" Version="1.6.2" /> <PackageReference Include="Confluent.Kafka" Version="1.6.3" />
<PackageReference Include="Confluent.SchemaRegistry.Serdes" Version="1.3.0" /> <PackageReference Include="Confluent.SchemaRegistry.Serdes" Version="1.3.0" />
<PackageReference Include="CoreTweet" Version="1.0.0.483" /> <PackageReference Include="CoreTweet" Version="1.0.0.483" />
<PackageReference Include="Datadog.Trace" Version="1.24.0" /> <PackageReference Include="Datadog.Trace" Version="1.24.0" />

2
backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Equals.Fody" Version="4.0.1" PrivateAssets="all" /> <PackageReference Include="Equals.Fody" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Fody" Version="6.3.0"> <PackageReference Include="Fody" Version="6.4.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

1
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsFluidExtension.cs

@ -13,6 +13,7 @@ using Fluid;
using Fluid.Ast; using Fluid.Ast;
using Fluid.Tags; using Fluid.Tags;
using GraphQL.Utilities; using GraphQL.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Templates; using Squidex.Domain.Apps.Core.Templates;
using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Core.ValidateContent;

2
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsJintExtension.cs

@ -10,9 +10,9 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using GraphQL.Utilities;
using Jint.Native; using Jint.Native;
using Jint.Runtime; using Jint.Runtime;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Infrastructure; using Squidex.Infrastructure;

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

@ -14,20 +14,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
public static class AllTypes public static class AllTypes
{ {
public static readonly Type None = typeof(NoopGraphType);
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 Long = new LongGraphType(); public static readonly IGraphType Long = new LongGraphType();
public static readonly IGraphType Guid = new GuidGraphType();
public static readonly IGraphType Date = new InstantGraphType();
public static readonly IGraphType Json = new JsonGraphType(); public static readonly IGraphType Json = new JsonGraphType();
public static readonly IGraphType JsonNoop = new JsonNoopGraphType();
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();
@ -36,18 +30,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
public static readonly IGraphType Boolean = new BooleanGraphType(); public static readonly IGraphType Boolean = new BooleanGraphType();
public static readonly IGraphType DateTime = new InstantGraphType();
public static readonly IGraphType AssetType = new EnumerationGraphType<AssetType>(); public static readonly IGraphType AssetType = new EnumerationGraphType<AssetType>();
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 NonNullLong = new NonNullGraphType(Long); public static readonly IGraphType NonNullLong = new NonNullGraphType(Long);
public static readonly IGraphType NonNullGuid = new NonNullGraphType(Guid);
public static readonly IGraphType NonNullDate = new NonNullGraphType(Date);
public static readonly IGraphType NonNullFloat = new NonNullGraphType(Float); public static readonly IGraphType NonNullFloat = new NonNullGraphType(Float);
public static readonly IGraphType NonNullString = new NonNullGraphType(String); public static readonly IGraphType NonNullString = new NonNullGraphType(String);
@ -56,8 +46,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
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 NonNullDateTime = new NonNullGraphType(DateTime);
public static readonly IGraphType NoopJson = new NoopGraphType(Json); public static readonly IGraphType NonNullAssetType = new NonNullGraphType(AssetType);
} }
} }

32
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetActions.cs

@ -19,12 +19,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "path", Name = "path",
Description = "The path to the json value", Description = "The path to the json value",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
} }
}; };
@ -32,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{ {
if (fieldContext.Arguments.TryGetValue("path", out var path)) if (fieldContext.Arguments.TryGetValue("path", out var path))
{ {
source.Metadata.TryGetByPath(path as string, out var result); source.Metadata.TryGetByPath(path.Value as string, out var result);
return result; return result;
} }
@ -45,12 +44,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.NonNullString)
{ {
Name = "id", Name = "id",
Description = "The id of the asset (usually GUID).", Description = "The id of the asset (usually GUID).",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.NonNullDomainId
} }
}; };
@ -66,33 +64,29 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "top", Name = "top",
Description = "Optional number of assets to take.", Description = "Optional number of assets to take.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.Int
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "skip", Name = "skip",
Description = "Optional number of assets to skip.", Description = "Optional number of assets to skip.",
DefaultValue = 0, DefaultValue = 0
ResolvedType = AllTypes.Int
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "filter", Name = "filter",
Description = "Optional OData filter.", Description = "Optional OData filter.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "orderby", Name = "orderby",
Description = "Optional OData order definition.", Description = "Optional OData order definition.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
} }
}; };

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

@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
AddField(new FieldType AddField(new FieldType
{ {
Name = "created", Name = "created",
ResolvedType = AllTypes.NonNullDate, ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.Created, Resolver = EntityResolvers.Created,
Description = "The date and time when the asset has been created." Description = "The date and time when the asset has been created."
}); });
@ -57,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
AddField(new FieldType AddField(new FieldType
{ {
Name = "lastModified", Name = "lastModified",
ResolvedType = AllTypes.NonNullDate, ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.LastModified, Resolver = EntityResolvers.LastModified,
Description = "The date and time when the asset has been modified last." Description = "The date and time when the asset has been modified last."
}); });
@ -205,7 +205,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{ {
Name = "metadata", Name = "metadata",
Arguments = AssetActions.Metadata.Arguments, Arguments = AssetActions.Metadata.Arguments,
ResolvedType = AllTypes.NoopJson, ResolvedType = AllTypes.JsonNoop,
Resolver = AssetActions.Metadata.Resolver, Resolver = AssetActions.Metadata.Resolver,
Description = "The asset metadata." Description = "The asset metadata."
}); });

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

@ -5,9 +5,7 @@
// 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 GraphQL; using GraphQL;
using GraphQL.Resolvers; using GraphQL.Resolvers;
@ -16,10 +14,8 @@ using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
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.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 GraphQLSchema = GraphQL.Types.Schema; using GraphQLSchema = GraphQL.Types.Schema;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
@ -28,31 +24,21 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
private readonly Dictionary<SchemaInfo, ContentGraphType> contentTypes = new Dictionary<SchemaInfo, ContentGraphType>(ReferenceEqualityComparer.Instance); 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 Dictionary<SchemaInfo, ContentResultGraphType> contentResultTypes = new Dictionary<SchemaInfo, ContentResultGraphType>(ReferenceEqualityComparer.Instance);
private readonly SharedTypes sharedTypes;
private readonly FieldVisitor fieldVisitor; private readonly FieldVisitor fieldVisitor;
private readonly FieldInputVisitor fieldInputVisitor; private readonly FieldInputVisitor fieldInputVisitor;
private readonly PartitionResolver partitionResolver; private readonly PartitionResolver partitionResolver;
public SharedTypes SharedTypes public SharedTypes SharedTypes { get; }
{
get => sharedTypes;
}
static Builder() 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, DomainId>(DomainId.Create);
ValueConverter.Register<string, Status>(x => new Status(x)); ValueConverter.Register<string, Status>(x => new Status(x));
} }
public Builder(IAppEntity app, SharedTypes sharedTypes) public Builder(IAppEntity app, SharedTypes sharedTypes)
{ {
this.sharedTypes = sharedTypes; SharedTypes = sharedTypes;
partitionResolver = app.PartitionResolver(); partitionResolver = app.PartitionResolver();
@ -77,10 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
Query = new AppQueriesGraphType(this, schemaInfos) Query = new AppQueriesGraphType(this, schemaInfos)
}; };
newSchema.RegisterValueConverter(JsonConverter.Instance); newSchema.RegisterType(SharedTypes.ContentInterface);
newSchema.RegisterValueConverter(InstantConverter.Instance);
newSchema.RegisterType(sharedTypes.ContentInterface);
if (schemas.Any()) if (schemas.Any())
{ {
@ -98,7 +81,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
} }
newSchema.Initialize(); newSchema.Initialize();
newSchema.CleanupMetadata();
return newSchema; return newSchema;
} }

167
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs

@ -27,18 +27,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "path", Name = "path",
Description = "The path to the json value", Description = "The path to the json value",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
} }
}; };
public static readonly ValueResolver Resolver = (value, fieldContext, context) => public static readonly ValueResolver Resolver = (value, fieldContext, context) =>
{ {
if (fieldContext.Arguments.TryGetValue("path", out var p) && p is string path) if (fieldContext.Arguments.TryGetValue("path", out var v) && v.Value is string path)
{ {
value.TryGetByPath(path, out var result); value.TryGetByPath(path, out var result);
@ -51,12 +50,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly QueryArguments JsonPath = new QueryArguments public static readonly QueryArguments JsonPath = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "path", Name = "path",
Description = "The path to the json value", Description = "The path to the json value",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
} }
}; };
@ -64,19 +62,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.NonNullString)
{ {
Name = "id", Name = "id",
Description = "The id of the content (usually GUID).", Description = "The id of the content (usually GUID).",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.NonNullDomainId
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "version", Name = "version",
Description = "The optional version of the content to retrieve an older instance (not cached).", Description = "The optional version of the content to retrieve an older instance (not cached).",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.Int
} }
}; };
@ -101,40 +97,35 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "top", Name = "top",
Description = "Optional number of contents to take.", Description = "Optional number of contents to take.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.Int
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "skip", Name = "skip",
Description = "Optional number of contents to skip.", Description = "Optional number of contents to skip.",
DefaultValue = 0, DefaultValue = 0
ResolvedType = AllTypes.Int
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "filter", Name = "filter",
Description = "Optional OData filter.", Description = "Optional OData filter.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "orderby", Name = "orderby",
Description = "Optional OData order definition.", Description = "Optional OData order definition.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "search", Name = "search",
Description = "Optional OData full text search.", Description = "Optional OData full text search.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
} }
}; };
@ -181,41 +172,37 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
return new QueryArguments return new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(new NonNullGraphType(inputType))
{ {
Name = "data", Name = "data",
Description = "The data for the content.", Description = "The data for the content.",
DefaultValue = null, DefaultValue = null
ResolvedType = new NonNullGraphType(inputType)
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Boolean)
{ {
Name = "publish", Name = "publish",
Description = "Set to true to autopublish content on create.", Description = "Set to true to autopublish content on create.",
DefaultValue = false, DefaultValue = false
ResolvedType = AllTypes.Boolean
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "status", Name = "status",
Description = "The initial status.", Description = "The initial status.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "id", Name = "id",
Description = "The optional custom content id.", Description = "The optional custom content id.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
} }
}; };
} }
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsCreate, c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsCreate, c =>
{ {
var contentData = GetContentData(c);
var contentId = c.GetArgument<string?>("id"); var contentId = c.GetArgument<string?>("id");
var contentData = c.GetArgument<ContentData>("data");
var contentStatus = c.GetArgument<string?>("status"); var contentStatus = c.GetArgument<string?>("status");
var command = new CreateContent { Data = contentData }; var command = new CreateContent { Data = contentData };
@ -244,48 +231,43 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
return new QueryArguments return new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.NonNullString)
{ {
Name = "id", Name = "id",
Description = "The id of the content (usually GUID).", Description = "The id of the content (usually GUID).",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.NonNullDomainId
}, },
new QueryArgument(AllTypes.None) new QueryArgument(new NonNullGraphType(inputType))
{ {
Name = "data", Name = "data",
Description = "The data for the content.", Description = "The data for the content.",
DefaultValue = null, DefaultValue = null
ResolvedType = new NonNullGraphType(inputType)
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Boolean)
{ {
Name = "publish", Name = "publish",
Description = "Set to true to autopublish content on create.", Description = "Set to true to autopublish content on create.",
DefaultValue = false, DefaultValue = false
ResolvedType = AllTypes.Boolean
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "status", Name = "status",
Description = "The initial status.", Description = "The initial status.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "expectedVersion", Name = "expectedVersion",
Description = "The expected version", Description = "The expected version",
DefaultValue = EtagVersion.Any, DefaultValue = EtagVersion.Any
ResolvedType = AllTypes.Int
} }
}; };
} }
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpsert, c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpsert, c =>
{ {
var contentData = GetContentData(c);
var contentId = c.GetArgument<string>("id"); var contentId = c.GetArgument<string>("id");
var contentData = c.GetArgument<ContentData>("data");
var contentStatus = c.GetArgument<string?>("status"); var contentStatus = c.GetArgument<string?>("status");
var id = DomainId.Create(contentId); var id = DomainId.Create(contentId);
@ -311,26 +293,23 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
return new QueryArguments return new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "id", Name = "id",
Description = "The optional custom content id.", Description = "The optional custom content id.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
}, },
new QueryArgument(AllTypes.None) new QueryArgument(new NonNullGraphType(inputType))
{ {
Name = "data", Name = "data",
Description = "The data for the content.", Description = "The data for the content.",
DefaultValue = null, DefaultValue = null
ResolvedType = new NonNullGraphType(inputType)
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "expectedVersion", Name = "expectedVersion",
Description = "The expected version", Description = "The expected version",
DefaultValue = EtagVersion.Any, DefaultValue = EtagVersion.Any
ResolvedType = AllTypes.Int
} }
}; };
} }
@ -338,7 +317,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c =>
{ {
var contentId = c.GetArgument<DomainId>("id"); var contentId = c.GetArgument<DomainId>("id");
var contentData = GetContentData(c); var contentData = c.GetArgument<ContentData>("data");
return new UpdateContent { ContentId = contentId, Data = contentData }; return new UpdateContent { ContentId = contentId, Data = contentData };
}); });
@ -350,26 +329,23 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
return new QueryArguments return new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.String)
{ {
Name = "id", Name = "id",
Description = "The optional custom content id.", Description = "The optional custom content id.",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.String
}, },
new QueryArgument(AllTypes.None) new QueryArgument(new NonNullGraphType(inputType))
{ {
Name = "data", Name = "data",
Description = "The data for the content.", Description = "The data for the content.",
DefaultValue = null, DefaultValue = null
ResolvedType = new NonNullGraphType(inputType)
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "expectedVersion", Name = "expectedVersion",
Description = "The expected version", Description = "The expected version",
DefaultValue = EtagVersion.Any, DefaultValue = EtagVersion.Any
ResolvedType = AllTypes.Int
} }
}; };
} }
@ -377,7 +353,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c => public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c =>
{ {
var contentId = c.GetArgument<DomainId>("id"); var contentId = c.GetArgument<DomainId>("id");
var contentData = GetContentData(c); var contentData = c.GetArgument<ContentData>("data");
return new PatchContent { ContentId = contentId, Data = contentData }; return new PatchContent { ContentId = contentId, Data = contentData };
}); });
@ -387,33 +363,29 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.NonNullString)
{ {
Name = "id", Name = "id",
Description = "The id of the content (usually GUID).", Description = "The id of the content (usually GUID).",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.NonNullDomainId
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.NonNullString)
{ {
Name = "status", Name = "status",
Description = "The new status", Description = "The new status",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.NonNullString
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.DateTime)
{ {
Name = "dueTime", Name = "dueTime",
Description = "When to change the status", Description = "When to change the status",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.Date
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "expectedVersion", Name = "expectedVersion",
Description = "The expected version", Description = "The expected version",
DefaultValue = EtagVersion.Any, DefaultValue = EtagVersion.Any
ResolvedType = AllTypes.Int
} }
}; };
@ -431,19 +403,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
public static readonly QueryArguments Arguments = new QueryArguments public static readonly QueryArguments Arguments = new QueryArguments
{ {
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.NonNullString)
{ {
Name = "id", Name = "id",
Description = "The id of the content (usually GUID).", Description = "The id of the content (usually GUID).",
DefaultValue = null, DefaultValue = null
ResolvedType = AllTypes.NonNullDomainId
}, },
new QueryArgument(AllTypes.None) new QueryArgument(AllTypes.Int)
{ {
Name = "expectedVersion", Name = "expectedVersion",
Description = "The expected version", Description = "The expected version",
DefaultValue = EtagVersion.Any, DefaultValue = EtagVersion.Any
ResolvedType = AllTypes.Int
} }
}; };
@ -455,13 +425,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
}); });
} }
private static ContentData GetContentData(IResolveFieldContext c)
{
var source = c.GetArgument<IDictionary<string, object>>("data");
return source.ToContentData((IComplexGraphType)c.FieldDefinition.Arguments.Find("data").Flatten());
}
private static IFieldResolver ResolveAsync(string permissionId, Func<IResolveFieldContext, ContentCommand> action) private static IFieldResolver ResolveAsync(string permissionId, Func<IResolveFieldContext, ContentCommand> action)
{ {
return Resolvers.Async<object, object>(async (source, fieldContext, context) => return Resolvers.Async<object, object>(async (source, fieldContext, context) =>

4
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentFields.cs

@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly FieldType Created = new FieldType public static readonly FieldType Created = new FieldType
{ {
Name = "created", Name = "created",
ResolvedType = AllTypes.NonNullDate, ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.Created, Resolver = EntityResolvers.Created,
Description = "The date and time when the content has been created." Description = "The date and time when the content has been created."
}; };
@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly FieldType LastModified = new FieldType public static readonly FieldType LastModified = new FieldType
{ {
Name = "lastModified", Name = "lastModified",
ResolvedType = AllTypes.NonNullDate, ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.LastModified, Resolver = EntityResolvers.LastModified,
Description = "The date and time when the content has been modified last." Description = "The date and time when the content has been modified last."
}; };

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

@ -5,9 +5,14 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using System.Linq;
using GraphQL.Types; using GraphQL.Types;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
@ -54,5 +59,52 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Description = $"The structure of the {schemaInfo.DisplayName} data input type."; Description = $"The structure of the {schemaInfo.DisplayName} data input type.";
} }
public override object ParseDictionary(IDictionary<string, object> value)
{
var result = new ContentData();
static ContentFieldData ToFieldData(IDictionary<string, object> source, IComplexGraphType type)
{
var result = new ContentFieldData();
foreach (var field in type.Fields)
{
if (source.TryGetValue(field.Name, out var value))
{
if (value is IEnumerable<object> list && field.ResolvedType.Flatten() is IComplexGraphType nestedType)
{
var array = new JsonArray(list.Count());
foreach (var item in list)
{
if (item is JsonObject nested)
{
array.Add(nested);
}
}
result[field.SourceName()] = array;
}
else
{
result[field.SourceName()] = JsonGraphType.ParseJson(value);
}
}
}
return result;
}
foreach (var field in Fields)
{
if (field.ResolvedType is IComplexGraphType complexType && value.TryGetValue(field.Name, out var fieldValue) && fieldValue is IDictionary<string, object> nested)
{
result[field.SourceName()] = ToFieldData(nested, complexType);
}
}
return result;
}
} }
} }

2
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldInputVisitor.cs

@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public IGraphType? Visit(IField<DateTimeFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<DateTimeFieldProperties> field, FieldInfo args)
{ {
return AllTypes.Date; return AllTypes.DateTime;
} }
public IGraphType? Visit(IField<GeolocationFieldProperties> field, FieldInfo args) public IGraphType? Visit(IField<GeolocationFieldProperties> field, FieldInfo args)

84
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs

@ -5,6 +5,7 @@
// 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.Linq; using System.Linq;
using GraphQL; using GraphQL;
@ -19,8 +20,63 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
internal sealed class FieldVisitor : IFieldVisitor<(IGraphType?, IFieldResolver?, QueryArguments?), FieldInfo> internal sealed class FieldVisitor : IFieldVisitor<(IGraphType?, IFieldResolver?, QueryArguments?), FieldInfo>
{ {
private static readonly IFieldResolver Noop = CreateValueResolver((value, fieldContext, contex) => value); private static readonly IFieldResolver JsonNoop = CreateValueResolver((value, fieldContext, contex) => value);
private static readonly IFieldResolver Json = CreateValueResolver(ContentActions.Json.Resolver); private static readonly IFieldResolver JsonPath = CreateValueResolver(ContentActions.Json.Resolver);
private static readonly IFieldResolver JsonBoolean = CreateValueResolver((value, fieldContext, contex) =>
{
switch (value)
{
case JsonBoolean b:
return b.Value;
default:
throw new NotSupportedException();
}
});
private static readonly IFieldResolver JsonDateTime = CreateValueResolver((value, fieldContext, contex) =>
{
switch (value)
{
case JsonString n:
return n.Value;
default:
throw new NotSupportedException();
}
});
private static readonly IFieldResolver JsonNumber = CreateValueResolver((value, fieldContext, contex) =>
{
switch (value)
{
case JsonNumber n:
return n.Value;
default:
throw new NotSupportedException();
}
});
private static readonly IFieldResolver JsonString = CreateValueResolver((value, fieldContext, contex) =>
{
switch (value)
{
case JsonString s:
return s.Value;
default:
throw new NotSupportedException();
}
});
private static readonly IFieldResolver JsonStrings = CreateValueResolver((value, fieldContext, contex) =>
{
switch (value)
{
case JsonArray a:
return a.Select(x => x.ToString()).ToList();
default:
throw new NotSupportedException();
}
});
private static readonly IFieldResolver Assets = CreateValueResolver((value, _, context) => private static readonly IFieldResolver Assets = CreateValueResolver((value, _, context) =>
{ {
@ -46,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
new NonNullGraphType( new NonNullGraphType(
new NestedGraphType(builder, args))); new NestedGraphType(builder, args)));
return (schemaFieldType, Noop, null); return (schemaFieldType, JsonNoop, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<AssetsFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<AssetsFieldProperties> field, FieldInfo args)
@ -56,42 +112,42 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<BooleanFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<BooleanFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.Boolean, Noop, null); return (AllTypes.Boolean, JsonBoolean, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<DateTimeFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<DateTimeFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.Date, Noop, null); return (AllTypes.DateTime, JsonDateTime, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<JsonFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<JsonFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.Json, Json, ContentActions.Json.Arguments); return (AllTypes.Json, JsonPath, ContentActions.Json.Arguments);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<GeolocationFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<GeolocationFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.Json, Noop, null); return (AllTypes.Json, JsonPath, ContentActions.Json.Arguments);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<NumberFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<NumberFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.Float, Noop, null); return (AllTypes.Float, JsonNumber, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<ReferencesFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<StringFieldProperties> field, FieldInfo args)
{ {
return ResolveReferences(field, args); return (AllTypes.String, JsonString, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<StringFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<TagsFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.String, Noop, null); return (AllTypes.Strings, JsonStrings, null);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<TagsFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<ReferencesFieldProperties> field, FieldInfo args)
{ {
return (AllTypes.Strings, Noop, null); return ResolveReferences(field, args);
} }
public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<UIFieldProperties> field, FieldInfo args) public (IGraphType?, IFieldResolver?, QueryArguments?) Visit(IField<UIFieldProperties> field, FieldInfo args)

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

@ -5,7 +5,10 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using GraphQL.Types; using GraphQL.Types;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{ {
@ -33,5 +36,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
Description = $"The structure of the {fieldInfo.DisplayName} nested schema."; Description = $"The structure of the {fieldInfo.DisplayName} nested schema.";
} }
public override object ParseDictionary(IDictionary<string, object> value)
{
var result = JsonValue.Object();
foreach (var field in Fields)
{
if (value.TryGetValue(field.Name, out var fieldValue))
{
result[field.SourceName()] = JsonGraphType.ParseJson(fieldValue);
}
}
return result;
}
} }
} }

101
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs

@ -5,16 +5,12 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using System.Linq;
using GraphQL; using GraphQL;
using GraphQL.Types; using GraphQL.Types;
using GraphQL.Utilities;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.ObjectPool; using Squidex.Infrastructure.ObjectPool;
using GraphQLSchema = GraphQL.Types.Schema;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
@ -27,11 +23,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
sb.Append('?'); sb.Append('?');
foreach (var argument in context.Arguments) foreach (var (key, value) in context.Arguments)
{ {
var value = argument.Value?.ToString(); var formatted = value.Value?.ToString();
if (!string.IsNullOrWhiteSpace(value)) if (!string.IsNullOrWhiteSpace(formatted))
{ {
if (sb.Length > 1) if (sb.Length > 1)
{ {
@ -39,9 +35,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
} }
sb.Append('$'); sb.Append('$');
sb.Append(argument.Key); sb.Append(key);
sb.Append('='); sb.Append('=');
sb.Append(value); sb.Append(formatted);
} }
} }
@ -90,20 +86,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
private static FieldType WithMetadata(this FieldType field, string key, object value) private static FieldType WithMetadata(this FieldType field, string key, object value)
{ {
if (field is MetadataProvider metadataProvider) field.Metadata[key] = value;
{
if (metadataProvider.Metadata is Dictionary<string, object> dict)
{
dict[key] = value;
}
else
{
metadataProvider.Metadata = new Dictionary<string, object>
{
[key] = value
};
}
}
return field; return field;
} }
@ -122,77 +105,5 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
return type; return type;
} }
public static void CleanupMetadata(this GraphQLSchema schema)
{
var targets = new HashSet<IProvideMetadata>(ReferenceEqualityComparer.Instance);
foreach (var type in schema.AllTypes)
{
FindTargets(type, targets);
}
foreach (var target in targets.OfType<MetadataProvider>())
{
var metadata = target.Metadata;
if (metadata != null && metadata.Count == 0)
{
target.Metadata = null;
}
}
}
private static void FindTargets(IGraphType type, HashSet<IProvideMetadata> targets)
{
if (type == null)
{
return;
}
if (targets.Add(type))
{
if (type is IComplexGraphType complexType)
{
foreach (var field in complexType.Fields)
{
targets.Add(field);
FindTargets(field.ResolvedType, targets);
if (field.Arguments != null)
{
foreach (var argument in field.Arguments)
{
targets.Add(argument);
FindTargets(argument.ResolvedType, targets);
}
}
}
if (type is IObjectGraphType { ResolvedInterfaces: { } } objectGraphType)
{
foreach (var @interface in objectGraphType.ResolvedInterfaces)
{
FindTargets(@interface, targets);
}
}
if (type is IAbstractGraphType { PossibleTypes: { } } abstractGraphType)
{
foreach (var possibleType in abstractGraphType.PossibleTypes)
{
FindTargets(possibleType, targets);
}
}
}
if (type is IProvideResolvedType provideType)
{
FindTargets(provideType.ResolvedType, targets);
}
}
}
} }
} }

79
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/Converters.cs

@ -1,79 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using GraphQL.Types;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{
internal static class Converters
{
public static ContentData ToContentData(this IDictionary<string, object> source, IComplexGraphType type)
{
var result = new ContentData();
foreach (var field in type.Fields)
{
if (source.TryGetValue(field.Name, out var t) && t is IDictionary<string, object> nested && field.ResolvedType is IComplexGraphType complexType)
{
result[field.SourceName()] = nested.ToFieldData(complexType);
}
}
return result;
}
public static ContentFieldData ToFieldData(this IDictionary<string, object> source, IComplexGraphType type)
{
var result = new ContentFieldData();
foreach (var field in type.Fields)
{
if (source.TryGetValue(field.Name, out var value))
{
if (value is List<object> list && field.ResolvedType.Flatten() is IComplexGraphType nestedType)
{
var arr = new JsonArray();
foreach (var item in list)
{
if (item is IDictionary<string, object> nested)
{
arr.Add(nested.ToNestedData(nestedType));
}
}
result[field.SourceName()] = arr;
}
else
{
result[field.SourceName()] = JsonConverter.ParseJson(value);
}
}
}
return result;
}
public static IJsonValue ToNestedData(this IDictionary<string, object> source, IComplexGraphType type)
{
var result = JsonValue.Object();
foreach (var field in type.Fields)
{
if (source.TryGetValue(field.Name, out var value))
{
result[field.SourceName()] = JsonConverter.ParseJson(value);
}
}
return result;
}
}
}

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

@ -12,11 +12,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{ {
internal static class EntityResolvers internal static class EntityResolvers
{ {
public static readonly IFieldResolver Id = Resolve<IEntity>(x => x.Id); public static readonly IFieldResolver Id = Resolve<IEntity>(x => x.Id.ToString());
public static readonly IFieldResolver Created = Resolve<IEntity>(x => x.Created); public static readonly IFieldResolver Created = Resolve<IEntity>(x => x.Created.ToDateTimeUtc());
public static readonly IFieldResolver CreatedBy = Resolve<IEntityWithCreatedBy>(x => x.CreatedBy); public static readonly IFieldResolver CreatedBy = Resolve<IEntityWithCreatedBy>(x => x.CreatedBy.ToString());
public static readonly IFieldResolver LastModified = Resolve<IEntity>(x => x.LastModified); public static readonly IFieldResolver LastModified = Resolve<IEntity>(x => x.LastModified.ToDateTimeUtc());
public static readonly IFieldResolver LastModifiedBy = Resolve<IEntityWithLastModifiedBy>(x => x.LastModifiedBy); public static readonly IFieldResolver LastModifiedBy = Resolve<IEntityWithLastModifiedBy>(x => x.LastModifiedBy.ToString());
public static readonly IFieldResolver Version = Resolve<IEntityWithVersion>(x => x.Version); public static readonly IFieldResolver Version = Resolve<IEntityWithVersion>(x => x.Version);
private static IFieldResolver Resolve<TSource>(Func<TSource, object> resolver) private static IFieldResolver Resolve<TSource>(Func<TSource, object> resolver)

32
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/InstantConverter.cs

@ -1,32 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using GraphQL.Language.AST;
using GraphQL.Types;
using NodaTime;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{
internal sealed class InstantConverter : IAstFromValueConverter
{
public static readonly InstantConverter Instance = new InstantConverter();
private InstantConverter()
{
}
public IValue Convert(object value, IGraphType type)
{
return new InstantValueNode((Instant)value);
}
public bool Matches(object value, IGraphType type)
{
return type is InstantGraphType;
}
}
}

4
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/InstantGraphType.cs

@ -11,7 +11,7 @@ using NodaTime.Text;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{ {
internal sealed class InstantGraphType : DateTimeGraphType public sealed class InstantGraphType : DateTimeGraphType
{ {
public override object Serialize(object value) public override object Serialize(object value)
{ {
@ -27,8 +27,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{ {
switch (value) switch (value)
{ {
case InstantValueNode timeValue:
return timeValue.Value;
case StringValue stringValue: case StringValue stringValue:
return ParseValue(stringValue.Value); return ParseValue(stringValue.Value);
default: default:

25
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/InstantValueNode.cs

@ -1,25 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using GraphQL.Language.AST;
using NodaTime;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{
internal sealed class InstantValueNode : ValueNode<Instant>
{
public InstantValueNode(Instant value)
{
Value = value;
}
protected override bool Equals(ValueNode<Instant> node)
{
return Equals(Value, node.Value);
}
}
}

72
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonConverter.cs

@ -1,72 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using GraphQL.Language.AST;
using GraphQL.Types;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{
internal sealed class JsonConverter : IAstFromValueConverter
{
public static readonly JsonConverter Instance = new JsonConverter();
private JsonConverter()
{
}
public IValue Convert(object value, IGraphType type)
{
return new JsonValueNode(ParseJson(value));
}
public bool Matches(object value, IGraphType type)
{
return type is JsonGraphType;
}
public static IJsonValue ParseJson(object value)
{
switch (value)
{
case ListValue listValue:
return ParseJson(listValue.Value);
case ObjectValue objectValue:
return ParseJson(objectValue.Value);
case Dictionary<string, object> dictionary:
{
var json = JsonValue.Object();
foreach (var (key, inner) in dictionary)
{
json[key] = ParseJson(inner);
}
return json;
}
case List<object> list:
{
var array = JsonValue.Array();
foreach (var item in list)
{
array.Add(ParseJson(item));
}
return array;
}
default:
return JsonValue.Create(value);
}
}
}
}

58
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs

@ -5,20 +5,14 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using GraphQL.Language.AST; using GraphQL.Language.AST;
using GraphQL.Types; using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{ {
internal sealed class JsonGraphType : ScalarGraphType public sealed class JsonGraphType : JsonNoopGraphType
{ {
public JsonGraphType()
{
Name = "JsonScalar";
Description = "Unstructured Json object";
}
public override object Serialize(object value) public override object Serialize(object value)
{ {
return value; return value;
@ -26,7 +20,46 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
public override object ParseValue(object value) public override object ParseValue(object value)
{ {
return JsonConverter.ParseJson(value); return ParseJson(value);
}
public static IJsonValue ParseJson(object value)
{
switch (value)
{
case ListValue listValue:
return ParseJson(listValue.Value);
case ObjectValue objectValue:
return ParseJson(objectValue.Value);
case IReadOnlyDictionary<string, object> dictionary:
{
var json = JsonValue.Object();
foreach (var (key, inner) in dictionary)
{
json[key] = ParseJson(inner);
}
return json;
}
case IEnumerable<object> list:
{
var array = JsonValue.Array();
foreach (var item in list)
{
array.Add(ParseJson(item));
}
return array;
}
default:
return JsonValue.Create(value);
}
} }
public override object ParseLiteral(IValue value) public override object ParseLiteral(IValue value)
@ -38,5 +71,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
return value; return value;
} }
public override IValue ToAST(object value)
{
return new JsonValueNode(ParseJson(value));
}
} }
} }

20
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/NoopGraphType.cs → backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonNoopGraphType.cs

@ -10,22 +10,18 @@ using GraphQL.Types;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{ {
internal sealed class NoopGraphType : ScalarGraphType public class JsonNoopGraphType : ScalarGraphType
{ {
public NoopGraphType(string name) public JsonNoopGraphType()
{ {
Name = name; Name = "JsonScalar";
}
public NoopGraphType(IGraphType type) Description = "Unstructured Json object";
: this(type.Name)
{
Description = type.Description;
} }
public override object Serialize(object value) public override object ParseLiteral(IValue value)
{ {
return value; return value.Value;
} }
public override object ParseValue(object value) public override object ParseValue(object value)
@ -33,9 +29,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
return value; return value;
} }
public override object ParseLiteral(IValue value) public override object Serialize(object value)
{ {
return value.Value; return value;
} }
} }
} }

5
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonValueNode.cs

@ -16,10 +16,5 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{ {
Value = value; Value = value;
} }
protected override bool Equals(ValueNode<IJsonValue> node)
{
return Equals(Value, node.Value);
}
} }
} }

4
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Resolvers.cs

@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
executionContext.Log.LogWarning(ex, w => w executionContext.Log.LogWarning(ex, w => w
.WriteProperty("action", "resolveField") .WriteProperty("action", "resolveField")
.WriteProperty("status", "failed") .WriteProperty("status", "failed")
.WriteProperty("field", context.FieldName)); .WriteProperty("field", context.FieldDefinition.Name));
throw; throw;
} }
@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
executionContext.Log.LogWarning(ex, w => w executionContext.Log.LogWarning(ex, w => w
.WriteProperty("action", "resolveField") .WriteProperty("action", "resolveField")
.WriteProperty("status", "failed") .WriteProperty("status", "failed")
.WriteProperty("field", context.FieldName)); .WriteProperty("field", context.FieldDefinition.Name));
throw; throw;
} }

2
backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesFluidExtension.cs

@ -14,7 +14,7 @@ using System.Threading.Tasks;
using Fluid; using Fluid;
using Fluid.Ast; using Fluid.Ast;
using Fluid.Tags; using Fluid.Tags;
using GraphQL.Utilities; using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Templates; using Squidex.Domain.Apps.Core.Templates;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;

5
backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj

@ -20,11 +20,12 @@
<PackageReference Include="CsvHelper" Version="26.0.1" /> <PackageReference Include="CsvHelper" Version="26.0.1" />
<PackageReference Include="Elasticsearch.Net" Version="7.11.1" /> <PackageReference Include="Elasticsearch.Net" Version="7.11.1" />
<PackageReference Include="Equals.Fody" Version="4.0.1" PrivateAssets="all" /> <PackageReference Include="Equals.Fody" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Fody" Version="6.3.0"> <PackageReference Include="Fody" Version="6.4.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="GraphQL" Version="3.3.2" /> <PackageReference Include="GraphQL" Version="4.0.2" />
<PackageReference Include="GraphQL.DataLoader" Version="4.0.2" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
<PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="3.4.1"> <PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="3.4.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

2
backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj

@ -18,7 +18,7 @@
<ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" /> <ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityServer4" Version="4.1.1" /> <PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="MongoDB.Driver" Version="2.12.0" /> <PackageReference Include="MongoDB.Driver" Version="2.12.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />

4
backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj

@ -16,8 +16,8 @@
<ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" /> <ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityServer4" Version="4.1.1" /> <PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.3" /> <PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.4" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="SharpPwned.NET" Version="1.0.8" /> <PackageReference Include="SharpPwned.NET" Version="1.0.8" />

2
backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj

@ -10,7 +10,7 @@
<DebugSymbols>True</DebugSymbols> <DebugSymbols>True</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EventStore.Client" Version="20.10.0" /> <PackageReference Include="EventStore.Client" Version="21.2.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
</ItemGroup> </ItemGroup>

4
backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs

@ -28,7 +28,9 @@ namespace Squidex.Infrastructure.Json.Newtonsoft
public string Serialize<T>(T value, bool intented) public string Serialize<T>(T value, bool intented)
{ {
return JsonConvert.SerializeObject(value, intented ? Formatting.Indented : Formatting.None, settings); var formatting = intented ? Formatting.Indented : Formatting.None;
return JsonConvert.SerializeObject(value, formatting, settings);
} }
public void Serialize<T>(T value, Stream stream, bool leaveOpen = false) public void Serialize<T>(T value, Stream stream, bool leaveOpen = false)

5
backend/src/Squidex.Infrastructure/Json/Objects/JsonArray.cs

@ -25,6 +25,11 @@ namespace Squidex.Infrastructure.Json.Objects
{ {
} }
public JsonArray(int capacity)
: base(new List<IJsonValue>(capacity))
{
}
public JsonArray(JsonArray source) public JsonArray(JsonArray source)
: base(source.ToList()) : base(source.ToList())
{ {

4
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -10,10 +10,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="GeoJSON.Net" Version="1.2.19" /> <PackageReference Include="GeoJSON.Net" Version="1.2.19" />
<PackageReference Include="MailKit" Version="2.10.1" /> <PackageReference Include="MailKit" Version="2.11.1" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.3.1" /> <PackageReference Include="McMaster.NETCore.Plugins" Version="1.3.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="5.0.3" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="5.0.4" />
<PackageReference Include="Microsoft.OData.Core" Version="7.8.3" /> <PackageReference Include="Microsoft.OData.Core" Version="7.8.3" />
<PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="3.4.1"> <PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="3.4.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

3
backend/src/Squidex.Web/GraphQL/GraphQLMiddleware.cs

@ -7,7 +7,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using GraphQL.Server.Transports.AspNetCore; using GraphQL.Server.Transports.AspNetCore;
using GraphQL.Server.Transports.AspNetCore.Common;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Squidex.Web.GraphQL namespace Squidex.Web.GraphQL
@ -17,7 +16,7 @@ namespace Squidex.Web.GraphQL
private static readonly RequestDelegate Noop = _ => Task.CompletedTask; private static readonly RequestDelegate Noop = _ => Task.CompletedTask;
public GraphQLMiddleware(IGraphQLRequestDeserializer deserializer) public GraphQLMiddleware(IGraphQLRequestDeserializer deserializer)
: base(Noop, default, deserializer) : base(Noop, deserializer)
{ {
} }
} }

4
backend/src/Squidex.Web/Squidex.Web.csproj

@ -12,11 +12,11 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Fody" Version="6.3.0"> <PackageReference Include="Fody" Version="6.4.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="4.4.1" /> <PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="5.0.0" />
<PackageReference Include="Lazy.Fody" Version="1.9.0" PrivateAssets="all" /> <PackageReference Include="Lazy.Fody" Version="1.9.0" PrivateAssets="all" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />

10
backend/src/Squidex/Config/Domain/QueryServices.cs

@ -10,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Entities.Contents.GraphQL; using Squidex.Domain.Apps.Entities.Contents.GraphQL;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Web.Services; using Squidex.Web.Services;
namespace Squidex.Config.Domain namespace Squidex.Config.Domain
@ -29,6 +30,15 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<SharedTypes>() services.AddSingletonAs<SharedTypes>()
.AsSelf(); .AsSelf();
services.AddSingletonAs<InstantGraphType>()
.AsSelf();
services.AddSingletonAs<JsonGraphType>()
.AsSelf();
services.AddSingletonAs<JsonNoopGraphType>()
.AsSelf();
services.AddSingletonAs<CachingGraphQLService>() services.AddSingletonAs<CachingGraphQLService>()
.As<IGraphQLService>(); .As<IGraphQLService>();
} }

1
backend/src/Squidex/Config/Domain/SerializationServices.cs

@ -134,6 +134,7 @@ namespace Squidex.Config.Domain
builder.Services.AddSingleton<IDocumentWriter>(c => builder.Services.AddSingleton<IDocumentWriter>(c =>
{ {
var settings = ConfigureJson(new JsonSerializerSettings(), TypeNameHandling.None); var settings = ConfigureJson(new JsonSerializerSettings(), TypeNameHandling.None);
var serializer = new NewtonsoftJsonSerializer(settings); var serializer = new NewtonsoftJsonSerializer(settings);
return new DefaultDocumentWriter(serializer); return new DefaultDocumentWriter(serializer);

25
backend/src/Squidex/Squidex.csproj

@ -33,17 +33,18 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="5.0.1" /> <PackageReference Include="AspNet.Security.OAuth.GitHub" Version="5.0.2" />
<PackageReference Include="GraphQL.Server.Core" Version="4.4.1" /> <PackageReference Include="GraphQL.DataLoader" Version="4.0.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.NewtonsoftJson" Version="4.4.1" /> <PackageReference Include="GraphQL.Server.Core" Version="5.0.0" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="4.4.1" /> <PackageReference Include="GraphQL.Server.Transports.AspNetCore.NewtonsoftJson" Version="5.0.0" />
<PackageReference Include="IdentityServer4" Version="4.1.1" /> <PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="5.0.0" />
<PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" /> <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" /> <PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.4" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" /> <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Microsoft.Data.Edm" Version="5.8.4" /> <PackageReference Include="Microsoft.Data.Edm" Version="5.8.4" />
<PackageReference Include="Microsoft.OData.Core" Version="7.8.3" /> <PackageReference Include="Microsoft.OData.Core" Version="7.8.3" />
@ -55,7 +56,7 @@
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NJsonSchema" Version="10.3.11" /> <PackageReference Include="NJsonSchema" Version="10.3.11" />
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.0.0" /> <PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.0.0" />
<PackageReference Include="NSwag.AspNetCore" Version="13.10.7" /> <PackageReference Include="NSwag.AspNetCore" Version="13.10.8" />
<PackageReference Include="OpenCover" Version="4.7.922" PrivateAssets="all" /> <PackageReference Include="OpenCover" Version="4.7.922" PrivateAssets="all" />
<PackageReference Include="Orleans.Providers.MongoDB" Version="3.2.0" /> <PackageReference Include="Orleans.Providers.MongoDB" Version="3.2.0" />
<PackageReference Include="OrleansDashboard" Version="3.1.0" /> <PackageReference Include="OrleansDashboard" Version="3.1.0" />
@ -67,7 +68,7 @@
<PackageReference Include="Squidex.Assets.Mongo" Version="1.3.0" /> <PackageReference Include="Squidex.Assets.Mongo" Version="1.3.0" />
<PackageReference Include="Squidex.Assets.S3" Version="1.3.0" /> <PackageReference Include="Squidex.Assets.S3" Version="1.3.0" />
<PackageReference Include="Squidex.Caching.Orleans" Version="1.8.0" /> <PackageReference Include="Squidex.Caching.Orleans" Version="1.8.0" />
<PackageReference Include="Squidex.ClientLibrary" Version="6.16.0" /> <PackageReference Include="Squidex.ClientLibrary" Version="6.19.0" />
<PackageReference Include="Squidex.Hosting" Version="1.9.0" /> <PackageReference Include="Squidex.Hosting" Version="1.9.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Linq" Version="4.3.0" /> <PackageReference Include="System.Linq" Version="4.3.0" />

2
backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj

@ -12,7 +12,7 @@
<ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" /> <ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="6.2.1" /> <PackageReference Include="FakeItEasy" Version="7.0.0" />
<PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs

@ -76,7 +76,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 0))
.Throws(new AssetNotFoundException("fileName")); .Throws(new AssetNotFoundException("fileName"));
await sut.On(Envelope.Create(@event).SetEventStreamNumber(2));; await sut.On(Envelope.Create(@event).SetEventStreamNumber(2));
A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1)) A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, 1))
.MustHaveHappened(); .MustHaveHappened();

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLIntrospectionTests.cs

@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var result = await ExecuteAsync(new ExecutionOptions { Query = query, OperationName = "IntrospectionQuery" }); var result = await ExecuteAsync(new ExecutionOptions { Query = query, OperationName = "IntrospectionQuery" });
var json = serializer.Serialize(result.Data, true); var json = serializer.Serialize(result, true);
Assert.NotEmpty(json); Assert.NotEmpty(json);
} }

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

@ -68,7 +68,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"createMySchemaContent" "createMySchemaContent"
} }
} }
} },
data = (object?)null
}; };
AssertResult(expected, result); AssertResult(expected, result);
@ -209,7 +210,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"updateMySchemaContent" "updateMySchemaContent"
} }
} }
} },
data = (object?)null
}; };
AssertResult(expected, result); AssertResult(expected, result);
@ -316,7 +318,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"upsertMySchemaContent" "upsertMySchemaContent"
} }
} }
} },
data = (object?)null
}; };
AssertResult(expected, result); AssertResult(expected, result);
@ -425,7 +428,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"patchMySchemaContent" "patchMySchemaContent"
} }
} }
} },
data = (object?)null
}; };
AssertResult(expected, result); AssertResult(expected, result);
@ -532,7 +536,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"changeMySchemaContent" "changeMySchemaContent"
} }
} }
} },
data = (object?)null
}; };
AssertResult(expected, result); AssertResult(expected, result);
@ -677,7 +682,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"deleteMySchemaContent" "deleteMySchemaContent"
} }
} }
} },
data = (object?)null
}; };
AssertResult(expected, result); AssertResult(expected, result);

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs

@ -23,6 +23,7 @@ using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Domain.Apps.Entities.Contents.TestData; using Squidex.Domain.Apps.Entities.Contents.TestData;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
@ -198,6 +199,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.AddSingleton(contentQuery) .AddSingleton(contentQuery)
.AddSingleton(dataLoaderContext) .AddSingleton(dataLoaderContext)
.AddSingleton(dataLoaderListener) .AddSingleton(dataLoaderListener)
.AddSingleton<InstantGraphType>()
.AddSingleton<JsonGraphType>()
.AddSingleton<JsonNoopGraphType>()
.AddSingleton<SharedTypes>() .AddSingleton<SharedTypes>()
.AddSingleton<IUrlGenerator, .AddSingleton<IUrlGenerator,
FakeUrlGenerator>() FakeUrlGenerator>()

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj

@ -17,10 +17,10 @@
<ProjectReference Include="..\Squidex.Domain.Apps.Core.Tests\Squidex.Domain.Apps.Core.Tests.csproj" /> <ProjectReference Include="..\Squidex.Domain.Apps.Core.Tests\Squidex.Domain.Apps.Core.Tests.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="6.2.1" /> <PackageReference Include="FakeItEasy" Version="7.0.0" />
<PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="GraphQL" Version="3.3.2" /> <PackageReference Include="GraphQL" Version="4.0.2" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="3.3.2" /> <PackageReference Include="GraphQL.NewtonsoftJson" Version="4.0.2" />
<PackageReference Include="Lorem.Universal.Net" Version="4.0.80" /> <PackageReference Include="Lorem.Universal.Net" Version="4.0.80" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />

2
backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj

@ -13,7 +13,7 @@
<ProjectReference Include="..\..\src\Squidex.Shared\Squidex.Shared.csproj" /> <ProjectReference Include="..\..\src\Squidex.Shared\Squidex.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="6.2.1" /> <PackageReference Include="FakeItEasy" Version="7.0.0" />
<PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />

2
backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj

@ -13,7 +13,7 @@
<ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" /> <ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="6.2.1" /> <PackageReference Include="FakeItEasy" Version="7.0.0" />
<PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Google.Cloud.Storage.V1" Version="3.4.0" /> <PackageReference Include="Google.Cloud.Storage.V1" Version="3.4.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />

6
backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj

@ -11,9 +11,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="6.2.1" /> <PackageReference Include="FakeItEasy" Version="7.0.0" />
<PackageReference Include="IdentityServer4" Version="4.1.1" /> <PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" /> <PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />

Loading…
Cancel
Save