Browse Source

CancellationToken

pull/711/head
Sebastian Stehle 5 years ago
parent
commit
21bcad84b2
  1. 3
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs
  2. 5
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs
  3. 108
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs
  4. 18
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs
  5. 5
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs
  6. 50
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs
  7. 5
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs
  8. 58
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs
  9. 53
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  10. 3
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs
  11. 6
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/Extensions.cs
  12. 2
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/OperationBase.cs
  13. 2
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs
  14. 6
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryById.cs
  15. 11
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryByIds.cs
  16. 30
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryByQuery.cs
  17. 8
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryReferences.cs
  18. 9
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryReferrers.cs
  19. 7
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryScheduled.cs
  20. 3
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndex.cs
  21. 3
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs
  22. 19
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs
  23. 8
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleStatisticsCollection.cs
  24. 6
      backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs
  25. 6
      backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppImageStore.cs
  26. 3
      backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs
  27. 6
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsSearchSource.cs
  28. 15
      backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs
  29. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs
  30. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/GuardAsset.cs
  31. 7
      backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEnricher.cs
  32. 17
      backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs
  33. 16
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs
  34. 66
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs
  35. 75
      backend/src/Squidex.Domain.Apps.Entities/Assets/RebuildFiles.cs
  36. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/RecursiveDeleter.cs
  37. 7
      backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs
  38. 16
      backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs
  39. 8
      backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs
  40. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs
  41. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs
  42. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs
  43. 9
      backend/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs
  44. 20
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs
  45. 37
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs
  46. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricher.cs
  47. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs
  48. 25
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs
  49. 9
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs
  50. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithSchema.cs
  51. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithWorkflows.cs
  52. 11
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs
  53. 16
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs
  54. 11
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs
  55. 18
      backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs
  56. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs
  57. 6
      backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs
  58. 4
      backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs
  59. 3
      backend/src/Squidex.Domain.Apps.Entities/Search/ISearchManager.cs
  60. 3
      backend/src/Squidex.Domain.Apps.Entities/Search/ISearchSource.cs
  61. 11
      backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs
  62. 5
      backend/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs
  63. 5
      backend/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs
  64. 3
      backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore.cs
  65. 3
      backend/src/Squidex.Infrastructure.MongoDb/Log/MongoRequestLogRepository.cs
  66. 5
      backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs
  67. 5
      backend/src/Squidex.Infrastructure.MongoDb/UsageTracking/MongoUsageRepository.cs
  68. 10
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs
  69. 4
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs
  70. 6
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs
  71. 16
      backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs
  72. 2
      backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs
  73. 50
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs
  74. 5
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs
  75. 5
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs
  76. 9
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs
  77. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs
  78. 10
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs
  79. 9
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs
  80. 3
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs
  81. 13
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetFolderTests.cs
  82. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetTests.cs
  83. 12
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs
  84. 45
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs
  85. 7
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs
  86. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs
  87. 11
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs
  88. 7
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs
  89. 79
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs
  90. 7
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs
  91. 43
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs
  92. 30
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs
  93. 31
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs
  94. 15
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs
  95. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs
  96. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs
  97. 18
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs
  98. 25
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs
  99. 25
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs
  100. 15
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs

3
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs

@ -40,7 +40,8 @@ namespace Squidex.Domain.Apps.Core.Scripting
completion?.Invoke(exception); completion?.Invoke(exception);
} }
public ExecutionContext ExtendAsync(IEnumerable<IJintExtension> extensions, Func<Exception, bool> completion, CancellationToken ct) public ExecutionContext ExtendAsync(IEnumerable<IJintExtension> extensions, Func<Exception, bool> completion,
CancellationToken ct)
{ {
CancellationToken = ct; CancellationToken = ct;

5
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
@ -13,9 +14,9 @@ namespace Squidex.Domain.Apps.Core.Scripting
{ {
public interface IScriptEngine public interface IScriptEngine
{ {
Task<IJsonValue> ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default); Task<IJsonValue> ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default, CancellationToken ct = default);
Task<ContentData> TransformAsync(ScriptVars vars, string script, ScriptOptions options = default); Task<ContentData> TransformAsync(ScriptVars vars, string script, ScriptOptions options = default, CancellationToken ct = default);
IJsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default); IJsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default);

108
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -68,90 +68,98 @@ namespace Squidex.Domain.Apps.Core.Scripting
this.extensions = extensions?.ToArray() ?? Array.Empty<IJintExtension>(); this.extensions = extensions?.ToArray() ?? Array.Empty<IJintExtension>();
} }
public async Task<IJsonValue> ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default) public async Task<IJsonValue> ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default,
CancellationToken ct = default)
{ {
Guard.NotNull(vars, nameof(vars)); Guard.NotNull(vars, nameof(vars));
Guard.NotNullOrEmpty(script, nameof(script)); Guard.NotNullOrEmpty(script, nameof(script));
using (var cts = new CancellationTokenSource(ActualTimeoutExecution)) using (var cts = new CancellationTokenSource(ActualTimeoutExecution))
{ {
var tcs = new TaskCompletionSource<IJsonValue>(); using (var combined = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ct))
using (cts.Token.Register(() => tcs.TrySetCanceled()))
{ {
var context = var tcs = new TaskCompletionSource<IJsonValue>();
CreateEngine(options)
.Extend(vars, options)
.Extend(extensions)
.ExtendAsync(extensions, tcs.TrySetException, cts.Token);
context.Engine.SetValue("complete", new Action<JsValue?>(value => using (combined.Token.Register(() => tcs.TrySetCanceled()))
{ {
tcs.TrySetResult(JsonMapper.Map(value)); var context =
})); CreateEngine(options)
.Extend(vars, options)
.Extend(extensions)
.ExtendAsync(extensions, tcs.TrySetException, combined.Token);
Execute(context.Engine, script); context.Engine.SetValue("complete", new Action<JsValue?>(value =>
{
tcs.TrySetResult(JsonMapper.Map(value));
}));
if (!context.IsAsync) Execute(context.Engine, script);
{
tcs.TrySetResult(JsonMapper.Map(context.Engine.GetCompletionValue()));
}
return await tcs.Task; if (!context.IsAsync)
{
tcs.TrySetResult(JsonMapper.Map(context.Engine.GetCompletionValue()));
}
return await tcs.Task;
}
} }
} }
} }
public async Task<ContentData> TransformAsync(ScriptVars vars, string script, ScriptOptions options = default) public async Task<ContentData> TransformAsync(ScriptVars vars, string script, ScriptOptions options = default,
CancellationToken ct = default)
{ {
Guard.NotNull(vars, nameof(vars)); Guard.NotNull(vars, nameof(vars));
Guard.NotNullOrEmpty(script, nameof(script)); Guard.NotNullOrEmpty(script, nameof(script));
using (var cts = new CancellationTokenSource(ActualTimeoutExecution)) using (var cts = new CancellationTokenSource(ActualTimeoutExecution))
{ {
var tcs = new TaskCompletionSource<ContentData>(); using (var combined = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ct))
using (cts.Token.Register(() => tcs.TrySetCanceled()))
{ {
var context = var tcs = new TaskCompletionSource<ContentData>();
CreateEngine(options)
.Extend(vars, options)
.Extend(extensions)
.ExtendAsync(extensions, tcs.TrySetException, cts.Token);
context.Engine.SetValue("complete", new Action<JsValue?>(_ => using (combined.Token.Register(() => tcs.TrySetCanceled()))
{ {
tcs.TrySetResult(vars.Data!); var context =
})); CreateEngine(options)
.Extend(vars, options)
.Extend(extensions)
.ExtendAsync(extensions, tcs.TrySetException, combined.Token);
context.Engine.SetValue("replace", new Action(() => context.Engine.SetValue("complete", new Action<JsValue?>(_ =>
{ {
var dataInstance = context.Engine.GetValue("ctx").AsObject().Get("data"); tcs.TrySetResult(vars.Data!);
}));
if (dataInstance != null && dataInstance.IsObject() && dataInstance.AsObject() is ContentDataObject data) context.Engine.SetValue("replace", new Action(() =>
{ {
if (!tcs.Task.IsCompleted) var dataInstance = context.Engine.GetValue("ctx").AsObject().Get("data");
if (dataInstance != null && dataInstance.IsObject() && dataInstance.AsObject() is ContentDataObject data)
{ {
if (data.TryUpdate(out var modified)) if (!tcs.Task.IsCompleted)
{ {
tcs.TrySetResult(modified); if (data.TryUpdate(out var modified))
} {
else tcs.TrySetResult(modified);
{ }
tcs.TrySetResult(vars.Data!); else
{
tcs.TrySetResult(vars.Data!);
}
} }
} }
} }));
}));
Execute(context.Engine, script); Execute(context.Engine, script);
if (!context.IsAsync) if (!context.IsAsync)
{ {
tcs.TrySetResult(vars.Data!); tcs.TrySetResult(vars.Data!);
} }
return await tcs.Task; return await tcs.Task;
}
} }
} }
} }

18
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs

@ -30,7 +30,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
return "States_AssetFolders2"; return "States_AssetFolders2";
} }
protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetFolderEntity> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetFolderEntity> collection,
CancellationToken ct = default)
{ {
return collection.Indexes.CreateManyAsync(new[] return collection.Indexes.CreateManyAsync(new[]
{ {
@ -42,7 +43,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
}, ct); }, ct);
} }
public async Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId) public async Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetFolderRepository>("QueryAsyncByQuery")) using (Profiler.TraceMethod<MongoAssetFolderRepository>("QueryAsyncByQuery"))
{ {
@ -50,13 +52,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetFolderEntities = var assetFolderEntities =
await Collection.Find(filter).SortBy(x => x.FolderName) await Collection.Find(filter).SortBy(x => x.FolderName)
.ToListAsync(); .ToListAsync(ct = default);
return ResultList.Create<IAssetFolderEntity>(assetFolderEntities.Count, assetFolderEntities); return ResultList.Create<IAssetFolderEntity>(assetFolderEntities.Count, assetFolderEntities);
} }
} }
public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId) public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Profiler.TraceMethod<MongoAssetRepository>())
{ {
@ -64,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetFolderEntities = var assetFolderEntities =
await Collection.Find(filter).Only(x => x.Id) await Collection.Find(filter).Only(x => x.Id)
.ToListAsync(); .ToListAsync(ct = default);
var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id)); var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id));
@ -72,7 +75,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
} }
public async Task<IAssetFolderEntity?> FindAssetFolderAsync(DomainId appId, DomainId id) public async Task<IAssetFolderEntity?> FindAssetFolderAsync(DomainId appId, DomainId id,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetFolderRepository>()) using (Profiler.TraceMethod<MongoAssetFolderRepository>())
{ {
@ -80,7 +84,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetFolderEntity = var assetFolderEntity =
await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted) await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync(ct = default);
return assetFolderEntity; return assetFolderEntity;
} }

5
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs

@ -65,11 +65,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
} }
async Task ISnapshotStore<AssetFolderDomainObject.State>.ReadAllAsync(Func<AssetFolderDomainObject.State, long, Task> callback, CancellationToken ct) async Task ISnapshotStore<AssetFolderDomainObject.State>.ReadAllAsync(Func<AssetFolderDomainObject.State, long, Task> callback,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoAssetFolderRepository>()) using (Profiler.TraceMethod<MongoAssetFolderRepository>())
{ {
await Collection.Find(new BsonDocument(), options: Batching.Options).ForEachPipedAsync(x => callback(Map(x), x.Version), ct); await Collection.Find(new BsonDocument(), Batching.Options).ForEachPipedAsync(x => callback(Map(x), x.Version), ct);
} }
} }

50
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -39,7 +39,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
return "States_Assets2"; return "States_Assets2";
} }
protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetEntity> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetEntity> collection,
CancellationToken ct = default)
{ {
return collection.Indexes.CreateManyAsync(new[] return collection.Indexes.CreateManyAsync(new[]
{ {
@ -74,9 +75,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
var find = Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted); var find = Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted);
using (var cursor = await find.ToCursorAsync(ct)) using (var cursor = await find.ToCursorAsync(ct = default))
{ {
while (await cursor.MoveNextAsync(ct)) while (await cursor.MoveNextAsync(ct = default))
{ {
foreach (var entity in cursor.Current) foreach (var entity in cursor.Current)
{ {
@ -86,7 +87,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
} }
public async Task<IResultList<IAssetEntity>> QueryAsync(DomainId appId, DomainId? parentId, Q q) public async Task<IResultList<IAssetEntity>> QueryAsync(DomainId appId, DomainId? parentId, Q q,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByQuery")) using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByQuery"))
{ {
@ -100,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
await Collection.Find(filter).SortByDescending(x => x.LastModified) await Collection.Find(filter).SortByDescending(x => x.LastModified)
.QueryLimit(q.Query) .QueryLimit(q.Query)
.QuerySkip(q.Query) .QuerySkip(q.Query)
.ToListAsync(); .ToListAsync(ct = default);
long assetTotal = assetEntities.Count; long assetTotal = assetEntities.Count;
if (q.NoTotal) if (q.NoTotal)
@ -109,7 +111,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0) else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0)
{ {
assetTotal = await Collection.Find(filter).CountDocumentsAsync(); assetTotal = await Collection.Find(filter).CountDocumentsAsync(ct = default);
} }
return ResultList.Create(assetTotal, assetEntities.OfType<IAssetEntity>()); return ResultList.Create(assetTotal, assetEntities.OfType<IAssetEntity>());
@ -125,7 +127,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
.QueryLimit(query) .QueryLimit(query)
.QuerySkip(query) .QuerySkip(query)
.QuerySort(query) .QuerySort(query)
.ToListAsync(); .ToListAsync(ct = default);
long assetTotal = assetEntities.Count; long assetTotal = assetEntities.Count;
if (q.NoTotal) if (q.NoTotal)
@ -134,7 +136,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0) else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0)
{ {
assetTotal = await Collection.Find(filter).CountDocumentsAsync(); assetTotal = await Collection.Find(filter).CountDocumentsAsync(ct = default);
} }
return ResultList.Create<IAssetEntity>(assetTotal, assetEntities); return ResultList.Create<IAssetEntity>(assetTotal, assetEntities);
@ -147,13 +149,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
} }
public async Task<IReadOnlyList<DomainId>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids) public async Task<IReadOnlyList<DomainId>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByIds")) using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByIds"))
{ {
var assetEntities = var assetEntities =
await Collection.Find(BuildFilter(appId, ids)).Only(x => x.Id) await Collection.Find(BuildFilter(appId, ids)).Only(x => x.Id)
.ToListAsync(); .ToListAsync(ct = default);
var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id)); var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id));
@ -161,13 +164,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
} }
public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId) public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Profiler.TraceMethod<MongoAssetRepository>())
{ {
var assetEntities = var assetEntities =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id) await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id)
.ToListAsync(); .ToListAsync(ct = default);
var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id)); var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id));
@ -175,31 +179,34 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
} }
public async Task<IAssetEntity?> FindAssetByHashAsync(DomainId appId, string hash, string fileName, long fileSize) public async Task<IAssetEntity?> FindAssetByHashAsync(DomainId appId, string hash, string fileName, long fileSize,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Profiler.TraceMethod<MongoAssetRepository>())
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.FileHash == hash && x.FileName == fileName && x.FileSize == fileSize) await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.FileHash == hash && x.FileName == fileName && x.FileSize == fileSize)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync(ct = default);
return assetEntity; return assetEntity;
} }
} }
public async Task<IAssetEntity?> FindAssetBySlugAsync(DomainId appId, string slug) public async Task<IAssetEntity?> FindAssetBySlugAsync(DomainId appId, string slug,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Profiler.TraceMethod<MongoAssetRepository>())
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.Slug == slug) await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.Slug == slug)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync(ct = default);
return assetEntity; return assetEntity;
} }
} }
public async Task<IAssetEntity?> FindAssetAsync(DomainId appId, DomainId id) public async Task<IAssetEntity?> FindAssetAsync(DomainId appId, DomainId id,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Profiler.TraceMethod<MongoAssetRepository>())
{ {
@ -207,19 +214,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetEntity = var assetEntity =
await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted) await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync(ct = default);
return assetEntity; return assetEntity;
} }
} }
public async Task<IAssetEntity?> FindAssetAsync(DomainId id) public async Task<IAssetEntity?> FindAssetAsync(DomainId id,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Profiler.TraceMethod<MongoAssetRepository>())
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.Id == id && !x.IsDeleted) await Collection.Find(x => x.Id == id && !x.IsDeleted)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync(ct = default);
return assetEntity; return assetEntity;
} }

5
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs

@ -65,11 +65,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
} }
async Task ISnapshotStore<AssetDomainObject.State>.ReadAllAsync(Func<AssetDomainObject.State, long, Task> callback, CancellationToken ct) async Task ISnapshotStore<AssetDomainObject.State>.ReadAllAsync(Func<AssetDomainObject.State, long, Task> callback,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Profiler.TraceMethod<MongoAssetRepository>())
{ {
await Collection.Find(new BsonDocument(), options: Batching.Options).ForEachPipedAsync(x => callback(Map(x), x.Version), ct); await Collection.Find(new BsonDocument(), Batching.Options).ForEachPipedAsync(x => callback(Map(x), x.Version), ct);
} }
} }

58
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs

@ -61,7 +61,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
return name; return name;
} }
protected override async Task SetupCollectionAsync(IMongoCollection<MongoContentEntity> collection, CancellationToken ct = default) protected override async Task SetupCollectionAsync(IMongoCollection<MongoContentEntity> collection,
CancellationToken ct)
{ {
if (useWildcardIndex) if (useWildcardIndex)
{ {
@ -82,89 +83,103 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
await queryScheduled.PrepareAsync(collection, skipIndex, ct); await queryScheduled.PrepareAsync(collection, skipIndex, ct);
} }
public IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds, CancellationToken ct) public Task ResetScheduledAsync(DomainId documentId,
CancellationToken ct)
{
return Collection.UpdateOneAsync(x => x.DocumentId == documentId, Update.Unset(x => x.ScheduleJob).Unset(x => x.ScheduledAt), cancellationToken: ct);
}
public IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds,
CancellationToken ct)
{ {
return queryAsStream.StreamAll(appId, schemaIds, ct); return queryAsStream.StreamAll(appId, schemaIds, ct);
} }
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q) public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Profiler.TraceMethod<MongoContentRepository>())
{ {
if (q.Ids != null && q.Ids.Count > 0) if (q.Ids != null && q.Ids.Count > 0)
{ {
return await queryByIds.QueryAsync(app.Id, schemas, q); return await queryByIds.QueryAsync(app.Id, schemas, q, ct);
} }
if (q.Referencing != default) if (q.Referencing != default)
{ {
return await queryReferences.QueryAsync(app.Id, schemas, q); return await queryReferences.QueryAsync(app.Id, schemas, q, ct);
} }
if (q.Reference != default) if (q.Reference != default)
{ {
return await queryByQuery.QueryAsync(app, schemas, q); return await queryByQuery.QueryAsync(app, schemas, q, ct);
} }
return ResultList.CreateFrom<IContentEntity>(0); return ResultList.CreateFrom<IContentEntity>(0);
} }
} }
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q) public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Profiler.TraceMethod<MongoContentRepository>())
{ {
if (q.Ids != null && q.Ids.Count > 0) if (q.Ids != null && q.Ids.Count > 0)
{ {
return await queryByIds.QueryAsync(app.Id, new List<ISchemaEntity> { schema }, q); return await queryByIds.QueryAsync(app.Id, new List<ISchemaEntity> { schema }, q, ct);
} }
if (q.Referencing == default) if (q.Referencing == default)
{ {
return await queryByQuery.QueryAsync(app, schema, q); return await queryByQuery.QueryAsync(app, schema, q, ct);
} }
return ResultList.CreateFrom<IContentEntity>(0); return ResultList.CreateFrom<IContentEntity>(0);
} }
} }
public async Task<IContentEntity?> FindContentAsync(ISchemaEntity schema, DomainId id) public async Task<IContentEntity?> FindContentAsync(ISchemaEntity schema, DomainId id,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Profiler.TraceMethod<MongoContentRepository>())
{ {
return await queryBdId.QueryAsync(schema, id); return await queryBdId.QueryAsync(schema, id, ct);
} }
} }
public async Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback) public async Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Profiler.TraceMethod<MongoContentRepository>())
{ {
await queryScheduled.QueryAsync(now, callback); await queryScheduled.QueryAsync(now, callback, ct);
} }
} }
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids) public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Profiler.TraceMethod<MongoContentRepository>())
{ {
return await queryByIds.QueryIdsAsync(appId, ids); return await queryByIds.QueryIdsAsync(appId, ids, ct);
} }
} }
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode) public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Profiler.TraceMethod<MongoContentRepository>())
{ {
return await queryByQuery.QueryIdsAsync(appId, schemaId, filterNode); return await queryByQuery.QueryIdsAsync(appId, schemaId, filterNode, ct);
} }
} }
public async Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId) public async Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Profiler.TraceMethod<MongoContentRepository>())
{ {
return await queryReferrers.CheckExistsAsync(appId, contentId); return await queryReferrers.CheckExistsAsync(appId, contentId, ct);
} }
} }
@ -175,11 +190,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
return result?["vs"].AsInt64 ?? EtagVersion.Empty; return result?["vs"].AsInt64 ?? EtagVersion.Empty;
} }
public Task ResetScheduledAsync(DomainId documentId)
{
return Collection.UpdateOneAsync(x => x.DocumentId == documentId, Update.Unset(x => x.ScheduleJob).Unset(x => x.ScheduledAt));
}
public Task UpsertVersionedAsync(DomainId documentId, long oldVersion, MongoContentEntity entity) public Task UpsertVersionedAsync(DomainId documentId, long oldVersion, MongoContentEntity entity)
{ {
return Collection.UpsertVersionedAsync(documentId, oldVersion, entity.Version, entity); return Collection.UpsertVersionedAsync(documentId, oldVersion, entity.Version, entity);

53
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -55,84 +55,93 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
await collectionPublished.InitializeAsync(ct); await collectionPublished.InitializeAsync(ct);
} }
public IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds, CancellationToken ct) public IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds,
CancellationToken ct = default)
{ {
return collectionAll.StreamAll(appId, schemaIds, ct); return collectionAll.StreamAll(appId, schemaIds, ct);
} }
public Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q, SearchScope scope) public Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q, SearchScope scope,
CancellationToken ct = default)
{ {
if (scope == SearchScope.All) if (scope == SearchScope.All)
{ {
return collectionAll.QueryAsync(app, schemas, q); return collectionAll.QueryAsync(app, schemas, q, ct);
} }
else else
{ {
return collectionPublished.QueryAsync(app, schemas, q); return collectionPublished.QueryAsync(app, schemas, q, ct);
} }
} }
public Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q, SearchScope scope) public Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q, SearchScope scope,
CancellationToken ct = default)
{ {
if (scope == SearchScope.All) if (scope == SearchScope.All)
{ {
return collectionAll.QueryAsync(app, schema, q); return collectionAll.QueryAsync(app, schema, q, ct);
} }
else else
{ {
return collectionPublished.QueryAsync(app, schema, q); return collectionPublished.QueryAsync(app, schema, q, ct);
} }
} }
public Task<IContentEntity?> FindContentAsync(IAppEntity app, ISchemaEntity schema, DomainId id, SearchScope scope) public Task<IContentEntity?> FindContentAsync(IAppEntity app, ISchemaEntity schema, DomainId id, SearchScope scope,
CancellationToken ct = default)
{ {
if (scope == SearchScope.All) if (scope == SearchScope.All)
{ {
return collectionAll.FindContentAsync(schema, id); return collectionAll.FindContentAsync(schema, id, ct);
} }
else else
{ {
return collectionPublished.FindContentAsync(schema, id); return collectionPublished.FindContentAsync(schema, id, ct);
} }
} }
public Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids, SearchScope scope) public Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids, SearchScope scope,
CancellationToken ct = default)
{ {
if (scope == SearchScope.All) if (scope == SearchScope.All)
{ {
return collectionAll.QueryIdsAsync(appId, ids); return collectionAll.QueryIdsAsync(appId, ids, ct);
} }
else else
{ {
return collectionPublished.QueryIdsAsync(appId, ids); return collectionPublished.QueryIdsAsync(appId, ids, ct);
} }
} }
public Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId, SearchScope scope) public Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId, SearchScope scope,
CancellationToken ct = default)
{ {
if (scope == SearchScope.All) if (scope == SearchScope.All)
{ {
return collectionAll.HasReferrersAsync(appId, contentId); return collectionAll.HasReferrersAsync(appId, contentId, ct);
} }
else else
{ {
return collectionPublished.HasReferrersAsync(appId, contentId); return collectionPublished.HasReferrersAsync(appId, contentId, ct);
} }
} }
public Task ResetScheduledAsync(DomainId documentId) public Task ResetScheduledAsync(DomainId documentId,
CancellationToken ct = default)
{ {
return collectionAll.ResetScheduledAsync(documentId); return collectionAll.ResetScheduledAsync(documentId, ct);
} }
public Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback) public Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback,
CancellationToken ct = default)
{ {
return collectionAll.QueryScheduledWithoutDataAsync(now, callback); return collectionAll.QueryScheduledWithoutDataAsync(now, callback, ct);
} }
public Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode) public Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode,
CancellationToken ct = default)
{ {
return collectionAll.QueryIdsAsync(appId, schemaId, filterNode); return collectionAll.QueryIdsAsync(appId, schemaId, filterNode, ct);
} }
public IEnumerable<IMongoCollection<MongoContentEntity>> GetInternalCollections() public IEnumerable<IMongoCollection<MongoContentEntity>> GetInternalCollections()

3
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs

@ -21,7 +21,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
{ {
public partial class MongoContentRepository : ISnapshotStore<ContentDomainObject.State> public partial class MongoContentRepository : ISnapshotStore<ContentDomainObject.State>
{ {
Task ISnapshotStore<ContentDomainObject.State>.ReadAllAsync(Func<ContentDomainObject.State, long, Task> callback, CancellationToken ct) Task ISnapshotStore<ContentDomainObject.State>.ReadAllAsync(Func<ContentDomainObject.State, long, Task> callback,
CancellationToken ct)
{ {
return Task.CompletedTask; return Task.CompletedTask;
} }

6
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/Extensions.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver; using MongoDB.Driver;
@ -35,7 +36,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
public Status Status { get; set; } public Status Status { get; set; }
} }
public static Task<List<StatusModel>> FindStatusAsync(this IMongoCollection<MongoContentEntity> collection, FilterDefinition<MongoContentEntity> filter) public static Task<List<StatusModel>> FindStatusAsync(this IMongoCollection<MongoContentEntity> collection, FilterDefinition<MongoContentEntity> filter,
CancellationToken ct)
{ {
var projections = Builders<MongoContentEntity>.Projection; var projections = Builders<MongoContentEntity>.Projection;
@ -44,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
.Include(x => x.Id) .Include(x => x.Id)
.Include(x => x.IndexedSchemaId) .Include(x => x.IndexedSchemaId)
.Include(x => x.Status)) .Include(x => x.Status))
.ToListAsync(); .ToListAsync(ct);
} }
} }
} }

2
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/OperationBase.cs

@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
} }
} }
protected virtual Task PrepareAsync(CancellationToken ct = default) protected virtual Task PrepareAsync(CancellationToken ct)
{ {
return Task.CompletedTask; return Task.CompletedTask;
} }

2
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs

@ -17,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
public sealed class QueryAsStream : OperationBase public sealed class QueryAsStream : OperationBase
{ {
protected override async Task PrepareAsync(CancellationToken ct = default) protected override async Task PrepareAsync(CancellationToken ct)
{ {
var indexBySchema = var indexBySchema =
new CreateIndexModel<MongoContentEntity>(Index new CreateIndexModel<MongoContentEntity>(Index

6
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryById.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Contents;
@ -15,7 +16,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
internal sealed class QueryById : OperationBase internal sealed class QueryById : OperationBase
{ {
public async Task<IContentEntity?> QueryAsync(ISchemaEntity schema, DomainId id) public async Task<IContentEntity?> QueryAsync(ISchemaEntity schema, DomainId id,
CancellationToken ct)
{ {
Guard.NotNull(schema, nameof(schema)); Guard.NotNull(schema, nameof(schema));
@ -23,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
var find = Collection.Find(x => x.DocumentId == documentId); var find = Collection.Find(x => x.DocumentId == documentId);
var contentEntity = await find.FirstOrDefaultAsync(); var contentEntity = await find.FirstOrDefaultAsync(ct);
if (contentEntity != null) if (contentEntity != null)
{ {

11
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryByIds.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -20,7 +21,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
internal sealed class QueryByIds : OperationBase internal sealed class QueryByIds : OperationBase
{ {
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids) public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids,
CancellationToken ct)
{ {
if (ids == null || ids.Count == 0) if (ids == null || ids.Count == 0)
{ {
@ -29,12 +31,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
var filter = CreateFilter(appId, null, ids); var filter = CreateFilter(appId, null, ids);
var contentItems = await Collection.FindStatusAsync(filter); var contentItems = await Collection.FindStatusAsync(filter, ct);
return contentItems.Select(x => (x.IndexedSchemaId, x.Id, x.Status)).ToList(); return contentItems.Select(x => (x.IndexedSchemaId, x.Id, x.Status)).ToList();
} }
public async Task<IResultList<IContentEntity>> QueryAsync(DomainId appId, List<ISchemaEntity> schemas, Q q) public async Task<IResultList<IContentEntity>> QueryAsync(DomainId appId, List<ISchemaEntity> schemas, Q q,
CancellationToken ct)
{ {
Guard.NotNull(q, nameof(q)); Guard.NotNull(q, nameof(q));
@ -54,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
} }
else if (contentTotal >= q.Query.Take || q.Query.Skip > 0) else if (contentTotal >= q.Query.Take || q.Query.Skip > 0)
{ {
contentTotal = await Collection.Find(filter).CountDocumentsAsync(); contentTotal = await Collection.Find(filter).CountDocumentsAsync(ct);
} }
return ResultList.Create(contentTotal, contentEntities); return ResultList.Create(contentTotal, contentEntities);

30
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryByQuery.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
this.appProvider = appProvider; this.appProvider = appProvider;
} }
protected override async Task PrepareAsync(CancellationToken ct = default) protected override async Task PrepareAsync(CancellationToken ct)
{ {
var indexBySchemaWithRefs = var indexBySchemaWithRefs =
new CreateIndexModel<MongoContentEntity>(Index new CreateIndexModel<MongoContentEntity>(Index
@ -62,7 +62,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
await Collection.Indexes.CreateOneAsync(indexBySchema, cancellationToken: ct); await Collection.Indexes.CreateOneAsync(indexBySchema, cancellationToken: ct);
} }
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode) public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode,
CancellationToken ct)
{ {
Guard.NotNull(filterNode, nameof(filterNode)); Guard.NotNull(filterNode, nameof(filterNode));
@ -77,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
var filter = BuildFilter(appId, schemaId, filterNode.AdjustToModel(appId)); var filter = BuildFilter(appId, schemaId, filterNode.AdjustToModel(appId));
var contentItems = await Collection.FindStatusAsync(filter); var contentItems = await Collection.FindStatusAsync(filter, ct);
return contentItems.Select(x => (x.IndexedSchemaId, x.Id, x.Status)).ToList(); return contentItems.Select(x => (x.IndexedSchemaId, x.Id, x.Status)).ToList();
} }
@ -91,7 +92,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
} }
} }
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q) public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q,
CancellationToken ct)
{ {
Guard.NotNull(app, nameof(app)); Guard.NotNull(app, nameof(app));
Guard.NotNull(q, nameof(q)); Guard.NotNull(q, nameof(q));
@ -102,7 +104,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
var filter = CreateFilter(app.Id, schemas.Select(x => x.Id), query, q.Reference, q.CreatedBy); var filter = CreateFilter(app.Id, schemas.Select(x => x.Id), query, q.Reference, q.CreatedBy);
var contentEntities = await FindContentsAsync(query, filter); var contentEntities = await FindContentsAsync(query, filter, ct);
var contentTotal = (long)contentEntities.Count; var contentTotal = (long)contentEntities.Count;
if (q.NoTotal) if (q.NoTotal)
@ -111,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
} }
else if (contentTotal >= q.Query.Take || q.Query.Skip > 0) else if (contentTotal >= q.Query.Take || q.Query.Skip > 0)
{ {
contentTotal = await Collection.Find(filter).CountDocumentsAsync(); contentTotal = await Collection.Find(filter).CountDocumentsAsync(ct);
} }
return ResultList.Create<IContentEntity>(contentTotal, contentEntities); return ResultList.Create<IContentEntity>(contentTotal, contentEntities);
@ -126,7 +128,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
} }
} }
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q) public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q,
CancellationToken ct)
{ {
Guard.NotNull(app, nameof(app)); Guard.NotNull(app, nameof(app));
Guard.NotNull(schema, nameof(schema)); Guard.NotNull(schema, nameof(schema));
@ -138,7 +141,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
var filter = CreateFilter(schema.AppId.Id, Enumerable.Repeat(schema.Id, 1), query, q.Reference, q.CreatedBy); var filter = CreateFilter(schema.AppId.Id, Enumerable.Repeat(schema.Id, 1), query, q.Reference, q.CreatedBy);
var contentEntities = await FindContentsAsync(query, filter); var contentEntities = await FindContentsAsync(query, filter, ct);
var contentTotal = (long)contentEntities.Count; var contentTotal = (long)contentEntities.Count;
if (q.NoTotal) if (q.NoTotal)
@ -147,7 +150,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
} }
else if (contentTotal >= q.Query.Take || q.Query.Skip > 0) else if (contentTotal >= q.Query.Take || q.Query.Skip > 0)
{ {
contentTotal = await Collection.Find(filter).CountDocumentsAsync(); contentTotal = await Collection.Find(filter).CountDocumentsAsync(ct);
} }
return ResultList.Create<IContentEntity>(contentTotal, contentEntities); return ResultList.Create<IContentEntity>(contentTotal, contentEntities);
@ -162,7 +165,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
} }
} }
private async Task<List<MongoContentEntity>> FindContentsAsync(ClrQuery query, FilterDefinition<MongoContentEntity> filter) private async Task<List<MongoContentEntity>> FindContentsAsync(ClrQuery query, FilterDefinition<MongoContentEntity> filter,
CancellationToken ct)
{ {
if (query.Skip > 0 && !IsSatisfiedByIndex(query)) if (query.Skip > 0 && !IsSatisfiedByIndex(query))
{ {
@ -181,7 +185,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
.QuerySkip(query) .QuerySkip(query)
.QueryLimit(query) .QueryLimit(query)
.Lookup<IdOnly, MongoContentEntity, IdOnly>(Collection, x => x.Id, x => x.DocumentId, x => x.Joined) .Lookup<IdOnly, MongoContentEntity, IdOnly>(Collection, x => x.Id, x => x.DocumentId, x => x.Joined)
.ToListAsync(); .ToListAsync(ct);
return joined.Select(x => x.Joined[0]).ToList(); return joined.Select(x => x.Joined[0]).ToList();
} }
@ -191,7 +195,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
.QuerySort(query) .QuerySort(query)
.QueryLimit(query) .QueryLimit(query)
.QuerySkip(query) .QuerySkip(query)
.ToListAsync(); .ToListAsync(ct);
return await result; return await result;
} }

8
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryReferences.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver; using MongoDB.Driver;
@ -36,7 +37,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
this.queryByIds = queryByIds; this.queryByIds = queryByIds;
} }
public async Task<IResultList<IContentEntity>> QueryAsync(DomainId appId, List<ISchemaEntity> schemas, Q q) public async Task<IResultList<IContentEntity>> QueryAsync(DomainId appId, List<ISchemaEntity> schemas, Q q,
CancellationToken ct)
{ {
var documentId = DomainId.Combine(appId, q.Referencing); var documentId = DomainId.Combine(appId, q.Referencing);
@ -45,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
.Find(x => x.DocumentId == documentId) .Find(x => x.DocumentId == documentId)
.Project<ReferencedIdsOnly>(Projection.Include(x => x.ReferencedIds)); .Project<ReferencedIdsOnly>(Projection.Include(x => x.ReferencedIds));
var contentEntity = await find.FirstOrDefaultAsync(); var contentEntity = await find.FirstOrDefaultAsync(ct);
if (contentEntity == null) if (contentEntity == null)
{ {
@ -59,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
q = q.WithReferencing(default).WithIds(contentEntity.ReferencedIds!); q = q.WithReferencing(default).WithIds(contentEntity.ReferencedIds!);
return await queryByIds.QueryAsync(appId, schemas, q); return await queryByIds.QueryAsync(appId, schemas, q, ct);
} }
} }
} }

9
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryReferrers.cs

@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
internal sealed class QueryReferrers : OperationBase internal sealed class QueryReferrers : OperationBase
{ {
protected override Task PrepareAsync(CancellationToken ct = default) protected override Task PrepareAsync(CancellationToken ct)
{ {
var index = var index =
new CreateIndexModel<MongoContentEntity>(Index new CreateIndexModel<MongoContentEntity>(Index
@ -26,7 +26,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct); return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct);
} }
public async Task<bool> CheckExistsAsync(DomainId appId, DomainId contentId) public async Task<bool> CheckExistsAsync(DomainId appId, DomainId contentId,
CancellationToken ct)
{ {
var filter = var filter =
Filter.And( Filter.And(
@ -37,9 +38,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
var hasReferrerAsync = var hasReferrerAsync =
await Collection.Find(filter).Only(x => x.Id) await Collection.Find(filter).Only(x => x.Id)
.AnyAsync(); .AnyAsync(ct);
return hasReferrerAsync; return hasReferrerAsync;
} }
} }
} }

7
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryScheduled.cs

@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
internal sealed class QueryScheduled : OperationBase internal sealed class QueryScheduled : OperationBase
{ {
protected override Task PrepareAsync(CancellationToken ct = default) protected override Task PrepareAsync(CancellationToken ct)
{ {
var index = var index =
new CreateIndexModel<MongoContentEntity>(Index new CreateIndexModel<MongoContentEntity>(Index
@ -28,7 +28,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct); return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct);
} }
public Task QueryAsync(Instant now, Func<IContentEntity, Task> callback) public Task QueryAsync(Instant now, Func<IContentEntity, Task> callback,
CancellationToken ct)
{ {
Guard.NotNull(callback, nameof(callback)); Guard.NotNull(callback, nameof(callback));
@ -36,7 +37,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
.ForEachAsync(c => .ForEachAsync(c =>
{ {
callback(c); callback(c);
}); }, ct);
} }
} }
} }

3
backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoTextIndex.cs

@ -30,7 +30,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.FullText
{ {
} }
protected override Task SetupCollectionAsync(IMongoCollection<MongoTextIndexEntity> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<MongoTextIndexEntity> collection,
CancellationToken ct)
{ {
return collection.Indexes.CreateManyAsync(new[] return collection.Indexes.CreateManyAsync(new[]
{ {

3
backend/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs

@ -41,7 +41,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.History
return "Projections_History"; return "Projections_History";
} }
protected override Task SetupCollectionAsync(IMongoCollection<HistoryEvent> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<HistoryEvent> collection,
CancellationToken ct = default)
{ {
return collection.Indexes.CreateManyAsync(new[] return collection.Indexes.CreateManyAsync(new[]
{ {

19
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs

@ -36,9 +36,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
return "RuleEvents"; return "RuleEvents";
} }
protected override async Task SetupCollectionAsync(IMongoCollection<MongoRuleEventEntity> collection, CancellationToken ct = default) protected override async Task SetupCollectionAsync(IMongoCollection<MongoRuleEventEntity> collection,
CancellationToken ct = default)
{ {
await statisticsCollection.InitializeAsync(ct); await statisticsCollection.InitializeAsync(ct = default);
await collection.Indexes.CreateManyAsync(new[] await collection.Indexes.CreateManyAsync(new[]
{ {
@ -63,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
return Collection.Find(x => x.NextAttempt < now).ForEachAsync(callback, ct); return Collection.Find(x => x.NextAttempt < now).ForEachAsync(callback, ct);
} }
public async Task<IResultList<IRuleEventEntity>> QueryByAppAsync(DomainId appId, DomainId? ruleId = null, int skip = 0, int take = 20) public async Task<IResultList<IRuleEventEntity>> QueryByAppAsync(DomainId appId, DomainId? ruleId = null, int skip = 0, int take = 20, CancellationToken ct = default)
{ {
var filter = Filter.Eq(x => x.AppId, appId); var filter = Filter.Eq(x => x.AppId, appId);
@ -72,22 +73,22 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
filter = Filter.And(filter, Filter.Eq(x => x.RuleId, ruleId.Value)); filter = Filter.And(filter, Filter.Eq(x => x.RuleId, ruleId.Value));
} }
var ruleEventEntities = await Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.Created).ToListAsync(); var ruleEventEntities = await Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.Created).ToListAsync(ct = default);
var ruleEventTotal = (long)ruleEventEntities.Count; var ruleEventTotal = (long)ruleEventEntities.Count;
if (ruleEventTotal >= take || skip > 0) if (ruleEventTotal >= take || skip > 0)
{ {
ruleEventTotal = await Collection.Find(filter).CountDocumentsAsync(); ruleEventTotal = await Collection.Find(filter).CountDocumentsAsync(ct = default);
} }
return ResultList.Create(ruleEventTotal, ruleEventEntities); return ResultList.Create(ruleEventTotal, ruleEventEntities);
} }
public async Task<IRuleEventEntity> FindAsync(DomainId id) public async Task<IRuleEventEntity> FindAsync(DomainId id, CancellationToken ct = default)
{ {
var ruleEvent = var ruleEvent =
await Collection.Find(x => x.DocumentId == id) await Collection.Find(x => x.DocumentId == id)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync(ct = default);
return ruleEvent; return ruleEvent;
} }
@ -149,9 +150,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
} }
} }
public Task<IReadOnlyList<RuleStatistics>> QueryStatisticsByAppAsync(DomainId appId) public Task<IReadOnlyList<RuleStatistics>> QueryStatisticsByAppAsync(DomainId appId, CancellationToken ct = default)
{ {
return statisticsCollection.QueryByAppAsync(appId); return statisticsCollection.QueryByAppAsync(appId, ct);
} }
} }
} }

8
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleStatisticsCollection.cs

@ -39,7 +39,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
return "RuleStatistics"; return "RuleStatistics";
} }
protected override Task SetupCollectionAsync(IMongoCollection<RuleStatistics> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<RuleStatistics> collection,
CancellationToken ct)
{ {
return collection.Indexes.CreateOneAsync( return collection.Indexes.CreateOneAsync(
new CreateIndexModel<RuleStatistics>( new CreateIndexModel<RuleStatistics>(
@ -49,9 +50,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
cancellationToken: ct); cancellationToken: ct);
} }
public async Task<IReadOnlyList<RuleStatistics>> QueryByAppAsync(DomainId appId) public async Task<IReadOnlyList<RuleStatistics>> QueryByAppAsync(DomainId appId,
CancellationToken ct)
{ {
var statistics = await Collection.Find(x => x.AppId == appId).ToListAsync(); var statistics = await Collection.Find(x => x.AppId == appId).ToListAsync(ct);
return statistics; return statistics;
} }

6
backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Entities.Search; using Squidex.Domain.Apps.Entities.Search;
@ -26,7 +27,8 @@ namespace Squidex.Domain.Apps.Entities.Apps
this.urlGenerator = urlGenerator; this.urlGenerator = urlGenerator;
} }
public Task<SearchResults> SearchAsync(string query, Context context) public Task<SearchResults> SearchAsync(string query, Context context,
CancellationToken ct)
{ {
var result = new SearchResults(); var result = new SearchResults();
@ -81,4 +83,4 @@ namespace Squidex.Domain.Apps.Entities.Apps
return Task.FromResult(result); return Task.FromResult(result);
} }
} }
} }

