diff --git a/src/dajet-metadata-tests/ConfigDiff.cs b/src/dajet-metadata-tests/ConfigDiff.cs new file mode 100644 index 0000000..7d1edba --- /dev/null +++ b/src/dajet-metadata-tests/ConfigDiff.cs @@ -0,0 +1,59 @@ +using DaJet.Metadata.Model; +using DaJet.Metadata.Services; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.IO; +using System.Text; + +namespace DaJet.Metadata.ConfigDiff +{ + [TestClass] public sealed class ConfigDiff + { + [TestMethod] public void TestDiff() + { + IMetadataService metadata = new MetadataService(); + IMetaDiffService metadiff = new MetaDiffService(); + + metadata + .UseDatabaseProvider(DatabaseProvider.SQLServer) + .UseConnectionString("Data Source=ZHICHKIN;Initial Catalog=cerberus;Integrated Security=True"); + InfoBase ibOld = metadata.LoadInfoBase(); + + metadata + .UseDatabaseProvider(DatabaseProvider.SQLServer) + .UseConnectionString("Data Source=ZHICHKIN;Initial Catalog=cerberus_new;Integrated Security=True"); + InfoBase ibNew = metadata.LoadInfoBase(); + + MetaDiff diff = metadiff.Compare(ibOld, ibNew); + + WriteDiffToFile(diff); + } + + private void WriteDiffToFile(MetaDiff diff) + { + using (StreamWriter stream = new StreamWriter(@"C:\temp\diff.txt", false, Encoding.UTF8)) + { + WriteToFile(stream, diff, 0, string.Empty); + } + } + private void WriteToFile(StreamWriter stream, MetaDiff diff, int level, string path) + { + string indent = level == 0 ? string.Empty : "-".PadLeft(level * 4, '-'); + //string thisPath = path + (string.IsNullOrEmpty(path) ? string.Empty : ".") + i.ToString(); + stream.WriteLine(indent + "[" + level.ToString() + "] (" + diff.Difference.ToString() + ") " + + diff.Target.ToString() + + (diff.Target is MetadataProperty property ? " (" + property.PropertyType.ToString() + ")" : string.Empty)); + + foreach (var entry in diff.NewValues) + { + indent = "-".PadLeft((level + 1) * 4, '-'); + stream.WriteLine(indent + "[*] " + entry.Key + " = " + entry.Value.ToString()); + } + + for (int i = 0; i < diff.Children.Count; i++) + { + //thisPath = path + (string.IsNullOrEmpty(path) ? string.Empty : ".") + i.ToString(); + WriteToFile(stream, diff.Children[i], level + 1, path); + } + } + } +} \ No newline at end of file diff --git a/src/dajet-metadata/enrichers/InfoBaseEnricher.cs b/src/dajet-metadata/enrichers/InfoBaseEnricher.cs index 699770c..bbe6870 100644 --- a/src/dajet-metadata/enrichers/InfoBaseEnricher.cs +++ b/src/dajet-metadata/enrichers/InfoBaseEnricher.cs @@ -28,6 +28,11 @@ public void Enrich(MetadataObject metadataObject) ConfigureConfigInfo(infoBase, config); ConfigureCommonObjects(infoBase, config); + + if (string.IsNullOrWhiteSpace(infoBase.Name) && infoBase.ConfigInfo != null) + { + infoBase.Name = infoBase.ConfigInfo.Name; + } } private void ConfigureConfigInfo(InfoBase infoBase, ConfigObject config) diff --git a/src/dajet-metadata/model/DataTypeInfo.cs b/src/dajet-metadata/model/DataTypeInfo.cs index 2af8da3..1a58d34 100644 --- a/src/dajet-metadata/model/DataTypeInfo.cs +++ b/src/dajet-metadata/model/DataTypeInfo.cs @@ -72,5 +72,18 @@ public bool IsMultipleType return false; } } + public override string ToString() + { + if (IsMultipleType) return "Multiple"; + else if (IsUuid) return "Uuid"; + else if (IsBinary) return "Binary"; + else if (IsValueStorage) return "ValueStorage"; + else if (CanBeString) return "String"; + else if (CanBeBoolean) return "Boolean"; + else if (CanBeNumeric) return "Numeric"; + else if (CanBeDateTime) return "DateTime"; + else if (CanBeReference) return "Reference"; + else return "Unknown"; + } } } \ No newline at end of file diff --git a/src/dajet-metadata/model/MetaDiff.cs b/src/dajet-metadata/model/MetaDiff.cs new file mode 100644 index 0000000..7c57529 --- /dev/null +++ b/src/dajet-metadata/model/MetaDiff.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +namespace DaJet.Metadata.Model +{ + public enum DiffType + { + ///No difference (used just as a root of child differences) + None, + ///New item to add + Insert, + ///Some properties has been changed + Update, + ///Target item to be deleted + Delete + } + public sealed class MetaDiff + { + public MetaDiff() { } + public MetaDiff(MetaDiff parent, MetadataObject target, DiffType difference) + { + Parent = parent; + Target = target; + Difference = difference; + } + public MetaDiff Parent { set; get; } + public DiffType Difference { set; get; } + public MetadataObject Target { set; get; } + public List Children { get; } = new List(); + public Dictionary NewValues { get; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/dajet-metadata/model/MetadataObject.cs b/src/dajet-metadata/model/MetadataObject.cs index 4ab42ef..b52b3a1 100644 --- a/src/dajet-metadata/model/MetadataObject.cs +++ b/src/dajet-metadata/model/MetadataObject.cs @@ -2,15 +2,28 @@ namespace DaJet.Metadata.Model { - public abstract class MetadataObject + public abstract class MetadataObject : IComparable { - ///Идентификатор объекта метаданных из файла объекта метаданных + ///Внутренний идентификатор объекта метаданных public Guid Uuid { get; set; } = Guid.Empty; ///Идентификатор файла объекта метаданных в таблице Config и DBNames public Guid FileName { get; set; } = Guid.Empty; + ///Имя объекта метаданных public string Name { get; set; } = string.Empty; + ///Синоним объекта метаданных public string Alias { get; set; } = string.Empty; + // TODO: add Comment property ? - public override string ToString() { return string.Format("{0}.{1}", GetType().Name, Name); } + + public int CompareTo(object other) + { + return this.CompareTo((MetadataObject)other); + } + public int CompareTo(MetadataObject other) + { + if (other == null) return 1; // this instance is bigger than other + return this.Name.CompareTo(other.Name); + } + public override string ToString() { return string.Format("{0}.{1}", this.GetType().Name, this.Name); } } } \ No newline at end of file diff --git a/src/dajet-metadata/model/MetadataProperty.cs b/src/dajet-metadata/model/MetadataProperty.cs index 6c8245f..814b960 100644 --- a/src/dajet-metadata/model/MetadataProperty.cs +++ b/src/dajet-metadata/model/MetadataProperty.cs @@ -5,17 +5,8 @@ namespace DaJet.Metadata.Model { ///Класс для описания свойств объекта метаданных (реквизитов, измерений и ресурсов) - public class MetadataProperty + public class MetadataProperty : MetadataObject { - /// - /// Идентификатор свойства объекта метаданных из файла DBNames таблицы Params. - /// Используется для того, чтобы ссылаться на свойство в файле объекта метаданных из таблицы Config. - /// - public Guid FileName { get; set; } = Guid.Empty; - ///Имя свойства объекта метаданных - public string Name { get; set; } = string.Empty; - ///Синоним свойства объекта метаданных - public string Alias { get; set; } = string.Empty; ///Основа имени поля в таблице СУБД (может быть дополнено постфиксами в зависимости от типа данных свойства) public string DbName { get; set; } = string.Empty; ///Коллекция для описания полей таблицы СУБД свойства объекта метаданных diff --git a/src/dajet-metadata/services/Configurator.cs b/src/dajet-metadata/services/Configurator.cs index d88c149..8613170 100644 --- a/src/dajet-metadata/services/Configurator.cs +++ b/src/dajet-metadata/services/Configurator.cs @@ -223,6 +223,7 @@ public MetadataProperty CreateProperty(Guid uuid, string token, int code) { return new MetadataProperty() { + Uuid = uuid, FileName = uuid, DbName = CreateDbName(token, code) }; diff --git a/src/dajet-metadata/services/MetaDiffService.cs b/src/dajet-metadata/services/MetaDiffService.cs new file mode 100644 index 0000000..322b903 --- /dev/null +++ b/src/dajet-metadata/services/MetaDiffService.cs @@ -0,0 +1,166 @@ +using DaJet.Metadata.Model; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DaJet.Metadata.Services +{ + public interface IMetaDiffService + { + MetaDiff Compare(InfoBase target, InfoBase source); + } + public sealed class MetaDiffService : IMetaDiffService + { + public MetaDiff Compare(InfoBase target, InfoBase source) + { + MetaDiff root = new MetaDiff(null, target, DiffType.None); + CompareLists(root, target.Catalogs.Values.ToList(), source.Catalogs.Values.ToList()); + CompareLists(root, target.Documents.Values.ToList(), source.Documents.Values.ToList()); + CompareLists(root, target.Characteristics.Values.ToList(), source.Characteristics.Values.ToList()); + CompareLists(root, target.InformationRegisters.Values.ToList(), source.InformationRegisters.Values.ToList()); + CompareLists(root, target.AccumulationRegisters.Values.ToList(), source.AccumulationRegisters.Values.ToList()); + return root; + } + private void CompareLists(MetaDiff parent, List target_list, List source_list) where T : MetadataObject, IComparable + { + int target_count = target_list.Count; + int source_count = source_list.Count; + int target_index = 0; + int source_index = 0; + int compareResult; + + if (target_count == 0 && source_count == 0) return; + + target_list.Sort(); + source_list.Sort(); + + while (target_index < target_count) + { + if (source_index < source_count) + { + compareResult = target_list[target_index].CompareTo(source_list[source_index]); + if (compareResult < 0) + { + MetaDiff difference = new MetaDiff(parent, target_list[target_index], DiffType.Delete); + parent.Children.Add(difference); + SetUpdateDiffType(parent); + AddChildren(difference); + target_index++; + } + else if (compareResult == 0) + { + MetaDiff difference = new MetaDiff(parent, target_list[target_index], DiffType.None); + CompareListItems(difference, target_list[target_index], source_list[source_index]); + if (difference.Difference == DiffType.Update) parent.Children.Add(difference); + target_index++; + source_index++; + } + else + { + MetaDiff difference = new MetaDiff(parent, source_list[source_index], DiffType.Insert); + parent.Children.Add(difference); + SetUpdateDiffType(parent); + AddChildren(difference); + source_index++; + } + } + else + { + MetaDiff difference = new MetaDiff(parent, target_list[target_index], DiffType.Delete); + parent.Children.Add(difference); + SetUpdateDiffType(parent); + AddChildren(difference); + target_index++; + } + } + while (source_index < source_count) + { + MetaDiff difference = new MetaDiff(parent, source_list[source_index], DiffType.Insert); + parent.Children.Add(difference); + SetUpdateDiffType(parent); + AddChildren(difference); + source_index++; + } + } + // Compare methods is used by Update difference + private void CompareListItems(MetaDiff difference, MetadataObject target, MetadataObject source) + { + if (target is ApplicationObject) + { + CompareObjects(difference, (ApplicationObject)target, (ApplicationObject)source); + } + else if (typeof(MetadataProperty) == target.GetType()) + { + CompareProperties(difference, (MetadataProperty)target, (MetadataProperty)source); + } + } + private void CompareObjects(MetaDiff difference, ApplicationObject target, ApplicationObject source) + { + //difference.NewValues.Clear(); + //if (target.TypeCode != source.TypeCode) + //{ + // difference.NewValues.Add("TypeCode", source.TypeCode); + //} + //if (difference.NewValues.Count > 0) SetUpdateDiffType(difference); + + //if (target.Uuid == source.Uuid || target.FileName == source.FileName) + //{ + + //} + + CompareLists(difference, target.Properties, source.Properties); + CompareLists(difference, target.TableParts, source.TableParts); + } + private void CompareProperties(MetaDiff difference, MetadataProperty target, MetadataProperty source) + { + difference.NewValues.Clear(); + if (target.PropertyType.CanBeBoolean != source.PropertyType.CanBeBoolean + || target.PropertyType.CanBeString != source.PropertyType.CanBeString + || target.PropertyType.CanBeNumeric != source.PropertyType.CanBeNumeric + || target.PropertyType.CanBeDateTime != source.PropertyType.CanBeDateTime + || target.PropertyType.CanBeReference != source.PropertyType.CanBeReference + || target.PropertyType.IsUuid != source.PropertyType.IsUuid + || target.PropertyType.IsValueStorage != source.PropertyType.IsValueStorage + || target.PropertyType.IsMultipleType != source.PropertyType.IsMultipleType) + { + difference.NewValues.Add("PropertyType", source.PropertyType); + } + if (difference.NewValues.Count > 0) SetUpdateDiffType(difference); + } + private void SetUpdateDiffType(MetaDiff difference) + { + if (difference.Difference != DiffType.None) return; + difference.Difference = DiffType.Update; + MetaDiff parent = difference.Parent; + while (parent != null) + { + parent.Difference = DiffType.Update; + parent = parent.Parent; + } + } + // Add children is used by Insert and Delete differences + private void AddChildren(MetaDiff difference) + { + if (difference.Target is ApplicationObject) + { + AddObjectChildren(difference); + } + } + private void AddObjectChildren(MetaDiff difference) + { + ApplicationObject target = (ApplicationObject)difference.Target; + + foreach (MetadataProperty child in target.Properties) + { + MetaDiff diff = new MetaDiff(difference, child, difference.Difference); + difference.Children.Add(diff); + } + foreach (TablePart child in target.TableParts) + { + MetaDiff diff = new MetaDiff(difference, child, difference.Difference); + difference.Children.Add(diff); + AddObjectChildren(diff); + } + } + } +} \ No newline at end of file