// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using GraphQL.DataLoader; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Contents.Queries; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Json.Objects; using Squidex.Log; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { public sealed class GraphQLExecutionContext : QueryExecutionContext { private static readonly List EmptyAssets = new List(); private static readonly List EmptyContents = new List(); private readonly IDataLoaderContextAccessor dataLoaders; public IUrlGenerator UrlGenerator { get; } public ICommandBus CommandBus { get; } public ISemanticLog Log { get; } public override Context Context { get; } public GraphQLExecutionContext(IAssetQueryService assetQuery, IContentQueryService contentQuery, Context context, IDataLoaderContextAccessor dataLoaders, ICommandBus commandBus, IUrlGenerator urlGenerator, ISemanticLog log) : base(assetQuery, contentQuery) { this.dataLoaders = dataLoaders; CommandBus = commandBus; UrlGenerator = urlGenerator; Context = context.Clone(b => b .WithoutCleanup() .WithoutContentEnrichment()); Log = log; } public async Task FindAssetAsync(DomainId id) { var dataLoader = GetAssetsLoader(); return await dataLoader.LoadAsync(id).GetResultAsync(); } public async Task FindContentAsync(DomainId id) { var dataLoader = GetContentsLoader(); return await dataLoader.LoadAsync(id).GetResultAsync(); } public Task> GetReferencedAssetsAsync(IJsonValue value) { var ids = ParseIds(value); if (ids == null) { return Task.FromResult>(EmptyAssets); } var dataLoader = GetAssetsLoader(); return LoadManyAsync(dataLoader, ids); } public Task> GetReferencedContentsAsync(IJsonValue value) { var ids = ParseIds(value); if (ids == null) { return Task.FromResult>(EmptyContents); } var dataLoader = GetContentsLoader(); return LoadManyAsync(dataLoader, ids); } private IDataLoader GetAssetsLoader() { return dataLoaders.Context.GetOrAddBatchLoader(nameof(GetAssetsLoader), async batch => { var result = await GetReferencedAssetsAsync(new List(batch)); return result.ToDictionary(x => x.Id); }); } private IDataLoader GetContentsLoader() { return dataLoaders.Context.GetOrAddBatchLoader(nameof(GetContentsLoader), async batch => { var result = await GetReferencedContentsAsync(new List(batch)); return result.ToDictionary(x => x.Id); }); } private static async Task> LoadManyAsync(IDataLoader dataLoader, ICollection keys) where T : class { var contents = await Task.WhenAll(keys.Select(x => dataLoader.LoadAsync(x).GetResultAsync())); return contents.NotNull().ToList(); } private static ICollection? ParseIds(IJsonValue value) { try { var result = new List(); if (value is JsonArray array) { foreach (var id in array) { result.Add(DomainId.Create(id.ToString())); } } return result; } catch { return null; } } } }