mirror of https://github.com/Squidex/squidex.git
10 changed files with 920 additions and 9 deletions
@ -0,0 +1,16 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.EventSynchronization |
||||
|
{ |
||||
|
public sealed class SchemaSynchronizationOptions |
||||
|
{ |
||||
|
public bool NoFieldDeletion { get; set; } |
||||
|
|
||||
|
public bool NoFieldRecreation { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,208 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Domain.Apps.Events; |
||||
|
using Squidex.Domain.Apps.Events.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.EventSourcing; |
||||
|
using Squidex.Infrastructure.Json; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.EventSynchronization |
||||
|
{ |
||||
|
public static class SchemaSynchronizer |
||||
|
{ |
||||
|
public static IEnumerable<IEvent> Synchronize(this Schema source, Schema target, IJsonSerializer serializer, Func<long> idGenerator, SchemaSynchronizationOptions options = null) |
||||
|
{ |
||||
|
Guard.NotNull(source, nameof(source)); |
||||
|
Guard.NotNull(serializer, nameof(serializer)); |
||||
|
Guard.NotNull(idGenerator, nameof(idGenerator)); |
||||
|
|
||||
|
if (target == null) |
||||
|
{ |
||||
|
yield return new SchemaDeleted(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
options = options ?? new SchemaSynchronizationOptions(); |
||||
|
|
||||
|
SchemaEvent E(SchemaEvent @event) |
||||
|
{ |
||||
|
return @event; |
||||
|
} |
||||
|
|
||||
|
var events = SyncFields(source.FieldCollection, target.FieldCollection, serializer, idGenerator, null, options); |
||||
|
|
||||
|
foreach (var @event in events) |
||||
|
{ |
||||
|
yield return E(@event); |
||||
|
} |
||||
|
|
||||
|
if (!source.Properties.EqualsJson(target.Properties, serializer)) |
||||
|
{ |
||||
|
yield return E(new SchemaUpdated { Properties = target.Properties }); |
||||
|
} |
||||
|
|
||||
|
if (!source.Category.StringEquals(target.Category)) |
||||
|
{ |
||||
|
yield return E(new SchemaCategoryChanged { Name = target.Category }); |
||||
|
} |
||||
|
|
||||
|
if (!source.PreviewUrls.EqualsDictionary(target.PreviewUrls)) |
||||
|
{ |
||||
|
yield return E(new SchemaPreviewUrlsConfigured { PreviewUrls = target.PreviewUrls.ToDictionary(x => x.Key, x => x.Value) }); |
||||
|
} |
||||
|
|
||||
|
if (!source.Scripts.EqualsDictionary(target.Scripts)) |
||||
|
{ |
||||
|
yield return E(new SchemaScriptsConfigured { Scripts = target.Scripts.ToDictionary(x => x.Key, x => x.Value) }); |
||||
|
} |
||||
|
|
||||
|
if (source.IsPublished != target.IsPublished) |
||||
|
{ |
||||
|
yield return target.IsPublished ? |
||||
|
E(new SchemaPublished()) : |
||||
|
E(new SchemaUnpublished()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static IEnumerable<SchemaEvent> SyncFields<T>( |
||||
|
FieldCollection<T> source, |
||||
|
FieldCollection<T> target, |
||||
|
IJsonSerializer serializer, |
||||
|
Func<long> idGenerator, |
||||
|
NamedId<long> parentId, SchemaSynchronizationOptions options) where T : class, IField |
||||
|
{ |
||||
|
FieldEvent E(FieldEvent @event) |
||||
|
{ |
||||
|
@event.ParentFieldId = parentId; |
||||
|
|
||||
|
return @event; |
||||
|
} |
||||
|
|
||||
|
var sourceIds = new List<NamedId<long>>(source.Ordered.Select(x => x.NamedId())); |
||||
|
var sourceNames = sourceIds.Select(x => x.Name).ToList(); |
||||
|
|
||||
|
if (!options.NoFieldDeletion) |
||||
|
{ |
||||
|
foreach (var sourceField in source.Ordered) |
||||
|
{ |
||||
|
if (!target.ByName.TryGetValue(sourceField.Name, out var targetField)) |
||||
|
{ |
||||
|
var id = sourceField.NamedId(); |
||||
|
|
||||
|
sourceIds.Remove(id); |
||||
|
sourceNames.Remove(id.Name); |
||||
|
|
||||
|
yield return E(new FieldDeleted { FieldId = id }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
foreach (var targetField in target.Ordered) |
||||
|
{ |
||||
|
NamedId<long> id = null; |
||||
|
|
||||
|
var canCreateField = true; |
||||
|
|
||||
|
if (source.ByName.TryGetValue(targetField.Name, out var sourceField)) |
||||
|
{ |
||||
|
id = sourceField.NamedId(); |
||||
|
|
||||
|
if (CanUpdate(sourceField, targetField)) |
||||
|
{ |
||||
|
if (!sourceField.RawProperties.EqualsJson(targetField.RawProperties, serializer)) |
||||
|
{ |
||||
|
yield return E(new FieldUpdated { FieldId = id, Properties = targetField.RawProperties }); |
||||
|
} |
||||
|
} |
||||
|
else if (!sourceField.IsLocked && !options.NoFieldRecreation) |
||||
|
{ |
||||
|
yield return E(new FieldDeleted { FieldId = id }); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
canCreateField = false; |
||||
|
} |
||||
|
} |
||||
|
else if (canCreateField) |
||||
|
{ |
||||
|
var partitioning = (string)null; |
||||
|
|
||||
|
if (targetField is IRootField rootField) |
||||
|
{ |
||||
|
partitioning = rootField.Partitioning.Key; |
||||
|
} |
||||
|
|
||||
|
id = NamedId.Of(idGenerator(), targetField.Name); |
||||
|
|
||||
|
yield return new FieldAdded |
||||
|
{ |
||||
|
Name = targetField.Name, |
||||
|
ParentFieldId = parentId, |
||||
|
Partitioning = partitioning, |
||||
|
Properties = targetField.RawProperties, |
||||
|
FieldId = id |
||||
|
}; |
||||
|
|
||||
|
sourceIds.Add(id); |
||||
|
sourceNames.Add(id.Name); |
||||
|
} |
||||
|
|
||||
|
if (id != null && (sourceField == null || CanUpdate(sourceField, targetField))) |
||||
|
{ |
||||
|
if (!targetField.IsLocked.BoolEquals(sourceField?.IsLocked)) |
||||
|
{ |
||||
|
yield return E(new FieldLocked { FieldId = id }); |
||||
|
} |
||||
|
|
||||
|
if (!targetField.IsHidden.BoolEquals(sourceField?.IsHidden)) |
||||
|
{ |
||||
|
yield return targetField.IsHidden ? |
||||
|
E(new FieldHidden { FieldId = id }) : |
||||
|
E(new FieldShown { FieldId = id }); |
||||
|
} |
||||
|
|
||||
|
if (!targetField.IsDisabled.BoolEquals(sourceField?.IsDisabled)) |
||||
|
{ |
||||
|
yield return targetField.IsDisabled ? |
||||
|
E(new FieldDisabled { FieldId = id }) : |
||||
|
E(new FieldEnabled { FieldId = id }); |
||||
|
} |
||||
|
|
||||
|
if ((sourceField == null || sourceField is IArrayField) && targetField is IArrayField targetArrayField) |
||||
|
{ |
||||
|
var fields = (sourceField as IArrayField)?.FieldCollection ?? FieldCollection<NestedField>.Empty; |
||||
|
|
||||
|
var events = SyncFields(fields, targetArrayField.FieldCollection, serializer, idGenerator, id, options); |
||||
|
|
||||
|
foreach (var @event in events) |
||||
|
{ |
||||
|
yield return @event; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var targetNames = target.Ordered.Select(x => x.Name); |
||||
|
|
||||
|
if (sourceNames.Intersect(targetNames).Count() == target.Ordered.Count && !sourceNames.SequenceEqual(targetNames)) |
||||
|
{ |
||||
|
yield return new SchemaFieldsReordered { FieldIds = sourceIds.Select(x => x.Id).ToList(), ParentFieldId = parentId }; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static bool CanUpdate(IField source, IField target) |
||||
|
{ |
||||
|
return !source.IsLocked && source.Name == target.Name && source.RawProperties.TypeEquals(target.RawProperties); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Json; |
||||
|
using NamedIdStatic = Squidex.Infrastructure.NamedId; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.EventSynchronization |
||||
|
{ |
||||
|
public static class SyncHelpers |
||||
|
{ |
||||
|
public static bool BoolEquals(this bool lhs, bool? rhs) |
||||
|
{ |
||||
|
return lhs == (rhs ?? false); |
||||
|
} |
||||
|
|
||||
|
public static bool StringEquals(this string lhs, string rhs) |
||||
|
{ |
||||
|
return string.Equals(lhs ?? string.Empty, rhs ?? string.Empty, StringComparison.Ordinal); |
||||
|
} |
||||
|
|
||||
|
public static bool TypeEquals(this object lhs, object rhs) |
||||
|
{ |
||||
|
return lhs.GetType() == rhs.GetType(); |
||||
|
} |
||||
|
|
||||
|
public static NamedId<long> NamedId(this IField field) |
||||
|
{ |
||||
|
return NamedIdStatic.Of(field.Id, field.Name); |
||||
|
} |
||||
|
|
||||
|
public static bool EqualsJson<T>(this T lhs, T rhs, IJsonSerializer serializer) |
||||
|
{ |
||||
|
var lhsJson = serializer.Serialize(lhs); |
||||
|
var rhsJson = serializer.Serialize(rhs); |
||||
|
|
||||
|
return string.Equals(lhsJson, rhsJson); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Infrastructure.EventSourcing; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Events.Schemas |
||||
|
{ |
||||
|
[EventType(nameof(SchemaScriptsConfigured))] |
||||
|
public sealed class SchemaScriptsConfigured : SchemaEvent |
||||
|
{ |
||||
|
public Dictionary<string, string> Scripts { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using FluentAssertions; |
||||
|
using FluentAssertions.Equivalency; |
||||
|
using Squidex.Infrastructure.EventSourcing; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Operations.EventSynchronization |
||||
|
{ |
||||
|
public static class AssertHelper |
||||
|
{ |
||||
|
public static void ShouldHaveSameEvents(this IEnumerable<IEvent> events, params IEvent[] others) |
||||
|
{ |
||||
|
var source = events.ToArray(); |
||||
|
|
||||
|
source.Should().HaveSameCount(others); |
||||
|
|
||||
|
for (var i = 0; i < source.Length; i++) |
||||
|
{ |
||||
|
var lhs = source[i]; |
||||
|
var rhs = others[i]; |
||||
|
|
||||
|
lhs.ShouldBeSameEvent(rhs); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void ShouldBeSameEvent(this IEvent lhs, IEvent rhs) |
||||
|
{ |
||||
|
lhs.Should().BeOfType(rhs.GetType()); |
||||
|
|
||||
|
((object)lhs).Should().BeEquivalentTo(rhs, o => o.IncludingAllRuntimeProperties().Excluding((IMemberInfo x) => x.SelectedMemberPath == "Properties.IsFrozen")); |
||||
|
} |
||||
|
|
||||
|
public static void ShouldBeSameEventType(this IEvent lhs, IEvent rhs) |
||||
|
{ |
||||
|
lhs.Should().BeOfType(rhs.GetType()); |
||||
|
} |
||||
|
|
||||
|
public static void ShouldBeEquivalent<T>(this J<T> lhs, T rhs) |
||||
|
{ |
||||
|
lhs.Value.Should().BeEquivalentTo(rhs, o => o.IncludingProperties()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,505 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Domain.Apps.Core.EventSynchronization; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Domain.Apps.Events.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Json; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Operations.EventSynchronization |
||||
|
{ |
||||
|
public class SchemaSynchronizerTests |
||||
|
{ |
||||
|
private readonly Func<long> idGenerator; |
||||
|
private readonly IJsonSerializer jsonSerializer = TestUtils.DefaultSerializer; |
||||
|
private readonly NamedId<long> stringId = NamedId.Of(13L, "my-value"); |
||||
|
private readonly NamedId<long> nestedId = NamedId.Of(141L, "my-value"); |
||||
|
private readonly NamedId<long> arrayId = NamedId.Of(14L, "11-array"); |
||||
|
private int fields = 50; |
||||
|
|
||||
|
public SchemaSynchronizerTests() |
||||
|
{ |
||||
|
idGenerator = () => fields++; |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_schema_deleted() |
||||
|
{ |
||||
|
var sourceSchema = new Schema("source"); |
||||
|
var targetSchema = (Schema)null; |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaDeleted() |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_category_changed() |
||||
|
{ |
||||
|
var sourceSchema = new Schema("source"); |
||||
|
var targetSchema = new Schema("target").MoveTo("Category"); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaCategoryChanged { Name = "Category" } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_scripts_configured() |
||||
|
{ |
||||
|
var scripts = new Dictionary<string, string> |
||||
|
{ |
||||
|
["Create"] = "Script" |
||||
|
}; |
||||
|
|
||||
|
var sourceSchema = new Schema("source"); |
||||
|
var targetSchema = new Schema("target").ConfigureScripts(scripts); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaScriptsConfigured { Scripts = scripts } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_preview_urls_configured() |
||||
|
{ |
||||
|
var previewUrls = new Dictionary<string, string> |
||||
|
{ |
||||
|
["Web"] = "Url" |
||||
|
}; |
||||
|
|
||||
|
var sourceSchema = new Schema("source"); |
||||
|
var targetSchema = new Schema("target").ConfigurePreviewUrls(previewUrls); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaPreviewUrlsConfigured { PreviewUrls = previewUrls } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_schema_published() |
||||
|
{ |
||||
|
var sourceSchema = new Schema("source"); |
||||
|
var targetSchema = new Schema("target").Publish(); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaPublished() |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_schema_unpublished() |
||||
|
{ |
||||
|
var sourceSchema = new Schema("source").Publish(); |
||||
|
var targetSchema = new Schema("target"); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaUnpublished() |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_deleted() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldDeleted { FieldId = nestedId, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_deleted() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target"); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldDeleted { FieldId = stringId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_updated() |
||||
|
{ |
||||
|
var properties = new StringFieldProperties { IsRequired = true }; |
||||
|
|
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name, properties)); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldUpdated { Properties = properties, FieldId = nestedId, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_updated() |
||||
|
{ |
||||
|
var properties = new StringFieldProperties { IsRequired = true }; |
||||
|
|
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant, properties); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldUpdated { Properties = properties, FieldId = stringId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_locked() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)).LockField(nestedId.Id, arrayId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldLocked { FieldId = nestedId, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_locked() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant).LockField(stringId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldLocked { FieldId = stringId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_hidden() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)).HideField(nestedId.Id, arrayId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldHidden { FieldId = nestedId, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_hidden() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant).HideField(stringId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldHidden { FieldId = stringId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_shown() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)).HideField(nestedId.Id, arrayId.Id); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldShown { FieldId = nestedId, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_shown() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant).HideField(stringId.Id); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldShown { FieldId = stringId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_disabled() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)).DisableField(nestedId.Id, arrayId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldDisabled { FieldId = nestedId, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_disabled() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant).DisableField(stringId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldDisabled { FieldId = stringId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_enabled() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)).DisableField(nestedId.Id, arrayId.Id); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldEnabled { FieldId = nestedId, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_enabled() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant).DisableField(stringId.Id); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldEnabled { FieldId = stringId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_field_created() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source"); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(stringId.Id, stringId.Name, Partitioning.Invariant).HideField(stringId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
var createdId = NamedId.Of(50L, stringId.Name); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldAdded { FieldId = createdId, Name = stringId.Name, Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties() }, |
||||
|
new FieldHidden { FieldId = createdId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_field_created() |
||||
|
{ |
||||
|
var sourceSchema = |
||||
|
new Schema("source"); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(nestedId.Id, nestedId.Name)).HideField(nestedId.Id, arrayId.Id); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
var id1 = NamedId.Of(50L, arrayId.Name); |
||||
|
var id2 = NamedId.Of(51L, stringId.Name); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldAdded { FieldId = id1, Name = arrayId.Name, Partitioning = Partitioning.Invariant.Key, Properties = new ArrayFieldProperties() }, |
||||
|
new FieldAdded { FieldId = id2, Name = stringId.Name, ParentFieldId = id1, Properties = new StringFieldProperties() }, |
||||
|
new FieldHidden { FieldId = id2, ParentFieldId = id1 } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_nested_fields_reordered() |
||||
|
{ |
||||
|
var id1 = NamedId.Of(1, "f1"); |
||||
|
var id2 = NamedId.Of(2, "f1"); |
||||
|
|
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(10, "f1") |
||||
|
.AddString(11, "f2")); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddArray(arrayId.Id, arrayId.Name, Partitioning.Invariant, f => f |
||||
|
.AddString(20, "f2") |
||||
|
.AddString(15, "f1")); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaFieldsReordered { FieldIds = new List<long> { 11, 10 }, ParentFieldId = arrayId } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_fields_reordered() |
||||
|
{ |
||||
|
var id1 = NamedId.Of(1, "f1"); |
||||
|
var id2 = NamedId.Of(2, "f1"); |
||||
|
|
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(10, "f1", Partitioning.Invariant) |
||||
|
.AddString(11, "f2", Partitioning.Invariant); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(20, "f2", Partitioning.Invariant) |
||||
|
.AddString(15, "f1", Partitioning.Invariant); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new SchemaFieldsReordered { FieldIds = new List<long> { 11, 10 } } |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_events_if_fields_reordered_after_sync() |
||||
|
{ |
||||
|
var id1 = NamedId.Of(1, "f1"); |
||||
|
var id2 = NamedId.Of(2, "f1"); |
||||
|
|
||||
|
var sourceSchema = |
||||
|
new Schema("source") |
||||
|
.AddString(10, "f1", Partitioning.Invariant) |
||||
|
.AddString(11, "f2", Partitioning.Invariant); |
||||
|
|
||||
|
var targetSchema = |
||||
|
new Schema("target") |
||||
|
.AddString(25, "f3", Partitioning.Invariant) |
||||
|
.AddString(20, "f1", Partitioning.Invariant); |
||||
|
|
||||
|
var events = sourceSchema.Synchronize(targetSchema, jsonSerializer, idGenerator); |
||||
|
|
||||
|
events.ShouldHaveSameEvents( |
||||
|
new FieldDeleted { FieldId = NamedId.Of(11L, "f2") }, |
||||
|
new FieldAdded { FieldId = NamedId.Of(50L, "f3"), Name = "f3", Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties() }, |
||||
|
new SchemaFieldsReordered { FieldIds = new List<long> { 50, 10 } } |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue