Browse Source

Performance improvements.

pull/141/head
Sebastian Stehle 8 years ago
parent
commit
90f637056e
  1. 14
      Squidex.sln.DotSettings
  2. 27
      src/Squidex.Domain.Apps.Core/Schemas/Field.cs
  3. 2
      src/Squidex.Domain.Apps.Core/Schemas/IFieldPropertiesVisitor.cs
  4. 2
      src/Squidex.Domain.Apps.Core/Schemas/IFieldVisitor.cs
  5. 8
      src/Squidex.Domain.Apps.Core/Schemas/Json/JsonSchemaModel.cs
  6. 3
      src/Squidex.Domain.Apps.Core/Schemas/JsonSchema/ContentSchemaBuilder.cs
  7. 32
      src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppEntity.cs
  8. 4
      src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppEntityContributor.cs
  9. 69
      src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository_EventHandling.cs
  10. 2
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs
  11. 16
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs
  12. 14
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs
  13. 1
      src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs
  14. 28
      src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs
  15. 2
      src/Squidex.Domain.Apps.Read/Apps/IAppClientEntity.cs
  16. 2
      src/Squidex.Domain.Apps.Read/Apps/IAppContributorEntity.cs
  17. 5
      src/Squidex.Domain.Apps.Read/Apps/IAppEntity.cs
  18. 3
      src/Squidex.Domain.Apps.Read/Apps/Repositories/IAppRepository.cs
  19. 3
      src/Squidex.Domain.Apps.Read/Apps/Services/IAppProvider.cs
  20. 49
      src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/CachingAppProvider.cs
  21. 4
      src/Squidex.Domain.Apps.Read/Assets/Repositories/IAssetRepository.cs
  22. 3
      src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaRepository.cs
  23. 3
      src/Squidex.Domain.Apps.Read/Schemas/Services/ISchemaProvider.cs
  24. 33
      src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs
  25. 2
      src/Squidex.Infrastructure.GetEventStore/CQRS/Events/GetEventStoreSubscription.cs
  26. 8
      src/Squidex.Infrastructure.MongoDb/MongoDb/BsonConverter.cs
  27. 84
      src/Squidex.Infrastructure/DictionaryWrapper.cs
  28. 4
      src/Squidex.Infrastructure/Json/TypeNameSerializationBinder.cs
  29. 14
      src/Squidex.Infrastructure/TypeNameRegistry.cs
  30. 4
      src/Squidex/Config/Domain/InfrastructureModule.cs
  31. 21
      src/Squidex/Config/Domain/Serializers.cs
  32. 22
      src/Squidex/Config/Domain/StoreMongoDbModule.cs
  33. 30
      src/Squidex/Config/Domain/Usages.cs
  34. 4
      src/Squidex/Config/Domain/WriteModule.cs
  35. 2
      src/Squidex/Config/Identity/LazyClientStore.cs
  36. 2
      src/Squidex/Controllers/Api/Apps/AppClientsController.cs
  37. 2
      src/Squidex/Controllers/Api/Apps/AppContributorsController.cs
  38. 2
      src/Squidex/Controllers/Api/Apps/AppsController.cs
  39. 1
      src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs
  40. 18
      src/Squidex/Pipeline/AppApiFilter.cs
  41. 2
      src/Squidex/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs
  42. 2
      src/Squidex/app/features/webhooks/pages/webhook.component.ts
  43. 4
      src/Squidex/app/framework/angular/modal-target.directive.ts
  44. 2
      src/Squidex/app/framework/services/dialog.service.spec.ts
  45. 2
      tests/Squidex.Domain.Apps.Core.Tests/ContentEnrichmentTests.cs
  46. 28
      tests/Squidex.Domain.Apps.Read.Tests/Apps/CachingAppProviderTests.cs
  47. 26
      tests/Squidex.Domain.Apps.Read.Tests/Schemas/CachingSchemaProviderTests.cs
  48. 7
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentVersionLoaderTests.cs
  49. 2
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/AssetsFieldPropertiesTests.cs
  50. 2
      tests/Squidex.Infrastructure.Tests/CQRS/Commands/InMemoryCommandBusTests.cs
  51. 2
      tests/Squidex.Infrastructure.Tests/CQRS/Events/Actors/EventConsumerActorTests.cs
  52. 2
      tests/Squidex.Infrastructure.Tests/CQRS/Events/PollingSubscriptionTests.cs
  53. 12
      tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs

14
Squidex.sln.DotSettings

@ -1,4 +1,18 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Djs/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Djs/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ecshtml/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ecshtml/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ecss/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ecss/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ejs/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ejs/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Escss/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Escss/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ets/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ets/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002E_002A/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Header/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Header"&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;/Profile&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Header/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Header"&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Namespaces/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Namespaces"&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;/Profile&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Namespaces/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Namespaces"&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Typescript/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Typescript"&gt;&lt;JsInsertSemicolon&gt;True&lt;/JsInsertSemicolon&gt;&lt;FormatAttributeQuoteDescriptor&gt;True&lt;/FormatAttributeQuoteDescriptor&gt;&lt;CorrectVariableKindsDescriptor&gt;True&lt;/CorrectVariableKindsDescriptor&gt;&lt;VariablesToInnerScopesDescriptor&gt;True&lt;/VariablesToInnerScopesDescriptor&gt;&lt;StringToTemplatesDescriptor&gt;True&lt;/StringToTemplatesDescriptor&gt;&lt;RemoveRedundantQualifiersTs&gt;True&lt;/RemoveRedundantQualifiersTs&gt;&lt;OptimizeImportsTs&gt;True&lt;/OptimizeImportsTs&gt;&lt;/Profile&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Typescript/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Typescript"&gt;&lt;JsInsertSemicolon&gt;True&lt;/JsInsertSemicolon&gt;&lt;FormatAttributeQuoteDescriptor&gt;True&lt;/FormatAttributeQuoteDescriptor&gt;&lt;CorrectVariableKindsDescriptor&gt;True&lt;/CorrectVariableKindsDescriptor&gt;&lt;VariablesToInnerScopesDescriptor&gt;True&lt;/VariablesToInnerScopesDescriptor&gt;&lt;StringToTemplatesDescriptor&gt;True&lt;/StringToTemplatesDescriptor&gt;&lt;RemoveRedundantQualifiersTs&gt;True&lt;/RemoveRedundantQualifiersTs&gt;&lt;OptimizeImportsTs&gt;True&lt;/OptimizeImportsTs&gt;&lt;/Profile&gt;</s:String>

27
src/Squidex.Domain.Apps.Core/Schemas/Field.cs

@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Core.Schemas
private readonly Lazy<List<IValidator>> validators; private readonly Lazy<List<IValidator>> validators;
private readonly long fieldId; private readonly long fieldId;
private readonly Partitioning partitioning; private readonly Partitioning partitioning;
private string fieldName; private readonly string fieldName;
private bool isDisabled; private bool isDisabled;
private bool isHidden; private bool isHidden;
private bool isLocked; private bool isLocked;
@ -83,27 +83,42 @@ namespace Squidex.Domain.Apps.Core.Schemas
public Field Lock() public Field Lock()
{ {
return Clone<Field>(clone => clone.isLocked = true); return Clone<Field>(clone =>
{
clone.isLocked = true;
});
} }
public Field Hide() public Field Hide()
{ {
return Clone<Field>(clone => clone.isHidden = true); return Clone<Field>(clone =>
{
clone.isHidden = true;
});
} }
public Field Show() public Field Show()
{ {
return Clone<Field>(clone => clone.isHidden = false); return Clone<Field>(clone =>
{
clone.isHidden = false;
});
} }
public Field Disable() public Field Disable()
{ {
return Clone<Field>(clone => clone.isDisabled = true); return Clone<Field>(clone =>
{
clone.isDisabled = true;
});
} }
public Field Enable() public Field Enable()
{ {
return Clone<Field>(clone => clone.isDisabled = false); return Clone<Field>(clone =>
{
clone.isDisabled = false;
});
} }
public Field Update(FieldProperties newProperties) public Field Update(FieldProperties newProperties)

2
src/Squidex.Domain.Apps.Core/Schemas/IFieldPropertiesVisitor.cs

@ -8,7 +8,7 @@
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
{ {
public interface IFieldPropertiesVisitor<T> public interface IFieldPropertiesVisitor<out T>
{ {
T Visit(AssetsFieldProperties properties); T Visit(AssetsFieldProperties properties);

2
src/Squidex.Domain.Apps.Core/Schemas/IFieldVisitor.cs

@ -8,7 +8,7 @@
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
{ {
public interface IFieldVisitor<T> public interface IFieldVisitor<out T>
{ {
T Visit(AssetsField field); T Visit(AssetsField field);

8
src/Squidex.Domain.Apps.Core/Schemas/Json/JsonSchemaModel.cs

@ -33,10 +33,12 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
public JsonSchemaModel(Schema schema) public JsonSchemaModel(Schema schema)
{ {
var model = new JsonSchemaModel { Name = schema.Name, IsPublished = schema.IsPublished, Properties = schema.Properties }; Name = schema.Name;
Properties = schema.Properties;
Fields = Fields =
schema.Fields.Select(x => schema.Fields?.Select(x =>
new JsonFieldModel new JsonFieldModel
{ {
Id = x.Id, Id = x.Id,
@ -47,6 +49,8 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
Partitioning = x.Partitioning.Key, Partitioning = x.Partitioning.Key,
Properties = x.RawProperties Properties = x.RawProperties
}).ToList(); }).ToList();
IsPublished = schema.IsPublished;
} }
public Schema ToSchema(FieldRegistry fieldRegistry) public Schema ToSchema(FieldRegistry fieldRegistry)

3
src/Squidex.Domain.Apps.Read/Contents/JsonSchema/ContentSchemaBuilder.cs → src/Squidex.Domain.Apps.Core/Schemas/JsonSchema/ContentSchemaBuilder.cs

@ -7,10 +7,9 @@
// ========================================================================== // ==========================================================================
using NJsonSchema; using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.Contents.JsonSchema namespace Squidex.Domain.Apps.Core.Schemas.JsonSchema
{ {
public sealed class ContentSchemaBuilder public sealed class ContentSchemaBuilder
{ {

32
src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppEntity.cs

@ -19,6 +19,8 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
{ {
public sealed class MongoAppEntity : MongoEntity, IAppEntity public sealed class MongoAppEntity : MongoEntity, IAppEntity
{ {
private readonly IReadOnlyDictionary<string, IAppClientEntity> clientWrapper;
private readonly IReadOnlyDictionary<string, IAppContributorEntity> contributorWrapper;
private LanguagesConfig languagesConfig; private LanguagesConfig languagesConfig;
[BsonRequired] [BsonRequired]
@ -47,15 +49,15 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public List<MongoAppEntityLanguage> Languages { get; set; } = new List<MongoAppEntityLanguage>(); public List<MongoAppEntityLanguage> Languages { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public Dictionary<string, MongoAppEntityClient> Clients { get; set; } = new Dictionary<string, MongoAppEntityClient>(); public Dictionary<string, MongoAppEntityClient> Clients { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public Dictionary<string, MongoAppEntityContributor> Contributors { get; set; } = new Dictionary<string, MongoAppEntityContributor>(); public Dictionary<string, MongoAppEntityContributor> Contributors { get; set; }
public PartitionResolver PartitionResolver public PartitionResolver PartitionResolver
{ {
@ -67,14 +69,28 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
get { return languagesConfig ?? (languagesConfig = CreateLanguagesConfig()); } get { return languagesConfig ?? (languagesConfig = CreateLanguagesConfig()); }
} }
IReadOnlyCollection<IAppClientEntity> IAppEntity.Clients IReadOnlyDictionary<string, IAppClientEntity> IAppEntity.Clients
{ {
get { return Clients.Values; } get { return clientWrapper; }
} }
IReadOnlyCollection<IAppContributorEntity> IAppEntity.Contributors IReadOnlyDictionary<string, IAppContributorEntity> IAppEntity.Contributors
{ {
get { return Contributors.Values; } get { return contributorWrapper; }
}
public MongoAppEntity()
{
clientWrapper = new DictionaryWrapper<string, IAppClientEntity, MongoAppEntityClient>(() => Clients);
contributorWrapper = new DictionaryWrapper<string, IAppContributorEntity, MongoAppEntityContributor>(() => Contributors);
}
public void ChangePlan(string planId, RefToken planOwner)
{
PlanId = planId;
PlanOwner = planOwner.Identifier;
} }
public void UpdateLanguages(Func<LanguagesConfig, LanguagesConfig> updater) public void UpdateLanguages(Func<LanguagesConfig, LanguagesConfig> updater)
@ -92,7 +108,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
private LanguagesConfig CreateLanguagesConfig() private LanguagesConfig CreateLanguagesConfig()
{ {
languagesConfig = LanguagesConfig.Create(Languages.Select(ToLanguageConfig).ToList()); languagesConfig = LanguagesConfig.Create(Languages?.Select(ToLanguageConfig).ToList() ?? new List<LanguageConfig>());
if (MasterLanguage != null) if (MasterLanguage != null)
{ {

4
src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppEntityContributor.cs

@ -14,10 +14,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
{ {
public sealed class MongoAppEntityContributor : IAppContributorEntity public sealed class MongoAppEntityContributor : IAppContributorEntity
{ {
[BsonRequired]
[BsonElement]
public string ContributorId { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public AppContributorPermission Permission { get; set; } public AppContributorPermission Permission { get; set; }

69
src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository_EventHandling.cs

@ -6,8 +6,11 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Apps;
using Squidex.Domain.Apps.Read.MongoDb.Utils; using Squidex.Domain.Apps.Read.MongoDb.Utils;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -19,6 +22,8 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
{ {
public partial class MongoAppRepository public partial class MongoAppRepository
{ {
private readonly List<Action<NamedId<Guid>>> subscribers = new List<Action<NamedId<Guid>>>();
public string Name public string Name
{ {
get { return GetType().Name; } get { return GetType().Name; }
@ -29,6 +34,11 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
get { return "^app-"; } get { return "^app-"; }
} }
public void SubscribeOnChanged(Action<NamedId<Guid>> subscriber)
{
subscribers.Add(subscriber);
}
public Task On(Envelope<IEvent> @event) public Task On(Envelope<IEvent> @event)
{ {
return this.DispatchActionAsync(@event.Payload, @event.Headers); return this.DispatchActionAsync(@event.Payload, @event.Headers);
@ -38,13 +48,17 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
{ {
return Collection.CreateAsync(@event, headers, a => return Collection.CreateAsync(@event, headers, a =>
{ {
a.Clients = new Dictionary<string, MongoAppEntityClient>();
a.Contributors = new Dictionary<string, MongoAppEntityContributor>();
a.ContributorIds = new List<string>();
SimpleMapper.Map(@event, a); SimpleMapper.Map(@event, a);
}); });
} }
protected Task On(AppClientAttached @event, EnvelopeHeaders headers) protected Task On(AppClientAttached @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.Clients[@event.Id] = SimpleMapper.Map(@event, new MongoAppEntityClient()); a.Clients[@event.Id] = SimpleMapper.Map(@event, new MongoAppEntityClient());
}); });
@ -52,7 +66,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
protected Task On(AppClientRevoked @event, EnvelopeHeaders headers) protected Task On(AppClientRevoked @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.Clients.Remove(@event.Id); a.Clients.Remove(@event.Id);
}); });
@ -60,7 +74,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
protected Task On(AppClientRenamed @event, EnvelopeHeaders headers) protected Task On(AppClientRenamed @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.Clients[@event.Id].Name = @event.Name; a.Clients[@event.Id].Name = @event.Name;
}); });
@ -68,15 +82,31 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
protected Task On(AppClientUpdated @event, EnvelopeHeaders headers) protected Task On(AppClientUpdated @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.Clients[@event.Id].Permission = @event.Permission; a.Clients[@event.Id].Permission = @event.Permission;
}); });
} }
protected Task On(AppContributorRemoved @event, EnvelopeHeaders headers)
{
return UpdateAppAsync(@event, headers, a =>
{
a.Contributors.Remove(@event.ContributorId);
});
}
protected Task On(AppContributorAssigned @event, EnvelopeHeaders headers)
{
return UpdateAppAsync(@event, headers, a =>
{
a.Contributors[@event.ContributorId] = new MongoAppEntityContributor { Permission = @event.Permission };
});
}
protected Task On(AppLanguageAdded @event, EnvelopeHeaders headers) protected Task On(AppLanguageAdded @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.UpdateLanguages(c => c.Add(@event.Language)); a.UpdateLanguages(c => c.Add(@event.Language));
}); });
@ -84,7 +114,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
protected Task On(AppLanguageRemoved @event, EnvelopeHeaders headers) protected Task On(AppLanguageRemoved @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.UpdateLanguages(c => c.Remove(@event.Language)); a.UpdateLanguages(c => c.Remove(@event.Language));
}); });
@ -92,7 +122,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
protected Task On(AppLanguageUpdated @event, EnvelopeHeaders headers) protected Task On(AppLanguageUpdated @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.UpdateLanguages(c => c.Update(@event.Language, @event.IsOptional, @event.IsMaster, @event.Fallback)); a.UpdateLanguages(c => c.Update(@event.Language, @event.IsOptional, @event.IsMaster, @event.Fallback));
}); });
@ -100,32 +130,25 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps
protected Task On(AppPlanChanged @event, EnvelopeHeaders headers) protected Task On(AppPlanChanged @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return UpdateAppAsync(@event, headers, a =>
{ {
a.PlanOwner = @event.Actor.Identifier; a.ChangePlan(@event.PlanId, @event.Actor);
a.PlanId = @event.PlanId;
}); });
} }
protected Task On(AppContributorRemoved @event, EnvelopeHeaders headers) private async Task UpdateAppAsync(AppEvent @event, EnvelopeHeaders headers, Action<MongoAppEntity> updater)
{ {
return Collection.UpdateAsync(@event, headers, a => await Collection.UpdateAsync(@event, headers, a =>
{ {
a.Contributors.Remove(@event.ContributorId); updater(a);
a.ContributorIds = a.Contributors.Keys.ToList(); a.ContributorIds = a.Contributors.Keys.ToList();
}); });
}
protected Task On(AppContributorAssigned @event, EnvelopeHeaders headers) foreach (var subscriber in subscribers)
{
return Collection.UpdateAsync(@event, headers, a =>
{ {
var contributor = a.Contributors.GetOrAddNew(@event.ContributorId); subscriber(@event.AppId);
}
SimpleMapper.Map(@event, contributor);
a.ContributorIds = a.Contributors.Keys.ToList();
});
} }
} }
} }

2
src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs

@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
return document return document
.ToJson() .ToJson()
.ToObject<IdContentData>() .ToObject<IdContentData>()
.ToCleanedReferences(schema, new HashSet<Guid>(deletedIds)) .ToCleanedReferences(schema, new HashSet<Guid>(deletedIds ?? new List<Guid>()))
.ToNameModel(schema, true); .ToNameModel(schema, true);
} }

16
src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs

@ -9,7 +9,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -22,7 +21,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{ {
public sealed class MongoContentEntity : IContentEntity, IMongoEntity public sealed class MongoContentEntity : IContentEntity, IMongoEntity
{ {
private static readonly JsonWriterSettings Settings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
private NamedContentData data; private NamedContentData data;
[BsonId] [BsonId]
@ -73,11 +71,11 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
[BsonRequired] [BsonRequired]
[BsonElement("rf")] [BsonElement("rf")]
public List<Guid> ReferencedIds { get; set; } = new List<Guid>(); public List<Guid> ReferencedIds { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement("rd")] [BsonElement("rd")]
public List<Guid> ReferencedIdsDeleted { get; set; } = new List<Guid>(); public List<Guid> ReferencedIdsDeleted { get; set; }
NamedContentData IContentEntity.Data NamedContentData IContentEntity.Data
{ {
@ -88,15 +86,5 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{ {
data = DataDocument.ToData(schema, ReferencedIdsDeleted); data = DataDocument.ToData(schema, ReferencedIdsDeleted);
} }
public void SetData(Schema schema, NamedContentData data)
{
var idData = data?.ToIdModel(schema, true);
DataText = idData?.ToFullText();
DataDocument = idData?.ToBsonDocument();
ReferencedIds = idData?.ToReferencedIds(schema);
}
} }
} }

14
src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs

@ -70,13 +70,17 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{ {
return ForSchemaAsync(@event.AppId.Id, @event.SchemaId.Id, (collection, schema) => return ForSchemaAsync(@event.AppId.Id, @event.SchemaId.Id, (collection, schema) =>
{ {
return collection.CreateAsync(@event, headers, x => return collection.CreateAsync(@event, headers, content =>
{ {
x.SchemaId = @event.SchemaId.Id; content.SchemaId = @event.SchemaId.Id;
SimpleMapper.Map(@event, x); SimpleMapper.Map(@event, content);
x.SetData(schema.SchemaDef, @event.Data); var idData = @event.Data?.ToIdModel(schema.SchemaDef, true);
content.DataText = idData?.ToFullText();
content.DataDocument = idData?.ToBsonDocument();
content.ReferencedIds = idData?.ToReferencedIds(schema.SchemaDef);
}); });
}); });
} }
@ -90,9 +94,9 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
return collection.UpdateOneAsync( return collection.UpdateOneAsync(
Filter.Eq(x => x.Id, @event.ContentId), Filter.Eq(x => x.Id, @event.ContentId),
Update Update
.Set(x => x.ReferencedIds, idData.ToReferencedIds(schema.SchemaDef))
.Set(x => x.DataText, idData.ToFullText()) .Set(x => x.DataText, idData.ToFullText())
.Set(x => x.DataDocument, idData.ToBsonDocument()) .Set(x => x.DataDocument, idData.ToBsonDocument())
.Set(x => x.ReferencedIds, idData.ToReferencedIds(schema.SchemaDef))
.Set(x => x.LastModified, headers.Timestamp()) .Set(x => x.LastModified, headers.Timestamp())
.Set(x => x.LastModifiedBy, @event.Actor) .Set(x => x.LastModifiedBy, @event.Actor)
.Set(x => x.Version, headers.EventStreamNumber())); .Set(x => x.Version, headers.EventStreamNumber()));

1
src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs

@ -73,6 +73,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
[BsonElement] [BsonElement]
public string ScriptChange { get; set; } public string ScriptChange { get; set; }
[BsonIgnore]
public Schema SchemaDef public Schema SchemaDef
{ {
get get

28
src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs

@ -7,6 +7,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
@ -14,6 +15,7 @@ using Squidex.Domain.Apps.Events.Schemas;
using Squidex.Domain.Apps.Events.Schemas.Old; using Squidex.Domain.Apps.Events.Schemas.Old;
using Squidex.Domain.Apps.Events.Schemas.Utils; using Squidex.Domain.Apps.Events.Schemas.Utils;
using Squidex.Domain.Apps.Read.MongoDb.Utils; using Squidex.Domain.Apps.Read.MongoDb.Utils;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Dispatching; using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
@ -24,6 +26,8 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
{ {
public partial class MongoSchemaRepository public partial class MongoSchemaRepository
{ {
private readonly List<Action<NamedId<Guid>, NamedId<Guid>>> subscribers = new List<Action<NamedId<Guid>, NamedId<Guid>>>();
public string Name public string Name
{ {
get { return GetType().Name; } get { return GetType().Name; }
@ -34,6 +38,11 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
get { return "^schema-"; } get { return "^schema-"; }
} }
public void SubscribeOnChanged(Action<NamedId<Guid>, NamedId<Guid>> subscriber)
{
subscribers.Add(subscriber);
}
public Task On(Envelope<IEvent> @event) public Task On(Envelope<IEvent> @event)
{ {
return this.DispatchActionAsync(@event.Payload, @event.Headers); return this.DispatchActionAsync(@event.Payload, @event.Headers);
@ -43,7 +52,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
{ {
var schema = SchemaEventDispatcher.Dispatch(@event, registry); var schema = SchemaEventDispatcher.Dispatch(@event, registry);
return Collection.CreateAsync(@event, headers, s => { UpdateSchema(s, schema); SimpleMapper.Map(@event, s); }); return Collection.CreateAsync(@event, headers, s => { s.SchemaDef = schema; SimpleMapper.Map(@event, s); });
} }
protected Task On(FieldDeleted @event, EnvelopeHeaders headers) protected Task On(FieldDeleted @event, EnvelopeHeaders headers)
@ -126,19 +135,20 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
return Collection.UpdateAsync(@event, headers, e => { }); return Collection.UpdateAsync(@event, headers, e => { });
} }
private Task UpdateSchema(SquidexEvent @event, EnvelopeHeaders headers, Func<Schema, Schema> updater) private async Task UpdateSchema(SchemaEvent @event, EnvelopeHeaders headers, Func<Schema, Schema> updater = null)
{ {
return Collection.UpdateAsync(@event, headers, e => UpdateSchema(e, updater)); await Collection.UpdateAsync(@event, headers, e =>
}
private void UpdateSchema(MongoSchemaEntity entity, Func<Schema, Schema> updater)
{ {
entity.SchemaDef = updater(entity.SchemaDef); if (updater != null)
{
e.SchemaDef = updater(e.SchemaDef);
} }
});
private void UpdateSchema(MongoSchemaEntity entity, Schema schema) foreach (var subscriber in subscribers)
{ {
entity.SchemaDef = schema; subscriber(@event.AppId, @event.SchemaId);
}
} }
} }
} }

2
src/Squidex.Domain.Apps.Read/Apps/IAppClientEntity.cs

@ -12,8 +12,6 @@ namespace Squidex.Domain.Apps.Read.Apps
{ {
public interface IAppClientEntity public interface IAppClientEntity
{ {
string Id { get; }
string Name { get; } string Name { get; }
string Secret { get; } string Secret { get; }

2
src/Squidex.Domain.Apps.Read/Apps/IAppContributorEntity.cs

@ -12,8 +12,6 @@ namespace Squidex.Domain.Apps.Read.Apps
{ {
public interface IAppContributorEntity public interface IAppContributorEntity
{ {
string ContributorId { get; }
AppContributorPermission Permission { get; } AppContributorPermission Permission { get; }
} }
} }

5
src/Squidex.Domain.Apps.Read/Apps/IAppEntity.cs

@ -8,6 +8,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Apps;
namespace Squidex.Domain.Apps.Read.Apps namespace Squidex.Domain.Apps.Read.Apps
{ {
@ -21,9 +22,9 @@ namespace Squidex.Domain.Apps.Read.Apps
LanguagesConfig LanguagesConfig { get; } LanguagesConfig LanguagesConfig { get; }
IReadOnlyCollection<IAppClientEntity> Clients { get; } IReadOnlyDictionary<string, IAppClientEntity> Clients { get; }
IReadOnlyCollection<IAppContributorEntity> Contributors { get; } IReadOnlyDictionary<string, IAppContributorEntity> Contributors { get; }
PartitionResolver PartitionResolver { get; } PartitionResolver PartitionResolver { get; }
} }

3
src/Squidex.Domain.Apps.Read/Apps/Repositories/IAppRepository.cs

@ -9,6 +9,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.Apps.Repositories namespace Squidex.Domain.Apps.Read.Apps.Repositories
{ {
@ -19,5 +20,7 @@ namespace Squidex.Domain.Apps.Read.Apps.Repositories
Task<IAppEntity> FindAppAsync(Guid appId); Task<IAppEntity> FindAppAsync(Guid appId);
Task<IAppEntity> FindAppAsync(string name); Task<IAppEntity> FindAppAsync(string name);
void SubscribeOnChanged(Action<NamedId<Guid>> subscriber);
} }
} }

3
src/Squidex.Domain.Apps.Read/Apps/Services/IAppProvider.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.Apps.Services namespace Squidex.Domain.Apps.Read.Apps.Services
{ {
@ -16,5 +17,7 @@ namespace Squidex.Domain.Apps.Read.Apps.Services
Task<IAppEntity> FindAppByIdAsync(Guid id); Task<IAppEntity> FindAppByIdAsync(Guid id);
Task<IAppEntity> FindAppByNameAsync(string name); Task<IAppEntity> FindAppByNameAsync(string name);
void Invalidate(NamedId<Guid> appId);
} }
} }

49
src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/CachingAppProvider.cs

@ -9,31 +9,18 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Domain.Apps.Read.Apps.Repositories; using Squidex.Domain.Apps.Read.Apps.Repositories;
using Squidex.Domain.Apps.Read.Utils; using Squidex.Domain.Apps.Read.Utils;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations
{ {
public class CachingAppProvider : CachingProviderBase, IAppProvider, IEventConsumer public class CachingAppProvider : CachingProviderBase, IAppProvider
{ {
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(30); private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(30);
private readonly IAppRepository repository;
public string Name
{
get { return GetType().Name; }
}
public string EventsFilter private readonly IAppRepository repository;
{
get { return string.Empty; }
}
public CachingAppProvider(IMemoryCache cache, IAppRepository repository) public CachingAppProvider(IMemoryCache cache, IAppRepository repository)
: base(cache) : base(cache)
@ -83,12 +70,10 @@ namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations
return result; return result;
} }
public Task On(Envelope<IEvent> @event) public void Invalidate(NamedId<Guid> appId)
{
void Remove(NamedId<Guid> id)
{ {
var cacheKeyById = BuildIdCacheKey(id.Id); var cacheKeyById = BuildIdCacheKey(appId.Id);
var cacheKeyByName = BuildNameCacheKey(id.Name); var cacheKeyByName = BuildNameCacheKey(appId.Name);
Cache.Remove(cacheKeyById); Cache.Remove(cacheKeyById);
Cache.Remove(cacheKeyByName); Cache.Remove(cacheKeyByName);
@ -97,25 +82,6 @@ namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations
Cache.Invalidate(cacheKeyByName); Cache.Invalidate(cacheKeyByName);
} }
if (@event.Payload is AppClientAttached ||
@event.Payload is AppClientUpdated ||
@event.Payload is AppClientRenamed ||
@event.Payload is AppClientRevoked ||
@event.Payload is AppPlanChanged ||
@event.Payload is AppContributorAssigned ||
@event.Payload is AppContributorRemoved ||
@event.Payload is AppCreated ||
@event.Payload is AppLanguageAdded ||
@event.Payload is AppLanguageRemoved ||
@event.Payload is AppLanguageUpdated ||
@event.Payload is AppMasterLanguageSet)
{
Remove(((AppEvent)@event.Payload).AppId);
}
return TaskHelper.Done;
}
private static string BuildNameCacheKey(string name) private static string BuildNameCacheKey(string name)
{ {
return $"App_Ids_{name}"; return $"App_Ids_{name}";
@ -125,10 +91,5 @@ namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations
{ {
return $"App_Names_{schemaId}"; return $"App_Names_{schemaId}";
} }
public Task ClearAsync()
{
return TaskHelper.Done;
}
} }
} }

4
src/Squidex.Domain.Apps.Read/Assets/Repositories/IAssetRepository.cs

@ -18,8 +18,8 @@ namespace Squidex.Domain.Apps.Read.Assets.Repositories
Task<IReadOnlyList<Guid>> QueryNotFoundAsync(Guid appId, IList<Guid> assetIds); Task<IReadOnlyList<Guid>> QueryNotFoundAsync(Guid appId, IList<Guid> assetIds);
Task<long> CountAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null);
Task<IAssetEntity> FindAssetAsync(Guid id); Task<IAssetEntity> FindAssetAsync(Guid id);
Task<long> CountAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null);
} }
} }

