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>
<PackageReference Include="Algolia.Search" Version="6.9.1" />
<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="CoreTweet" Version="1.0.0.483" />
<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>
<ItemGroup>
<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>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

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

@ -13,6 +13,7 @@ using Fluid;
using Fluid.Ast;
using Fluid.Tags;
using GraphQL.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Templates;
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.Security.Claims;
using System.Threading.Tasks;
using GraphQL.Utilities;
using Jint.Native;
using Jint.Runtime;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Entities.Apps;
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 readonly Type None = typeof(NoopGraphType);
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 Guid = new GuidGraphType();
public static readonly IGraphType Date = new InstantGraphType();
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 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 DateTime = new InstantGraphType();
public static readonly IGraphType AssetType = new EnumerationGraphType<AssetType>();
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 NonNullGuid = new NonNullGraphType(Guid);
public static readonly IGraphType NonNullDate = new NonNullGraphType(Date);
public static readonly IGraphType NonNullFloat = new NonNullGraphType(Float);
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 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
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "path",
Description = "The path to the json value",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
}
};
@ -32,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{
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;
}
@ -45,12 +44,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{
public static readonly QueryArguments Arguments = new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.NonNullString)
{
Name = "id",
Description = "The id of the asset (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
DefaultValue = null
}
};
@ -66,33 +64,29 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets
{
public static readonly QueryArguments Arguments = new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "top",
Description = "Optional number of assets to take.",
DefaultValue = null,
ResolvedType = AllTypes.Int
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "skip",
Description = "Optional number of assets to skip.",
DefaultValue = 0,
ResolvedType = AllTypes.Int
DefaultValue = 0
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "filter",
Description = "Optional OData filter.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "orderby",
Description = "Optional OData order definition.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
}
};

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
{
Name = "created",
ResolvedType = AllTypes.NonNullDate,
ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.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
{
Name = "lastModified",
ResolvedType = AllTypes.NonNullDate,
ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.LastModified,
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",
Arguments = AssetActions.Metadata.Arguments,
ResolvedType = AllTypes.NoopJson,
ResolvedType = AllTypes.JsonNoop,
Resolver = AssetActions.Metadata.Resolver,
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.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using GraphQL;
using GraphQL.Resolvers;
@ -16,10 +14,8 @@ 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
@ -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, ContentResultGraphType> contentResultTypes = new Dictionary<SchemaInfo, ContentResultGraphType>(ReferenceEqualityComparer.Instance);
private readonly SharedTypes sharedTypes;
private readonly FieldVisitor fieldVisitor;
private readonly FieldInputVisitor fieldInputVisitor;
private readonly PartitionResolver partitionResolver;
public SharedTypes SharedTypes
{
get => sharedTypes;
}
public SharedTypes SharedTypes { get; }
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, SharedTypes sharedTypes)
{
this.sharedTypes = sharedTypes;
SharedTypes = sharedTypes;
partitionResolver = app.PartitionResolver();
@ -77,10 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
Query = new AppQueriesGraphType(this, schemaInfos)
};
newSchema.RegisterValueConverter(JsonConverter.Instance);
newSchema.RegisterValueConverter(InstantConverter.Instance);
newSchema.RegisterType(sharedTypes.ContentInterface);
newSchema.RegisterType(SharedTypes.ContentInterface);
if (schemas.Any())
{
@ -98,7 +81,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
}
newSchema.Initialize();
newSchema.CleanupMetadata();
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
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "path",
Description = "The path to the json value",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
}
};
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);
@ -51,12 +50,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly QueryArguments JsonPath = new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "path",
Description = "The path to the json value",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
}
};
@ -64,19 +62,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{
public static readonly QueryArguments Arguments = new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.NonNullString)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "version",
Description = "The optional version of the content to retrieve an older instance (not cached).",
DefaultValue = null,
ResolvedType = AllTypes.Int
DefaultValue = null
}
};
@ -101,40 +97,35 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{
public static readonly QueryArguments Arguments = new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "top",
Description = "Optional number of contents to take.",
DefaultValue = null,
ResolvedType = AllTypes.Int
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "skip",
Description = "Optional number of contents to skip.",
DefaultValue = 0,
ResolvedType = AllTypes.Int
DefaultValue = 0
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "filter",
Description = "Optional OData filter.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "orderby",
Description = "Optional OData order definition.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "search",
Description = "Optional OData full text search.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
}
};
@ -181,41 +172,37 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{
return new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(new NonNullGraphType(inputType))
{
Name = "data",
Description = "The data for the content.",
DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType)
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Boolean)
{
Name = "publish",
Description = "Set to true to autopublish content on create.",
DefaultValue = false,
ResolvedType = AllTypes.Boolean
DefaultValue = false
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "status",
Description = "The initial status.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "id",
Description = "The optional custom content id.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
}
};
}
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsCreate, c =>
{
var contentData = GetContentData(c);
var contentId = c.GetArgument<string?>("id");
var contentData = c.GetArgument<ContentData>("data");
var contentStatus = c.GetArgument<string?>("status");
var command = new CreateContent { Data = contentData };
@ -244,48 +231,43 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{
return new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.NonNullString)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(new NonNullGraphType(inputType))
{
Name = "data",
Description = "The data for the content.",
DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType)
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Boolean)
{
Name = "publish",
Description = "Set to true to autopublish content on create.",
DefaultValue = false,
ResolvedType = AllTypes.Boolean
DefaultValue = false
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "status",
Description = "The initial status.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
DefaultValue = EtagVersion.Any
}
};
}
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpsert, c =>
{
var contentData = GetContentData(c);
var contentId = c.GetArgument<string>("id");
var contentData = c.GetArgument<ContentData>("data");
var contentStatus = c.GetArgument<string?>("status");
var id = DomainId.Create(contentId);
@ -311,26 +293,23 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{
return new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "id",
Description = "The optional custom content id.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(new NonNullGraphType(inputType))
{
Name = "data",
Description = "The data for the content.",
DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType)
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
DefaultValue = EtagVersion.Any
}
};
}
@ -338,7 +317,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c =>
{
var contentId = c.GetArgument<DomainId>("id");
var contentData = GetContentData(c);
var contentData = c.GetArgument<ContentData>("data");
return new UpdateContent { ContentId = contentId, Data = contentData };
});
@ -350,26 +329,23 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{
return new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.String)
{
Name = "id",
Description = "The optional custom content id.",
DefaultValue = null,
ResolvedType = AllTypes.String
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(new NonNullGraphType(inputType))
{
Name = "data",
Description = "The data for the content.",
DefaultValue = null,
ResolvedType = new NonNullGraphType(inputType)
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
DefaultValue = EtagVersion.Any
}
};
}
@ -377,7 +353,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public static readonly IFieldResolver Resolver = ResolveAsync(Permissions.AppContentsUpdateOwn, c =>
{
var contentId = c.GetArgument<DomainId>("id");
var contentData = GetContentData(c);
var contentData = c.GetArgument<ContentData>("data");
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
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.NonNullString)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.NonNullString)
{
Name = "status",
Description = "The new status",
DefaultValue = null,
ResolvedType = AllTypes.NonNullString
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.DateTime)
{
Name = "dueTime",
Description = "When to change the status",
DefaultValue = null,
ResolvedType = AllTypes.Date
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
DefaultValue = EtagVersion.Any
}
};
@ -431,19 +403,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
{
public static readonly QueryArguments Arguments = new QueryArguments
{
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.NonNullString)
{
Name = "id",
Description = "The id of the content (usually GUID).",
DefaultValue = null,
ResolvedType = AllTypes.NonNullDomainId
DefaultValue = null
},
new QueryArgument(AllTypes.None)
new QueryArgument(AllTypes.Int)
{
Name = "expectedVersion",
Description = "The expected version",
DefaultValue = EtagVersion.Any,
ResolvedType = AllTypes.Int
DefaultValue = EtagVersion.Any
}
};
@ -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)
{
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
{
Name = "created",
ResolvedType = AllTypes.NonNullDate,
ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.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
{
Name = "lastModified",
ResolvedType = AllTypes.NonNullDate,
ResolvedType = AllTypes.NonNullDateTime,
Resolver = EntityResolvers.LastModified,
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.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using GraphQL.Types;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure.Json.Objects;
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.";
}
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)
{
return AllTypes.Date;
return AllTypes.DateTime;
}
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.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using GraphQL;
@ -19,8 +20,63 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
internal sealed class FieldVisitor : IFieldVisitor<(IGraphType?, IFieldResolver?, QueryArguments?), FieldInfo>
{
private static readonly IFieldResolver Noop = CreateValueResolver((value, fieldContext, contex) => value);
private static readonly IFieldResolver Json = CreateValueResolver(ContentActions.Json.Resolver);
private static readonly IFieldResolver JsonNoop = CreateValueResolver((value, fieldContext, contex) => value);
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) =>
{
@ -46,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
new NonNullGraphType(
new NestedGraphType(builder, args)));
return (schemaFieldType, Noop, null);
return (schemaFieldType, JsonNoop, null);
}
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)
{
return (AllTypes.Boolean, Noop, null);
return (AllTypes.Boolean, JsonBoolean, null);
}
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)
{
return (AllTypes.Json, Json, ContentActions.Json.Arguments);
return (AllTypes.Json, JsonPath, ContentActions.Json.Arguments);
}
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)
{
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)

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.
// ==========================================================================
using System.Collections.Generic;
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
{
@ -33,5 +36,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
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.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using GraphQL;
using GraphQL.Types;
using GraphQL.Utilities;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.ObjectPool;
using GraphQLSchema = GraphQL.Types.Schema;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{
@ -27,11 +23,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{
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)
{
@ -39,9 +35,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
}
sb.Append('$');
sb.Append(argument.Key);
sb.Append(key);
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)
{
if (field is MetadataProvider metadataProvider)
{
if (metadataProvider.Metadata is Dictionary<string, object> dict)
{
dict[key] = value;
}
else
{
metadataProvider.Metadata = new Dictionary<string, object>
{
[key] = value
};
}
}
field.Metadata[key] = value;
return field;
}
@ -122,77 +105,5 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
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
{
public static readonly IFieldResolver Id = Resolve<IEntity>(x => x.Id);
public static readonly IFieldResolver Created = Resolve<IEntity>(x => x.Created);
public static readonly IFieldResolver CreatedBy = Resolve<IEntityWithCreatedBy>(x => x.CreatedBy);
public static readonly IFieldResolver LastModified = Resolve<IEntity>(x => x.LastModified);
public static readonly IFieldResolver LastModifiedBy = Resolve<IEntityWithLastModifiedBy>(x => x.LastModifiedBy);
public static readonly IFieldResolver Id = Resolve<IEntity>(x => x.Id.ToString());
public static readonly IFieldResolver Created = Resolve<IEntity>(x => x.Created.ToDateTimeUtc());
public static readonly IFieldResolver CreatedBy = Resolve<IEntityWithCreatedBy>(x => x.CreatedBy.ToString());
public static readonly IFieldResolver LastModified = Resolve<IEntity>(x => x.LastModified.ToDateTimeUtc());
public static readonly IFieldResolver LastModifiedBy = Resolve<IEntityWithLastModifiedBy>(x => x.LastModifiedBy.ToString());
public static readonly IFieldResolver Version = Resolve<IEntityWithVersion>(x => x.Version);
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
{
internal sealed class InstantGraphType : DateTimeGraphType
public sealed class InstantGraphType : DateTimeGraphType
{
public override object Serialize(object value)
{
@ -27,8 +27,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
{
switch (value)
{
case InstantValueNode timeValue:
return timeValue.Value;
case StringValue stringValue:
return ParseValue(stringValue.Value);
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.
// ==========================================================================
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 JsonGraphType : ScalarGraphType
public sealed class JsonGraphType : JsonNoopGraphType
{
public JsonGraphType()
{
Name = "JsonScalar";
Description = "Unstructured Json object";
}
public override object Serialize(object value)
{
return value;
@ -26,7 +20,46 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
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)
@ -38,5 +71,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
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
{
internal sealed class NoopGraphType : ScalarGraphType
public class JsonNoopGraphType : ScalarGraphType
{
public NoopGraphType(string name)
public JsonNoopGraphType()
{
Name = name;
}
Name = "JsonScalar";
public NoopGraphType(IGraphType type)
: this(type.Name)
{
Description = type.Description;
Description = "Unstructured Json object";
}
public override object Serialize(object value)
public override object ParseLiteral(IValue value)
{
return value;
return value.Value;
}
public override object ParseValue(object value)
@ -33,9 +29,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives
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;
}
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
.WriteProperty("action", "resolveField")
.WriteProperty("status", "failed")
.WriteProperty("field", context.FieldName));
.WriteProperty("field", context.FieldDefinition.Name));
throw;
}
@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
executionContext.Log.LogWarning(ex, w => w
.WriteProperty("action", "resolveField")
.WriteProperty("status", "failed")
.WriteProperty("field", context.FieldName));
.WriteProperty("field", context.FieldDefinition.Name));
throw;
}

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

@ -14,7 +14,7 @@ using System.Threading.Tasks;
using Fluid;
using Fluid.Ast;
using Fluid.Tags;
using GraphQL.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Templates;
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="Elasticsearch.Net" Version="7.11.1" />
<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>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</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.Orleans.CodeGenerator.MSBuild" Version="3.4.1">
<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" />
</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="MongoDB.Driver" Version="2.12.0" />
<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" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IdentityServer4" Version="4.1.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.3" />
<PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.4" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<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>
</PropertyGroup>
<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="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
</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)
{
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)

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)
: base(source.ToList())
{

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

@ -10,10 +10,10 @@
</PropertyGroup>
<ItemGroup>
<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="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.Orleans.CodeGenerator.MSBuild" Version="3.4.1">
<PrivateAssets>all</PrivateAssets>

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

@ -7,7 +7,6 @@
using System.Threading.Tasks;
using GraphQL.Server.Transports.AspNetCore;
using GraphQL.Server.Transports.AspNetCore.Common;
using Microsoft.AspNetCore.Http;
namespace Squidex.Web.GraphQL
@ -17,7 +16,7 @@ namespace Squidex.Web.GraphQL
private static readonly RequestDelegate Noop = _ => Task.CompletedTask;
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" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Fody" Version="6.3.0">
<PackageReference Include="Fody" Version="6.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</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="RefactoringEssentials" Version="5.6.0" 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.Entities.Contents.GraphQL;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Web.Services;
namespace Squidex.Config.Domain
@ -29,6 +30,15 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<SharedTypes>()
.AsSelf();
services.AddSingletonAs<InstantGraphType>()
.AsSelf();
services.AddSingletonAs<JsonGraphType>()
.AsSelf();
services.AddSingletonAs<JsonNoopGraphType>()
.AsSelf();
services.AddSingletonAs<CachingGraphQLService>()
.As<IGraphQLService>();
}

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

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

25
backend/src/Squidex/Squidex.csproj

@ -33,17 +33,18 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="5.0.1" />
<PackageReference Include="GraphQL.Server.Core" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.NewtonsoftJson" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="4.4.1" />
<PackageReference Include="IdentityServer4" Version="4.1.1" />
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="5.0.2" />
<PackageReference Include="GraphQL.DataLoader" Version="4.0.2" />
<PackageReference Include="GraphQL.Server.Core" Version="5.0.0" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.NewtonsoftJson" Version="5.0.0" />
<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.AspNetIdentity" Version="4.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.3" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.4" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Microsoft.Data.Edm" Version="5.8.4" />
<PackageReference Include="Microsoft.OData.Core" Version="7.8.3" />
@ -55,7 +56,7 @@
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NJsonSchema" Version="10.3.11" />
<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="Orleans.Providers.MongoDB" Version="3.2.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.S3" Version="1.3.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="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<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" />
</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="Microsoft.Extensions.Caching.Memory" 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))
.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))
.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 json = serializer.Serialize(result.Data, true);
var json = serializer.Serialize(result, true);
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"
}
}
}
},
data = (object?)null
};
AssertResult(expected, result);
@ -209,7 +210,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"updateMySchemaContent"
}
}
}
},
data = (object?)null
};
AssertResult(expected, result);
@ -316,7 +318,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"upsertMySchemaContent"
}
}
}
},
data = (object?)null
};
AssertResult(expected, result);
@ -425,7 +428,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"patchMySchemaContent"
}
}
}
},
data = (object?)null
};
AssertResult(expected, result);
@ -532,7 +536,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"changeMySchemaContent"
}
}
}
},
data = (object?)null
};
AssertResult(expected, result);
@ -677,7 +682,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
"deleteMySchemaContent"
}
}
}
},
data = (object?)null
};
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.Assets;
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.Schemas;
using Squidex.Domain.Apps.Entities.TestHelpers;
@ -198,6 +199,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.AddSingleton(contentQuery)
.AddSingleton(dataLoaderContext)
.AddSingleton(dataLoaderListener)
.AddSingleton<InstantGraphType>()
.AddSingleton<JsonGraphType>()
.AddSingleton<JsonNoopGraphType>()
.AddSingleton<SharedTypes>()
.AddSingleton<IUrlGenerator,
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" />
</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="GraphQL" Version="3.3.2" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="3.3.2" />
<PackageReference Include="GraphQL" Version="4.0.2" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="4.0.2" />
<PackageReference Include="Lorem.Universal.Net" Version="4.0.80" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" 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" />
</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="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<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" />
</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="Google.Cloud.Storage.V1" Version="3.4.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>
<PackageReference Include="FakeItEasy" Version="6.2.1" />
<PackageReference Include="IdentityServer4" Version="4.1.1" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" />
<PackageReference Include="FakeItEasy" Version="7.0.0" />
<PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />

Loading…
Cancel
Save