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