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 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)) { canCreateField = false; 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) { canCreateField = true; sourceIds.Remove(id); sourceNames.Remove(id.Name); yield return(E(new FieldDeleted { FieldId = id })); } } 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 = ((IArrayField)sourceField)?.FieldCollection ?? FieldCollection <NestedField> .Empty; var events = SyncFields(fields, targetArrayField.FieldCollection, serializer, idGenerator, id, options); foreach (var @event in events) { yield return(@event); } } } } if (sourceNames.Count > 1) { 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 IEnumerable <ParentFieldEvent> SyncFields <T>( FieldCollection <T> source, FieldCollection <T> target, Func <long> idGenerator, Func <T, T, bool> canUpdate, SchemaSynchronizationOptions options) where T : class, IField { var sourceIds = source.Ordered.Select(x => x.NamedId()).ToList(); if (!options.NoFieldDeletion) { foreach (var sourceField in source.Ordered) { if (!target.ByName.TryGetValue(sourceField.Name, out _)) { var id = sourceField.NamedId(); sourceIds.Remove(id); yield return(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)) { canCreateField = false; id = sourceField.NamedId(); if (canUpdate(sourceField, targetField)) { if (!sourceField.RawProperties.Equals(targetField.RawProperties as object)) { yield return(new FieldUpdated { FieldId = id, Properties = targetField.RawProperties }); } } else if (!sourceField.IsLocked && !options.NoFieldRecreation) { canCreateField = true; sourceIds.Remove(id); yield return(new FieldDeleted { FieldId = id }); } } 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, Partitioning = partitioning, Properties = targetField.RawProperties, FieldId = id }); sourceIds.Add(id); } if (id != null && (sourceField == null || CanUpdate(sourceField, targetField))) { if (!targetField.IsLocked.BoolEquals(sourceField?.IsLocked)) { yield return(new FieldLocked { FieldId = id }); } if (!targetField.IsHidden.BoolEquals(sourceField?.IsHidden)) { yield return(targetField.IsHidden ? new FieldHidden { FieldId = id } : new FieldShown { FieldId = id }); } if (!targetField.IsDisabled.BoolEquals(sourceField?.IsDisabled)) { yield return(targetField.IsDisabled ? new FieldDisabled { FieldId = id } : 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, idGenerator, CanUpdate, options); foreach (var @event in events) { @event.ParentFieldId = id; yield return(@event); } } } } if (sourceIds.Count > 1) { var sourceNames = sourceIds.Select(x => x.Name).ToHashSet(); var targetNames = target.Ordered.Select(x => x.Name).ToHashSet(); if (sourceNames.SetEquals(targetNames) && !sourceNames.SequenceEqual(targetNames)) { var fieldIds = targetNames.Select(x => sourceIds.Find(y => y.Name == x) !.Id).ToArray(); yield return(new SchemaFieldsReordered { FieldIds = fieldIds }); } } }
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); } 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.Scripts.EqualsJson(target.Scripts, serializer)) { yield return(E(new SchemaScriptsConfigured { Scripts = target.Scripts })); } if (!source.PreviewUrls.EqualsDictionary(target.PreviewUrls)) { yield return(E(new SchemaPreviewUrlsConfigured { PreviewUrls = target.PreviewUrls.ToDictionary(x => x.Key, x => x.Value) })); } if (source.IsPublished != target.IsPublished) { yield return(target.IsPublished ? E(new SchemaPublished()) : E(new SchemaUnpublished())); } var events = SyncFields(source.FieldCollection, target.FieldCollection, serializer, idGenerator, null, options); foreach (var @event in events) { yield return(E(@event)); } } }