3
src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaRepository.cs

@ -9,6 +9,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.Schemas.Repositories namespace Squidex.Domain.Apps.Read.Schemas.Repositories
{ {
@ -19,5 +20,7 @@ namespace Squidex.Domain.Apps.Read.Schemas.Repositories
Task<ISchemaEntity> FindSchemaAsync(Guid appId, string name); Task<ISchemaEntity> FindSchemaAsync(Guid appId, string name);
Task<ISchemaEntity> FindSchemaAsync(Guid schemaId); Task<ISchemaEntity> FindSchemaAsync(Guid schemaId);
void SubscribeOnChanged(Action<NamedId<Guid>, NamedId<Guid>> subscriber);
} }
} }

3
src/Squidex.Domain.Apps.Read/Schemas/Services/ISchemaProvider.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.Schemas.Services namespace Squidex.Domain.Apps.Read.Schemas.Services
{ {
@ -16,5 +17,7 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services
Task<ISchemaEntity> FindSchemaByIdAsync(Guid id, bool provideDeleted = false); Task<ISchemaEntity> FindSchemaByIdAsync(Guid id, bool provideDeleted = false);
Task<ISchemaEntity> FindSchemaByNameAsync(Guid appId, string name); Task<ISchemaEntity> FindSchemaByNameAsync(Guid appId, string name);
void Invalidate(NamedId<Guid> appId, NamedId<Guid> schemaId);
} }
} }