6
backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppImageStore.cs

@ -24,14 +24,16 @@ namespace Squidex.Domain.Apps.Entities.Apps
this.assetStore = assetStore; this.assetStore = assetStore;
} }
public Task DownloadAsync(DomainId appId, Stream stream, CancellationToken ct = default) public Task DownloadAsync(DomainId appId, Stream stream,
CancellationToken ct = default)
{ {
var fileName = GetFileName(appId); var fileName = GetFileName(appId);
return assetStore.DownloadAsync(fileName, stream, default, ct); return assetStore.DownloadAsync(fileName, stream, default, ct);
} }
public Task UploadAsync(DomainId appId, Stream stream, CancellationToken ct = default) public Task UploadAsync(DomainId appId, Stream stream,
CancellationToken ct = default)
{ {
var fileName = GetFileName(appId); var fileName = GetFileName(appId);

3
backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs

@ -74,7 +74,8 @@ namespace Squidex.Domain.Apps.Entities.Apps
return requestLogStore.LogAsync(storedRequest); return requestLogStore.LogAsync(storedRequest);
} }
public async Task ReadLogAsync(DomainId appId, DateTime fromDate, DateTime toDate, Stream stream, CancellationToken ct = default) public async Task ReadLogAsync(DomainId appId, DateTime fromDate, DateTime toDate, Stream stream,
CancellationToken ct = default)
{ {
Guard.NotNull(appId, nameof(appId)); Guard.NotNull(appId, nameof(appId));

6
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsSearchSource.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
@ -30,7 +31,8 @@ namespace Squidex.Domain.Apps.Entities.Assets
this.urlGenerator = urlGenerator; this.urlGenerator = urlGenerator;
} }
public async Task<SearchResults> SearchAsync(string query, Context context) public async Task<SearchResults> SearchAsync(string query, Context context,
CancellationToken ct)
{ {
var result = new SearchResults(); var result = new SearchResults();
@ -40,7 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
var clrQuery = new ClrQuery { Filter = filter, Take = 5 }; var clrQuery = new ClrQuery { Filter = filter, Take = 5 };
var assets = await assetQuery.QueryAsync(context, null, Q.Empty.WithQuery(clrQuery)); var assets = await assetQuery.QueryAsync(context, null, Q.Empty.WithQuery(clrQuery), ct);
if (assets.Count > 0) if (assets.Count > 0)
{ {

15
backend/src/Squidex.Domain.Apps.Entities/Assets/DefaultAssetFileStore.cs

@ -29,7 +29,8 @@ namespace Squidex.Domain.Apps.Entities.Assets
return assetStore.GeneratePublicUrl(fileName); return assetStore.GeneratePublicUrl(fileName);
} }
public async Task<long> GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default) public async Task<long> GetFileSizeAsync(DomainId appId, DomainId id, long fileVersion,
CancellationToken ct = default)
{ {
try try
{ {
@ -45,7 +46,8 @@ namespace Squidex.Domain.Apps.Entities.Assets
} }
} }
public async Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, BytesRange range = default, CancellationToken ct = default) public async Task DownloadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, BytesRange range = default,
CancellationToken ct = default)
{ {
try try
{ {
@ -61,19 +63,22 @@ namespace Squidex.Domain.Apps.Entities.Assets
} }
} }
public Task UploadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream, CancellationToken ct = default) public Task UploadAsync(DomainId appId, DomainId id, long fileVersion, Stream stream,
CancellationToken ct = default)
{ {
var fileName = GetFileName(appId, id, fileVersion); var fileName = GetFileName(appId, id, fileVersion);
return assetStore.UploadAsync(fileName, stream, true, ct); return assetStore.UploadAsync(fileName, stream, true, ct);
} }
public Task UploadAsync(string tempFile, Stream stream, CancellationToken ct = default) public Task UploadAsync(string tempFile, Stream stream,
CancellationToken ct = default)
{ {
return assetStore.UploadAsync(tempFile, stream, false, ct); return assetStore.UploadAsync(tempFile, stream, false, ct);
} }
public Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion, CancellationToken ct = default) public Task CopyAsync(string tempFile, DomainId appId, DomainId id, long fileVersion,
CancellationToken ct = default)
{ {
var fileName = GetFileName(appId, id, fileVersion); var fileName = GetFileName(appId, id, fileVersion);

2
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs

@ -158,7 +158,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
if (payload is not IEnrichedAssetEntity) if (payload is not IEnrichedAssetEntity)
{ {
payload = await assetEnricher.EnrichAsync(asset, contextProvider.Context); payload = await assetEnricher.EnrichAsync(asset, contextProvider.Context, default);
} }
} }

4
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/GuardAsset.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -43,7 +43,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
if (command.CheckReferrers) if (command.CheckReferrers)
{ {
var hasReferrer = await contentRepository.HasReferrersAsync(asset.AppId.Id, asset.Id, SearchScope.All); var hasReferrer = await contentRepository.HasReferrersAsync(asset.AppId.Id, asset.Id, SearchScope.All, default);
if (hasReferrer) if (hasReferrer)
{ {

7
backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEnricher.cs

@ -6,14 +6,15 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Entities.Assets namespace Squidex.Domain.Apps.Entities.Assets
{ {
public interface IAssetEnricher public interface IAssetEnricher
{ {
Task<IEnrichedAssetEntity> EnrichAsync(IAssetEntity asset, Context context); Task<IEnrichedAssetEntity> EnrichAsync(IAssetEntity asset, Context context, CancellationToken ct = default);
Task<IReadOnlyList<IEnrichedAssetEntity>> EnrichAsync(IEnumerable<IAssetEntity> assets, Context context); Task<IReadOnlyList<IEnrichedAssetEntity>> EnrichAsync(IEnumerable<IAssetEntity> assets, Context context, CancellationToken ct = default);
} }
} }

17
backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -13,20 +14,20 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
public interface IAssetQueryService public interface IAssetQueryService
{ {
Task<IResultList<IEnrichedAssetEntity>> QueryAsync(Context context, DomainId? parentId, Q q); Task<IResultList<IEnrichedAssetEntity>> QueryAsync(Context context, DomainId? parentId, Q q, CancellationToken ct = default);
Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId); Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId, CancellationToken ct = default);
Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId); Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId, CancellationToken ct = default);
Task<IReadOnlyList<IAssetFolderEntity>> FindAssetFolderAsync(DomainId appId, DomainId id); Task<IReadOnlyList<IAssetFolderEntity>> FindAssetFolderAsync(DomainId appId, DomainId id, CancellationToken ct = default);
Task<IEnrichedAssetEntity?> FindByHashAsync(Context context, string hash, string fileName, long fileSize); Task<IEnrichedAssetEntity?> FindByHashAsync(Context context, string hash, string fileName, long fileSize, CancellationToken ct = default);
Task<IEnrichedAssetEntity?> FindAsync(Context context, DomainId id, long version = EtagVersion.Any); Task<IEnrichedAssetEntity?> FindAsync(Context context, DomainId id, long version = EtagVersion.Any, CancellationToken ct = default);
Task<IEnrichedAssetEntity?> FindBySlugAsync(Context context, string slug); Task<IEnrichedAssetEntity?> FindBySlugAsync(Context context, string slug, CancellationToken ct = default);
Task<IEnrichedAssetEntity?> FindGlobalAsync(Context context, DomainId id); Task<IEnrichedAssetEntity?> FindGlobalAsync(Context context, DomainId id, CancellationToken ct = default);
} }
} }

16
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs

@ -8,6 +8,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Core.Tags;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -34,17 +35,19 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
this.requestCache = requestCache; this.requestCache = requestCache;
} }
public async Task<IEnrichedAssetEntity> EnrichAsync(IAssetEntity asset, Context context) public async Task<IEnrichedAssetEntity> EnrichAsync(IAssetEntity asset, Context context,
CancellationToken ct)
{ {
Guard.NotNull(asset, nameof(asset)); Guard.NotNull(asset, nameof(asset));
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
var enriched = await EnrichAsync(Enumerable.Repeat(asset, 1), context); var enriched = await EnrichAsync(Enumerable.Repeat(asset, 1), context, ct);
return enriched[0]; return enriched[0];
} }
public async Task<IReadOnlyList<IEnrichedAssetEntity>> EnrichAsync(IEnumerable<IAssetEntity> assets, Context context) public async Task<IReadOnlyList<IEnrichedAssetEntity>> EnrichAsync(IEnumerable<IAssetEntity> assets, Context context,
CancellationToken ct)
{ {
Guard.NotNull(assets, nameof(assets)); Guard.NotNull(assets, nameof(assets));
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
@ -60,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
if (!context.ShouldSkipAssetEnrichment()) if (!context.ShouldSkipAssetEnrichment())
{ {
await EnrichTagsAsync(results); await EnrichTagsAsync(results, ct);
EnrichWithMetadataText(results); EnrichWithMetadataText(results);
} }
@ -104,10 +107,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
} }
} }
private async Task EnrichTagsAsync(List<AssetEntity> assets) private async Task EnrichTagsAsync(List<AssetEntity> assets,
CancellationToken ct)
{ {
foreach (var group in assets.GroupBy(x => x.AppId.Id)) foreach (var group in assets.GroupBy(x => x.AppId.Id))
{ {
ct.ThrowIfCancellationRequested();
var tagsById = await CalculateTags(group); var tagsById = await CalculateTags(group);
foreach (var asset in group) foreach (var asset in group)

66
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -43,7 +44,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
this.queryParser = queryParser; this.queryParser = queryParser;
} }
public async Task<IReadOnlyList<IAssetFolderEntity>> FindAssetFolderAsync(DomainId appId, DomainId id) public async Task<IReadOnlyList<IAssetFolderEntity>> FindAssetFolderAsync(DomainId appId, DomainId id,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Profiler.TraceMethod<AssetQueryService>())
{ {
@ -51,7 +53,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
while (id != DomainId.Empty) while (id != DomainId.Empty)
{ {
var folder = await assetFolderRepository.FindAssetFolderAsync(appId, id); var folder = await assetFolderRepository.FindAssetFolderAsync(appId, id, ct);
if (folder == null || result.Any(x => x.Id == folder.Id)) if (folder == null || result.Any(x => x.Id == folder.Id))
{ {
@ -68,78 +70,84 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
} }
} }
public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId) public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Profiler.TraceMethod<AssetQueryService>())
{ {
var assetFolders = await assetFolderRepository.QueryAsync(appId, parentId); var assetFolders = await assetFolderRepository.QueryAsync(appId, parentId, ct);
return assetFolders; return assetFolders;
} }
} }
public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId) public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId,
CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Profiler.TraceMethod<AssetQueryService>())
{ {
var assetFolders = await assetFolderRepository.QueryAsync(context.App.Id, parentId); var assetFolders = await assetFolderRepository.QueryAsync(context.App.Id, parentId, ct);
return assetFolders; return assetFolders;
} }
} }
public async Task<IEnrichedAssetEntity?> FindByHashAsync(Context context, string hash, string fileName, long fileSize) public async Task<IEnrichedAssetEntity?> FindByHashAsync(Context context, string hash, string fileName, long fileSize,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>()) using (Profiler.TraceMethod<AssetQueryService>())
{ {
var asset = await assetRepository.FindAssetByHashAsync(context.App.Id, hash, fileName, fileSize); var asset = await assetRepository.FindAssetByHashAsync(context.App.Id, hash, fileName, fileSize, ct);
if (asset == null) if (asset == null)
{ {
return null; return null;
} }
return await TransformAsync(context, asset); return await TransformAsync(context, asset, ct);
} }
} }
public async Task<IEnrichedAssetEntity?> FindBySlugAsync(Context context, string slug) public async Task<IEnrichedAssetEntity?> FindBySlugAsync(Context context, string slug,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>()) using (Profiler.TraceMethod<AssetQueryService>())
{ {
var asset = await assetRepository.FindAssetBySlugAsync(context.App.Id, slug); var asset = await assetRepository.FindAssetBySlugAsync(context.App.Id, slug, ct);
if (asset == null) if (asset == null)
{ {
return null; return null;
} }
return await TransformAsync(context, asset); return await TransformAsync(context, asset, ct);
} }
} }
public async Task<IEnrichedAssetEntity?> FindGlobalAsync(Context context, DomainId id) public async Task<IEnrichedAssetEntity?> FindGlobalAsync(Context context, DomainId id,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>()) using (Profiler.TraceMethod<AssetQueryService>())
{ {
var asset = await assetRepository.FindAssetAsync(id); var asset = await assetRepository.FindAssetAsync(id, ct);
if (asset == null) if (asset == null)
{ {
return null; return null;
} }
return await TransformAsync(context, asset); return await TransformAsync(context, asset, ct);
} }
} }
public async Task<IEnrichedAssetEntity?> FindAsync(Context context, DomainId id, long version = EtagVersion.Any) public async Task<IEnrichedAssetEntity?> FindAsync(Context context, DomainId id, long version = EtagVersion.Any,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
@ -153,7 +161,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
} }
else else
{ {
asset = await assetRepository.FindAssetAsync(context.App.Id, id); asset = await assetRepository.FindAssetAsync(context.App.Id, id, ct);
} }
if (asset == null) if (asset == null)
@ -161,11 +169,12 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
return null; return null;
} }
return await TransformAsync(context, asset); return await TransformAsync(context, asset, ct);
} }
} }
public async Task<IResultList<IEnrichedAssetEntity>> QueryAsync(Context context, DomainId? parentId, Q q) public async Task<IResultList<IEnrichedAssetEntity>> QueryAsync(Context context, DomainId? parentId, Q q,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
@ -178,36 +187,39 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
q = await queryParser.ParseAsync(context, q); q = await queryParser.ParseAsync(context, q);
var assets = await assetRepository.QueryAsync(context.App.Id, parentId, q); var assets = await assetRepository.QueryAsync(context.App.Id, parentId, q, ct);
if (q.Ids != null && q.Ids.Count > 0) if (q.Ids != null && q.Ids.Count > 0)
{ {
assets = assets.SortSet(x => x.Id, q.Ids); assets = assets.SortSet(x => x.Id, q.Ids);
} }
return await TransformAsync(context, assets); return await TransformAsync(context, assets, ct);
} }
} }
private async Task<IResultList<IEnrichedAssetEntity>> TransformAsync(Context context, IResultList<IAssetEntity> assets) private async Task<IResultList<IEnrichedAssetEntity>> TransformAsync(Context context, IResultList<IAssetEntity> assets,
CancellationToken ct)
{ {
var transformed = await TransformCoreAsync(context, assets); var transformed = await TransformCoreAsync(context, assets, ct);
return ResultList.Create(assets.Total, transformed); return ResultList.Create(assets.Total, transformed);
} }
private async Task<IEnrichedAssetEntity> TransformAsync(Context context, IAssetEntity asset) private async Task<IEnrichedAssetEntity> TransformAsync(Context context, IAssetEntity asset,
CancellationToken ct)
{ {
var transformed = await TransformCoreAsync(context, Enumerable.Repeat(asset, 1)); var transformed = await TransformCoreAsync(context, Enumerable.Repeat(asset, 1), ct);
return transformed[0]; return transformed[0];
} }
private async Task<IReadOnlyList<IEnrichedAssetEntity>> TransformCoreAsync(Context context, IEnumerable<IAssetEntity> assets) private async Task<IReadOnlyList<IEnrichedAssetEntity>> TransformCoreAsync(Context context, IEnumerable<IAssetEntity> assets,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Profiler.TraceMethod<AssetQueryService>())
{ {
return await assetEnricher.EnrichAsync(assets, context); return await assetEnricher.EnrichAsync(assets, context, ct);
} }
} }
} }

75
backend/src/Squidex.Domain.Apps.Entities/Assets/RebuildFiles.cs

@ -0,0 +1,75 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Squidex.Assets;
using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Entities.Assets
{
public sealed class RebuildFiles
{
private static readonly MemoryStream DummyStream = new MemoryStream(Encoding.UTF8.GetBytes("dummy"));
private readonly IAssetFileStore assetFileStore;
private readonly IEventStore eventStore;
private readonly IEventDataFormatter eventDataFormatter;
public RebuildFiles(
IAssetFileStore assetFileStore,
IEventStore eventStore,
IEventDataFormatter eventDataFormatter)
{
Guard.NotNull(assetFileStore, nameof(assetFileStore));
Guard.NotNull(eventStore, nameof(eventStore));
Guard.NotNull(eventDataFormatter, nameof(eventDataFormatter));
this.assetFileStore = assetFileStore;
this.eventStore = eventStore;
this.eventDataFormatter = eventDataFormatter;
}
public async Task RepairAsync(CancellationToken ct = default)
{
await foreach (var storedEvent in eventStore.QueryAllAsync("^asset\\-", ct: ct))
{
var @event = eventDataFormatter.ParseIfKnown(storedEvent);
if (@event != null)
{
switch (@event.Payload)
{
case AssetCreated assetCreated:
await TryRepairAsync(assetCreated.AppId, assetCreated.AssetId, assetCreated.FileVersion, ct);
break;
case AssetUpdated assetUpdated:
await TryRepairAsync(assetUpdated.AppId, assetUpdated.AssetId, assetUpdated.FileVersion, ct);
break;
}
}
}
}
private async Task TryRepairAsync(NamedId<DomainId> appId, DomainId id, long fileVersion, CancellationToken ct)
{
try
{
await assetFileStore.GetFileSizeAsync(appId.Id, id, fileVersion, ct);
}
catch (AssetNotFoundException)
{
DummyStream.Position = 0;
await assetFileStore.UploadAsync(appId.Id, id, fileVersion, DummyStream, ct);
}
}
}
}

4
backend/src/Squidex.Domain.Apps.Entities/Assets/RecursiveDeleter.cs

@ -88,14 +88,14 @@ namespace Squidex.Domain.Apps.Entities.Assets
var appId = folderDeleted.AppId; var appId = folderDeleted.AppId;
var childAssetFolders = await assetFolderRepository.QueryChildIdsAsync(appId.Id, folderDeleted.AssetFolderId); var childAssetFolders = await assetFolderRepository.QueryChildIdsAsync(appId.Id, folderDeleted.AssetFolderId, default);
foreach (var assetFolderId in childAssetFolders) foreach (var assetFolderId in childAssetFolders)
{ {
await PublishAsync(new DeleteAssetFolder { AppId = appId, AssetFolderId = assetFolderId }); await PublishAsync(new DeleteAssetFolder { AppId = appId, AssetFolderId = assetFolderId });
} }
var childAssets = await assetRepository.QueryChildIdsAsync(appId.Id, folderDeleted.AssetFolderId); var childAssets = await assetRepository.QueryChildIdsAsync(appId.Id, folderDeleted.AssetFolderId, default);
foreach (var assetId in childAssets) foreach (var assetId in childAssets)
{ {

7
backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -13,10 +14,10 @@ namespace Squidex.Domain.Apps.Entities.Assets.Repositories
{ {
public interface IAssetFolderRepository public interface IAssetFolderRepository
{ {
Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId); Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId, CancellationToken ct = default);
Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId); Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId, CancellationToken ct = default);
Task<IAssetFolderEntity?> FindAssetFolderAsync(DomainId appId, DomainId id); Task<IAssetFolderEntity?> FindAssetFolderAsync(DomainId appId, DomainId id, CancellationToken ct = default);
} }
} }

16
backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs

@ -14,20 +14,20 @@ namespace Squidex.Domain.Apps.Entities.Assets.Repositories
{ {
public interface IAssetRepository public interface IAssetRepository
{ {
IAsyncEnumerable<IAssetEntity> StreamAll(DomainId appId, CancellationToken ct); IAsyncEnumerable<IAssetEntity> StreamAll(DomainId appId, CancellationToken ct = default);
Task<IResultList<IAssetEntity>> QueryAsync(DomainId appId, DomainId? parentId, Q q); Task<IResultList<IAssetEntity>> QueryAsync(DomainId appId, DomainId? parentId, Q q, CancellationToken ct = default);
Task<IReadOnlyList<DomainId>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids); Task<IReadOnlyList<DomainId>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids, CancellationToken ct = default);
Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId); Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId, CancellationToken ct = default);
Task<IAssetEntity?> FindAssetByHashAsync(DomainId appId, string hash, string fileName, long fileSize); Task<IAssetEntity?> FindAssetByHashAsync(DomainId appId, string hash, string fileName, long fileSize, CancellationToken ct = default);
Task<IAssetEntity?> FindAssetBySlugAsync(DomainId appId, string slug); Task<IAssetEntity?> FindAssetBySlugAsync(DomainId appId, string slug, CancellationToken ct = default);
Task<IAssetEntity?> FindAssetAsync(DomainId appId); Task<IAssetEntity?> FindAssetAsync(DomainId id, CancellationToken ct = default);
Task<IAssetEntity?> FindAssetAsync(DomainId appId, DomainId id); Task<IAssetEntity?> FindAssetAsync(DomainId appId, DomainId id, CancellationToken ct = default);
} }
} }

