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