Browse Source

Schema sync.

pull/343/head
Sebastian Stehle 7 years ago
parent
commit
61d82b042f
  1. 5
      src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs
  2. 2
      src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs
  3. 2
      src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs
  4. 76
      src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs
  5. 16
      src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizationOptions.cs
  6. 208
      src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs
  7. 46
      src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SyncHelpers.cs
  8. 18
      src/Squidex.Domain.Apps.Events/Schemas/SchemaScriptsConfigured.cs
  9. 51
      tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/AssertHelper.cs
  10. 505
      tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/SchemaSynchronizerTests.cs

5
src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs

@ -31,6 +31,11 @@ namespace Squidex.Domain.Apps.Core.Schemas
get { return fields.ByName; }
}
public FieldCollection<NestedField> FieldCollection
{
get { return fields; }
}
public ArrayField(long id, string name, Partitioning partitioning, ArrayFieldProperties properties = null, IFieldSettings settings = null)
: base(id, name, partitioning, properties)
{

2
src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs

@ -111,7 +111,7 @@ namespace Squidex.Domain.Apps.Core.Schemas
return new NestedField<TagsFieldProperties>(id, name, properties, settings);
}
public static Schema AddArray(this Schema schema, long id, string name, Partitioning partitioning, Func<ArrayField, ArrayField> handler, ArrayFieldProperties properties = null, IFieldSettings settings = null)
public static Schema AddArray(this Schema schema, long id, string name, Partitioning partitioning, Func<ArrayField, ArrayField> handler = null, ArrayFieldProperties properties = null, IFieldSettings settings = null)
{
var field = Array(id, name, partitioning, properties, settings);

2
src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs

@ -16,5 +16,7 @@ namespace Squidex.Domain.Apps.Core.Schemas
IReadOnlyDictionary<long, NestedField> FieldsById { get; }
IReadOnlyDictionary<string, NestedField> FieldsByName { get; }
FieldCollection<NestedField> FieldCollection { get; }
}
}

76
src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs

@ -14,8 +14,14 @@ namespace Squidex.Domain.Apps.Core.Schemas
{
public sealed class Schema : Cloneable<Schema>
{
private static readonly Dictionary<string, string> EmptyScripts = new Dictionary<string, string>();
private static readonly Dictionary<string, string> EmptyPreviewUrls = new Dictionary<string, string>();
private readonly string name;
private readonly bool isSingleton;
private string category;
private FieldCollection<RootField> fields = FieldCollection<RootField>.Empty;
private IReadOnlyDictionary<string, string> scripts = EmptyScripts;
private IReadOnlyDictionary<string, string> previewUrls = EmptyPreviewUrls;
private SchemaProperties properties;
private bool isPublished;
@ -24,11 +30,21 @@ namespace Squidex.Domain.Apps.Core.Schemas
get { return name; }
}
public string Category
{
get { return category; }
}
public bool IsPublished
{
get { return isPublished; }
}
public bool IsSingleton
{
get { return isSingleton; }
}
public IReadOnlyList<RootField> Fields
{
get { return fields.Ordered; }
@ -44,12 +60,27 @@ namespace Squidex.Domain.Apps.Core.Schemas
get { return fields.ByName; }
}
public IReadOnlyDictionary<string, string> Scripts
{
get { return scripts; }
}
public IReadOnlyDictionary<string, string> PreviewUrls
{
get { return previewUrls; }
}
public FieldCollection<RootField> FieldCollection
{
get { return fields; }
}
public SchemaProperties Properties
{
get { return properties; }
}
public Schema(string name, SchemaProperties properties = null)
public Schema(string name, SchemaProperties properties = null, bool isSingleton = false)
{
Guard.NotNullOrEmpty(name, nameof(name));
@ -57,10 +88,12 @@ namespace Squidex.Domain.Apps.Core.Schemas
this.properties = properties ?? new SchemaProperties();
this.properties.Freeze();
this.isSingleton = isSingleton;
}
public Schema(string name, RootField[] fields, SchemaProperties properties, bool isPublished)
: this(name, properties)
public Schema(string name, RootField[] fields, SchemaProperties properties, bool isPublished, bool isSingleton = false)
: this(name, properties, isSingleton)
{
Guard.NotNull(fields, nameof(fields));
@ -99,31 +132,58 @@ namespace Squidex.Domain.Apps.Core.Schemas
});
}
[Pure]
public Schema MoveTo(string category)
{
return Clone(clone =>
{
clone.category = category;
});
}
[Pure]
public Schema ConfigureScripts(IReadOnlyDictionary<string, string> scripts)
{
return Clone(clone =>
{
clone.scripts = scripts ?? EmptyScripts;
});
}
[Pure]
public Schema ConfigurePreviewUrls(IReadOnlyDictionary<string, string> previewUrls)
{
return Clone(clone =>
{
clone.previewUrls = previewUrls ?? EmptyPreviewUrls;
});
}
[Pure]
public Schema DeleteField(long fieldId)
{
return Updatefields(f => f.Remove(fieldId));
return UpdateFields(f => f.Remove(fieldId));
}
[Pure]
public Schema ReorderFields(List<long> ids)
{
return Updatefields(f => f.Reorder(ids));
return UpdateFields(f => f.Reorder(ids));
}
[Pure]
public Schema AddField(RootField field)
{
return Updatefields(f => f.Add(field));
return UpdateFields(f => f.Add(field));
}
[Pure]
public Schema UpdateField(long fieldId, Func<RootField, RootField> updater)
{
return Updatefields(f => f.Update(fieldId, updater));
return UpdateFields(f => f.Update(fieldId, updater));
}
private Schema Updatefields(Func<FieldCollection<RootField>, FieldCollection<RootField>> updater)
private Schema UpdateFields(Func<FieldCollection<RootField>, FieldCollection<RootField>> updater)
{
var newFields = updater(fields);

16
src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizationOptions.cs

@ -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; }
}
}

208
src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs

@ -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);
}
}
}

46
src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SyncHelpers.cs

@ -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);
}
}
}

18
src/Squidex.Domain.Apps.Events/Schemas/SchemaScriptsConfigured.cs

@ -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; }
}
}

51
tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/AssertHelper.cs

@ -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());
}
}
}

505
tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/SchemaSynchronizerTests.cs

@ -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…
Cancel
Save