8
backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -119,12 +119,14 @@ namespace Squidex.Domain.Apps.Entities.Backup
Process(job, actor, currentJobToken.Token); Process(job, actor, currentJobToken.Token);
} }
private void Process(BackupJob job, RefToken actor, CancellationToken ct) private void Process(BackupJob job, RefToken actor,
CancellationToken ct)
{ {
ProcessAsync(job, actor, ct).Forget(); ProcessAsync(job, actor, ct).Forget();
} }
private async Task ProcessAsync(BackupJob job, RefToken actor, CancellationToken ct) private async Task ProcessAsync(BackupJob job, RefToken actor,
CancellationToken ct)
{ {
var handlers = CreateHandlers(); var handlers = CreateHandlers();

4
backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs

@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
} }
catch (DomainObjectNotFoundException) catch (DomainObjectNotFoundException)
{ {
await contentRepository.ResetScheduledAsync(content.UniqueId); await contentRepository.ResetScheduledAsync(content.UniqueId, default);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -104,7 +104,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
.WriteProperty("contentId", logContentId)); .WriteProperty("contentId", logContentId));
} }
}); });
}); }, default);
} }
public Task ReceiveReminder(string reminderName, TickStatus status) public Task ReceiveReminder(string reminderName, TickStatus status)

6
backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -45,7 +46,8 @@ namespace Squidex.Domain.Apps.Entities.Contents
this.urlGenerator = urlGenerator; this.urlGenerator = urlGenerator;
} }
public async Task<SearchResults> SearchAsync(string query, Context context) public async Task<SearchResults> SearchAsync(string query, Context context,
CancellationToken ct)
{ {
var result = new SearchResults(); var result = new SearchResults();
@ -67,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var appId = context.App.NamedId(); var appId = context.App.NamedId();
var contents = await contentQuery.QueryAsync(context, Q.Empty.WithIds(ids)); var contents = await contentQuery.QueryAsync(context, Q.Empty.WithIds(ids), ct);
foreach (var content in contents) foreach (var content in contents)
{ {

2
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs

@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
{ {
var contentRepository = context.Resolve<IContentRepository>(); var contentRepository = context.Resolve<IContentRepository>();
var hasReferrer = await contentRepository.HasReferrersAsync(context.App.Id, context.ContentId, SearchScope.All); var hasReferrer = await contentRepository.HasReferrersAsync(context.App.Id, context.ContentId, SearchScope.All, default);
if (hasReferrer) if (hasReferrer)
{ {

9
backend/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -13,14 +14,14 @@ namespace Squidex.Domain.Apps.Entities.Contents
{ {
public interface IContentQueryService public interface IContentQueryService
{ {
Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, Q q); Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, Q q, CancellationToken ct = default);
Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, string schemaIdOrName, Q query); Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, string schemaIdOrName, Q query, CancellationToken ct = default);
Task<IEnrichedContentEntity?> FindAsync(Context context, string schemaIdOrName, DomainId id, long version = EtagVersion.Any); Task<IEnrichedContentEntity?> FindAsync(Context context, string schemaIdOrName, DomainId id, long version = EtagVersion.Any, CancellationToken ct = default);
Task<ISchemaEntity> GetSchemaOrThrowAsync(Context context, string schemaIdOrName); Task<ISchemaEntity> GetSchemaOrThrowAsync(Context context, string schemaIdOrName);
Task<ISchemaEntity?> GetSchemaAsync(Context context, string schemaIdOrName); Task<ISchemaEntity?> GetSchemaAsync(Context context, string schemaIdOrNama);
} }
} }

20
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -36,24 +37,27 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
this.contentQuery = contentQuery; this.contentQuery = contentQuery;
} }
public async Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, bool cloneData, Context context) public async Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, bool cloneData, Context context,
CancellationToken ct)
{ {
Guard.NotNull(content, nameof(content)); Guard.NotNull(content, nameof(content));
var enriched = await EnrichInternalAsync(Enumerable.Repeat(content, 1), cloneData, context); var enriched = await EnrichInternalAsync(Enumerable.Repeat(content, 1), cloneData, context, ct);
return enriched[0]; return enriched[0];
} }
public Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, Context context) public Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, Context context,
CancellationToken ct)
{ {
Guard.NotNull(contents, nameof(contents)); Guard.NotNull(contents, nameof(contents));
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
return EnrichInternalAsync(contents, false, context); return EnrichInternalAsync(contents, false, context, ct);
} }
private async Task<IReadOnlyList<IEnrichedContentEntity>> EnrichInternalAsync(IEnumerable<IContentEntity> contents, bool cloneData, Context context) private async Task<IReadOnlyList<IEnrichedContentEntity>> EnrichInternalAsync(IEnumerable<IContentEntity> contents, bool cloneData, Context context,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<ContentEnricher>()) using (Profiler.TraceMethod<ContentEnricher>())
{ {
@ -63,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
foreach (var step in steps) foreach (var step in steps)
{ {
await step.EnrichAsync(context); await step.EnrichAsync(context, ct);
} }
} }
@ -92,9 +96,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
foreach (var step in steps) foreach (var step in steps)
{ {
ct.ThrowIfCancellationRequested();
using (Profiler.TraceMethod(step.ToString()!)) using (Profiler.TraceMethod(step.ToString()!))
{ {
await step.EnrichAsync(context, results, GetSchema); await step.EnrichAsync(context, results, GetSchema, ct);
} }
} }
} }

37
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
@ -49,7 +50,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
this.queryParser = queryParser; this.queryParser = queryParser;
} }
public async Task<IEnrichedContentEntity?> FindAsync(Context context, string schemaIdOrName, DomainId id, long version = EtagVersion.Any) public async Task<IEnrichedContentEntity?> FindAsync(Context context, string schemaIdOrName, DomainId id, long version = EtagVersion.Any,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
@ -65,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
} }
else else
{ {
content = await contentRepository.FindContentAsync(context.App, schema, id, context.Scope()); content = await contentRepository.FindContentAsync(context.App, schema, id, context.Scope(), ct);
} }
if (content == null || content.SchemaId.Id != schema.Id) if (content == null || content.SchemaId.Id != schema.Id)
@ -73,11 +75,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
return null; return null;
} }
return await TransformAsync(context, content); return await TransformAsync(context, content, ct);
} }
} }
public async Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, string schemaIdOrName, Q q) public async Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, string schemaIdOrName, Q q,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
@ -97,18 +100,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
q = await queryParser.ParseAsync(context, q, schema); q = await queryParser.ParseAsync(context, q, schema);
var contents = await contentRepository.QueryAsync(context.App, schema, q, context.Scope()); var contents = await contentRepository.QueryAsync(context.App, schema, q, context.Scope(), ct);
if (q.Ids != null && q.Ids.Count > 0) if (q.Ids != null && q.Ids.Count > 0)
{ {
contents = contents.SortSet(x => x.Id, q.Ids); contents = contents.SortSet(x => x.Id, q.Ids);
} }
return await TransformAsync(context, contents); return await TransformAsync(context, contents, ct);
} }
} }
public async Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, Q q) public async Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, Q q,
CancellationToken ct = default)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
@ -128,36 +132,39 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
q = await queryParser.ParseAsync(context, q); q = await queryParser.ParseAsync(context, q);
var contents = await contentRepository.QueryAsync(context.App, schemas, q, context.Scope()); var contents = await contentRepository.QueryAsync(context.App, schemas, q, context.Scope(), ct);
if (q.Ids != null && q.Ids.Count > 0) if (q.Ids != null && q.Ids.Count > 0)
{ {
contents = contents.SortSet(x => x.Id, q.Ids); contents = contents.SortSet(x => x.Id, q.Ids);
} }
return await TransformAsync(context, contents); return await TransformAsync(context, contents, ct);
} }
} }
private async Task<IResultList<IEnrichedContentEntity>> TransformAsync(Context context, IResultList<IContentEntity> contents) private async Task<IResultList<IEnrichedContentEntity>> TransformAsync(Context context, IResultList<IContentEntity> contents,
CancellationToken ct)
{ {
var transformed = await TransformCoreAsync(context, contents); var transformed = await TransformCoreAsync(context, contents, ct);
return ResultList.Create(contents.Total, transformed); return ResultList.Create(contents.Total, transformed);
} }
private async Task<IEnrichedContentEntity> TransformAsync(Context context, IContentEntity content) private async Task<IEnrichedContentEntity> TransformAsync(Context context, IContentEntity content,
CancellationToken ct)
{ {
var transformed = await TransformCoreAsync(context, Enumerable.Repeat(content, 1)); var transformed = await TransformCoreAsync(context, Enumerable.Repeat(content, 1), ct);
return transformed[0]; return transformed[0];
} }
private async Task<IReadOnlyList<IEnrichedContentEntity>> TransformCoreAsync(Context context, IEnumerable<IContentEntity> contents) private async Task<IReadOnlyList<IEnrichedContentEntity>> TransformCoreAsync(Context context, IEnumerable<IContentEntity> contents,
CancellationToken ct)
{ {
using (Profiler.TraceMethod<ContentQueryService>()) using (Profiler.TraceMethod<ContentQueryService>())
{ {
return await contentEnricher.EnrichAsync(contents, context); return await contentEnricher.EnrichAsync(contents, context, ct);
} }
} }

5
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricher.cs

@ -6,14 +6,15 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Entities.Contents.Queries namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
public interface IContentEnricher public interface IContentEnricher
{ {
Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, bool cloneData, Context context); Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, bool cloneData, Context context, CancellationToken ct = default);
Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, Context context); Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, Context context, CancellationToken ct = default);
} }
} }

5
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -16,9 +17,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
public interface IContentEnricherStep public interface IContentEnricherStep
{ {
Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas); Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas, CancellationToken ct);
Task EnrichAsync(Context context) Task EnrichAsync(Context context, CancellationToken ct)
{ {
return Task.CompletedTask; return Task.CompletedTask;
} }

25
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.ConvertContent;
@ -49,14 +50,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
excludedHiddenValue = FieldConverters.ForValues(ValueConverters.ExcludeHidden); excludedHiddenValue = FieldConverters.ForValues(ValueConverters.ExcludeHidden);
} }
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
var referenceCleaner = await CleanReferencesAsync(context, contents, schemas); var referenceCleaner = await CleanReferencesAsync(context, contents, schemas, ct);
var converters = GenerateConverters(context, referenceCleaner).ToArray(); var converters = GenerateConverters(context, referenceCleaner).ToArray();
foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) foreach (var group in contents.GroupBy(x => x.SchemaId.Id))
{ {
ct.ThrowIfCancellationRequested();
var schema = await schemas(group.Key); var schema = await schemas(group.Key);
foreach (var content in group) foreach (var content in group)
@ -66,7 +70,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
} }
} }
private async Task<ValueConverter?> CleanReferencesAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) private async Task<ValueConverter?> CleanReferencesAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
if (!context.ShouldSkipCleanup()) if (!context.ShouldSkipCleanup())
{ {
@ -85,8 +90,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
if (ids.Count > 0) if (ids.Count > 0)
{ {
var (assets, refContents) = await AsyncHelper.WhenAll( var (assets, refContents) = await AsyncHelper.WhenAll(
QueryAssetIdsAsync(context, ids), QueryAssetIdsAsync(context, ids, ct),
QueryContentIdsAsync(context, ids)); QueryContentIdsAsync(context, ids, ct));
var foundIds = assets.Union(refContents).ToHashSet(); var foundIds = assets.Union(refContents).ToHashSet();
@ -97,16 +102,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
return null; return null;
} }
private async Task<IEnumerable<DomainId>> QueryContentIdsAsync(Context context, HashSet<DomainId> ids) private async Task<IEnumerable<DomainId>> QueryContentIdsAsync(Context context, HashSet<DomainId> ids,
CancellationToken ct)
{ {
var result = await contentRepository.QueryIdsAsync(context.App.Id, ids, context.Scope()); var result = await contentRepository.QueryIdsAsync(context.App.Id, ids, context.Scope(), ct);
return result.Select(x => x.Id); return result.Select(x => x.Id);
} }
private async Task<IEnumerable<DomainId>> QueryAssetIdsAsync(Context context, HashSet<DomainId> ids) private async Task<IEnumerable<DomainId>> QueryAssetIdsAsync(Context context, HashSet<DomainId> ids,
CancellationToken ct)
{ {
var result = await assetRepository.QueryIdsAsync(context.App.Id, ids); var result = await assetRepository.QueryIdsAsync(context.App.Id, ids, ct);
return result; return result;
} }

9
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Caching;
@ -24,19 +25,23 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
this.requestCache = requestCache; this.requestCache = requestCache;
} }
public Task EnrichAsync(Context context) public Task EnrichAsync(Context context,
CancellationToken ct)
{ {
context.AddCacheHeaders(requestCache); context.AddCacheHeaders(requestCache);
return Task.CompletedTask; return Task.CompletedTask;
} }
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
var app = context.App; var app = context.App;
foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) foreach (var group in contents.GroupBy(x => x.SchemaId.Id))
{ {
ct.ThrowIfCancellationRequested();
var schema = await schemas(group.Key); var schema = await schemas(group.Key);
foreach (var content in group) foreach (var content in group)

6
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithSchema.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
@ -14,10 +15,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
{ {
public sealed class EnrichWithSchema : IContentEnricherStep public sealed class EnrichWithSchema : IContentEnricherStep
{ {
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) foreach (var group in contents.GroupBy(x => x.SchemaId.Id))
{ {
ct.ThrowIfCancellationRequested();
var schema = await schemas(group.Key); var schema = await schemas(group.Key);
var schemaName = schema.SchemaDef.Name; var schemaName = schema.SchemaDef.Name;

6
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithWorkflows.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -26,12 +27,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
this.contentWorkflow = contentWorkflow; this.contentWorkflow = contentWorkflow;
} }
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
var cache = new Dictionary<(DomainId, Status), StatusInfo>(); var cache = new Dictionary<(DomainId, Status), StatusInfo>();
foreach (var content in contents) foreach (var content in contents)
{ {
ct.ThrowIfCancellationRequested();
await EnrichColorAsync(content, content, cache); await EnrichColorAsync(content, content, cache);
if (ShouldEnrichWithStatuses(context)) if (ShouldEnrichWithStatuses(context))

11
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Assets;
@ -40,7 +41,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
this.requestCache = requestCache; this.requestCache = requestCache;
} }
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
if (ShouldEnrich(context)) if (ShouldEnrich(context))
{ {
@ -53,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
AddAssetIds(ids, schema, group); AddAssetIds(ids, schema, group);
} }
var assets = await GetAssetsAsync(context, ids); var assets = await GetAssetsAsync(context, ids, ct);
foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) foreach (var group in contents.GroupBy(x => x.SchemaId.Id))
{ {
@ -111,7 +113,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
} }
} }
private async Task<ILookup<DomainId, IEnrichedAssetEntity>> GetAssetsAsync(Context context, HashSet<DomainId> ids) private async Task<ILookup<DomainId, IEnrichedAssetEntity>> GetAssetsAsync(Context context, HashSet<DomainId> ids,
CancellationToken ct)
{ {
if (ids.Count == 0) if (ids.Count == 0)
{ {
@ -122,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
.WithoutAssetEnrichment(true) .WithoutAssetEnrichment(true)
.WithoutTotal()); .WithoutTotal());
var assets = await assetQuery.QueryAsync(queryContext, null, Q.Empty.WithIds(ids)); var assets = await assetQuery.QueryAsync(queryContext, null, Q.Empty.WithIds(ids), ct);
return assets.ToLookup(x => x.Id); return assets.ToLookup(x => x.Id);
} }

16
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -8,6 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.ExtractReferenceIds; using Squidex.Domain.Apps.Core.ExtractReferenceIds;
@ -41,7 +42,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
this.requestCache = requestCache; this.requestCache = requestCache;
} }
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
if (ShouldEnrich(context)) if (ShouldEnrich(context))
{ {
@ -54,7 +56,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
AddReferenceIds(ids, schema, group); AddReferenceIds(ids, schema, group);
} }
var references = await GetReferencesAsync(context, ids); var references = await GetReferencesAsync(context, ids, ct);
foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) foreach (var group in contents.GroupBy(x => x.SchemaId.Id))
{ {
@ -65,7 +67,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
} }
} }
private async Task ResolveReferencesAsync(Context context, ISchemaEntity schema, IEnumerable<ContentEntity> contents, ILookup<DomainId, IEnrichedContentEntity> references, ProvideSchema schemas) private async Task ResolveReferencesAsync(Context context, ISchemaEntity schema, IEnumerable<ContentEntity> contents, ILookup<DomainId, IEnrichedContentEntity> references,
ProvideSchema schemas)
{ {
var formatted = new Dictionary<IContentEntity, JsonObject>(); var formatted = new Dictionary<IContentEntity, JsonObject>();
@ -146,7 +149,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
} }
} }
private async Task<ILookup<DomainId, IEnrichedContentEntity>> GetReferencesAsync(Context context, HashSet<DomainId> ids) private async Task<ILookup<DomainId, IEnrichedContentEntity>> GetReferencesAsync(Context context, HashSet<DomainId> ids,
CancellationToken ct)
{ {
if (ids.Count == 0) if (ids.Count == 0)
{ {
@ -157,7 +161,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
.WithoutContentEnrichment(true) .WithoutContentEnrichment(true)
.WithoutTotal()); .WithoutTotal());
var references = await ContentQuery.QueryAsync(queryContext, Q.Empty.WithIds(ids)); var references = await ContentQuery.QueryAsync(queryContext, Q.Empty.WithIds(ids), ct);
return references.ToLookup(x => x.Id); return references.ToLookup(x => x.Id);
} }

11
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -24,7 +25,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
this.scriptEngine = scriptEngine; this.scriptEngine = scriptEngine;
} }
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
if (ShouldEnrich(context)) if (ShouldEnrich(context))
{ {
@ -36,13 +38,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
if (!string.IsNullOrWhiteSpace(script)) if (!string.IsNullOrWhiteSpace(script))
{ {
await Task.WhenAll(group.Select(x => TransformAsync(context, script, x))); await Task.WhenAll(group.Select(x => TransformAsync(context, script, x, ct)));
} }
} }
} }
} }
private async Task TransformAsync(Context context, string script, ContentEntity content) private async Task TransformAsync(Context context, string script, ContentEntity content,
CancellationToken ct)
{ {
var vars = new ScriptVars var vars = new ScriptVars
{ {
@ -58,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps
AsContext = true AsContext = true
}; };
content.Data = await scriptEngine.TransformAsync(vars, script, options); content.Data = await scriptEngine.TransformAsync(vars, script, options, ct);
} }
private static bool ShouldEnrich(Context context) private static bool ShouldEnrich(Context context)

18
backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs

@ -20,22 +20,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.Repositories
{ {
public interface IContentRepository public interface IContentRepository
{ {
IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds, CancellationToken ct); IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds, CancellationToken ct = default);
Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q, SearchScope scope); Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q, SearchScope scope, CancellationToken ct = default);
Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q, SearchScope scope); Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q, SearchScope scope, CancellationToken ct = default);
Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode); Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode, CancellationToken ct = default);
Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids, SearchScope scope); Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids, SearchScope scope, CancellationToken ct = default);
Task<IContentEntity?> FindContentAsync(IAppEntity app, ISchemaEntity schema, DomainId id, SearchScope scope); Task<IContentEntity?> FindContentAsync(IAppEntity app, ISchemaEntity schema, DomainId id, SearchScope scope, CancellationToken ct = default);
Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId, SearchScope scope); Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId, SearchScope scope, CancellationToken ct = default);
Task ResetScheduledAsync(DomainId documentId); Task ResetScheduledAsync(DomainId documentId, CancellationToken ct = default);
Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback); Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback, CancellationToken ct = default);
} }
} }

8
backend/src/Squidex.Domain.Apps.Entities/Contents/Validation/DependencyValidatorsFactory.cs

