mirror of https://github.com/Squidex/squidex.git
Browse Source
* Reduce memory usage for graphql. * Added missing files. * More allocation improvements. * Removed backup file.pull/630/head
committed by
GitHub
43 changed files with 873 additions and 791 deletions
@ -1,62 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using GraphQL; |
|||
using GraphQL.Instrumentation; |
|||
using GraphQL.Types; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Log; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL |
|||
{ |
|||
public static class Middlewares |
|||
{ |
|||
public static Func<ISchema, FieldMiddlewareDelegate, FieldMiddlewareDelegate> Logging(ISemanticLog log) |
|||
{ |
|||
Guard.NotNull(log, nameof(log)); |
|||
|
|||
return (_, next) => |
|||
{ |
|||
return async context => |
|||
{ |
|||
try |
|||
{ |
|||
return await next(context); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
log.LogWarning(ex, w => w |
|||
.WriteProperty("action", "resolveField") |
|||
.WriteProperty("status", "failed") |
|||
.WriteProperty("field", context.FieldName)); |
|||
|
|||
throw; |
|||
} |
|||
}; |
|||
}; |
|||
} |
|||
|
|||
public static Func<ISchema, FieldMiddlewareDelegate, FieldMiddlewareDelegate> Errors() |
|||
{ |
|||
return (_, next) => |
|||
{ |
|||
return async context => |
|||
{ |
|||
try |
|||
{ |
|||
return await next(context); |
|||
} |
|||
catch (DomainException ex) |
|||
{ |
|||
throw new ExecutionError(ex.Message); |
|||
} |
|||
}; |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
@ -1,112 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using GraphQL; |
|||
using GraphQL.Resolvers; |
|||
using GraphQL.Types; |
|||
using Squidex.Domain.Apps.Entities.Assets; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types |
|||
{ |
|||
public static class AssetActions |
|||
{ |
|||
public static class Metadata |
|||
{ |
|||
public static readonly QueryArguments Arguments = new QueryArguments |
|||
{ |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "path", |
|||
Description = "The path to the json value", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.String |
|||
} |
|||
}; |
|||
|
|||
public static readonly IFieldResolver Resolver = new FuncFieldResolver<IEnrichedAssetEntity, object?>(c => |
|||
{ |
|||
if (c.Arguments.TryGetValue("path", out var path)) |
|||
{ |
|||
c.Source.Metadata.TryGetByPath(path as string, out var result); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
return c.Source.Metadata; |
|||
}); |
|||
} |
|||
|
|||
public static class Find |
|||
{ |
|||
public static readonly QueryArguments Arguments = new QueryArguments |
|||
{ |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "id", |
|||
Description = "The id of the asset (usually GUID).", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.NonNullDomainId |
|||
} |
|||
}; |
|||
|
|||
public static readonly IFieldResolver Resolver = new FuncFieldResolver<object?>(c => |
|||
{ |
|||
var assetId = c.GetArgument<DomainId>("id"); |
|||
|
|||
return ((GraphQLExecutionContext)c.UserContext).FindAssetAsync(assetId); |
|||
}); |
|||
} |
|||
|
|||
public static class Query |
|||
{ |
|||
private static QueryArguments? resolver; |
|||
|
|||
public static QueryArguments Arguments(int pageSize) |
|||
{ |
|||
return resolver ??= new QueryArguments |
|||
{ |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "top", |
|||
Description = $"Optional number of assets to take (Default: {pageSize}).", |
|||
DefaultValue = pageSize, |
|||
ResolvedType = AllTypes.Int |
|||
}, |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "skip", |
|||
Description = "Optional number of assets to skip.", |
|||
DefaultValue = 0, |
|||
ResolvedType = AllTypes.Int |
|||
}, |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "filter", |
|||
Description = "Optional OData filter.", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.String |
|||
}, |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "orderby", |
|||
Description = "Optional OData order definition.", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.String |
|||
} |
|||
}; |
|||
} |
|||
|
|||
public static readonly IFieldResolver Resolver = new FuncFieldResolver<object?>(c => |
|||
{ |
|||
var query = c.BuildODataQuery(); |
|||
|
|||
return ((GraphQLExecutionContext)c.UserContext).QueryAssetsAsync(query); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,66 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using GraphQL; |
|||
using GraphQL.Resolvers; |
|||
using Squidex.Domain.Apps.Core.Assets; |
|||
using Squidex.Domain.Apps.Entities.Assets; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types |
|||
{ |
|||
public static class AssetResolvers |
|||
{ |
|||
public static readonly IFieldResolver Url = Resolve((asset, _, context) => |
|||
{ |
|||
return context.UrlGenerator.AssetContent(asset.AppId, asset.Id.ToString()); |
|||
}); |
|||
|
|||
public static readonly IFieldResolver SourceUrl = Resolve((asset, _, context) => |
|||
{ |
|||
return context.UrlGenerator.AssetSource(asset.AppId, asset.Id, asset.FileVersion); |
|||
}); |
|||
|
|||
public static readonly IFieldResolver ThumbnailUrl = Resolve((asset, _, context) => |
|||
{ |
|||
return context.UrlGenerator.AssetThumbnail(asset.AppId, asset.Id.ToString(), asset.Type); |
|||
}); |
|||
|
|||
public static readonly IFieldResolver FileHash = Resolve(x => x.FileHash); |
|||
public static readonly IFieldResolver FileName = Resolve(x => x.FileName); |
|||
public static readonly IFieldResolver FileSize = Resolve(x => x.FileSize); |
|||
public static readonly IFieldResolver FileType = Resolve(x => x.FileName.FileType()); |
|||
public static readonly IFieldResolver FileVersion = Resolve(x => x.FileVersion); |
|||
public static readonly IFieldResolver IsImage = Resolve(x => x.Type == AssetType.Image); |
|||
public static readonly IFieldResolver IsProtected = Resolve(x => x.IsProtected); |
|||
public static readonly IFieldResolver ListTotal = ResolveList(x => x.Total); |
|||
public static readonly IFieldResolver ListItems = ResolveList(x => x); |
|||
public static readonly IFieldResolver MetadataText = Resolve(x => x.MetadataText); |
|||
public static readonly IFieldResolver MimeType = Resolve(x => x.MimeType); |
|||
public static readonly IFieldResolver PixelHeight = Resolve(x => x.Metadata.GetPixelHeight()); |
|||
public static readonly IFieldResolver PixelWidth = Resolve(x => x.Metadata.GetPixelWidth()); |
|||
public static readonly IFieldResolver Slug = Resolve(x => x.Slug); |
|||
public static readonly IFieldResolver Tags = Resolve(x => x.TagNames); |
|||
public static readonly IFieldResolver Type = Resolve(x => x.Type); |
|||
|
|||
private static IFieldResolver Resolve<T>(Func<IEnrichedAssetEntity, IResolveFieldContext, GraphQLExecutionContext, T> action) |
|||
{ |
|||
return new FuncFieldResolver<IEnrichedAssetEntity, object?>(c => action(c.Source, c, (GraphQLExecutionContext)c.UserContext)); |
|||
} |
|||
|
|||
private static IFieldResolver Resolve<T>(Func<IEnrichedAssetEntity, T> action) |
|||
{ |
|||
return new FuncFieldResolver<IEnrichedAssetEntity, object?>(c => action(c.Source)); |
|||
} |
|||
|
|||
private static IFieldResolver ResolveList<T>(Func<IResultList<IEnrichedAssetEntity>, T> action) |
|||
{ |
|||
return new FuncFieldResolver<IResultList<IEnrichedAssetEntity>, object?>(c => action(c.Source)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,107 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using GraphQL; |
|||
using GraphQL.Resolvers; |
|||
using GraphQL.Types; |
|||
using Squidex.Domain.Apps.Entities.Assets; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets |
|||
{ |
|||
internal static class AssetActions |
|||
{ |
|||
public static class Metadata |
|||
{ |
|||
public static readonly QueryArguments Arguments = new QueryArguments |
|||
{ |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "path", |
|||
Description = "The path to the json value", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.String |
|||
} |
|||
}; |
|||
|
|||
public static readonly IFieldResolver Resolver = Resolvers.Sync<IEnrichedAssetEntity, object?>((source, fieldContext, _) => |
|||
{ |
|||
if (fieldContext.Arguments.TryGetValue("path", out var path)) |
|||
{ |
|||
source.Metadata.TryGetByPath(path as string, out var result); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
return source.Metadata; |
|||
}); |
|||
} |
|||
|
|||
public static class Find |
|||
{ |
|||
public static readonly QueryArguments Arguments = new QueryArguments |
|||
{ |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "id", |
|||
Description = "The id of the asset (usually GUID).", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.NonNullDomainId |
|||
} |
|||
}; |
|||
|
|||
public static readonly IFieldResolver Resolver = Resolvers.Async<object, object?>(async (_, fieldContext, context) => |
|||
{ |
|||
var assetId = fieldContext.GetArgument<DomainId>("id"); |
|||
|
|||
return await context.FindAssetAsync(assetId); |
|||
}); |
|||
} |
|||
|
|||
public static class Query |
|||
{ |
|||
public static readonly QueryArguments Arguments = new QueryArguments |
|||
{ |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "top", |
|||
Description = $"Optional number of assets to take.", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.Int |
|||
}, |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "skip", |
|||
Description = "Optional number of assets to skip.", |
|||
DefaultValue = 0, |
|||
ResolvedType = AllTypes.Int |
|||
}, |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "filter", |
|||
Description = "Optional OData filter.", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.String |
|||
}, |
|||
new QueryArgument(AllTypes.None) |
|||
{ |
|||
Name = "orderby", |
|||
Description = "Optional OData order definition.", |
|||
DefaultValue = null, |
|||
ResolvedType = AllTypes.String |
|||
} |
|||
}; |
|||
|
|||
public static readonly IFieldResolver Resolver = Resolvers.Async<object, object>(async (_, fieldContext, context) => |
|||
{ |
|||
var query = fieldContext.BuildODataQuery(); |
|||
|
|||
return await context.QueryAssetsAsync(query); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,85 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using GraphQL.Types; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types |
|||
{ |
|||
public sealed class ContentInterfaceGraphType : InterfaceGraphType<IEnrichedContentEntity> |
|||
{ |
|||
public ContentInterfaceGraphType() |
|||
{ |
|||
Name = "Content"; |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "id", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = EntityResolvers.Id, |
|||
Description = "The id of the content." |
|||
}); |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "version", |
|||
ResolvedType = AllTypes.NonNullInt, |
|||
Resolver = EntityResolvers.Version, |
|||
Description = "The version of the content." |
|||
}); |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "created", |
|||
ResolvedType = AllTypes.NonNullDate, |
|||
Resolver = EntityResolvers.Created, |
|||
Description = "The date and time when the content has been created." |
|||
}); |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "createdBy", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = EntityResolvers.CreatedBy, |
|||
Description = "The user that has created the content." |
|||
}); |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "lastModified", |
|||
ResolvedType = AllTypes.NonNullDate, |
|||
Resolver = EntityResolvers.LastModified, |
|||
Description = "The date and time when the content has been modified last." |
|||
}); |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "lastModifiedBy", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = EntityResolvers.LastModifiedBy, |
|||
Description = "The user that has updated the content last." |
|||
}); |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "status", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = ContentResolvers.Status, |
|||
Description = "The the status of the content." |
|||
}); |
|||
|
|||
AddField(new FieldType |
|||
{ |
|||
Name = "statusColor", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = ContentResolvers.StatusColor, |
|||
Description = "The color status of the content." |
|||
}); |
|||
|
|||
Description = "The structure of all content types."; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using GraphQL.Resolvers; |
|||
using GraphQL.Types; |
|||
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents |
|||
{ |
|||
public static class ContentFields |
|||
{ |
|||
public static readonly FieldType Id = new FieldType |
|||
{ |
|||
Name = "id", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = EntityResolvers.Id, |
|||
Description = "The id of the content." |
|||
}; |
|||
|
|||
public static readonly FieldType Version = new FieldType |
|||
{ |
|||
Name = "version", |
|||
ResolvedType = AllTypes.NonNullInt, |
|||
Resolver = EntityResolvers.Version, |
|||
Description = "The version of the content." |
|||
}; |
|||
|
|||
public static readonly FieldType Created = new FieldType |
|||
{ |
|||
Name = "created", |
|||
ResolvedType = AllTypes.NonNullDate, |
|||
Resolver = EntityResolvers.Created, |
|||
Description = "The date and time when the content has been created." |
|||
}; |
|||
|
|||
public static readonly FieldType CreatedBy = new FieldType |
|||
{ |
|||
Name = "createdBy", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = EntityResolvers.CreatedBy, |
|||
Description = "The user that has created the content." |
|||
}; |
|||
|
|||
public static readonly FieldType LastModified = new FieldType |
|||
{ |
|||
Name = "lastModified", |
|||
ResolvedType = AllTypes.NonNullDate, |
|||
Resolver = EntityResolvers.LastModified, |
|||
Description = "The date and time when the content has been modified last." |
|||
}; |
|||
|
|||
public static readonly FieldType LastModifiedBy = new FieldType |
|||
{ |
|||
Name = "lastModifiedBy", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = EntityResolvers.LastModifiedBy, |
|||
Description = "The user that has updated the content last." |
|||
}; |
|||
|
|||
public static readonly FieldType Status = new FieldType |
|||
{ |
|||
Name = "status", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = Resolve(x => x.Status.ToString().ToUpperInvariant()), |
|||
Description = "The the status of the content." |
|||
}; |
|||
|
|||
public static readonly FieldType StatusColor = new FieldType |
|||
{ |
|||
Name = "statusColor", |
|||
ResolvedType = AllTypes.NonNullString, |
|||
Resolver = Resolve(x => x.StatusColor), |
|||
Description = "The color status of the content." |
|||
}; |
|||
|
|||
private static IFieldResolver Resolve<T>(Func<IEnrichedContentEntity, T> resolver) |
|||
{ |
|||
return Resolvers.Sync(resolver); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using GraphQL.Types; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents |
|||
{ |
|||
internal sealed class ContentInterfaceGraphType : InterfaceGraphType<IEnrichedContentEntity> |
|||
{ |
|||
public static readonly IInterfaceGraphType Instance = new ContentInterfaceGraphType(); |
|||
|
|||
private ContentInterfaceGraphType() |
|||
{ |
|||
Name = "Content"; |
|||
|
|||
AddField(ContentFields.Id); |
|||
AddField(ContentFields.Version); |
|||
AddField(ContentFields.Created); |
|||
AddField(ContentFields.CreatedBy); |
|||
AddField(ContentFields.LastModified); |
|||
AddField(ContentFields.LastModifiedBy); |
|||
AddField(ContentFields.Status); |
|||
AddField(ContentFields.StatusColor); |
|||
|
|||
Description = "The structure of all content types."; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,90 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using GraphQL.Types; |
|||
using Squidex.Domain.Apps.Core; |
|||
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types |
|||
{ |
|||
public class GraphQLTypeFactory |
|||
{ |
|||
private readonly Lazy<IGraphType> asset; |
|||
private readonly Lazy<IGraphType> assetsList; |
|||
private readonly Lazy<IGraphType> assetsResult; |
|||
private readonly Lazy<FieldType> findAsset; |
|||
private readonly Lazy<FieldType> queryAssets; |
|||
private readonly Lazy<FieldType> queryAssetsWithTotal; |
|||
|
|||
public IGraphType Asset => asset.Value; |
|||
|
|||
public IGraphType AssetsList => assetsList.Value; |
|||
|
|||
public IGraphType AssetsResult => assetsResult.Value; |
|||
|
|||
public FieldType FindAsset => findAsset.Value; |
|||
|
|||
public FieldType QueryAssets => queryAssets.Value; |
|||
|
|||
public FieldType QueryAssetsWithTotal => queryAssetsWithTotal.Value; |
|||
|
|||
public GraphQLTypeFactory(IUrlGenerator urlGenerator) |
|||
{ |
|||
asset = new Lazy<IGraphType>(() => |
|||
{ |
|||
return new AssetGraphType(urlGenerator.CanGenerateAssetSourceUrl); |
|||
}); |
|||
|
|||
assetsList = new Lazy<IGraphType>(() => |
|||
{ |
|||
return new NonNullGraphType(new ListGraphType(new NonNullGraphType(Asset))); |
|||
}); |
|||
|
|||
assetsResult = new Lazy<IGraphType>(() => |
|||
{ |
|||
return new AssetsResultGraphType(AssetsList); |
|||
}); |
|||
|
|||
findAsset = new Lazy<FieldType>(() => |
|||
{ |
|||
return new FieldType |
|||
{ |
|||
Name = "findAsset", |
|||
Arguments = AssetActions.Find.Arguments, |
|||
ResolvedType = Asset, |
|||
Resolver = AssetActions.Find.Resolver, |
|||
Description = "Find an asset by id." |
|||
}; |
|||
}); |
|||
|
|||
queryAssets = new Lazy<FieldType>(() => |
|||
{ |
|||
return new FieldType |
|||
{ |
|||
Name = "queryAssets", |
|||
Arguments = AssetActions.Query.Arguments, |
|||
ResolvedType = AssetsList, |
|||
Resolver = AssetActions.Query.Resolver, |
|||
Description = "Get assets." |
|||
}; |
|||
}); |
|||
|
|||
queryAssetsWithTotal = new Lazy<FieldType>(() => |
|||
{ |
|||
return new FieldType |
|||
{ |
|||
Name = "queryAssetsWithTotal", |
|||
Arguments = AssetActions.Query.Arguments, |
|||
ResolvedType = AssetsResult, |
|||
Resolver = AssetActions.Query.Resolver, |
|||
Description = "Get assets and total count." |
|||
}; |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,124 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using GraphQL; |
|||
using GraphQL.Resolvers; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Validation; |
|||
using Squidex.Log; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types |
|||
{ |
|||
public static class Resolvers |
|||
{ |
|||
public static IFieldResolver Sync<TSource, T>(Func<TSource, T> resolver) |
|||
{ |
|||
return new SyncResolver<TSource, T>((source, context, execution) => resolver(source)); |
|||
} |
|||
|
|||
public static IFieldResolver Sync<TSource, T>(Func<TSource, IResolveFieldContext, GraphQLExecutionContext, T> resolver) |
|||
{ |
|||
return new SyncResolver<TSource, T>(resolver); |
|||
} |
|||
|
|||
public static IFieldResolver Async<TSource, T>(Func<TSource, Task<T>> resolver) |
|||
{ |
|||
return new AsyncResolver<TSource, T>((source, context, execution) => resolver(source)); |
|||
} |
|||
|
|||
public static IFieldResolver Async<TSource, T>(Func<TSource, IResolveFieldContext, GraphQLExecutionContext, Task<T>> resolver) |
|||
{ |
|||
return new AsyncResolver<TSource, T>(resolver); |
|||
} |
|||
|
|||
private sealed class SyncResolver<TSource, T> : IFieldResolver<T>, IFieldResolver |
|||
{ |
|||
private readonly Func<TSource, IResolveFieldContext, GraphQLExecutionContext, T> resolver; |
|||
|
|||
public SyncResolver(Func<TSource, IResolveFieldContext, GraphQLExecutionContext, T> resolver) |
|||
{ |
|||
this.resolver = resolver; |
|||
} |
|||
|
|||
public T Resolve(IResolveFieldContext context) |
|||
{ |
|||
var executionContext = (GraphQLExecutionContext)context.UserContext; |
|||
|
|||
try |
|||
{ |
|||
return resolver((TSource)context.Source, context, executionContext); |
|||
} |
|||
catch (ValidationException ex) |
|||
{ |
|||
throw new ExecutionError(ex.Message); |
|||
} |
|||
catch (DomainException ex) |
|||
{ |
|||
throw new ExecutionError(ex.Message); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
executionContext.Log.LogWarning(ex, w => w |
|||
.WriteProperty("action", "resolveField") |
|||
.WriteProperty("status", "failed") |
|||
.WriteProperty("field", context.FieldName)); |
|||
|
|||
throw; |
|||
} |
|||
} |
|||
|
|||
object IFieldResolver.Resolve(IResolveFieldContext context) |
|||
{ |
|||
return Resolve(context)!; |
|||
} |
|||
} |
|||
|
|||
private sealed class AsyncResolver<TSource, T> : IFieldResolver<Task<T>>, IFieldResolver |
|||
{ |
|||
private readonly Func<TSource, IResolveFieldContext, GraphQLExecutionContext, Task<T>> resolver; |
|||
|
|||
public AsyncResolver(Func<TSource, IResolveFieldContext, GraphQLExecutionContext, Task<T>> resolver) |
|||
{ |
|||
this.resolver = resolver; |
|||
} |
|||
|
|||
public async Task<T> Resolve(IResolveFieldContext context) |
|||
{ |
|||
var executionContext = (GraphQLExecutionContext)context.UserContext; |
|||
|
|||
try |
|||
{ |
|||
return await resolver((TSource)context.Source, context, executionContext); |
|||
} |
|||
catch (ValidationException ex) |
|||
{ |
|||
throw new ExecutionError(ex.Message); |
|||
} |
|||
catch (DomainException ex) |
|||
{ |
|||
throw new ExecutionError(ex.Message); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
executionContext.Log.LogWarning(ex, w => w |
|||
.WriteProperty("action", "resolveField") |
|||
.WriteProperty("status", "failed") |
|||
.WriteProperty("field", context.FieldName)); |
|||
|
|||
throw; |
|||
} |
|||
} |
|||
|
|||
object IFieldResolver.Resolve(IResolveFieldContext context) |
|||
{ |
|||
return Resolve(context)!; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue