private void TestUpdate(Action <Server, Server, HintSet> update, bool useHints)
        {
            var s1    = Clone(srv);
            var s2    = Clone(srv);
            var hints = new HintSet(s1, s2);

            update.Invoke(s1, s2, hints);
            if (!useHints)
            {
                hints = new HintSet(s1, s2);
            }
            TestLog.Info("Update test ({0} hints)", useHints ? "with" : "without");
//      s1.Dump();
//      s2.Dump();
            s1.Validate();
            s2.Validate();

            // Comparing different models
            TestLog.Info("Comparing models:");
            var comparer = new Comparer();
            var diff     = comparer.Compare(s1, s2, hints);

            TestLog.Info("\r\nDifference:\r\n{0}", diff);
            var actions = new ActionSequence()
            {
                new Upgrader().GetUpgradeSequence(diff, hints, comparer)
            };

            TestLog.Info("\r\nActions:\r\n{0}", actions);
        }
        public void BaseComparisonTest()
        {
            var source = new Server("Source");
            var target = srv;

            target.Validate();

            TestLog.Info("Source model:");
//      source.Dump();
            TestLog.Info("Target model:");
//      target.Dump();

            var comparer = new Comparer();
            var hints    = new HintSet(source, target)
            {
                new RenameHint("", "")
            };
            Difference diff = comparer.Compare(source, target, hints);

            TestLog.Info("Difference: \r\n{0}", diff);

            var actions = new ActionSequence {
                new Upgrader().GetUpgradeSequence(diff, hints, comparer)
            };

            TestLog.Info("Actions: \r\n{0}", actions);

            TestLog.Info("Applying actions...");
            actions.Apply(source);

            TestLog.Info("Updated Model 1:");
//      source.Dump();
        }
        private static void TestUpdate(StorageInfo origin, Action <StorageInfo, StorageInfo, HintSet> mutator, Action <Difference, ActionSequence> validator, bool useHints)
        {
            var s1    = Clone(origin);
            var s2    = Clone(origin);
            var hints = new HintSet(s1, s2);

            mutator.Invoke(s1, s2, hints);
            if (!useHints)
            {
                hints = new HintSet(s1, s2);
            }
            TestLog.Info("Update test ({0} hints)", useHints ? "with" : "without");
            s1.Dump();
            s2.Dump();
            s1.Validate();
            s2.Validate();

            // Comparing different models
            TestLog.Info("Comparing models:");
            var comparer = new Comparer();
            var diff     = comparer.Compare(s1, s2, hints);

            TestLog.Info("\r\nDifference:\r\n{0}", diff);
            var actions = new ActionSequence()
            {
                new Upgrader().GetUpgradeSequence(diff, hints, comparer)
            };

            TestLog.Info("\r\nActions:\r\n{0}", actions);
            if (validator != null)
            {
                validator.Invoke(diff, actions);
            }
        }
Esempio n. 4
0
        /// <inheritdoc/>
        /// <exception cref="ArgumentOutOfRangeException"><c>hints.SourceModel</c> or <c>hints.TargetModel</c>
        /// is out of range.</exception>
        public Difference Compare(IModel source, IModel target, HintSet hints)
        {
            Source = source;
            Target = target;
            Hints  = hints ?? new HintSet(Source, Target);
            if (Hints.SourceModel != Source)
            {
                throw new ArgumentOutOfRangeException("hints.SourceModel");
            }
            if (Hints.TargetModel != Target)
            {
                throw new ArgumentOutOfRangeException("hints.TargetModel");
            }
            var previous = currentAsync.Value;

            currentAsync.Value = this;
            Results            = new Dictionary <object, Difference>();
            try {
                Stage = ComparisonStage.BaseComparison;
                Visit(Source, Target);
                CoreLog.Info("Base comparison complete.");
                Stage = ComparisonStage.ReferenceComparison;
                return(Visit(Source, Target));
            }
            finally {
                currentAsync.Value = previous;
                Results            = null;
            }
        }
Esempio n. 5
0
        private void UpdateHints()
        {
            var originalHints = Hints;

            Hints = new HintSet(CurrentModel, TargetModel);

            // Process RenameHints
            foreach (var renameHint in originalHints.OfType <RenameHint>())
            {
                if (TemporaryRenames.TryGetValue(renameHint.SourcePath, out var sourceNode))
                {
                    Hints.Add(new RenameHint(sourceNode.Path, renameHint.TargetPath));
                }
                else
                {
                    Hints.Add(renameHint);
                }
            }

            // Process CopyDataHints
            foreach (var copyDataHint in originalHints.OfType <CopyDataHint>())
            {
                var sourceTablePath = GetActualPath(copyDataHint.SourceTablePath);
                var identities      = copyDataHint.Identities.Select(pair =>
                                                                     new IdentityPair(GetActualPath(pair.Source), pair.Target, pair.IsIdentifiedByConstant))
                                      .ToList();
                var copiedColumns = copyDataHint.CopiedColumns.Select(pair =>
                                                                      new Pair <string>(GetActualPath(pair.First), pair.Second))
                                    .ToList();
                var newCopyDataHint = new CopyDataHint(sourceTablePath, identities, copiedColumns);
                Hints.Add(newCopyDataHint);
            }

            // Process DeleteDataHints
            foreach (var deleteDataHint in originalHints.OfType <DeleteDataHint>())
            {
                if (!deleteDataHint.PostCopy)
                {
                    continue; // It's not necessary to copy this hint
                }

                var sourceTablePath = GetActualPath(deleteDataHint.SourceTablePath);
                var identities      = deleteDataHint.Identities.Select(pair =>
                                                                       new IdentityPair(GetActualPath(pair.Source), pair.Target, pair.IsIdentifiedByConstant))
                                      .ToList();
                var newDeleteDataHint = new DeleteDataHint(sourceTablePath, identities, true);
                Hints.Add(newDeleteDataHint);
            }

            // Process IgnoreHints
            foreach (var ignoreHint in originalHints.OfType <IgnoreHint>())
            {
                Hints.Add(ignoreHint);
            }
        }
Esempio n. 6
0
        // Constructors

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="schemaComparisonStatus">The comparison status.</param>
        /// <param name="hasColumnTypeChanges">Indicates whether there are column type changes.</param>
        /// <param name="isCompatibleInLegacyMode">Indicates whether schemes are compatible in legacy mode.</param>
        /// <param name="hints">The upgrade hints.</param>
        /// <param name="difference">The difference.</param>
        /// <param name="upgradeActions">The upgrade actions.</param>
        /// <param name="unsafeActions">The unsafe (breaking) actions.</param>
        public SchemaComparisonResult(
            SchemaComparisonStatus schemaComparisonStatus,
            bool hasColumnTypeChanges,
            bool?isCompatibleInLegacyMode,
            HintSet hints,
            Difference difference,
            ActionSequence upgradeActions,
            IList <NodeAction> unsafeActions)
        {
            SchemaComparisonStatus   = schemaComparisonStatus;
            IsCompatibleInLegacyMode = isCompatibleInLegacyMode;
            HasColumnTypeChanges     = hasColumnTypeChanges;
            Hints          = hints;
            Difference     = difference;
            UpgradeActions = upgradeActions;
            UnsafeActions  = unsafeActions != null
        ? new ReadOnlyList <NodeAction>(unsafeActions)
        : new ReadOnlyList <NodeAction>(new List <NodeAction>());
            HasUnsafeActions = UnsafeActions.Any();
        }
        /// <summary>
        /// Compares <paramref name="sourceSchema"/> and <paramref name="targetSchema"/>.
        /// </summary>
        /// <param name="sourceSchema">The source schema.</param>
        /// <param name="targetSchema">The target schema.</param>
        /// <param name="schemaHints">The upgrade hints.</param>
        /// <param name="upgradeHints"><see cref="UpgradeHint"/>s to be applied.</param>
        /// <param name="schemaUpgradeMode">A <see cref="SchemaUpgradeMode"/> being used.</param>
        /// <param name="model">A <see cref="DomainModel"/> of a storage.</param>
        /// <param name="briefExceptionFormat">Indicates whether brief or full exception format should be used.</param>
        /// <param name="upgradeStage">A current <see cref="UpgradeStage"/>.</param>
        /// <returns>Comparison result.</returns>
        public static SchemaComparisonResult Compare(
            StorageModel sourceSchema, StorageModel targetSchema,
            HintSet schemaHints, SetSlim <UpgradeHint> upgradeHints,
            SchemaUpgradeMode schemaUpgradeMode, DomainModel model,
            bool briefExceptionFormat, UpgradeStage upgradeStage)
        {
            if (schemaHints == null)
            {
                schemaHints = new HintSet(sourceSchema, targetSchema);
            }

            var comparer                = new Comparer();
            var difference              = comparer.Compare(sourceSchema, targetSchema, schemaHints);
            var actions                 = GetUpgradeActions(comparer, difference, schemaHints);
            var actionList              = actions.Flatten().ToList();
            var comparisonStatus        = GetComparisonStatus(actionList, schemaUpgradeMode);
            var unsafeActions           = GetUnsafeActions(actionList, upgradeHints);
            var columnTypeChangeActions = actionList.OfType <PropertyChangeAction>().Where(IsTypeChangeAction).ToList();

            if (schemaUpgradeMode != SchemaUpgradeMode.ValidateLegacy)
            {
                return(new SchemaComparisonResult(
                           comparisonStatus, columnTypeChangeActions.Count > 0, null,
                           schemaHints, difference, actions, unsafeActions));
            }

            // Legacy comparison

            var systemTablesSequence = model.Types.Where(type => type.IsSystem).Select(type => type.MappingName);
            var systemTables         = new HashSet <string>(systemTablesSequence, Comparer);

            var createTableActions = actionList
                                     .OfType <CreateNodeAction>()
                                     .Where(
                action => {
                var table = action.Difference.Target as TableInfo;
                return(table != null && !systemTables.Contains(table.Name));
            })
                                     .ToList();

            var createColumnActions = actionList
                                      .OfType <CreateNodeAction>()
                                      .Where(
                action => {
                var column = action.Difference.Target as StorageColumnInfo;
                return(column != null && !systemTables.Contains(column.Parent.Name));
            })
                                      .ToList();

            columnTypeChangeActions = columnTypeChangeActions
                                      .Where(
                action => {
                var sourceType = action.Difference.Source as StorageTypeInfo;
                var targetType = action.Difference.Target as StorageTypeInfo;
                return(sourceType == null || targetType == null || sourceType.IsTypeUndefined ||
                       sourceType.Type.ToNullable() != targetType.Type.ToNullable());
            })
                                      .ToList();


            var isCompatibleInLegacyMode =
                createTableActions.Count == 0 &&
                createColumnActions.Count == 0 &&
                columnTypeChangeActions.Count == 0;

            if (briefExceptionFormat)
            {
                unsafeActions =
                    createTableActions.Cast <NodeAction>()
                    .Concat(createColumnActions.Cast <NodeAction>())
                    .Concat(columnTypeChangeActions.Cast <NodeAction>())
                    .ToList();
            }

            return(new SchemaComparisonResult(
                       comparisonStatus, columnTypeChangeActions.Count > 0, isCompatibleInLegacyMode,
                       schemaHints, difference, actions, unsafeActions));
        }
        private static ActionSequence GetUpgradeActions(Comparer comparer, Difference difference, HintSet hints)
        {
            var actions = difference != null
        ? new Upgrader().GetUpgradeSequence(difference, hints, comparer)
        : EnumerableUtils <NodeAction> .Empty;

            return(new ActionSequence {
                actions
            });
        }
Esempio n. 9
0
        /// <inheritdoc/>
        /// <exception cref="ArgumentOutOfRangeException"><c>hints.SourceModel</c> or <c>hints.TargetModel</c>
        /// is out of range.</exception>
        /// <exception cref="InvalidOperationException">Upgrade sequence validation has failed.</exception>
        public ReadOnlyList <NodeAction> GetUpgradeSequence(Difference difference, HintSet hints, IComparer comparer)
        {
            ArgumentValidator.EnsureArgumentNotNull(hints, nameof(hints));
            ArgumentValidator.EnsureArgumentNotNull(comparer, nameof(comparer));
            if (difference == null)
            {
                return(new ReadOnlyList <NodeAction>(Enumerable.Empty <NodeAction>().ToList()));
            }

            TemporaryRenames = new Dictionary <string, Node>(StringComparer.OrdinalIgnoreCase);
            SourceModel      = (IModel)difference.Source;
            TargetModel      = (IModel)difference.Target;
            Hints            = hints ?? new HintSet(SourceModel, TargetModel);
            Comparer         = comparer;
            if (Hints.SourceModel != SourceModel)
            {
                throw new ArgumentOutOfRangeException("hints.SourceModel");
            }

            if (Hints.TargetModel != TargetModel)
            {
                throw new ArgumentOutOfRangeException("hints.TargetModel");
            }

            CurrentModel = (IModel)SourceModel.Clone(null, SourceModel.Name);
            Difference   = difference;
            var previous = currentAsync.Value;

            currentAsync.Value = this;
            using (NullActionHandler.Instance.Activate()) {
                try {
                    var actions = new GroupingNodeAction();

                    ProcessStage(UpgradeStage.CleanupData, actions);
                    ProcessStage(UpgradeStage.Prepare, actions);
                    ProcessStage(UpgradeStage.TemporaryRename, actions);
                    ProcessStage(UpgradeStage.Upgrade, actions);
                    ProcessStage(UpgradeStage.CopyData, actions);
                    ProcessStage(UpgradeStage.PostCopyData, actions);
                    ProcessStage(UpgradeStage.Cleanup, actions);

                    var validationHints = new HintSet(CurrentModel, TargetModel);
                    Hints.OfType <IgnoreHint>()
                    .Where(h => CurrentModel.Resolve(h.Path, false) != null && SourceModel.Resolve(h.Path, false) != null)
                    .ForEach(validationHints.Add);
                    var diff = comparer.Compare(CurrentModel, TargetModel, validationHints);
                    if (diff != null)
                    {
                        CoreLog.InfoRegion(Strings.LogAutomaticUpgradeSequenceValidation);
                        CoreLog.Info(Strings.LogValidationFailed);
                        CoreLog.Info(Strings.LogItemFormat, Strings.Difference);
                        CoreLog.Info("{0}", diff);
                        CoreLog.Info(Strings.LogItemFormat + "\r\n{1}", Strings.UpgradeSequence,
                                     new ActionSequence()
                        {
                            actions
                        });
                        CoreLog.Info(Strings.LogItemFormat, Strings.ExpectedTargetModel);
                        TargetModel.Dump();
                        CoreLog.Info(Strings.LogItemFormat, Strings.ActualTargetModel);
                        CurrentModel.Dump();
                        throw new InvalidOperationException(Strings.ExUpgradeSequenceValidationFailure);
                    }

                    return(new ReadOnlyList <NodeAction>(actions.Actions, true));
                }
                finally {
                    currentAsync.Value = previous;
                }
            }
        }
Esempio n. 10
0
 /// <inheritdoc/>
 /// <exception cref="ArgumentOutOfRangeException"><c>hints.SourceModel</c> or <c>hints.TargetModel</c>
 /// is out of range.</exception>
 public ReadOnlyList <NodeAction> GetUpgradeSequence(Difference difference, HintSet hints) =>
 GetUpgradeSequence(difference, hints, new Comparer());