@ -42,7 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Validation
{ {
var checkAssets = new CheckAssets(async ids => var checkAssets = new CheckAssets(async ids =>
{ {
return await assetRepository.QueryAsync(context.AppId.Id, null, Q.Empty.WithIds(ids)); return await assetRepository.QueryAsync(context.AppId.Id, null, Q.Empty.WithIds(ids), default);
}); });
yield return new AssetsValidator(isRequired, assetsField.Properties, checkAssets); yield return new AssetsValidator(isRequired, assetsField.Properties, checkAssets);
@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Validation
{ {
var checkReferences = new CheckContentsByIds(async ids => var checkReferences = new CheckContentsByIds(async ids =>
{ {
return await contentRepository.QueryIdsAsync(context.AppId.Id, ids, SearchScope.All); return await contentRepository.QueryIdsAsync(context.AppId.Id, ids, SearchScope.All, default);
}); });
yield return new ReferencesValidator(isRequired, referencesField.Properties, checkReferences); yield return new ReferencesValidator(isRequired, referencesField.Properties, checkReferences);
@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Validation
{ {
var checkUniqueness = new CheckUniqueness(async filter => var checkUniqueness = new CheckUniqueness(async filter =>
{ {
return await contentRepository.QueryIdsAsync(context.AppId.Id, context.SchemaId.Id, filter); return await contentRepository.QueryIdsAsync(context.AppId.Id, context.SchemaId.Id, filter, default);
}); });
yield return new UniqueValidator(checkUniqueness); yield return new UniqueValidator(checkUniqueness);
@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Validation
{ {
var checkUniqueness = new CheckUniqueness(async filter => var checkUniqueness = new CheckUniqueness(async filter =>
{ {
return await contentRepository.QueryIdsAsync(context.AppId.Id, context.SchemaId.Id, filter); return await contentRepository.QueryIdsAsync(context.AppId.Id, context.SchemaId.Id, filter, default);
}); });
yield return new UniqueValidator(checkUniqueness); yield return new UniqueValidator(checkUniqueness);

6
backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs

@ -48,10 +48,10 @@ namespace Squidex.Domain.Apps.Entities.Rules.Repositories
Task QueryPendingAsync(Instant now, Func<IRuleEventEntity, Task> callback, CancellationToken ct = default); Task QueryPendingAsync(Instant now, Func<IRuleEventEntity, Task> callback, CancellationToken ct = default);
Task<IReadOnlyList<RuleStatistics>> QueryStatisticsByAppAsync(DomainId appId); Task<IReadOnlyList<RuleStatistics>> QueryStatisticsByAppAsync(DomainId appId, CancellationToken ct = default);
Task<IResultList<IRuleEventEntity>> QueryByAppAsync(DomainId appId, DomainId? ruleId = null, int skip = 0, int take = 20); Task<IResultList<IRuleEventEntity>> QueryByAppAsync(DomainId appId, DomainId? ruleId = null, int skip = 0, int take = 20, CancellationToken ct = default);
Task<IRuleEventEntity> FindAsync(DomainId id); Task<IRuleEventEntity> FindAsync(DomainId id, CancellationToken ct = default);
} }
} }

4
backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
@ -31,7 +32,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas
this.urlGenerator = urlGenerator; this.urlGenerator = urlGenerator;
} }
public async Task<SearchResults> SearchAsync(string query, Context context) public async Task<SearchResults> SearchAsync(string query, Context context,
CancellationToken ct)
{ {
var result = new SearchResults(); var result = new SearchResults();

3
backend/src/Squidex.Domain.Apps.Entities/Search/ISearchManager.cs

@ -5,12 +5,13 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Entities.Search namespace Squidex.Domain.Apps.Entities.Search
{ {
public interface ISearchManager public interface ISearchManager
{ {
Task<SearchResults> SearchAsync(string? query, Context context); Task<SearchResults> SearchAsync(string? query, Context context, CancellationToken ct = default);
} }
} }

3
backend/src/Squidex.Domain.Apps.Entities/Search/ISearchSource.cs

@ -5,12 +5,13 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Entities.Search namespace Squidex.Domain.Apps.Entities.Search
{ {
public interface ISearchSource public interface ISearchSource
{ {
Task<SearchResults> SearchAsync(string query, Context context); Task<SearchResults> SearchAsync(string query, Context context, CancellationToken ct);
} }
} }

11
backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log; using Squidex.Log;
@ -30,25 +31,27 @@ namespace Squidex.Domain.Apps.Entities.Search
this.log = log; this.log = log;
} }
public async Task<SearchResults> SearchAsync(string? query, Context context) public async Task<SearchResults> SearchAsync(string? query, Context context,
CancellationToken ct = default)
{ {
if (string.IsNullOrWhiteSpace(query) || query.Length < 3) if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
{ {
return new SearchResults(); return new SearchResults();
} }
var tasks = searchSources.Select(x => SearchAsync(x, query, context)); var tasks = searchSources.Select(x => SearchAsync(x, query, context, ct));
var results = await Task.WhenAll(tasks); var results = await Task.WhenAll(tasks);
return new SearchResults(results.SelectMany(x => x)); return new SearchResults(results.SelectMany(x => x));
} }
private async Task<SearchResults> SearchAsync(ISearchSource source, string query, Context context) private async Task<SearchResults> SearchAsync(ISearchSource source, string query, Context context,
CancellationToken ct)
{ {
try try
{ {
return await source.SearchAsync(query, context); return await source.SearchAsync(query, context, ct);
} }
catch (Exception ex) catch (Exception ex)
{ {

5
backend/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs

@ -41,7 +41,8 @@ namespace Squidex.Domain.Users.MongoDb
return "Identity_Roles"; return "Identity_Roles";
} }
protected override Task SetupCollectionAsync(IMongoCollection<IdentityRole> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<IdentityRole> collection,
CancellationToken ct)
{ {
return collection.Indexes.CreateOneAsync( return collection.Indexes.CreateOneAsync(
new CreateIndexModel<IdentityRole>( new CreateIndexModel<IdentityRole>(
@ -123,4 +124,4 @@ namespace Squidex.Domain.Users.MongoDb
return Task.CompletedTask; return Task.CompletedTask;
} }
} }
} }

5
backend/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs

@ -138,7 +138,8 @@ namespace Squidex.Domain.Users.MongoDb
return "Identity_Users"; return "Identity_Users";
} }
protected override Task SetupCollectionAsync(IMongoCollection<MongoUser> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<MongoUser> collection,
CancellationToken ct)
{ {
return collection.Indexes.CreateManyAsync(new[] return collection.Indexes.CreateManyAsync(new[]
{ {
@ -601,4 +602,4 @@ namespace Squidex.Domain.Users.MongoDb
return Task.FromResult(false); return Task.FromResult(false);
} }
} }
} }

3
backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore.cs

@ -53,7 +53,8 @@ namespace Squidex.Infrastructure.EventSourcing
return new MongoCollectionSettings { WriteConcern = WriteConcern.WMajority }; return new MongoCollectionSettings { WriteConcern = WriteConcern.WMajority };
} }
protected override async Task SetupCollectionAsync(IMongoCollection<MongoEventCommit> collection, CancellationToken ct = default) protected override async Task SetupCollectionAsync(IMongoCollection<MongoEventCommit> collection,
CancellationToken ct)
{ {
await collection.Indexes.CreateManyAsync(new[] await collection.Indexes.CreateManyAsync(new[]
{ {

3
backend/src/Squidex.Infrastructure.MongoDb/Log/MongoRequestLogRepository.cs

@ -34,7 +34,8 @@ namespace Squidex.Infrastructure.Log
return "RequestLog"; return "RequestLog";
} }
protected override Task SetupCollectionAsync(IMongoCollection<MongoRequest> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<MongoRequest> collection,
CancellationToken ct = default)
{ {
return collection.Indexes.CreateManyAsync(new[] return collection.Indexes.CreateManyAsync(new[]
{ {

5
backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs

@ -84,7 +84,8 @@ namespace Squidex.Infrastructure.MongoDb
return string.Format(CultureInfo.InvariantCulture, CollectionFormat, typeof(TEntity).Name); return string.Format(CultureInfo.InvariantCulture, CollectionFormat, typeof(TEntity).Name);
} }
protected virtual Task SetupCollectionAsync(IMongoCollection<TEntity> collection, CancellationToken ct = default) protected virtual Task SetupCollectionAsync(IMongoCollection<TEntity> collection,
CancellationToken ct)
{ {
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -131,4 +132,4 @@ namespace Squidex.Infrastructure.MongoDb
CollectionSettings() ?? new MongoCollectionSettings()); CollectionSettings() ?? new MongoCollectionSettings());
} }
} }
} }

5
backend/src/Squidex.Infrastructure.MongoDb/UsageTracking/MongoUsageRepository.cs

@ -29,7 +29,8 @@ namespace Squidex.Infrastructure.UsageTracking
return "UsagesV2"; return "UsagesV2";
} }
protected override Task SetupCollectionAsync(IMongoCollection<MongoUsage> collection, CancellationToken ct = default) protected override Task SetupCollectionAsync(IMongoCollection<MongoUsage> collection,
CancellationToken ct = default)
{ {
return collection.Indexes.CreateOneAsync( return collection.Indexes.CreateOneAsync(
new CreateIndexModel<MongoUsage>( new CreateIndexModel<MongoUsage>(
@ -37,7 +38,7 @@ namespace Squidex.Infrastructure.UsageTracking
.Ascending(x => x.Key) .Ascending(x => x.Key)
.Ascending(x => x.Category) .Ascending(x => x.Category)
.Ascending(x => x.Date)), .Ascending(x => x.Date)),
cancellationToken: ct); cancellationToken: ct = default);
} }
public async Task TrackUsagesAsync(UsageUpdate update) public async Task TrackUsagesAsync(UsageUpdate update)

10
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs

@ -76,11 +76,11 @@ namespace Squidex.Areas.Api.Controllers.Assets
{ {
var requestContext = Context.Clone(b => b.WithoutAssetEnrichment()); var requestContext = Context.Clone(b => b.WithoutAssetEnrichment());
var asset = await assetQuery.FindAsync(requestContext, DomainId.Create(idOrSlug)); var asset = await assetQuery.FindAsync(requestContext, DomainId.Create(idOrSlug), ct: HttpContext.RequestAborted);
if (asset == null) if (asset == null)
{ {
asset = await assetQuery.FindBySlugAsync(requestContext, idOrSlug); asset = await assetQuery.FindBySlugAsync(requestContext, idOrSlug, HttpContext.RequestAborted);
} }
return await DeliverAssetAsync(requestContext, asset, request); return await DeliverAssetAsync(requestContext, asset, request);
@ -106,7 +106,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
{ {
var requestContext = Context.Clone(b => b.WithoutAssetEnrichment()); var requestContext = Context.Clone(b => b.WithoutAssetEnrichment());
var asset = await assetQuery.FindGlobalAsync(requestContext, id); var asset = await assetQuery.FindGlobalAsync(requestContext, id, HttpContext.RequestAborted);
return await DeliverAssetAsync(requestContext, asset, request); return await DeliverAssetAsync(requestContext, asset, request);
} }
@ -131,7 +131,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
{ {
if (context.App != null) if (context.App != null)
{ {
asset = await assetQuery.FindAsync(context, asset.Id, request.Version); asset = await assetQuery.FindAsync(context, asset.Id, request.Version, HttpContext.RequestAborted);
} }
else else
{ {
@ -265,4 +265,4 @@ namespace Squidex.Areas.Api.Controllers.Assets
FileOptions.SequentialScan); FileOptions.SequentialScan);
} }
} }
} }

4
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs

@ -54,8 +54,8 @@ namespace Squidex.Areas.Api.Controllers.Assets
public async Task<IActionResult> GetAssetFolders(string app, [FromQuery] DomainId parentId) public async Task<IActionResult> GetAssetFolders(string app, [FromQuery] DomainId parentId)
{ {
var (folders, path) = await AsyncHelper.WhenAll( var (folders, path) = await AsyncHelper.WhenAll(
assetQuery.QueryAssetFoldersAsync(Context, parentId), assetQuery.QueryAssetFoldersAsync(Context, parentId, HttpContext.RequestAborted),
assetQuery.FindAssetFolderAsync(Context.App.Id, parentId)); assetQuery.FindAssetFolderAsync(Context.App.Id, parentId, HttpContext.RequestAborted));
var response = Deferred.Response(() => var response = Deferred.Response(() =>
{ {

6
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs

@ -98,7 +98,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetAssets(string app, [FromQuery] DomainId? parentId, [FromQuery] string? ids = null, [FromQuery] string? q = null) public async Task<IActionResult> GetAssets(string app, [FromQuery] DomainId? parentId, [FromQuery] string? ids = null, [FromQuery] string? q = null)
{ {
var assets = await assetQuery.QueryAsync(Context, parentId, CreateQuery(ids, q)); var assets = await assetQuery.QueryAsync(Context, parentId, CreateQuery(ids, q), HttpContext.RequestAborted);
var response = Deferred.Response(() => var response = Deferred.Response(() =>
{ {
@ -127,7 +127,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetAssetsPost(string app, [FromBody] QueryDto query) public async Task<IActionResult> GetAssetsPost(string app, [FromBody] QueryDto query)
{ {
var assets = await assetQuery.QueryAsync(Context, query?.ParentId, query?.ToQuery() ?? Q.Empty); var assets = await assetQuery.QueryAsync(Context, query?.ParentId, query?.ToQuery() ?? Q.Empty, HttpContext.RequestAborted);
var response = Deferred.Response(() => var response = Deferred.Response(() =>
{ {
@ -153,7 +153,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetAsset(string app, DomainId id) public async Task<IActionResult> GetAsset(string app, DomainId id)
{ {
var asset = await assetQuery.FindAsync(Context, id); var asset = await assetQuery.FindAsync(Context, id, ct: HttpContext.RequestAborted);
if (asset == null) if (asset == null)
{ {

16
backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs

@ -83,7 +83,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetAllContents(string app, [FromQuery] string ids) public async Task<IActionResult> GetAllContents(string app, [FromQuery] string ids)
{ {
var contents = await contentQuery.QueryAsync(Context, Q.Empty.WithIds(ids)); var contents = await contentQuery.QueryAsync(Context, Q.Empty.WithIds(ids), HttpContext.RequestAborted);
var response = Deferred.AsyncResponse(() => var response = Deferred.AsyncResponse(() =>
{ {
@ -112,7 +112,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetAllContentsPost(string app, [FromBody] ContentsIdsQueryDto query) public async Task<IActionResult> GetAllContentsPost(string app, [FromBody] ContentsIdsQueryDto query)
{ {
var contents = await contentQuery.QueryAsync(Context, Q.Empty.WithIds(query.Ids)); var contents = await contentQuery.QueryAsync(Context, Q.Empty.WithIds(query.Ids), HttpContext.RequestAborted);
var response = Deferred.AsyncResponse(() => var response = Deferred.AsyncResponse(() =>
{ {
@ -143,7 +143,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetContents(string app, string schema, [FromQuery] string? ids = null, [FromQuery] string? q = null) public async Task<IActionResult> GetContents(string app, string schema, [FromQuery] string? ids = null, [FromQuery] string? q = null)
{ {
var contents = await contentQuery.QueryAsync(Context, schema, CreateQuery(ids, q)); var contents = await contentQuery.QueryAsync(Context, schema, CreateQuery(ids, q), HttpContext.RequestAborted);
var response = Deferred.AsyncResponse(() => var response = Deferred.AsyncResponse(() =>
{ {
@ -173,7 +173,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetContentsPost(string app, string schema, [FromBody] QueryDto query) public async Task<IActionResult> GetContentsPost(string app, string schema, [FromBody] QueryDto query)
{ {
var contents = await contentQuery.QueryAsync(Context, schema, query?.ToQuery() ?? Q.Empty); var contents = await contentQuery.QueryAsync(Context, schema, query?.ToQuery() ?? Q.Empty, HttpContext.RequestAborted);
var response = Deferred.AsyncResponse(() => var response = Deferred.AsyncResponse(() =>
{ {
@ -203,7 +203,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetContent(string app, string schema, DomainId id) public async Task<IActionResult> GetContent(string app, string schema, DomainId id)
{ {
var content = await contentQuery.FindAsync(Context, schema, id); var content = await contentQuery.FindAsync(Context, schema, id, ct: HttpContext.RequestAborted);
if (content == null) if (content == null)
{ {
@ -263,7 +263,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetReferences(string app, string schema, DomainId id, [FromQuery] string? q = null) public async Task<IActionResult> GetReferences(string app, string schema, DomainId id, [FromQuery] string? q = null)
{ {
var contents = await contentQuery.QueryAsync(Context, CreateQuery(null, q).WithReferencing(id)); var contents = await contentQuery.QueryAsync(Context, CreateQuery(null, q).WithReferencing(id), HttpContext.RequestAborted);
var response = Deferred.AsyncResponse(() => var response = Deferred.AsyncResponse(() =>
{ {
@ -294,7 +294,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetReferencing(string app, string schema, DomainId id, [FromQuery] string? q = null) public async Task<IActionResult> GetReferencing(string app, string schema, DomainId id, [FromQuery] string? q = null)
{ {
var contents = await contentQuery.QueryAsync(Context, CreateQuery(null, q).WithReference(id)); var contents = await contentQuery.QueryAsync(Context, CreateQuery(null, q).WithReference(id), HttpContext.RequestAborted);
var response = Deferred.AsyncResponse(() => var response = Deferred.AsyncResponse(() =>
{ {
@ -324,7 +324,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetContentVersion(string app, string schema, DomainId id, int version) public async Task<IActionResult> GetContentVersion(string app, string schema, DomainId id, int version)
{ {
var content = await contentQuery.FindAsync(Context, schema, id, version); var content = await contentQuery.FindAsync(Context, schema, id, version, HttpContext.RequestAborted);
if (content == null) if (content == null)
{ {

2
backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs

@ -47,7 +47,7 @@ namespace Squidex.Areas.Api.Controllers.Search
[ApiCosts(0)] [ApiCosts(0)]
public async Task<IActionResult> GetSearchResults(string app, [FromQuery] string? query = null) public async Task<IActionResult> GetSearchResults(string app, [FromQuery] string? query = null)
{ {
var result = await searchManager.SearchAsync(query, Context); var result = await searchManager.SearchAsync(query, Context, HttpContext.RequestAborted);
var response = result.Select(SearchResultDto.FromSearchResult).ToArray(); var response = result.Select(SearchResultDto.FromSearchResult).ToArray();

50
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs

@ -35,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("xyz", ctx); var result = await sut.SearchAsync("xyz", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.DashboardUI(appId)) A.CallTo(() => urlGenerator.DashboardUI(appId))
.Returns("dashboard-url"); .Returns("dashboard-url");
var result = await sut.SearchAsync("dashboard", ctx); var result = await sut.SearchAsync("dashboard", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("assets", ctx); var result = await sut.SearchAsync("assets", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.LanguagesUI(appId)) A.CallTo(() => urlGenerator.LanguagesUI(appId))
.Returns("languages-url"); .Returns("languages-url");
var result = await sut.SearchAsync("languages", ctx); var result = await sut.SearchAsync("languages", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -89,7 +89,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("assets", ctx); var result = await sut.SearchAsync("assets", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -99,7 +99,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("patterns", ctx); var result = await sut.SearchAsync("patterns", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -114,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.SchemasUI(appId)) A.CallTo(() => urlGenerator.SchemasUI(appId))
.Returns("schemas-url"); .Returns("schemas-url");
var result = await sut.SearchAsync("schemas", ctx); var result = await sut.SearchAsync("schemas", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -126,7 +126,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("schemas", ctx); var result = await sut.SearchAsync("schemas", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -141,7 +141,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.AssetsUI(appId, A<string?>._)) A.CallTo(() => urlGenerator.AssetsUI(appId, A<string?>._))
.Returns("assets-url"); .Returns("assets-url");
var result = await sut.SearchAsync("assets", ctx); var result = await sut.SearchAsync("assets", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -153,7 +153,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("assets", ctx); var result = await sut.SearchAsync("assets", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -168,7 +168,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.BackupsUI(appId)) A.CallTo(() => urlGenerator.BackupsUI(appId))
.Returns("backups-url"); .Returns("backups-url");
var result = await sut.SearchAsync("backups", ctx); var result = await sut.SearchAsync("backups", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -180,7 +180,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("backups", ctx); var result = await sut.SearchAsync("backups", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -195,7 +195,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.ClientsUI(appId)) A.CallTo(() => urlGenerator.ClientsUI(appId))
.Returns("clients-url"); .Returns("clients-url");
var result = await sut.SearchAsync("clients", ctx); var result = await sut.SearchAsync("clients", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -207,7 +207,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("clients", ctx); var result = await sut.SearchAsync("clients", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -222,7 +222,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.ContributorsUI(appId)) A.CallTo(() => urlGenerator.ContributorsUI(appId))
.Returns("contributors-url"); .Returns("contributors-url");
var result = await sut.SearchAsync("contributors", ctx); var result = await sut.SearchAsync("contributors", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -234,7 +234,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("contributors", ctx); var result = await sut.SearchAsync("contributors", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -249,7 +249,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.PlansUI(appId)) A.CallTo(() => urlGenerator.PlansUI(appId))
.Returns("subscription-url"); .Returns("subscription-url");
var result = await sut.SearchAsync("subscription", ctx); var result = await sut.SearchAsync("subscription", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -261,7 +261,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("subscription", ctx); var result = await sut.SearchAsync("subscription", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -276,7 +276,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.RolesUI(appId)) A.CallTo(() => urlGenerator.RolesUI(appId))
.Returns("roles-url"); .Returns("roles-url");
var result = await sut.SearchAsync("roles", ctx); var result = await sut.SearchAsync("roles", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -288,7 +288,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("roles", ctx); var result = await sut.SearchAsync("roles", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -303,7 +303,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.RulesUI(appId)) A.CallTo(() => urlGenerator.RulesUI(appId))
.Returns("rules-url"); .Returns("rules-url");
var result = await sut.SearchAsync("rules", ctx); var result = await sut.SearchAsync("rules", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -315,7 +315,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("assets", ctx); var result = await sut.SearchAsync("assets", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -330,7 +330,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => urlGenerator.WorkflowsUI(appId)) A.CallTo(() => urlGenerator.WorkflowsUI(appId))
.Returns("workflows-url"); .Returns("workflows-url");
var result = await sut.SearchAsync("workflows", ctx); var result = await sut.SearchAsync("workflows", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()
@ -342,7 +342,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("workflows", ctx); var result = await sut.SearchAsync("workflows", ctx, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -360,4 +360,4 @@ namespace Squidex.Domain.Apps.Entities.Apps
return new Context(claimsPrincipal, Mocks.App(appId)); return new Context(claimsPrincipal, Mocks.App(appId));
} }
} }
} }

5
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -62,10 +63,10 @@ namespace Squidex.Domain.Apps.Entities.Assets
AppId = appId AppId = appId
}; };
A.CallTo(() => assetQuery.FindAsync(A<Context>._, assetId1, EtagVersion.Any)) A.CallTo(() => assetQuery.FindAsync(A<Context>._, assetId1, EtagVersion.Any, A<CancellationToken>._))
.Returns(asset1); .Returns(asset1);
A.CallTo(() => assetQuery.FindAsync(A<Context>._, assetId2, EtagVersion.Any)) A.CallTo(() => assetQuery.FindAsync(A<Context>._, assetId2, EtagVersion.Any, A<CancellationToken>._))
.Returns(asset2); .Returns(asset2);
var vars = new TemplateVars var vars = new TemplateVars

5
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
@ -62,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
.AddInvariant(JsonValue.Array(assetId1))); .AddInvariant(JsonValue.Array(assetId1)));
A.CallTo(() => assetQuery.QueryAsync( A.CallTo(() => assetQuery.QueryAsync(
A<Context>.That.Matches(x => x.App.Id == appId.Id && x.User == user), null, A<Q>.That.HasIds(assetId1))) A<Context>.That.Matches(x => x.App.Id == appId.Id && x.User == user), null, A<Q>.That.HasIds(assetId1), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, asset1)); .Returns(ResultList.CreateFrom(1, asset1));
var vars = new ScriptVars { Data = data, AppId = appId.Id, User = user }; var vars = new ScriptVars { Data = data, AppId = appId.Id, User = user };
@ -100,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
.AddInvariant(JsonValue.Array(assetId1, assetId2))); .AddInvariant(JsonValue.Array(assetId1, assetId2)));
A.CallTo(() => assetQuery.QueryAsync( A.CallTo(() => assetQuery.QueryAsync(
A<Context>.That.Matches(x => x.App.Id == appId.Id && x.User == user), null, A<Q>.That.HasIds(assetId1, assetId2))) A<Context>.That.Matches(x => x.App.Id == appId.Id && x.User == user), null, A<Q>.That.HasIds(assetId1, assetId2), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(2, asset1, asset2)); .Returns(ResultList.CreateFrom(2, asset1, asset2));
var vars = new ScriptVars { Data = data, AppId = appId.Id, User = user }; var vars = new ScriptVars { Data = data, AppId = appId.Id, User = user };

9
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using FluentAssertions; using FluentAssertions;
@ -36,11 +37,11 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
var ctx = ContextWithPermission(); var ctx = ContextWithPermission();
var result = await sut.SearchAsync("logo", ctx); var result = await sut.SearchAsync("logo", ctx, default);
Assert.Empty(result); Assert.Empty(result);
A.CallTo(() => assetQuery.QueryAsync(A<Context>._, A<DomainId?>._, A<Q>._)) A.CallTo(() => assetQuery.QueryAsync(A<Context>._, A<DomainId?>._, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -57,10 +58,10 @@ namespace Squidex.Domain.Apps.Entities.Assets
A.CallTo(() => urlGenerator.AssetsUI(appId, "logo")) A.CallTo(() => urlGenerator.AssetsUI(appId, "logo"))
.Returns("assets-url"); .Returns("assets-url");
A.CallTo(() => assetQuery.QueryAsync(ctx, null, A<Q>.That.HasQuery("Filter: contains(fileName, 'logo'); Take: 5"))) A.CallTo(() => assetQuery.QueryAsync(ctx, null, A<Q>.That.HasQuery("Filter: contains(fileName, 'logo'); Take: 5"), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(2, asset1, asset2)); .Returns(ResultList.CreateFrom(2, asset1, asset2));
var result = await sut.SearchAsync("logo", ctx); var result = await sut.SearchAsync("logo", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs

@ -229,7 +229,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
var rebuildAssets = new HashSet<DomainId>(); var rebuildAssets = new HashSet<DomainId>();
A.CallTo(() => rebuilder.InsertManyAsync<AssetDomainObject, AssetDomainObject.State>(A<IEnumerable<DomainId>>._, A<int>._, A<CancellationToken>._)) A.CallTo(() => rebuilder.InsertManyAsync<AssetDomainObject, AssetDomainObject.State>(A<IEnumerable<DomainId>>._, A<int>._, A<CancellationToken>._))
.Invokes((IEnumerable<DomainId> source, CancellationToken _) => rebuildAssets.AddRange(source)); .Invokes((IEnumerable<DomainId> source, int _, CancellationToken _) => rebuildAssets.AddRange(source));
await sut.RestoreAsync(context); await sut.RestoreAsync(context);
@ -266,7 +266,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
var rebuildAssetFolders = new HashSet<DomainId>(); var rebuildAssetFolders = new HashSet<DomainId>();
A.CallTo(() => rebuilder.InsertManyAsync<AssetFolderDomainObject, AssetFolderDomainObject.State>(A<IEnumerable<DomainId>>._, A<int>._, A<CancellationToken>._)) A.CallTo(() => rebuilder.InsertManyAsync<AssetFolderDomainObject, AssetFolderDomainObject.State>(A<IEnumerable<DomainId>>._, A<int>._, A<CancellationToken>._))
.Invokes((IEnumerable<DomainId> source, CancellationToken _) => rebuildAssetFolders.AddRange(source)); .Invokes((IEnumerable<DomainId> source, int _, CancellationToken _) => rebuildAssetFolders.AddRange(source));
await sut.RestoreAsync(context); await sut.RestoreAsync(context);

10
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs

@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
A.CallTo(() => contextProvider.Context) A.CallTo(() => contextProvider.Context)
.Returns(requestContext); .Returns(requestContext);
A.CallTo(() => assetQuery.FindByHashAsync(A<Context>._, A<string>._, A<string>._, A<long>._)) A.CallTo(() => assetQuery.FindByHashAsync(A<Context>._, A<string>._, A<string>._, A<long>._, A<CancellationToken>._))
.Returns(Task.FromResult<IEnrichedAssetEntity?>(null)); .Returns(Task.FromResult<IEnrichedAssetEntity?>(null));
sut = new AssetCommandMiddleware(grainFactory, sut = new AssetCommandMiddleware(grainFactory,
@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
await HandleAsync(new AnnotateAsset(), 12); await HandleAsync(new AnnotateAsset(), 12);
A.CallTo(() => assetEnricher.EnrichAsync(A<IEnrichedAssetEntity>._, requestContext)) A.CallTo(() => assetEnricher.EnrichAsync(A<IEnrichedAssetEntity>._, requestContext, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
await HandleAsync(new AnnotateAsset(), await HandleAsync(new AnnotateAsset(),
result); result);
A.CallTo(() => assetEnricher.EnrichAsync(A<IEnrichedAssetEntity>._, requestContext)) A.CallTo(() => assetEnricher.EnrichAsync(A<IEnrichedAssetEntity>._, requestContext, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -89,7 +89,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
var enriched = new AssetEntity(); var enriched = new AssetEntity();
A.CallTo(() => assetEnricher.EnrichAsync(result, requestContext)) A.CallTo(() => assetEnricher.EnrichAsync(result, requestContext, A<CancellationToken>._))
.Returns(enriched); .Returns(enriched);
var context = var context =
@ -206,7 +206,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
FileSize = fileSize FileSize = fileSize
}; };
A.CallTo(() => assetQuery.FindByHashAsync(requestContext, A<string>._, fileName, fileSize)) A.CallTo(() => assetQuery.FindByHashAsync(requestContext, A<string>._, fileName, fileSize, A<CancellationToken>._))
.Returns(duplicate); .Returns(duplicate);
} }

9
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Assets; using Squidex.Assets;
@ -40,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
public AssetDomainObjectTests() public AssetDomainObjectTests()
{ {
A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity> { A.Fake<IAssetFolderEntity>() }); .Returns(new List<IAssetFolderEntity> { A.Fake<IAssetFolderEntity>() });
A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A<HashSet<string>>._, A<HashSet<string>>._)) A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A<HashSet<string>>._, A<HashSet<string>>._))
@ -330,7 +331,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
await ExecuteCreateAsync(); await ExecuteCreateAsync();
A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All, A<CancellationToken>._))
.Returns(true); .Returns(true);
var result = await PublishAsync(command); var result = await PublishAsync(command);
@ -348,7 +349,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
await ExecuteCreateAsync(); await ExecuteCreateAsync();
A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All, A<CancellationToken>._))
.Returns(true); .Returns(true);
await Assert.ThrowsAsync<DomainException>(() => PublishAsync(command)); await Assert.ThrowsAsync<DomainException>(() => PublishAsync(command));
@ -361,7 +362,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
await ExecuteCreateAsync(); await ExecuteCreateAsync();
A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All, A<CancellationToken>._))
.Returns(true); .Returns(true);
await PublishAsync(command); await PublishAsync(command);

3
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
@ -31,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
public AssetFolderDomainObjectTests() public AssetFolderDomainObjectTests()
{ {
A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity> { A.Fake<IAssetFolderEntity>() }); .Returns(new List<IAssetFolderEntity> { A.Fake<IAssetFolderEntity>() });
sut = new AssetFolderDomainObject(PersistenceFactory, A.Dummy<ISemanticLog>(), assetQuery); sut = new AssetFolderDomainObject(PersistenceFactory, A.Dummy<ISemanticLog>(), assetQuery);

13
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetFolderTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
@ -27,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
{ {
var command = new CreateAssetFolder { AppId = appId }; var command = new CreateAssetFolder { AppId = appId };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity>()); .Returns(new List<IAssetFolderEntity>());
await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanCreate(command, assetQuery), await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanCreate(command, assetQuery),
@ -39,7 +40,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
{ {
var command = new CreateAssetFolder { AppId = appId, FolderName = "My Folder", ParentId = DomainId.NewGuid() }; var command = new CreateAssetFolder { AppId = appId, FolderName = "My Folder", ParentId = DomainId.NewGuid() };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity>()); .Returns(new List<IAssetFolderEntity>());
await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanCreate(command, assetQuery), await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanCreate(command, assetQuery),
@ -51,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
{ {
var command = new CreateAssetFolder { AppId = appId, FolderName = "My Folder", ParentId = DomainId.NewGuid() }; var command = new CreateAssetFolder { AppId = appId, FolderName = "My Folder", ParentId = DomainId.NewGuid() };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity> { AssetFolder() }); .Returns(new List<IAssetFolderEntity> { AssetFolder() });
await GuardAssetFolder.CanCreate(command, assetQuery); await GuardAssetFolder.CanCreate(command, assetQuery);
@ -72,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() }; var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity> .Returns(new List<IAssetFolderEntity>
{ {
AssetFolder(id), AssetFolder(id),
@ -88,7 +89,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
{ {
var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() }; var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity>()); .Returns(new List<IAssetFolderEntity>());
await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanMove(command, AssetFolder(), assetQuery), await ValidationAssert.ThrowsAsync(() => GuardAssetFolder.CanMove(command, AssetFolder(), assetQuery),
@ -100,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
{ {
var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() }; var command = new MoveAssetFolder { AppId = appId, ParentId = DomainId.NewGuid() };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity> { AssetFolder() }); .Returns(new List<IAssetFolderEntity> { AssetFolder() });
await GuardAssetFolder.CanMove(command, AssetFolder(), assetQuery); await GuardAssetFolder.CanMove(command, AssetFolder(), assetQuery);

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetTests.cs

@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
var command = new MoveAsset { AppId = appId, ParentId = parentId }; var command = new MoveAsset { AppId = appId, ParentId = parentId };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, default))
.Returns(new List<IAssetFolderEntity>()); .Returns(new List<IAssetFolderEntity>());
await ValidationAssert.ThrowsAsync(() => GuardAsset.CanMove(command, Asset(), assetQuery), await ValidationAssert.ThrowsAsync(() => GuardAsset.CanMove(command, Asset(), assetQuery),
@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
var command = new MoveAsset { AppId = appId, ParentId = parentId, OptimizeValidation = true }; var command = new MoveAsset { AppId = appId, ParentId = parentId, OptimizeValidation = true };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, default))
.Returns(new List<IAssetFolderEntity>()); .Returns(new List<IAssetFolderEntity>());
await GuardAsset.CanMove(command, Asset(), assetQuery); await GuardAsset.CanMove(command, Asset(), assetQuery);
@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
var command = new MoveAsset { AppId = appId, ParentId = parentId }; var command = new MoveAsset { AppId = appId, ParentId = parentId };
A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId)) A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, command.ParentId, default))
.Returns(new List<IAssetFolderEntity> { AssetFolder() }); .Returns(new List<IAssetFolderEntity> { AssetFolder() });
await GuardAsset.CanMove(command, Asset(), assetQuery); await GuardAsset.CanMove(command, Asset(), assetQuery);
@ -90,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
var command = new DeleteAsset { AppId = appId, CheckReferrers = true }; var command = new DeleteAsset { AppId = appId, CheckReferrers = true };
A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, asset.Id, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, asset.Id, SearchScope.All, default))
.Returns(true); .Returns(true);
await Assert.ThrowsAsync<DomainException>(() => GuardAsset.CanDelete(command, asset, contentRepository)); await Assert.ThrowsAsync<DomainException>(() => GuardAsset.CanDelete(command, asset, contentRepository));

12
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs

@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var source = new AssetEntity { AppId = appId }; var source = new AssetEntity { AppId = appId };
var result = await sut.EnrichAsync(source, requestContext); var result = await sut.EnrichAsync(source, requestContext, default);
Assert.Empty(result.TagNames); Assert.Empty(result.TagNames);
} }
@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var source = new AssetEntity { AppId = appId, Id = DomainId.NewGuid(), Version = 13 }; var source = new AssetEntity { AppId = appId, Id = DomainId.NewGuid(), Version = 13 };
var result = await sut.EnrichAsync(source, requestContext); var result = await sut.EnrichAsync(source, requestContext, default);
A.CallTo(() => requestCache.AddDependency(result.UniqueId, result.Version)) A.CallTo(() => requestCache.AddDependency(result.UniqueId, result.Version))
.MustHaveHappened(); .MustHaveHappened();
@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
["id2"] = "name2" ["id2"] = "name2"
}); });
var result = await sut.EnrichAsync(source, requestContext); var result = await sut.EnrichAsync(source, requestContext, default);
Assert.Equal(new HashSet<string> { "name1", "name2" }, result.TagNames); Assert.Equal(new HashSet<string> { "name1", "name2" }, result.TagNames);
} }
@ -99,7 +99,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
AppId = appId AppId = appId
}; };
var result = await sut.EnrichAsync(source, requestContext.Clone(b => b.WithoutAssetEnrichment())); var result = await sut.EnrichAsync(source, requestContext.Clone(b => b.WithoutAssetEnrichment()), default);
Assert.Null(result.TagNames); Assert.Null(result.TagNames);
} }
@ -124,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
A.CallTo(() => assetMetadataSource2.Format(A<IAssetEntity>._)) A.CallTo(() => assetMetadataSource2.Format(A<IAssetEntity>._))
.Returns(new[] { "metadata2", "metadata3" }); .Returns(new[] { "metadata2", "metadata3" });
var result = await sut.EnrichAsync(source, requestContext); var result = await sut.EnrichAsync(source, requestContext, default);
Assert.Equal("metadata1, metadata2, metadata3, 2 kB", result.MetadataText); Assert.Equal("metadata1, metadata2, metadata3, 2 kB", result.MetadataText);
} }
@ -160,7 +160,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
["id3"] = "name3" ["id3"] = "name3"
}); });
var result = await sut.EnrichAsync(new[] { source1, source2 }, requestContext); var result = await sut.EnrichAsync(new[] { source1, source2 }, requestContext, default);
Assert.Equal(new HashSet<string> { "name1", "name2" }, result[0].TagNames); Assert.Equal(new HashSet<string> { "name1", "name2" }, result[0].TagNames);
Assert.Equal(new HashSet<string> { "name2", "name3" }, result[1].TagNames); Assert.Equal(new HashSet<string> { "name2", "name3" }, result[1].TagNames);

45
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Assets.Repositories;
@ -45,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetBySlugAsync(appId.Id, "slug")) A.CallTo(() => assetRepository.FindAssetBySlugAsync(appId.Id, "slug", A<CancellationToken>._))
.Returns(asset); .Returns(asset);
var result = await sut.FindBySlugAsync(requestContext, "slug"); var result = await sut.FindBySlugAsync(requestContext, "slug");
@ -58,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetBySlugAsync(appId.Id, "slug")) A.CallTo(() => assetRepository.FindAssetBySlugAsync(appId.Id, "slug", A<CancellationToken>._))
.Returns(Task.FromResult<IAssetEntity?>(null)); .Returns(Task.FromResult<IAssetEntity?>(null));
var result = await sut.FindBySlugAsync(requestContext, "slug"); var result = await sut.FindBySlugAsync(requestContext, "slug");
@ -71,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetAsync(appId.Id, asset.Id)) A.CallTo(() => assetRepository.FindAssetAsync(appId.Id, asset.Id, A<CancellationToken>._))
.Returns(asset); .Returns(asset);
var result = await sut.FindAsync(requestContext, asset.Id); var result = await sut.FindAsync(requestContext, asset.Id);
@ -84,7 +85,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetAsync(appId.Id, asset.Id)) A.CallTo(() => assetRepository.FindAssetAsync(appId.Id, asset.Id, A<CancellationToken>._))
.Returns(Task.FromResult<IAssetEntity?>(null)); .Returns(Task.FromResult<IAssetEntity?>(null));
var result = await sut.FindAsync(requestContext, asset.Id); var result = await sut.FindAsync(requestContext, asset.Id);
@ -123,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetAsync(asset.Id)) A.CallTo(() => assetRepository.FindAssetAsync(asset.Id, A<CancellationToken>._))
.Returns(asset); .Returns(asset);
var result = await sut.FindGlobalAsync(requestContext, asset.Id); var result = await sut.FindGlobalAsync(requestContext, asset.Id);
@ -136,7 +137,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetAsync(asset.Id)) A.CallTo(() => assetRepository.FindAssetAsync(asset.Id, A<CancellationToken>._))
.Returns(Task.FromResult<IAssetEntity?>(null)); .Returns(Task.FromResult<IAssetEntity?>(null));
var result = await sut.FindGlobalAsync(requestContext, asset.Id); var result = await sut.FindGlobalAsync(requestContext, asset.Id);
@ -149,7 +150,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetByHashAsync(appId.Id, "hash", "name", 123)) A.CallTo(() => assetRepository.FindAssetByHashAsync(appId.Id, "hash", "name", 123, A<CancellationToken>._))
.Returns(asset); .Returns(asset);
var result = await sut.FindByHashAsync(requestContext, "hash", "name", 123); var result = await sut.FindByHashAsync(requestContext, "hash", "name", 123);
@ -162,7 +163,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var asset = CreateAsset(DomainId.NewGuid()); var asset = CreateAsset(DomainId.NewGuid());
A.CallTo(() => assetRepository.FindAssetByHashAsync(appId.Id, "hash", "name", 123)) A.CallTo(() => assetRepository.FindAssetByHashAsync(appId.Id, "hash", "name", 123, A<CancellationToken>._))
.Returns(Task.FromResult<IAssetEntity?>(null)); .Returns(Task.FromResult<IAssetEntity?>(null));
var result = await sut.FindByHashAsync(requestContext, "hash", "name", 123); var result = await sut.FindByHashAsync(requestContext, "hash", "name", 123);
@ -180,7 +181,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
var q = Q.Empty.WithODataQuery("fileName eq 'Name'"); var q = Q.Empty.WithODataQuery("fileName eq 'Name'");
A.CallTo(() => assetRepository.QueryAsync(appId.Id, parentId, q)) A.CallTo(() => assetRepository.QueryAsync(appId.Id, parentId, q, A<CancellationToken>._))
.Returns(ResultList.CreateFrom(8, asset1, asset2)); .Returns(ResultList.CreateFrom(8, asset1, asset2));
var result = await sut.QueryAsync(requestContext, parentId, q); var result = await sut.QueryAsync(requestContext, parentId, q);
@ -198,7 +199,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
var assetFolders = ResultList.CreateFrom<IAssetFolderEntity>(10); var assetFolders = ResultList.CreateFrom<IAssetFolderEntity>(10);
A.CallTo(() => assetFolderRepository.QueryAsync(appId.Id, parentId)) A.CallTo(() => assetFolderRepository.QueryAsync(appId.Id, parentId, A<CancellationToken>._))
.Returns(assetFolders); .Returns(assetFolders);
var result = await sut.QueryAssetFoldersAsync(requestContext, parentId); var result = await sut.QueryAssetFoldersAsync(requestContext, parentId);
@ -213,7 +214,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
var assetFolders = ResultList.CreateFrom<IAssetFolderEntity>(10); var assetFolders = ResultList.CreateFrom<IAssetFolderEntity>(10);
A.CallTo(() => assetFolderRepository.QueryAsync(appId.Id, parentId)) A.CallTo(() => assetFolderRepository.QueryAsync(appId.Id, parentId, A<CancellationToken>._))
.Returns(assetFolders); .Returns(assetFolders);
var result = await sut.QueryAssetFoldersAsync(appId.Id, parentId); var result = await sut.QueryAssetFoldersAsync(appId.Id, parentId);
@ -227,7 +228,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
var folderId1 = DomainId.NewGuid(); var folderId1 = DomainId.NewGuid();
var folder1 = CreateFolder(folderId1); var folder1 = CreateFolder(folderId1);
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A<CancellationToken>._))
.Returns(folder1); .Returns(folder1);
var result = await sut.FindAssetFolderAsync(appId.Id, folderId1); var result = await sut.FindAssetFolderAsync(appId.Id, folderId1);
@ -246,13 +247,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
var folder2 = CreateFolder(folderId2, folderId1); var folder2 = CreateFolder(folderId2, folderId1);
var folder3 = CreateFolder(folderId3, folderId2); var folder3 = CreateFolder(folderId3, folderId2);
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A<CancellationToken>._))
.Returns(folder1); .Returns(folder1);
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2, A<CancellationToken>._))
.Returns(folder2); .Returns(folder2);
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId3)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId3, A<CancellationToken>._))
.Returns(folder3); .Returns(folder3);
var result = await sut.FindAssetFolderAsync(appId.Id, folderId3); var result = await sut.FindAssetFolderAsync(appId.Id, folderId3);
@ -265,7 +266,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
var folderId1 = DomainId.NewGuid(); var folderId1 = DomainId.NewGuid();
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A<CancellationToken>._))
.Returns(Task.FromResult<IAssetFolderEntity?>(null)); .Returns(Task.FromResult<IAssetFolderEntity?>(null));
var result = await sut.FindAssetFolderAsync(appId.Id, folderId1); var result = await sut.FindAssetFolderAsync(appId.Id, folderId1);
@ -282,10 +283,10 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
var folder1 = CreateFolder(folderId1); var folder1 = CreateFolder(folderId1);
var folder2 = CreateFolder(folderId2, folderId1); var folder2 = CreateFolder(folderId2, folderId1);
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A<CancellationToken>._))
.Returns(Task.FromResult<IAssetFolderEntity?>(null)); .Returns(Task.FromResult<IAssetFolderEntity?>(null));
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2, A<CancellationToken>._))
.Returns(folder2); .Returns(folder2);
var result = await sut.FindAssetFolderAsync(appId.Id, folderId2); var result = await sut.FindAssetFolderAsync(appId.Id, folderId2);
@ -302,10 +303,10 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
var folder1 = CreateFolder(folderId1, folderId2); var folder1 = CreateFolder(folderId1, folderId2);
var folder2 = CreateFolder(folderId2, folderId1); var folder2 = CreateFolder(folderId2, folderId1);
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A<CancellationToken>._))
.Returns(Task.FromResult<IAssetFolderEntity?>(null)); .Returns(Task.FromResult<IAssetFolderEntity?>(null));
A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2)) A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2, A<CancellationToken>._))
.Returns(folder2); .Returns(folder2);
var result = await sut.FindAssetFolderAsync(appId.Id, folderId2); var result = await sut.FindAssetFolderAsync(appId.Id, folderId2);
@ -337,7 +338,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
private void SetupEnricher() private void SetupEnricher()
{ {
A.CallTo(() => assetEnricher.EnrichAsync(A<IEnumerable<IAssetEntity>>._, A<Context>._)) A.CallTo(() => assetEnricher.EnrichAsync(A<IEnumerable<IAssetEntity>>._, A<Context>._, A<CancellationToken>._))
.ReturnsLazily(x => .ReturnsLazily(x =>
{ {
var input = x.GetArgument<IEnumerable<IAssetEntity>>(0)!; var input = x.GetArgument<IEnumerable<IAssetEntity>>(0)!;
@ -346,4 +347,4 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
}); });
} }
} }
} }

7
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
@ -80,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
var childFolderId1 = DomainId.NewGuid(); var childFolderId1 = DomainId.NewGuid();
var childFolderId2 = DomainId.NewGuid(); var childFolderId2 = DomainId.NewGuid();
A.CallTo(() => assetFolderRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) A.CallTo(() => assetFolderRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId, A<CancellationToken>._))
.Returns(new List<DomainId> { childFolderId1, childFolderId2 }); .Returns(new List<DomainId> { childFolderId1, childFolderId2 });
await sut.On(Envelope.Create(@event)); await sut.On(Envelope.Create(@event));
@ -100,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
var childId1 = DomainId.NewGuid(); var childId1 = DomainId.NewGuid();
var childId2 = DomainId.NewGuid(); var childId2 = DomainId.NewGuid();
A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId, A<CancellationToken>._))
.Returns(new List<DomainId> { childId1, childId2 }); .Returns(new List<DomainId> { childId1, childId2 });
await sut.On(Envelope.Create(@event)); await sut.On(Envelope.Create(@event));
@ -123,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId1))) A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId1)))
.Throws(new InvalidOperationException()); .Throws(new InvalidOperationException());
A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId, A<CancellationToken>._))
.Returns(new List<DomainId> { childId1, childId2 }); .Returns(new List<DomainId> { childId1, childId2 });
await sut.On(Envelope.Create(@event)); await sut.On(Envelope.Create(@event));

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

@ -193,7 +193,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var rebuildContents = new HashSet<DomainId>(); var rebuildContents = new HashSet<DomainId>();
A.CallTo(() => rebuilder.InsertManyAsync<ContentDomainObject, ContentDomainObject.State>(A<IEnumerable<DomainId>>._, A<int>._, A<CancellationToken>._)) A.CallTo(() => rebuilder.InsertManyAsync<ContentDomainObject, ContentDomainObject.State>(A<IEnumerable<DomainId>>._, A<int>._, A<CancellationToken>._))
.Invokes((IEnumerable<DomainId> source, CancellationToken _) => rebuildContents.AddRange(source)); .Invokes((IEnumerable<DomainId> source, int _, CancellationToken _) => rebuildContents.AddRange(source));
await sut.RestoreAsync(context); await sut.RestoreAsync(context);

11
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using FluentAssertions; using FluentAssertions;
@ -155,7 +156,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
{ {
var ctx = ContextWithPermissions(); var ctx = ContextWithPermissions();
var result = await sut.SearchAsync("query", ctx); var result = await sut.SearchAsync("query", ctx, default);
Assert.Empty(result); Assert.Empty(result);
@ -171,11 +172,11 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => contentIndex.SearchAsync(ctx.App, A<TextQuery>.That.Matches(x => x.Text == "query~"), ctx.Scope())) A.CallTo(() => contentIndex.SearchAsync(ctx.App, A<TextQuery>.That.Matches(x => x.Text == "query~"), ctx.Scope()))
.Returns(new List<DomainId>()); .Returns(new List<DomainId>());
var result = await sut.SearchAsync("query", ctx); var result = await sut.SearchAsync("query", ctx, default);
Assert.Empty(result); Assert.Empty(result);
A.CallTo(() => contentQuery.QueryAsync(ctx, A<Q>._)) A.CallTo(() => contentQuery.QueryAsync(ctx, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -190,13 +191,13 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => contentIndex.SearchAsync(ctx.App, A<TextQuery>.That.Matches(x => x.Text == "query~" && x.Filter != null), ctx.Scope())) A.CallTo(() => contentIndex.SearchAsync(ctx.App, A<TextQuery>.That.Matches(x => x.Text == "query~" && x.Filter != null), ctx.Scope()))
.Returns(ids); .Returns(ids);
A.CallTo(() => contentQuery.QueryAsync(ctx, A<Q>.That.HasIds(ids))) A.CallTo(() => contentQuery.QueryAsync(ctx, A<Q>.That.HasIds(ids), A<CancellationToken>._))
.Returns(ResultList.CreateFrom<IEnrichedContentEntity>(1, content)); .Returns(ResultList.CreateFrom<IEnrichedContentEntity>(1, content));
A.CallTo(() => urlGenerator.ContentUI(appId, schemaId1, content.Id)) A.CallTo(() => urlGenerator.ContentUI(appId, schemaId1, content.Id))
.Returns("content-url"); .Returns("content-url");
var result = await sut.SearchAsync("query", ctx); var result = await sut.SearchAsync("query", ctx, default);
result.Should().BeEquivalentTo( result.Should().BeEquivalentTo(
new SearchResults() new SearchResults()

7
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Orleans; using Orleans;
@ -51,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
{ {
await HandleAsync(new CreateContent(), 12); await HandleAsync(new CreateContent(), 12);
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>._, A<bool>._, requestContext)) A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>._, A<bool>._, requestContext, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -66,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
Assert.Same(result, context.Result<IEnrichedContentEntity>()); Assert.Same(result, context.Result<IEnrichedContentEntity>());
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>._, A<bool>._, requestContext)) A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>._, A<bool>._, requestContext, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -77,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
var enriched = new ContentEntity(); var enriched = new ContentEntity();
A.CallTo(() => contentEnricher.EnrichAsync(result, true, requestContext)) A.CallTo(() => contentEnricher.EnrichAsync(result, true, requestContext, A<CancellationToken>._))
.Returns(enriched); .Returns(enriched);
var context = var context =

79
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -100,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
A.CallTo(() => appProvider.GetAppWithSchemaAsync(AppId, SchemaId, false)) A.CallTo(() => appProvider.GetAppWithSchemaAsync(AppId, SchemaId, false))
.Returns((app, schema)); .Returns((app, schema));
A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, A<string>._, ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, A<string>._, ScriptOptions(), default))
.ReturnsLazily(x => Task.FromResult(x.GetArgument<ScriptVars>(0)!.Data!)); .ReturnsLazily(x => Task.FromResult(x.GetArgument<ScriptVars>(0)!.Data!));
patched = patch.MergeInto(data); patched = patch.MergeInto(data);
@ -148,9 +149,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft }) CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -171,9 +172,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft }) CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -195,9 +196,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) CreateContentEvent(new ContentStatusChanged { Status = Status.Archived })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -248,9 +249,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft }) CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -271,9 +272,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft }) CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -295,9 +296,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) CreateContentEvent(new ContentStatusChanged { Status = Status.Archived })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft), "<create-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -319,7 +320,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentUpdated { Data = otherData }) CreateContentEvent(new ContentUpdated { Data = otherData })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -341,7 +342,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentUpdated { Data = otherData }) CreateContentEvent(new ContentUpdated { Data = otherData })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -365,9 +366,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) CreateContentEvent(new ContentStatusChanged { Status = Status.Archived })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -421,7 +422,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentUpdated { Data = otherData }) CreateContentEvent(new ContentUpdated { Data = otherData })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -445,7 +446,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentUpdated { Data = otherData }) CreateContentEvent(new ContentUpdated { Data = otherData })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(otherData, data, Status.Draft), "<update-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -462,7 +463,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
Assert.Single(LastEvents); Assert.Single(LastEvents);
A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "<update-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -494,7 +495,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentUpdated { Data = patched }) CreateContentEvent(new ContentUpdated { Data = patched })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(patched, data, Status.Draft), "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(patched, data, Status.Draft), "<update-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -518,7 +519,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentUpdated { Data = patched }) CreateContentEvent(new ContentUpdated { Data = patched })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(patched, data, Status.Draft), "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(patched, data, Status.Draft), "<update-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -535,7 +536,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
Assert.Single(LastEvents); Assert.Single(LastEvents);
A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "<update-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "<update-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -557,7 +558,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) CreateContentEvent(new ContentStatusChanged { Status = Status.Archived })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -579,7 +580,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) CreateContentEvent(new ContentStatusChanged { Status = Status.Archived })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -602,7 +603,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Draft, Change = StatusChange.Unpublished }) CreateContentEvent(new ContentStatusChanged { Status = Status.Draft, Change = StatusChange.Unpublished })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft, Status.Published), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft, Status.Published), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -611,7 +612,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
{ {
var command = new ChangeContentStatus { Status = Status.Draft }; var command = new ChangeContentStatus { Status = Status.Draft };
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft, Status.Published), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft, Status.Published), "<change-script>", ScriptOptions(), default))
.Returns(otherData); .Returns(otherData);
await ExecuteCreateAsync(); await ExecuteCreateAsync();
@ -630,7 +631,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Draft, Change = StatusChange.Unpublished }) CreateContentEvent(new ContentStatusChanged { Status = Status.Draft, Change = StatusChange.Unpublished })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft, Status.Published), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Draft, Status.Published), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -654,7 +655,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Change = StatusChange.Change, Status = Status.Archived }) CreateContentEvent(new ContentStatusChanged { Change = StatusChange.Change, Status = Status.Archived })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Archived, Status.Draft), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -678,7 +679,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Change = StatusChange.Published, Status = Status.Published }) CreateContentEvent(new ContentStatusChanged { Change = StatusChange.Published, Status = Status.Published })
); );
A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Published, Status.Draft), "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(ScriptVars(data, null, Status.Published, Status.Draft), "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -705,7 +706,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusScheduled { Status = Status.Published, DueTime = dueTime }) CreateContentEvent(new ContentStatusScheduled { Status = Status.Published, DueTime = dueTime })
); );
A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -733,7 +734,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) CreateContentEvent(new ContentStatusChanged { Status = Status.Archived })
); );
A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "<change-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -761,7 +762,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentSchedulingCancelled()) CreateContentEvent(new ContentSchedulingCancelled())
); );
A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(A<ScriptVars>._, "<change-script>", ScriptOptions(), default))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -773,7 +774,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
await ExecuteCreateAsync(); await ExecuteCreateAsync();
await ExecuteChangeStatusAsync(Status.Published); await ExecuteChangeStatusAsync(Status.Published);
A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All, A<CancellationToken>._))
.Returns(true); .Returns(true);
await Assert.ThrowsAsync<DomainException>(() => PublishAsync(command)); await Assert.ThrowsAsync<DomainException>(() => PublishAsync(command));
@ -787,7 +788,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
await ExecuteCreateAsync(); await ExecuteCreateAsync();
await ExecuteChangeStatusAsync(Status.Published); await ExecuteChangeStatusAsync(Status.Published);
A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.Published)) A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.Published, A<CancellationToken>._))
.Returns(true); .Returns(true);
await PublishAsync(command); await PublishAsync(command);
@ -823,7 +824,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
CreateContentEvent(new ContentDeleted()) CreateContentEvent(new ContentDeleted())
); );
A.CallTo(() => scriptEngine.ExecuteAsync(ScriptVars(data, null, Status.Draft), "<delete-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(ScriptVars(data, null, Status.Draft), "<delete-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -841,7 +842,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
Assert.Equal(EtagVersion.Empty, sut.Snapshot.Version); Assert.Equal(EtagVersion.Empty, sut.Snapshot.Version);
Assert.Empty(LastEvents); Assert.Empty(LastEvents);
A.CallTo(() => scriptEngine.ExecuteAsync(ScriptVars(data, null, Status.Draft), "<delete-script>", ScriptOptions())) A.CallTo(() => scriptEngine.ExecuteAsync(ScriptVars(data, null, Status.Draft), "<delete-script>", ScriptOptions(), default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -852,7 +853,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
var command = new DeleteContent { CheckReferrers = true }; var command = new DeleteContent { CheckReferrers = true };
A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All, A<CancellationToken>._))
.Returns(true); .Returns(true);
await Assert.ThrowsAsync<DomainException>(() => PublishAsync(command)); await Assert.ThrowsAsync<DomainException>(() => PublishAsync(command));
@ -865,7 +866,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
await ExecuteCreateAsync(); await ExecuteCreateAsync();
A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All, A<CancellationToken>._))
.Returns(true); .Returns(true);
await PublishAsync(command); await PublishAsync(command);

7
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using NodaTime; using NodaTime;
@ -88,7 +89,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
x.ShouldSkipCleanup() && x.ShouldSkipCleanup() &&
x.ShouldSkipContentEnrichment() && x.ShouldSkipContentEnrichment() &&
x.ShouldSkipTotal()), x.ShouldSkipTotal()),
schemaId.Name, A<Q>.That.Matches(x => x.JsonQuery == query))) schemaId.Name, A<Q>.That.Matches(x => x.JsonQuery == query), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(2, CreateContent(id), CreateContent(id))); .Returns(ResultList.CreateFrom(2, CreateContent(id), CreateContent(id)));
var command = BulkCommand(BulkUpdateContentType.ChangeStatus, query); var command = BulkCommand(BulkUpdateContentType.ChangeStatus, query);
@ -114,7 +115,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
x.ShouldSkipCleanup() && x.ShouldSkipCleanup() &&
x.ShouldSkipContentEnrichment() && x.ShouldSkipContentEnrichment() &&
x.ShouldSkipTotal()), x.ShouldSkipTotal()),
schemaId.Name, A<Q>.That.Matches(x => x.JsonQuery == query))) schemaId.Name, A<Q>.That.Matches(x => x.JsonQuery == query), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, CreateContent(id))); .Returns(ResultList.CreateFrom(1, CreateContent(id)));
var command = BulkCommand(BulkUpdateContentType.Upsert, query: query, data: data); var command = BulkCommand(BulkUpdateContentType.Upsert, query: query, data: data);
@ -144,7 +145,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
x.ShouldSkipCleanup() && x.ShouldSkipCleanup() &&
x.ShouldSkipContentEnrichment() && x.ShouldSkipContentEnrichment() &&
x.ShouldSkipTotal()), x.ShouldSkipTotal()),
schemaId.Name, A<Q>.That.Matches(x => x.JsonQuery == query))) schemaId.Name, A<Q>.That.Matches(x => x.JsonQuery == query), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(2, .Returns(ResultList.CreateFrom(2,
CreateContent(id1), CreateContent(id1),
CreateContent(id2))); CreateContent(id2)));

43
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using GraphQL; using GraphQL;
@ -60,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var asset = TestAsset.Create(appId, DomainId.NewGuid()); var asset = TestAsset.Create(appId, DomainId.NewGuid());
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null,
A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5&$filter=my-query" && x.NoTotal == true))) A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5&$filter=my-query" && x.NoTotal == true), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(0, asset)); .Returns(ResultList.CreateFrom(0, asset));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -95,7 +96,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var asset = TestAsset.Create(appId, DomainId.NewGuid()); var asset = TestAsset.Create(appId, DomainId.NewGuid());
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null,
A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5&$filter=my-query" && x.NoTotal == false))) A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5&$filter=my-query" && x.NoTotal == false), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(10, asset)); .Returns(ResultList.CreateFrom(10, asset));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -130,7 +131,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", assetId); }", assetId);
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A<Q>.That.HasIdsWithoutTotal(assetId))) A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A<Q>.That.HasIdsWithoutTotal(assetId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom<IEnrichedAssetEntity>(1)); .Returns(ResultList.CreateFrom<IEnrichedAssetEntity>(1));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -159,7 +160,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", assetId); }", assetId);
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A<Q>.That.HasIdsWithoutTotal(assetId))) A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A<Q>.That.HasIdsWithoutTotal(assetId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, asset)); .Returns(ResultList.CreateFrom(1, asset));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -211,7 +212,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var content = TestContent.Create(appId, schemaId, DomainId.NewGuid(), DomainId.Empty, DomainId.Empty); var content = TestContent.Create(appId, schemaId, DomainId.NewGuid(), DomainId.Empty, DomainId.Empty);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(), A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(),
A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.NoTotal == true))) A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.NoTotal == true), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(0, content)); .Returns(ResultList.CreateFrom(0, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -290,7 +291,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var content = TestContent.Create(appId, schemaId, DomainId.NewGuid(), DomainId.Empty, DomainId.Empty); var content = TestContent.Create(appId, schemaId, DomainId.NewGuid(), DomainId.Empty, DomainId.Empty);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(), A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(),
A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.NoTotal == true))) A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.NoTotal == true), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(0, content)); .Returns(ResultList.CreateFrom(0, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -325,7 +326,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var content = TestContent.Create(appId, schemaId, DomainId.NewGuid(), DomainId.Empty, DomainId.Empty); var content = TestContent.Create(appId, schemaId, DomainId.NewGuid(), DomainId.Empty, DomainId.Empty);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(), A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.Id.ToString(),
A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.NoTotal == false))) A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.NoTotal == false), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(10, content)); .Returns(ResultList.CreateFrom(10, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -360,7 +361,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentId); }", contentId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom<IEnrichedContentEntity>(1)); .Returns(ResultList.CreateFrom<IEnrichedContentEntity>(1));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -389,7 +390,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentId); }", contentId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, content)); .Returns(ResultList.CreateFrom(1, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -418,7 +419,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentId); }", contentId);
A.CallTo(() => contentQuery.FindAsync(MatchsContentContext(), schemaId.Id.ToString(), contentId, 3)) A.CallTo(() => contentQuery.FindAsync(MatchsContentContext(), schemaId.Id.ToString(), contentId, 3, A<CancellationToken>._))
.Returns(content); .Returns(content);
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -462,10 +463,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentId); }", contentId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(0, contentRef)); .Returns(ResultList.CreateFrom(0, contentRef));
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, content)); .Returns(ResultList.CreateFrom(1, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -528,11 +529,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentRefId); }", contentRefId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, contentRef)); .Returns(ResultList.CreateFrom(1, contentRef));
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), content.SchemaId.Id.ToString(), A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), content.SchemaId.Id.ToString(),
A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.Reference == contentRefId && x.NoTotal == true))) A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.Reference == contentRefId && x.NoTotal == true), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, content)); .Returns(ResultList.CreateFrom(1, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -592,11 +593,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentRefId); }", contentRefId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, contentRef)); .Returns(ResultList.CreateFrom(1, contentRef));
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), content.SchemaId.Id.ToString(), A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), content.SchemaId.Id.ToString(),
A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.Reference == contentRefId && x.NoTotal == false))) A<Q>.That.Matches(x => x.ODataQuery == "?$top=30&$skip=5" && x.Reference == contentRefId && x.NoTotal == false), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, content)); .Returns(ResultList.CreateFrom(1, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -666,10 +667,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentId); }", contentId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentRefId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(0, contentRef)); .Returns(ResultList.CreateFrom(0, contentRef));
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, content)); .Returns(ResultList.CreateFrom(1, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -732,10 +733,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentId); }", contentId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, content)); .Returns(ResultList.CreateFrom(1, content));
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A<Q>.That.HasIdsWithoutTotal(assetRefId))) A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), null, A<Q>.That.HasIdsWithoutTotal(assetRefId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(0, assetRef)); .Returns(ResultList.CreateFrom(0, assetRef));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });
@ -791,7 +792,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
} }
}", contentId); }", contentId);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId))) A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), A<Q>.That.HasIdsWithoutTotal(contentId), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(1, content)); .Returns(ResultList.CreateFrom(1, content));
var result = await ExecuteAsync(new ExecutionOptions { Query = query }); var result = await ExecuteAsync(new ExecutionOptions { Query = query });

30
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -30,7 +31,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
public ISchemaEntity Schema { get; private set; } public ISchemaEntity Schema { get; private set; }
public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas) public async Task EnrichAsync(Context context, IEnumerable<ContentEntity> contents, ProvideSchema schemas,
CancellationToken ct)
{ {
foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) foreach (var group in contents.GroupBy(x => x.SchemaId.Id))
{ {
@ -59,18 +61,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy<IContentQueryService>(() => contentQuery)); var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy<IContentQueryService>(() => contentQuery));
await sut.EnrichAsync(source, requestContext); await sut.EnrichAsync(source, requestContext, default);
A.CallTo(() => step1.EnrichAsync(requestContext)) A.CallTo(() => step1.EnrichAsync(requestContext, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => step2.EnrichAsync(requestContext)) A.CallTo(() => step2.EnrichAsync(requestContext, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => step1.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._)) A.CallTo(() => step1.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
A.CallTo(() => step2.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._)) A.CallTo(() => step2.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -84,18 +86,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy<IContentQueryService>(() => contentQuery)); var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy<IContentQueryService>(() => contentQuery));
await sut.EnrichAsync(source, false, requestContext); await sut.EnrichAsync(source, false, requestContext, default);
A.CallTo(() => step1.EnrichAsync(requestContext)) A.CallTo(() => step1.EnrichAsync(requestContext, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => step2.EnrichAsync(requestContext)) A.CallTo(() => step2.EnrichAsync(requestContext, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => step1.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._)) A.CallTo(() => step1.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => step2.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._)) A.CallTo(() => step2.EnrichAsync(requestContext, A<IEnumerable<ContentEntity>>._, A<ProvideSchema>._, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -109,7 +111,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy<IContentQueryService>(() => contentQuery)); var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy<IContentQueryService>(() => contentQuery));
await sut.EnrichAsync(source, false, requestContext); await sut.EnrichAsync(source, false, requestContext, default);
Assert.Same(schema, step1.Schema); Assert.Same(schema, step1.Schema);
Assert.Same(schema, step1.Schema); Assert.Same(schema, step1.Schema);
@ -125,7 +127,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var sut = new ContentEnricher(Enumerable.Empty<IContentEnricherStep>(), new Lazy<IContentQueryService>(() => contentQuery)); var sut = new ContentEnricher(Enumerable.Empty<IContentEnricherStep>(), new Lazy<IContentQueryService>(() => contentQuery));
var result = await sut.EnrichAsync(source, true, requestContext); var result = await sut.EnrichAsync(source, true, requestContext, default);
Assert.NotSame(source.Data, result.Data); Assert.NotSame(source.Data, result.Data);
} }
@ -137,7 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var sut = new ContentEnricher(Enumerable.Empty<IContentEnricherStep>(), new Lazy<IContentQueryService>(() => contentQuery)); var sut = new ContentEnricher(Enumerable.Empty<IContentEnricherStep>(), new Lazy<IContentQueryService>(() => contentQuery));
var result = await sut.EnrichAsync(source, false, requestContext); var result = await sut.EnrichAsync(source, false, requestContext, default);
Assert.Same(source.Data, result.Data); Assert.Same(source.Data, result.Data);
} }