33
src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs

@ -9,30 +9,18 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Read.Schemas.Repositories; using Squidex.Domain.Apps.Read.Schemas.Repositories;
using Squidex.Domain.Apps.Read.Utils; using Squidex.Domain.Apps.Read.Utils;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations
{ {
public class CachingSchemaProvider : CachingProviderBase, ISchemaProvider, IEventConsumer public class CachingSchemaProvider : CachingProviderBase, ISchemaProvider
{ {
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10); private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10);
private readonly ISchemaRepository repository;
public string Name
{
get { return GetType().Name; }
}
public string EventsFilter private readonly ISchemaRepository repository;
{
get { return string.Empty; }
}
public CachingSchemaProvider(IMemoryCache cache, ISchemaRepository repository) public CachingSchemaProvider(IMemoryCache cache, ISchemaRepository repository)
: base(cache) : base(cache)
@ -92,9 +80,7 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations
return result; return result;
} }
public Task On(Envelope<IEvent> @event) public void Invalidate(NamedId<Guid> appId, NamedId<Guid> schemaId)
{
void Remove(NamedId<Guid> appId, NamedId<Guid> schemaId)
{ {
var cacheKeyById = BuildIdCacheKey(schemaId.Id); var cacheKeyById = BuildIdCacheKey(schemaId.Id);
var cacheKeyByName = BuildNameCacheKey(appId.Id, schemaId.Name); var cacheKeyByName = BuildNameCacheKey(appId.Id, schemaId.Name);
@ -106,14 +92,6 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations
Cache.Invalidate(cacheKeyByName); Cache.Invalidate(cacheKeyByName);
} }
if (@event.Payload is SchemaEvent schemaEvent)
{
Remove(schemaEvent.AppId, schemaEvent.SchemaId);
}
return TaskHelper.Done;
}
private static string BuildNameCacheKey(Guid appId, string name) private static string BuildNameCacheKey(Guid appId, string name)
{ {
return $"Schema_Ids_{appId}_{name}"; return $"Schema_Ids_{appId}_{name}";
@ -123,10 +101,5 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations
{ {
return $"Schema_Names_{schemaId}"; return $"Schema_Names_{schemaId}";
} }
public Task ClearAsync()
{
return TaskHelper.Done;
}
} }
} }

2
src/Squidex.Infrastructure.GetEventStore/CQRS/Events/GetEventStoreSubscription.cs

@ -30,7 +30,7 @@ namespace Squidex.Infrastructure.CQRS.Events
private readonly string streamFilter; private readonly string streamFilter;
private readonly string projectionHost; private readonly string projectionHost;
private readonly EventStoreCatchUpSubscription subscription; private readonly EventStoreCatchUpSubscription subscription;
private long? position; private readonly long? position;
public GetEventStoreSubscription( public GetEventStoreSubscription(
IEventStoreConnection eventStoreConnection, IEventStoreConnection eventStoreConnection,

8
src/Squidex.Infrastructure.MongoDb/MongoDb/BsonConverter.cs

@ -20,7 +20,9 @@ namespace Squidex.Infrastructure.MongoDb
foreach (var property in source) foreach (var property in source)
{ {
result.Add(property.Key, property.Value.ToBson()); var key = property.Key == "$type" ? "&type" : property.Key;
result.Add(key, property.Value.ToBson());
} }
return result; return result;
@ -32,7 +34,9 @@ namespace Squidex.Infrastructure.MongoDb
foreach (var property in source) foreach (var property in source)
{ {
result.Add(property.Name, property.Value.ToJson()); var key = property.Name == "&type" ? "$type" : property.Name;
result.Add(key, property.Value.ToJson());
} }
return result; return result;

84
src/Squidex.Infrastructure/DictionaryWrapper.cs

@ -0,0 +1,84 @@
// ==========================================================================
// DictionaryWrapper.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Squidex.Infrastructure
{
public sealed class DictionaryWrapper<TKey, TValue, TSuper> : IReadOnlyDictionary<TKey, TValue> where TSuper : class, TValue where TValue : class
{
private readonly Func<Dictionary<TKey, TSuper>> inner;
public DictionaryWrapper(Func<Dictionary<TKey, TSuper>> inner)
{
Guard.NotNull(inner, nameof(inner));
this.inner = inner;
}
public IEnumerable<TKey> Keys
{
get { return inner().Keys; }
}
public IEnumerable<TValue> Values
{
get { return inner().Values.OfType<TValue>(); }
}
public int Count
{
get { return inner().Count; }
}
public TValue this[TKey key]
{
get { return inner()[key]; }
}
public bool ContainsKey(TKey key)
{
return inner().ContainsKey(key);
}
public bool TryGetValue(TKey key, out TValue value)
{
if (inner().TryGetValue(key, out var temp))
{
value = temp as TValue;
return value != null;
}
value = null;
return false;
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Enumerate().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private IEnumerable<KeyValuePair<TKey, TValue>> Enumerate()
{
foreach (var kvp in inner())
{
yield return new KeyValuePair<TKey, TValue>(kvp.Key, (TValue)kvp.Value);
}
}
}
}

4
src/Squidex.Infrastructure/Json/TypeNameSerializationBinder.cs

@ -24,7 +24,7 @@ namespace Squidex.Infrastructure.Json
public override Type BindToType(string assemblyName, string typeName) public override Type BindToType(string assemblyName, string typeName)
{ {
var type = typeNameRegistry.GetType(typeName); var type = typeNameRegistry.GetTypeOrNull(typeName);
return type ?? base.BindToType(assemblyName, typeName); return type ?? base.BindToType(assemblyName, typeName);
} }
@ -33,7 +33,7 @@ namespace Squidex.Infrastructure.Json
{ {
assemblyName = null; assemblyName = null;
var name = typeNameRegistry.GetName(serializedType); var name = typeNameRegistry.GetNameOrNull(serializedType);
if (name != null) if (name != null)
{ {

14
src/Squidex.Infrastructure/TypeNameRegistry.cs

@ -115,6 +115,20 @@ namespace Squidex.Infrastructure
return GetName(typeof(T)); return GetName(typeof(T));
} }
public string GetNameOrNull(Type type)
{
var result = namesByType.GetOrDefault(type);
return result;
}
public Type GetTypeOrNull(string name)
{
var result = typesByName.GetOrDefault(name);
return result;
}
public string GetName(Type type) public string GetName(Type type)
{ {
var result = namesByType.GetOrDefault(type); var result = namesByType.GetOrDefault(type);

4
src/Squidex/Config/Domain/InfrastructureModule.cs

@ -152,10 +152,6 @@ namespace Squidex.Config.Domain
builder.RegisterType<EventDataFormatter>() builder.RegisterType<EventDataFormatter>()
.AsSelf() .AsSelf()
.SingleInstance(); .SingleInstance();
builder.RegisterType<FieldRegistry>()
.AsSelf()
.SingleInstance();
} }
} }
} }

21
src/Squidex/Config/Domain/Serializers.cs

@ -24,6 +24,8 @@ namespace Squidex.Config.Domain
public static class Serializers public static class Serializers
{ {
private static readonly TypeNameRegistry TypeNameRegistry = new TypeNameRegistry(); private static readonly TypeNameRegistry TypeNameRegistry = new TypeNameRegistry();
private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings();
private static readonly FieldRegistry FieldRegistry = new FieldRegistry(TypeNameRegistry);
private static JsonSerializerSettings ConfigureJson(JsonSerializerSettings settings, TypeNameHandling typeNameHandling) private static JsonSerializerSettings ConfigureJson(JsonSerializerSettings settings, TypeNameHandling typeNameHandling)
{ {
@ -37,7 +39,7 @@ namespace Squidex.Config.Domain
new NamedStringIdConverter(), new NamedStringIdConverter(),
new PropertiesBagConverter(), new PropertiesBagConverter(),
new RefTokenConverter(), new RefTokenConverter(),
new SchemaConverter(new FieldRegistry(TypeNameRegistry)), new SchemaConverter(FieldRegistry),
new StringEnumConverter()); new StringEnumConverter());
settings.NullValueHandling = NullValueHandling.Ignore; settings.NullValueHandling = NullValueHandling.Ignore;
@ -49,8 +51,6 @@ namespace Squidex.Config.Domain
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
JsonConvert.DefaultSettings = () => settings;
return settings; return settings;
} }
@ -58,23 +58,18 @@ namespace Squidex.Config.Domain
{ {
TypeNameRegistry.Map(typeof(SquidexEvent).GetTypeInfo().Assembly); TypeNameRegistry.Map(typeof(SquidexEvent).GetTypeInfo().Assembly);
TypeNameRegistry.Map(typeof(NoopEvent).GetTypeInfo().Assembly); TypeNameRegistry.Map(typeof(NoopEvent).GetTypeInfo().Assembly);
}
private static JsonSerializerSettings CreateSettings() ConfigureJson(SerializerSettings, TypeNameHandling.Auto);
{
return ConfigureJson(new JsonSerializerSettings(), TypeNameHandling.Auto);
}
private static JsonSerializer CreateSerializer(JsonSerializerSettings settings) JsonConvert.DefaultSettings = () => SerializerSettings;
{
return JsonSerializer.Create(settings);
} }
public static IServiceCollection AddMyEventFormatter(this IServiceCollection services) public static IServiceCollection AddMyEventFormatter(this IServiceCollection services)
{ {
services.AddSingleton(t => TypeNameRegistry); services.AddSingleton(t => TypeNameRegistry);
services.AddSingleton(t => CreateSettings()); services.AddSingleton(t => FieldRegistry);
services.AddSingleton(t => CreateSerializer(t.GetRequiredService<JsonSerializerSettings>())); services.AddSingleton(t => SerializerSettings);
services.AddSingleton(t => JsonSerializer.Create(SerializerSettings));
return services; return services;
} }

22
src/Squidex/Config/Domain/StoreMongoDbModule.cs

@ -13,9 +13,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Domain.Apps.Read.Apps.Repositories; using Squidex.Domain.Apps.Read.Apps.Repositories;
using Squidex.Domain.Apps.Read.Apps.Services.Implementations;
using Squidex.Domain.Apps.Read.Assets.Repositories; using Squidex.Domain.Apps.Read.Assets.Repositories;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.Contents.Repositories; using Squidex.Domain.Apps.Read.Contents.Repositories;
using Squidex.Domain.Apps.Read.History.Repositories; using Squidex.Domain.Apps.Read.History.Repositories;
using Squidex.Domain.Apps.Read.MongoDb.Apps; using Squidex.Domain.Apps.Read.MongoDb.Apps;
@ -25,7 +23,6 @@ using Squidex.Domain.Apps.Read.MongoDb.History;
using Squidex.Domain.Apps.Read.MongoDb.Schemas; using Squidex.Domain.Apps.Read.MongoDb.Schemas;
using Squidex.Domain.Apps.Read.MongoDb.Webhooks; using Squidex.Domain.Apps.Read.MongoDb.Webhooks;
using Squidex.Domain.Apps.Read.Schemas.Repositories; using Squidex.Domain.Apps.Read.Schemas.Repositories;
using Squidex.Domain.Apps.Read.Schemas.Services.Implementations;
using Squidex.Domain.Apps.Read.Webhooks.Repositories; using Squidex.Domain.Apps.Read.Webhooks.Repositories;
using Squidex.Domain.Users; using Squidex.Domain.Users;
using Squidex.Domain.Users.MongoDb; using Squidex.Domain.Users.MongoDb;
@ -147,6 +144,7 @@ namespace Squidex.Config.Domain
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration)) .WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IAppRepository>() .As<IAppRepository>()
.As<IExternalSystem>() .As<IExternalSystem>()
.As<IEventConsumer>()
.AsSelf() .AsSelf()
.SingleInstance(); .SingleInstance();
@ -154,6 +152,7 @@ namespace Squidex.Config.Domain
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration)) .WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<ISchemaRepository>() .As<ISchemaRepository>()
.As<IExternalSystem>() .As<IExternalSystem>()
.As<IEventConsumer>()
.AsSelf() .AsSelf()
.SingleInstance(); .SingleInstance();
@ -186,23 +185,6 @@ namespace Squidex.Config.Domain
.As<IEventConsumer>() .As<IEventConsumer>()
.AsSelf() .AsSelf()
.SingleInstance(); .SingleInstance();
builder.Register(c =>
new CompoundEventConsumer(
c.Resolve<MongoSchemaRepository>(),
c.Resolve<CachingGraphQLService>(),
c.Resolve<CachingSchemaProvider>()))
.As<IEventConsumer>()
.AsSelf()
.SingleInstance();
builder.Register(c =>
new CompoundEventConsumer(
c.Resolve<MongoAppRepository>(),
c.Resolve<CachingAppProvider>()))
.As<IEventConsumer>()
.AsSelf()
.SingleInstance();
} }
} }
} }