31
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs

@ -8,6 +8,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -113,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = CreateContent(DomainId.NewGuid()); var content = CreateContent(DomainId.NewGuid());
A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, A<SearchScope>._)) A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, A<SearchScope>._, A<CancellationToken>._))
.Returns(CreateContent(DomainId.NewGuid())); .Returns(CreateContent(DomainId.NewGuid()));
await Assert.ThrowsAsync<DomainForbiddenException>(() => sut.FindAsync(requestContext, schemaId.Name, content.Id)); await Assert.ThrowsAsync<DomainForbiddenException>(() => sut.FindAsync(requestContext, schemaId.Name, content.Id));
@ -126,7 +127,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = CreateContent(DomainId.NewGuid()); var content = CreateContent(DomainId.NewGuid());
A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, A<SearchScope>._)) A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, A<SearchScope>._, A<CancellationToken>._))
.Returns<IContentEntity?>(null); .Returns<IContentEntity?>(null);
Assert.Null(await sut.FindAsync(requestContext, schemaId.Name, content.Id)); Assert.Null(await sut.FindAsync(requestContext, schemaId.Name, content.Id));
@ -143,7 +144,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = CreateContent(DomainId.NewGuid()); var content = CreateContent(DomainId.NewGuid());
A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, scope)) A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, scope, A<CancellationToken>._))
.Returns(content); .Returns(content);
var result = await sut.FindAsync(requestContext, schemaId.Name, content.Id); var result = await sut.FindAsync(requestContext, schemaId.Name, content.Id);
@ -171,7 +172,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var requestContext = CreateContext(allowSchema: false); var requestContext = CreateContext(allowSchema: false);
await Assert.ThrowsAsync<DomainForbiddenException>(() => sut.QueryAsync(requestContext, schemaId.Name, Q.Empty)); await Assert.ThrowsAsync<DomainForbiddenException>(() => sut.QueryAsync(requestContext, schemaId.Name, Q.Empty, default));
} }
[Theory] [Theory]
@ -188,10 +189,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var q = Q.Empty.WithReference(DomainId.NewGuid()); var q = Q.Empty.WithReference(DomainId.NewGuid());
A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema, q, scope)) A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema, q, scope, A<CancellationToken>._))
.Returns(ResultList.CreateFrom(5, content1, content2)); .Returns(ResultList.CreateFrom(5, content1, content2));
var result = await sut.QueryAsync(requestContext, schemaId.Name, q); var result = await sut.QueryAsync(requestContext, schemaId.Name, q, default);
Assert.Equal(5, result.Total); Assert.Equal(5, result.Total);
@ -215,10 +216,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var q = Q.Empty.WithIds(ids); var q = Q.Empty.WithIds(ids);
A.CallTo(() => contentRepository.QueryAsync(requestContext.App, A.CallTo(() => contentRepository.QueryAsync(requestContext.App,
A<List<ISchemaEntity>>.That.Matches(x => x.Count == 1), q, scope)) A<List<ISchemaEntity>>.That.Matches(x => x.Count == 1), q, scope, A<CancellationToken>._))
.Returns(ResultList.Create(5, contents)); .Returns(ResultList.Create(5, contents));
var result = await sut.QueryAsync(requestContext, q); var result = await sut.QueryAsync(requestContext, q, default);
Assert.Equal(5, result.Total); Assert.Equal(5, result.Total);
@ -238,10 +239,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var q = Q.Empty.WithIds(ids); var q = Q.Empty.WithIds(ids);
A.CallTo(() => contentRepository.QueryAsync(requestContext.App, A.CallTo(() => contentRepository.QueryAsync(requestContext.App,
A<List<ISchemaEntity>>.That.Matches(x => x.Count == 0), q, SearchScope.All)) A<List<ISchemaEntity>>.That.Matches(x => x.Count == 0), q, SearchScope.All, A<CancellationToken>._))
.Returns(ResultList.Create(0, ids.Select(CreateContent))); .Returns(ResultList.Create(0, ids.Select(CreateContent)));
var result = await sut.QueryAsync(requestContext, q); var result = await sut.QueryAsync(requestContext, q, default);
Assert.Empty(result); Assert.Empty(result);
} }
@ -251,10 +252,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var requestContext = CreateContext(permissionId: Permissions.AppContentsReadOwn); var requestContext = CreateContext(permissionId: Permissions.AppContentsReadOwn);
await sut.QueryAsync(requestContext, schemaId.Name, Q.Empty); await sut.QueryAsync(requestContext, schemaId.Name, Q.Empty, default);
A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema, A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema,
A<Q>.That.Matches(x => Equals(x.CreatedBy, requestContext.User.Token())), SearchScope.Published)) A<Q>.That.Matches(x => Equals(x.CreatedBy, requestContext.User.Token())), SearchScope.Published, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -263,16 +264,16 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var requestContext = CreateContext(permissionId: Permissions.AppContentsRead); var requestContext = CreateContext(permissionId: Permissions.AppContentsRead);
await sut.QueryAsync(requestContext, schemaId.Name, Q.Empty); await sut.QueryAsync(requestContext, schemaId.Name, Q.Empty, default);
A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema, A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema,
A<Q>.That.Matches(x => x.CreatedBy == null), SearchScope.Published)) A<Q>.That.Matches(x => x.CreatedBy == null), SearchScope.Published, A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
} }
private void SetupEnricher() private void SetupEnricher()
{ {
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnumerable<IContentEntity>>._, A<Context>._)) A.CallTo(() => contentEnricher.EnrichAsync(A<IEnumerable<IContentEntity>>._, A<Context>._, A<CancellationToken>._))
.ReturnsLazily(x => .ReturnsLazily(x =>
{ {
var input = x.GetArgument<IEnumerable<IContentEntity>>(0)!; var input = x.GetArgument<IEnumerable<IContentEntity>>(0)!;

15
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs

@ -7,6 +7,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
@ -58,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId));
await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider); await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default);
Assert.NotNull(content.Data); Assert.NotNull(content.Data);
} }
@ -88,15 +89,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
JsonValue.Object() JsonValue.Object()
.Add("nested", JsonValue.Array(id2))))); .Add("nested", JsonValue.Array(id2)))));
A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2))) A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2), A<CancellationToken>._))
.Returns(new List<DomainId> { id2 }); .Returns(new List<DomainId> { id2 });
A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2), SearchScope.All)) A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2), SearchScope.All, A<CancellationToken>._))
.Returns(new List<(DomainId, DomainId, Status)> { (id2, id2, Status.Published) }); .Returns(new List<(DomainId, DomainId, Status)> { (id2, id2, Status.Published) });
var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId));
await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider); await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default);
Assert.Equal(expected, content.Data); Assert.Equal(expected, content.Data);
} }
@ -126,15 +127,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
JsonValue.Object() JsonValue.Object()
.Add("nested", JsonValue.Array())))); .Add("nested", JsonValue.Array()))));
A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2))) A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2), A<CancellationToken>._))
.Returns(new List<DomainId>()); .Returns(new List<DomainId>());
A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2), SearchScope.All)) A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A<HashSet<DomainId>>.That.Is(id1, id2), SearchScope.All, A<CancellationToken>._))
.Returns(new List<(DomainId, DomainId, Status)>()); .Returns(new List<(DomainId, DomainId, Status)>());
var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId));
await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider); await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default);
Assert.Equal(expected, content.Data); Assert.Equal(expected, content.Data);
} }

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs

@ -47,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
A.CallTo(() => requestCache.AddHeader(A<string>._)) A.CallTo(() => requestCache.AddHeader(A<string>._))
.Invokes(new Action<string>(header => headers.Add(header))); .Invokes(new Action<string>(header => headers.Add(header)));
await sut.EnrichAsync(requestContext); await sut.EnrichAsync(requestContext, default);
Assert.Equal(new List<string> Assert.Equal(new List<string>
{ {
@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = CreateContent(); var content = CreateContent();
await sut.EnrichAsync(requestContext, Enumerable.Repeat(content, 1), schemaProvider); await sut.EnrichAsync(requestContext, Enumerable.Repeat(content, 1), schemaProvider, default);
A.CallTo(() => requestCache.AddDependency(content.UniqueId, content.Version)) A.CallTo(() => requestCache.AddDependency(content.UniqueId, content.Version))
.MustHaveHappened(); .MustHaveHappened();

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs

@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = CreateContent(); var content = CreateContent();
await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider); await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default);
Assert.NotNull(content.ReferenceFields); Assert.NotNull(content.ReferenceFields);
} }
@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var source = CreateContent(); var source = CreateContent();
await sut.EnrichAsync(ctx, Enumerable.Repeat(source, 1), schemaProvider); await sut.EnrichAsync(ctx, Enumerable.Repeat(source, 1), schemaProvider, default);
Assert.Null(source.ReferenceFields); Assert.Null(source.ReferenceFields);
} }
@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = CreateContent(); var content = CreateContent();
await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider); await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default);
Assert.Equal("my-schema", content.SchemaName); Assert.Equal("my-schema", content.SchemaName);
Assert.Equal("my-schema", content.SchemaDisplayName); Assert.Equal("my-schema", content.SchemaDisplayName);

18
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs

@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
A.CallTo(() => workflow.GetNextAsync(content, content.Status, requestContext.User)) A.CallTo(() => workflow.GetNextAsync(content, content.Status, requestContext.User))
.Returns(nexts); .Returns(nexts);
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!, default);
Assert.Equal(nexts, content.NextStatuses); Assert.Equal(nexts, content.NextStatuses);
} }
@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = new ContentEntity { SchemaId = schemaId, IsSingleton = true, Status = Status.Draft }; var content = new ContentEntity { SchemaId = schemaId, IsSingleton = true, Status = Status.Draft };
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!, default);
Assert.Equal(Status.Published, content.NextStatuses?.Single().Status); Assert.Equal(Status.Published, content.NextStatuses?.Single().Status);
@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = new ContentEntity { SchemaId = schemaId, IsSingleton = true, Status = Status.Published }; var content = new ContentEntity { SchemaId = schemaId, IsSingleton = true, Status = Status.Published };
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!, default);
Assert.Empty(content.NextStatuses); Assert.Empty(content.NextStatuses);
@ -84,7 +84,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
A.CallTo(() => workflow.GetInfoAsync(content, content.Status)) A.CallTo(() => workflow.GetInfoAsync(content, content.Status))
.Returns(new StatusInfo(Status.Published, StatusColors.Published)); .Returns(new StatusInfo(Status.Published, StatusColors.Published));
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!, default);
Assert.Equal(StatusColors.Published, content.StatusColor); Assert.Equal(StatusColors.Published, content.StatusColor);
} }
@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
A.CallTo(() => workflow.GetInfoAsync(content, content.NewStatus.Value)) A.CallTo(() => workflow.GetInfoAsync(content, content.NewStatus.Value))
.Returns(new StatusInfo(Status.Published, StatusColors.Archived)); .Returns(new StatusInfo(Status.Published, StatusColors.Archived));
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!, default);
Assert.Equal(StatusColors.Archived, content.NewStatusColor); Assert.Equal(StatusColors.Archived, content.NewStatusColor);
} }
@ -110,7 +110,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
A.CallTo(() => workflow.GetInfoAsync(content, content.ScheduleJob.Status)) A.CallTo(() => workflow.GetInfoAsync(content, content.ScheduleJob.Status))
.Returns(new StatusInfo(Status.Published, StatusColors.Archived)); .Returns(new StatusInfo(Status.Published, StatusColors.Archived));
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!, default);
Assert.Equal(StatusColors.Archived, content.ScheduledStatusColor); Assert.Equal(StatusColors.Archived, content.ScheduledStatusColor);
} }
@ -125,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); var ctx = requestContext.Clone(b => b.WithResolveFlow(false));
await sut.EnrichAsync(ctx, new[] { content }, null!); await sut.EnrichAsync(ctx, new[] { content }, null!, default);
Assert.Equal(StatusColors.Draft, content.StatusColor); Assert.Equal(StatusColors.Draft, content.StatusColor);
} }
@ -140,7 +140,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); var ctx = requestContext.Clone(b => b.WithResolveFlow(false));
await sut.EnrichAsync(ctx, new[] { content }, null!); await sut.EnrichAsync(ctx, new[] { content }, null!, default);
Assert.True(content.CanUpdate); Assert.True(content.CanUpdate);
} }
@ -152,7 +152,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)).Clone(b => b.WithResolveFlow(false)); var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)).Clone(b => b.WithResolveFlow(false));
await sut.EnrichAsync(ctx, new[] { content }, null!); await sut.EnrichAsync(ctx, new[] { content }, null!, default);
Assert.False(content.CanUpdate); Assert.False(content.CanUpdate);

25
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
@ -89,10 +90,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
}; };
A.CallTo(() => assetQuery.QueryAsync( A.CallTo(() => assetQuery.QueryAsync(
A<Context>.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A<Q>.That.HasIds(doc1.Id, doc2.Id))) A<Context>.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A<Q>.That.HasIds(doc1.Id, doc2.Id), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(4, doc1, doc2)); .Returns(ResultList.CreateFrom(4, doc1, doc2));
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
A.CallTo(() => requestCache.AddDependency(doc1.UniqueId, doc1.Version)) A.CallTo(() => requestCache.AddDependency(doc1.UniqueId, doc1.Version))
.MustHaveHappened(); .MustHaveHappened();
@ -121,10 +122,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
}; };
A.CallTo(() => assetQuery.QueryAsync( A.CallTo(() => assetQuery.QueryAsync(
A<Context>.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A<Q>.That.HasIds(doc1.Id, doc2.Id, img1.Id, img2.Id))) A<Context>.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A<Q>.That.HasIds(doc1.Id, doc2.Id, img1.Id, img2.Id), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(4, img1, img2, doc1, doc2)); .Returns(ResultList.CreateFrom(4, img1, img2, doc1, doc2));
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
Assert.Equal( Assert.Equal(
new ContentData() new ContentData()
@ -157,11 +158,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId));
await sut.EnrichAsync(ctx, contents, schemaProvider); await sut.EnrichAsync(ctx, contents, schemaProvider, default);
Assert.Null(contents[0].ReferenceData); Assert.Null(contents[0].ReferenceData);
A.CallTo(() => assetQuery.QueryAsync(A<Context>._, null, A<Q>._)) A.CallTo(() => assetQuery.QueryAsync(A<Context>._, null, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -175,11 +176,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).Clone(b => b.WithoutContentEnrichment(true)); var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).Clone(b => b.WithoutContentEnrichment(true));
await sut.EnrichAsync(ctx, contents, schemaProvider); await sut.EnrichAsync(ctx, contents, schemaProvider, default);
Assert.Null(contents[0].ReferenceData); Assert.Null(contents[0].ReferenceData);
A.CallTo(() => assetQuery.QueryAsync(A<Context>._, null, A<Q>._)) A.CallTo(() => assetQuery.QueryAsync(A<Context>._, null, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -191,11 +192,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
CreateContent(Array.Empty<DomainId>(), Array.Empty<DomainId>()) CreateContent(Array.Empty<DomainId>(), Array.Empty<DomainId>())
}; };
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
Assert.NotNull(contents[0].ReferenceData); Assert.NotNull(contents[0].ReferenceData);
A.CallTo(() => assetQuery.QueryAsync(A<Context>._, null, A<Q>._)) A.CallTo(() => assetQuery.QueryAsync(A<Context>._, null, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -210,12 +211,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
CreateContent(new[] { id1, id2 }, Array.Empty<DomainId>()) CreateContent(new[] { id1, id2 }, Array.Empty<DomainId>())
}; };
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
Assert.NotNull(contents[0].ReferenceData); Assert.NotNull(contents[0].ReferenceData);
A.CallTo(() => assetQuery.QueryAsync( A.CallTo(() => assetQuery.QueryAsync(
A<Context>.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A<Q>.That.HasIds(id1))) A<Context>.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A<Q>.That.HasIds(id1), A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
} }

25
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
@ -102,10 +103,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
}; };
A.CallTo(() => contentQuery.QueryAsync( A.CallTo(() => contentQuery.QueryAsync(
A<Context>.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A<Q>.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id))) A<Context>.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A<Q>.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2));
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
A.CallTo(() => requestCache.AddDependency(DomainId.Combine(appId, refSchemaId1.Id), 0)) A.CallTo(() => requestCache.AddDependency(DomainId.Combine(appId, refSchemaId1.Id), 0))
.MustHaveHappened(); .MustHaveHappened();
@ -141,10 +142,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
}; };
A.CallTo(() => contentQuery.QueryAsync( A.CallTo(() => contentQuery.QueryAsync(
A<Context>.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A<Q>.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id))) A<Context>.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A<Q>.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2));
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
Assert.Equal( Assert.Equal(
new ContentData() new ContentData()
@ -194,10 +195,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
}; };
A.CallTo(() => contentQuery.QueryAsync( A.CallTo(() => contentQuery.QueryAsync(
A<Context>.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A<Q>.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id))) A<Context>.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A<Q>.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), A<CancellationToken>._))
.Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2));
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
Assert.Equal( Assert.Equal(
new ContentData() new ContentData()
@ -242,11 +243,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId));
await sut.EnrichAsync(ctx, contents, schemaProvider); await sut.EnrichAsync(ctx, contents, schemaProvider, default);
Assert.Null(contents[0].ReferenceData); Assert.Null(contents[0].ReferenceData);
A.CallTo(() => contentQuery.QueryAsync(A<Context>._, A<Q>._)) A.CallTo(() => contentQuery.QueryAsync(A<Context>._, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -260,11 +261,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).Clone(b => b.WithoutContentEnrichment(true)); var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).Clone(b => b.WithoutContentEnrichment(true));
await sut.EnrichAsync(ctx, contents, schemaProvider); await sut.EnrichAsync(ctx, contents, schemaProvider, default);
Assert.Null(contents[0].ReferenceData); Assert.Null(contents[0].ReferenceData);
A.CallTo(() => contentQuery.QueryAsync(A<Context>._, A<Q>._)) A.CallTo(() => contentQuery.QueryAsync(A<Context>._, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -276,11 +277,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
CreateContent(Array.Empty<DomainId>(), Array.Empty<DomainId>()) CreateContent(Array.Empty<DomainId>(), Array.Empty<DomainId>())
}; };
await sut.EnrichAsync(requestContext, contents, schemaProvider); await sut.EnrichAsync(requestContext, contents, schemaProvider, default);
Assert.NotNull(contents[0].ReferenceData); Assert.NotNull(contents[0].ReferenceData);
A.CallTo(() => contentQuery.QueryAsync(A<Context>._, A<Q>._)) A.CallTo(() => contentQuery.QueryAsync(A<Context>._, A<Q>._, A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }

15
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -63,9 +64,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = new ContentEntity { SchemaId = schemaId }; var content = new ContentEntity { SchemaId = schemaId };
await sut.EnrichAsync(ctx, new[] { content }, schemaProvider); await sut.EnrichAsync(ctx, new[] { content }, schemaProvider, default);
A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, A<string>._, ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, A<string>._, ScriptOptions(), A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -76,9 +77,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = new ContentEntity { SchemaId = schemaWithScriptId }; var content = new ContentEntity { SchemaId = schemaWithScriptId };
await sut.EnrichAsync(ctx, new[] { content }, schemaProvider); await sut.EnrichAsync(ctx, new[] { content }, schemaProvider, default);
A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, A<string>._, ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, A<string>._, ScriptOptions(), A<CancellationToken>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -91,10 +92,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
var content = new ContentEntity { SchemaId = schemaWithScriptId, Data = oldData }; var content = new ContentEntity { SchemaId = schemaWithScriptId, Data = oldData };
A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "my-query", ScriptOptions())) A.CallTo(() => scriptEngine.TransformAsync(A<ScriptVars>._, "my-query", ScriptOptions(), A<CancellationToken>._))
.Returns(new ContentData()); .Returns(new ContentData());
await sut.EnrichAsync(ctx, new[] { content }, schemaProvider); await sut.EnrichAsync(ctx, new[] { content }, schemaProvider, default);
Assert.NotSame(oldData, content.Data); Assert.NotSame(oldData, content.Data);
@ -104,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
ReferenceEquals(x.Data, oldData) && ReferenceEquals(x.Data, oldData) &&
x.ContentId == content.Id), x.ContentId == content.Id),
"my-query", "my-query",
ScriptOptions())) ScriptOptions(), A<CancellationToken>._))
.MustHaveHappened(); .MustHaveHappened();
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save