30
src/Squidex/Config/Domain/Usages.cs

@ -9,6 +9,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Read.Apps.Repositories;
using Squidex.Domain.Apps.Read.Apps.Services;
using Squidex.Domain.Apps.Read.Schemas.Repositories;
using Squidex.Domain.Apps.Read.Schemas.Services;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Actors; using Squidex.Infrastructure.Actors;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
@ -20,20 +24,38 @@ namespace Squidex.Config.Domain
{ {
public static IApplicationBuilder UseMyEventStore(this IApplicationBuilder app) public static IApplicationBuilder UseMyEventStore(this IApplicationBuilder app)
{ {
app.ApplicationServices.GetService<EventConsumerCleaner>().CleanAsync().Wait(); var services = app.ApplicationServices;
var consumers = app.ApplicationServices.GetServices<IEventConsumer>(); services.GetService<EventConsumerCleaner>().CleanAsync().Wait();
var consumers = services.GetServices<IEventConsumer>();
foreach (var consumer in consumers) foreach (var consumer in consumers)
{ {
var actor = app.ApplicationServices.GetService<EventConsumerActor>(); var actor = services.GetService<EventConsumerActor>();
if (actor != null) if (actor != null)
{ {
actor.SubscribeAsync(consumer); actor.SubscribeAsync(consumer);
app.ApplicationServices.GetService<RemoteActors>().Connect(consumer.Name, actor); services.GetService<RemoteActors>().Connect(consumer.Name, actor);
}
} }
var appRepository = services.GetService<IAppRepository>();
var appProvider = services.GetService<IAppProvider>();
if (appProvider != null)
{
appRepository?.SubscribeOnChanged(appProvider.Invalidate);
}
var schemaRepository = services.GetService<ISchemaRepository>();
var schemaProvider = services.GetService<ISchemaProvider>();
if (schemaProvider != null)
{
schemaRepository?.SubscribeOnChanged(schemaProvider.Invalidate);
} }
return app; return app;

4
src/Squidex/Config/Domain/WriteModule.cs

@ -59,10 +59,6 @@ namespace Squidex.Config.Domain
.As<IContentVersionLoader>() .As<IContentVersionLoader>()
.SingleInstance(); .SingleInstance();
builder.RegisterType<FieldRegistry>()
.AsSelf()
.SingleInstance();
builder.RegisterType<AppCommandMiddleware>() builder.RegisterType<AppCommandMiddleware>()
.As<ICommandMiddleware>() .As<ICommandMiddleware>()
.SingleInstance(); .SingleInstance();

2
src/Squidex/Config/Identity/LazyClientStore.cs

@ -53,7 +53,7 @@ namespace Squidex.Config.Identity
var app = await appProvider.FindAppByNameAsync(token[0]); var app = await appProvider.FindAppByNameAsync(token[0]);
var appClient = app?.Clients.FirstOrDefault(x => x.Id == token[1]); var appClient = app?.Clients.GetOrDefault(token[1]);
if (appClient == null) if (appClient == null)
{ {

2
src/Squidex/Controllers/Api/Apps/AppClientsController.cs

@ -50,7 +50,7 @@ namespace Squidex.Controllers.Api.Apps
[ApiCosts(1)] [ApiCosts(1)]
public IActionResult GetClients(string app) public IActionResult GetClients(string app)
{ {
var response = App.Clients.Select(x => SimpleMapper.Map(x, new ClientDto())).ToList(); var response = App.Clients.Select(x => SimpleMapper.Map(x.Value, new ClientDto { Id = x.Key })).ToList();
Response.Headers["ETag"] = new StringValues(App.Version.ToString()); Response.Headers["ETag"] = new StringValues(App.Version.ToString());

2
src/Squidex/Controllers/Api/Apps/AppContributorsController.cs

@ -51,7 +51,7 @@ namespace Squidex.Controllers.Api.Apps
[ApiCosts(1)] [ApiCosts(1)]
public IActionResult GetContributors(string app) public IActionResult GetContributors(string app)
{ {
var contributors = App.Contributors.Select(x => SimpleMapper.Map(x, new ContributorDto())).ToArray(); var contributors = App.Contributors.Select(x => SimpleMapper.Map(x.Value, new ContributorDto { ContributorId = x.Key })).ToArray();
var response = new ContributorsDto { Contributors = contributors, MaxContributors = appPlansProvider.GetPlanForApp(App).MaxContributors }; var response = new ContributorsDto { Contributors = contributors, MaxContributors = appPlansProvider.GetPlanForApp(App).MaxContributors };

2
src/Squidex/Controllers/Api/Apps/AppsController.cs

@ -62,7 +62,7 @@ namespace Squidex.Controllers.Api.Apps
{ {
var dto = SimpleMapper.Map(s, new AppDto()); var dto = SimpleMapper.Map(s, new AppDto());
dto.Permission = s.Contributors.Single(x => x.ContributorId == subject).Permission; dto.Permission = s.Contributors[subject].Permission;
return dto; return dto;
}).ToList(); }).ToList();

1
src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs

@ -15,7 +15,6 @@ using Squidex.Config;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Schemas.JsonSchema; using Squidex.Domain.Apps.Core.Schemas.JsonSchema;
using Squidex.Domain.Apps.Read.Contents.JsonSchema;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Pipeline.Swagger; using Squidex.Pipeline.Swagger;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;

18
src/Squidex/Pipeline/AppApiFilter.cs

@ -117,28 +117,26 @@ namespace Squidex.Pipeline
private static AppPermission? FindByOpenIdClient(IAppEntity app, ClaimsPrincipal user) private static AppPermission? FindByOpenIdClient(IAppEntity app, ClaimsPrincipal user)
{ {
var client = app.Clients.FirstOrDefault(x => string.Equals(x.Id, user.GetClientId(), StringComparison.OrdinalIgnoreCase)); var clientId = user.GetClientId();
if (client == null) if (clientId != null && app.Clients.TryGetValue(clientId, out var client))
{ {
return null; return client.Permission.ToAppPermission();
} }
return client.Permission.ToAppPermission(); return null;
} }
private static AppPermission? FindByOpenIdSubject(IAppEntity app, ClaimsPrincipal user) private static AppPermission? FindByOpenIdSubject(IAppEntity app, ClaimsPrincipal user)
{ {
var subject = user.FindFirst(OpenIdClaims.Subject)?.Value; var subjectId = user.FindFirst(OpenIdClaims.Subject)?.Value;
if (subject == null) if (subjectId != null && app.Contributors.TryGetValue(subjectId, out var contributor))
{ {
return null; return contributor.Permission.ToAppPermission();
} }
var contributor = app.Contributors.FirstOrDefault(x => string.Equals(x.ContributorId, subject, StringComparison.OrdinalIgnoreCase)); return null;
return contributor?.Permission.ToAppPermission();
} }
} }
} }

2
src/Squidex/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs

@ -44,7 +44,7 @@ namespace Squidex.Pipeline.CommandMiddlewares
{ {
var subjectId = httpContextAccessor.HttpContext.User.OpenIdSubject(); var subjectId = httpContextAccessor.HttpContext.User.OpenIdSubject();
return subjectId == null ? null : new RefToken("subject.", subjectId); return subjectId == null ? null : new RefToken("subject", subjectId);
} }
private RefToken FindActorFromClient() private RefToken FindActorFromClient()

2
src/Squidex/app/features/webhooks/pages/webhook.component.ts

@ -22,7 +22,7 @@ export interface WebhookSchemaForm {
sendCreate: boolean; sendCreate: boolean;
sendUpdate: boolean; sendUpdate: boolean;
sendDelete: boolean; sendDelete: boolean;
sendPublish: boolean sendPublish: boolean;
} }
@Component({ @Component({

4
src/Squidex/app/framework/angular/modal-target.directive.ts

@ -97,7 +97,7 @@ export class ModalTargetDirective implements AfterViewInit, OnDestroy, OnInit {
const fix = this.autoPosition; const fix = this.autoPosition;
let t = 0 let t = 0;
let l = 0; let l = 0;
switch (this.position) { switch (this.position) {
@ -153,7 +153,7 @@ export class ModalTargetDirective implements AfterViewInit, OnDestroy, OnInit {
case POSITION_TOPRIGHT: case POSITION_TOPRIGHT:
case POSITION_BOTTOMRIGHT: case POSITION_BOTTOMRIGHT:
{ {
l = targetRect.right - modalRect.width l = targetRect.right - modalRect.width;
break; break;
} }
case POSITION_RIGHTTOP: case POSITION_RIGHTTOP:

2
src/Squidex/app/framework/services/dialog.service.spec.ts

@ -58,7 +58,7 @@ describe('DialogService', () => {
isNext = result; isNext = result;
}, undefined, () => { }, undefined, () => {
isCompleted = true; isCompleted = true;
}) });
dialog.complete(true); dialog.complete(true);

2
tests/Squidex.Domain.Apps.Core.Tests/ContentEnrichmentTests.cs

@ -66,8 +66,6 @@ namespace Squidex.Domain.Apps.Core
[Fact] [Fact]
private void Should_also_enrich_with_default_values_when_string_is_empty() private void Should_also_enrich_with_default_values_when_string_is_empty()
{ {
var now = Instant.FromUnixTimeSeconds(SystemClock.Instance.GetCurrentInstant().ToUnixTimeSeconds());
var data = var data =
new NamedContentData() new NamedContentData()
.AddField("my-string", .AddField("my-string",

28
tests/Squidex.Domain.Apps.Read.Tests/Apps/CachingAppProviderTests.cs

@ -11,11 +11,9 @@ using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Domain.Apps.Read.Apps.Repositories; using Squidex.Domain.Apps.Read.Apps.Repositories;
using Squidex.Domain.Apps.Read.Apps.Services.Implementations; using Squidex.Domain.Apps.Read.Apps.Services.Implementations;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Read.Apps namespace Squidex.Domain.Apps.Read.Apps
@ -40,24 +38,6 @@ namespace Squidex.Domain.Apps.Read.Apps
sut = new CachingAppProvider(cache, repository); sut = new CachingAppProvider(cache, repository);
} }
[Fact]
public void Should_return_empty_for_events_filter()
{
Assert.Equal(string.Empty, sut.EventsFilter);
}
[Fact]
public void Should_return_empty_for_name()
{
Assert.Equal(typeof(CachingAppProvider).Name, sut.Name);
}
[Fact]
public void Should_do_nothing_when_clearing()
{
Assert.NotNull(sut.ClearAsync());
}
[Fact] [Fact]
public async Task Should_also_retrieve_app_by_name_if_retrieved_by_id_before() public async Task Should_also_retrieve_app_by_name_if_retrieved_by_id_before()
{ {
@ -85,7 +65,7 @@ namespace Squidex.Domain.Apps.Read.Apps
} }
[Fact] [Fact]
public async Task Should_clear_cache_for_id_after_update_event() public async Task Should_clear_cache_for_id_after_invalidating()
{ {
A.CallTo(() => repository.FindAppAsync(appId.Id)) A.CallTo(() => repository.FindAppAsync(appId.Id))
.Returns(appV2); .Returns(appV2);
@ -94,7 +74,7 @@ namespace Squidex.Domain.Apps.Read.Apps
await ProvideAppByIdAsync(appV1); await ProvideAppByIdAsync(appV1);
sut.On(Envelope.Create(new AppLanguageAdded { AppId = appId }).To<IEvent>()).Wait(); sut.Invalidate(appId);
await ProvideAppByIdAsync(appV2); await ProvideAppByIdAsync(appV2);
@ -102,7 +82,7 @@ namespace Squidex.Domain.Apps.Read.Apps
} }
[Fact] [Fact]
public async Task Should_clear_cache_for_name_after_update_event() public async Task Should_clear_cache_for_name_after_invalidating()
{ {
A.CallTo(() => repository.FindAppAsync(appId.Name)) A.CallTo(() => repository.FindAppAsync(appId.Name))
.Returns(appV2); .Returns(appV2);
@ -111,7 +91,7 @@ namespace Squidex.Domain.Apps.Read.Apps
await ProvideAppByNameAsync(appV1); await ProvideAppByNameAsync(appV1);
sut.On(Envelope.Create(new AppLanguageAdded { AppId = appId }).To<IEvent>()).Wait(); sut.Invalidate(appId);
await ProvideAppByNameAsync(appV2); await ProvideAppByNameAsync(appV2);

26
tests/Squidex.Domain.Apps.Read.Tests/Schemas/CachingSchemaProviderTests.cs

@ -43,24 +43,6 @@ namespace Squidex.Domain.Apps.Read.Schemas
sut = new CachingSchemaProvider(cache, repository); sut = new CachingSchemaProvider(cache, repository);
} }
[Fact]
public void Should_return_empty_for_events_filter()
{
Assert.Equal(string.Empty, sut.EventsFilter);
}
[Fact]
public void Should_return_empty_for_name()
{
Assert.Equal(typeof(CachingSchemaProvider).Name, sut.Name);
}
[Fact]
public void Should_do_nothing_when_clearing()
{
Assert.NotNull(sut.ClearAsync());
}
[Fact] [Fact]
public async Task Should_also_retrieve_schema_by_name_if_retrieved_by_id_before() public async Task Should_also_retrieve_schema_by_name_if_retrieved_by_id_before()
{ {
@ -88,7 +70,7 @@ namespace Squidex.Domain.Apps.Read.Schemas
} }
[Fact] [Fact]
public async Task Should_clear_cache_for_id_after_update_event() public async Task Should_clear_cache_for_id_after_invalidating()
{ {
A.CallTo(() => repository.FindSchemaAsync(schemaId.Id)) A.CallTo(() => repository.FindSchemaAsync(schemaId.Id))
.Returns(schemaV2); .Returns(schemaV2);
@ -97,7 +79,7 @@ namespace Squidex.Domain.Apps.Read.Schemas
await ProvideSchemaById(schemaV1); await ProvideSchemaById(schemaV1);
sut.On(Envelope.Create(new FieldAdded { AppId = appId, SchemaId = schemaId })).Wait(); sut.Invalidate(appId, schemaId);
await ProvideSchemaById(schemaV2); await ProvideSchemaById(schemaV2);
@ -105,7 +87,7 @@ namespace Squidex.Domain.Apps.Read.Schemas
} }
[Fact] [Fact]
public async Task Should_clear_cache_for_name_after_update_event() public async Task Should_clear_cache_for_name_after_invalidating()
{ {
A.CallTo(() => repository.FindSchemaAsync(appId.Id, schemaId.Name)) A.CallTo(() => repository.FindSchemaAsync(appId.Id, schemaId.Name))
.Returns(schemaV2); .Returns(schemaV2);
@ -114,7 +96,7 @@ namespace Squidex.Domain.Apps.Read.Schemas
await ProvideSchemaByName(schemaV1); await ProvideSchemaByName(schemaV1);
sut.On(Envelope.Create(new SchemaUpdated { AppId = appId, SchemaId = schemaId })).Wait(); sut.Invalidate(appId, schemaId);
await ProvideSchemaByName(schemaV2); await ProvideSchemaByName(schemaV2);

7
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentVersionLoaderTests.cs

@ -48,13 +48,6 @@ namespace Squidex.Domain.Apps.Write.Contents
[Fact] [Fact]
public async Task Should_throw_exception_when_version_not_found() public async Task Should_throw_exception_when_version_not_found()
{ {
var events = new List<StoredEvent>
{
new StoredEvent("0", 0, new EventData()),
new StoredEvent("1", 1, new EventData()),
new StoredEvent("2", 2, new EventData())
};
A.CallTo(() => eventStore.GetEventsAsync(streamName)) A.CallTo(() => eventStore.GetEventsAsync(streamName))
.Returns(new List<StoredEvent>()); .Returns(new List<StoredEvent>());

2
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/AssetsFieldPropertiesTests.cs

@ -13,7 +13,7 @@ using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldPro namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{ {
public class AssetsFieldPropertiesTests public class AssetsFieldPropertiesTests
{ {

2
tests/Squidex.Infrastructure.Tests/CQRS/Commands/InMemoryCommandBusTests.cs

@ -20,7 +20,7 @@ namespace Squidex.Infrastructure.CQRS.Commands
private sealed class HandledHandler : ICommandMiddleware private sealed class HandledHandler : ICommandMiddleware
{ {
public ICommand LastCommand { get; set; } public ICommand LastCommand { get; private set; }
public Task HandleAsync(CommandContext context, Func<Task> next) public Task HandleAsync(CommandContext context, Func<Task> next)
{ {

2
tests/Squidex.Infrastructure.Tests/CQRS/Events/Actors/EventConsumerActorTests.cs

@ -251,8 +251,6 @@ namespace Squidex.Infrastructure.CQRS.Events.Actors
A.CallTo(() => eventConsumer.ClearAsync()) A.CallTo(() => eventConsumer.ClearAsync())
.Throws(ex); .Throws(ex);
var @event = new StoredEvent(Guid.NewGuid().ToString(), 123, eventData);
await OnSubscribeAsync(); await OnSubscribeAsync();
sutActor.Tell(new ResetConsumerMessage()); sutActor.Tell(new ResetConsumerMessage());

2
tests/Squidex.Infrastructure.Tests/CQRS/Events/PollingSubscriptionTests.cs

@ -106,7 +106,7 @@ namespace Squidex.Infrastructure.CQRS.Events
.MustHaveHappened(Repeated.Exactly.Twice); .MustHaveHappened(Repeated.Exactly.Twice);
} }
private async Task WaitAndStopAsync(PollingSubscription sut) private static async Task WaitAndStopAsync(IEventSubscription sut)
{ {
await Task.Delay(200); await Task.Delay(200);

12
tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs

@ -122,10 +122,22 @@ namespace Squidex.Infrastructure
Assert.Throws<TypeNameNotFoundException>(() => sut.GetType("unsupported")); Assert.Throws<TypeNameNotFoundException>(() => sut.GetType("unsupported"));
} }
[Fact]
public void Should_return_null_if_name_is_not_supported()
{
Assert.Null(sut.GetType("unsupported"));
}
[Fact] [Fact]
public void Should_throw_exception_if_type_is_not_supported() public void Should_throw_exception_if_type_is_not_supported()
{ {
Assert.Throws<TypeNameNotFoundException>(() => sut.GetName<Guid>()); Assert.Throws<TypeNameNotFoundException>(() => sut.GetName<Guid>());
} }
[Fact]
public void Should_return_null_if_type_is_not_supported()
{
Assert.Null(sut.GetName<Guid>());
}
} }
} }

Loading…
Cancel
Save