Пример #1
0
 private static MList <RuleTypeConditionEmbedded> Conditions(XElement xr, Replacements replacements)
 {
     return((from xc in xr.Elements("Condition")
             let cn = SymbolLogic <TypeConditionSymbol> .TryToSymbol(replacements.Apply(typeConditionReplacementKey, xc.Attribute("Name").Value))
                      where cn != null
                      select new RuleTypeConditionEmbedded
     {
         Condition = cn,
         Allowed = xc.Attribute("Allowed").Value.ToEnum <TypeAllowed>()
     }).ToMList());
 }
Пример #2
0
        internal SqlPreCommand?ImportXml(XElement element, Dictionary <string, Lite <RoleEntity> > roles, Replacements replacements)
        {
            var current = Database.RetrieveAll <RuleTypeEntity>().GroupToDictionary(a => a.Role);
            var xRoles  = (element.Element("Types")?.Elements("Role")).EmptyIfNull();
            var should  = xRoles.ToDictionary(x => roles.GetOrThrow(x.Attribute("Name").Value));

            Table table = Schema.Current.Table(typeof(RuleTypeEntity));

            replacements.AskForReplacements(
                xRoles.SelectMany(x => x.Elements("Type")).Select(x => x.Attribute("Resource").Value).ToHashSet(),
                TypeLogic.NameToType.Where(a => !a.Value.IsEnumEntity()).Select(a => a.Key).ToHashSet(), typeReplacementKey);

            replacements.AskForReplacements(
                xRoles.SelectMany(x => x.Elements("Type")).SelectMany(t => t.Elements("Condition")).Select(x => x.Attribute("Name").Value).ToHashSet(),
                SymbolLogic <TypeConditionSymbol> .AllUniqueKeys(),
                typeConditionReplacementKey);

            Func <string, TypeEntity?> getResource = s =>
            {
                Type?type = TypeLogic.NameToType.TryGetC(replacements.Apply(typeReplacementKey, s));

                if (type == null)
                {
                    return(null);
                }

                return(TypeLogic.TypeToEntity.GetOrThrow(type));
            };


            return(Synchronizer.SynchronizeScript(Spacing.Double, should, current,
                                                  createNew: (role, x) =>
            {
                var dic = (from xr in x.Elements("Type")
                           let t = getResource(xr.Attribute("Resource").Value)
                                   where t != null
                                   select KVP.Create(t, new
                {
                    Allowed = xr.Attribute("Allowed").Value.ToEnum <TypeAllowed>(),
                    Condition = Conditions(xr, replacements)
                })).ToDictionaryEx("Type rules for {0}".FormatWith(role));

                SqlPreCommand?restSql = dic.Select(kvp => table.InsertSqlSync(new RuleTypeEntity
                {
                    Resource = kvp.Key,
                    Role = role,
                    Allowed = kvp.Value.Allowed,
                    Conditions = kvp.Value.Condition !    /*CSBUG*/
                }, comment: Comment(role, kvp.Key, kvp.Value.Allowed))).Combine(Spacing.Simple)?.Do(p => p.GoBefore = true);
        public static SqlPreCommand SynchronizeTablesScript(Replacements replacements)
        {
            Schema s = Schema.Current;

            Dictionary<string, ITable> model = s.GetDatabaseTables().Where(t => !s.IsExternalDatabase(t.Name.Schema.Database)).ToDictionaryEx(a => a.Name.ToString(), "schema tables");
            HashSet<SchemaName> modelSchemas = model.Values.Select(a => a.Name.Schema).Where(a => !SqlBuilder.SystemSchemas.Contains(a.Name)).ToHashSet();

            Dictionary<string, DiffTable> database = DefaultGetDatabaseDescription(s.DatabaseNames());
            HashSet<SchemaName> databaseSchemas = DefaultGetSchemas(s.DatabaseNames());

            if (SimplifyDiffTables != null) 
                SimplifyDiffTables(database);

            replacements.AskForReplacements(database.Keys.ToHashSet(), model.Keys.ToHashSet(), Replacements.KeyTables);

            database = replacements.ApplyReplacementsToOld(database, Replacements.KeyTables);

            Dictionary<ITable, Dictionary<string, Index>> modelIndices = model.Values
                .ToDictionary(t => t, t => t.GeneratAllIndexes().ToDictionaryEx(a => a.IndexName, "Indexes for {0}".FormatWith(t.Name)));

            model.JoinDictionaryForeach(database, (tn, tab, diff) =>
            {
                var key = Replacements.KeyColumnsForTable(tn);

                replacements.AskForReplacements(diff.Columns.Keys.ToHashSet(), tab.Columns.Keys.ToHashSet(), key);

                diff.Columns = replacements.ApplyReplacementsToOld(diff.Columns, key);

                diff.Indices = ApplyIndexAutoReplacements(diff, tab, modelIndices[tab]);
            });

            Func<ObjectName, ObjectName> ChangeName = (ObjectName objectName) =>
            {
                string name = replacements.Apply(Replacements.KeyTables, objectName.ToString());

                return model.TryGetC(name)?.Name ?? objectName;
            };


            Func<ObjectName, SqlPreCommand> DeleteAllForeignKey = tableName =>
            {
                var dropFks = (from t in database.Values
                               from c in t.Columns.Values
                               where c.ForeignKey != null && c.ForeignKey.TargetTable.Equals(tableName)
                               select SqlBuilder.AlterTableDropConstraint(t.Name, c.ForeignKey.Name)).Combine(Spacing.Simple);

                if (dropFks == null)
                    return null;

                return SqlPreCommand.Combine(Spacing.Simple, new SqlPreCommandSimple("---In order to remove the PK of " + tableName.Name), dropFks);
            };

            using (replacements.WithReplacedDatabaseName())
            {
                SqlPreCommand createSchemas = Synchronizer.SynchronizeScriptReplacing(replacements, "Schemas",
                    modelSchemas.ToDictionary(a => a.ToString()),
                    databaseSchemas.ToDictionary(a => a.ToString()),
                    (_, newSN) => SqlBuilder.CreateSchema(newSN),
                    null,
                    (_, newSN, oldSN) => newSN.Equals(oldSN) ? null : SqlBuilder.CreateSchema(newSN),
                    Spacing.Double);

                //use database without replacements to just remove indexes
                SqlPreCommand dropStatistics =
                    Synchronizer.SynchronizeScript(model, database,
                     null,
                    (tn, dif) => SqlBuilder.DropStatistics(tn, dif.Stats),
                    (tn, tab, dif) =>
                    {
                        var removedColums = dif.Columns.Keys.Except(tab.Columns.Keys).ToHashSet();

                        return SqlBuilder.DropStatistics(tn, dif.Stats.Where(a => a.Columns.Any(removedColums.Contains)).ToList());
                    },
                     Spacing.Double);
                
                SqlPreCommand dropIndices =
                    Synchronizer.SynchronizeScript(model, database,
                     null,
                    (tn, dif) => dif.Indices.Values.Where(ix => !ix.IsPrimary).Select(ix => SqlBuilder.DropIndex(dif.Name, ix)).Combine(Spacing.Simple),
                    (tn, tab, dif) =>
                    {
                        Dictionary<string, Index> modelIxs = modelIndices[tab];

                        var removedColums = dif.Columns.Keys.Except(tab.Columns.Keys).ToHashSet();

                        var changes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                            null,
                            (i, dix) => dix.Columns.Any(removedColums.Contains) || dix.IsControlledIndex ? SqlBuilder.DropIndex(dif.Name, dix) : null,
                            (i, mix, dix) => !dix.IndexEquals(dif, mix) ? SqlPreCommand.Combine(Spacing.Double, dix.IsPrimary ? DeleteAllForeignKey(dif.Name) : null, SqlBuilder.DropIndex(dif.Name, dix)) : null,
                            Spacing.Simple);

                        return changes;
                    },
                     Spacing.Double);

                SqlPreCommand dropForeignKeys = Synchronizer.SynchronizeScript(
                     model,
                     database,
                     null,
                     (tn, dif) => dif.Columns.Values.Select(c => c.ForeignKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, c.ForeignKey.Name) : null)
                         .Concat(dif.MultiForeignKeys.Select(fk => SqlBuilder.AlterTableDropConstraint(dif.Name, fk.Name))).Combine(Spacing.Simple),
                     (tn, tab, dif) => SqlPreCommand.Combine(Spacing.Simple,
                         Synchronizer.SynchronizeScript(
                         tab.Columns,
                         dif.Columns,
                         null,
                         (cn, colDb) => colDb.ForeignKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeignKey.Name) : null,
                         (cn, colModel, colDb) => colDb.ForeignKey == null ? null :
                             colModel.ReferenceTable == null || colModel.AvoidForeignKey || !colModel.ReferenceTable.Name.Equals(ChangeName(colDb.ForeignKey.TargetTable)) ?
                             SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeignKey.Name) :
                             null, Spacing.Simple),
                        dif.MultiForeignKeys.Select(fk => SqlBuilder.AlterTableDropConstraint(dif.Name, fk.Name)).Combine(Spacing.Simple)),
                        Spacing.Double);

                SqlPreCommand tables =
                    Synchronizer.SynchronizeScript(
                    model,
                    database,
                    (tn, tab) => SqlBuilder.CreateTableSql(tab),
                    (tn, dif) => SqlBuilder.DropTable(dif.Name),
                    (tn, tab, dif) =>
                        SqlPreCommand.Combine(Spacing.Simple,
                        !object.Equals(dif.Name, tab.Name) ? SqlBuilder.RenameOrMove(dif, tab) : null,
                        Synchronizer.SynchronizeScript(
                            tab.Columns,
                            dif.Columns,
                            (cn, tabCol) => SqlPreCommandSimple.Combine(Spacing.Simple,
                                tabCol.PrimaryKey && dif.PrimaryKeyName != null ? SqlBuilder.DropPrimaryKeyConstraint(tab.Name) : null,
                                AlterTableAddColumnDefault(tab, tabCol, replacements)),
                            (cn, difCol) => SqlPreCommandSimple.Combine(Spacing.Simple,
                                 difCol.Default != null ? SqlBuilder.DropDefaultConstraint(tab.Name, difCol.Name) : null,
                                SqlBuilder.AlterTableDropColumn(tab, cn)),
                            (cn, tabCol, difCol) => SqlPreCommand.Combine(Spacing.Simple,
                                difCol.Name == tabCol.Name ? null : SqlBuilder.RenameColumn(tab, difCol.Name, tabCol.Name),
                                difCol.ColumnEquals(tabCol, ignorePrimaryKey: true) ? null : SqlPreCommand.Combine(Spacing.Simple,
                                    tabCol.PrimaryKey && !difCol.PrimaryKey && dif.PrimaryKeyName != null ? SqlBuilder.DropPrimaryKeyConstraint(tab.Name) : null,
                                    SqlBuilder.AlterTableAlterColumn(tab, tabCol),
                                    tabCol.SqlDbType == SqlDbType.NVarChar && difCol.SqlDbType == SqlDbType.NChar ? SqlBuilder.UpdateTrim(tab, tabCol) : null),
                                difCol.DefaultEquals(tabCol) ? null : SqlPreCommand.Combine(Spacing.Simple,
                                    difCol.Default != null ? SqlBuilder.DropDefaultConstraint(tab.Name, tabCol.Name) : null,
                                    tabCol.Default != null ? SqlBuilder.AddDefaultConstraint(tab.Name, tabCol.Name, tabCol.Default) : null),
                                UpdateByFkChange(tn, difCol, tabCol, ChangeName)),
                            Spacing.Simple)),
                     Spacing.Double);

                if (tables != null)
                    tables.GoAfter = true;

                var tableReplacements = replacements.TryGetC(Replacements.KeyTables);
                if (tableReplacements != null)
                    replacements[Replacements.KeyTablesInverse] = tableReplacements.Inverse();

                SqlPreCommand syncEnums;

                try
                {
                    syncEnums = SynchronizeEnumsScript(replacements);
                }
                catch(Exception e)
                {
                    syncEnums = new SqlPreCommandSimple("-- Exception synchronizing enums: " + e.Message);
                }

                SqlPreCommand addForeingKeys = Synchronizer.SynchronizeScript(
                     model,
                     database,
                     (tn, tab) => SqlBuilder.AlterTableForeignKeys(tab),
                     null,
                     (tn, tab, dif) => Synchronizer.SynchronizeScript(
                         tab.Columns,
                         dif.Columns,
                         (cn, colModel) => colModel.ReferenceTable == null || colModel.AvoidForeignKey ? null :
                             SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable),
                         null,
                         (cn, colModel, coldb) =>
                         {
                             if (colModel.ReferenceTable == null || colModel.AvoidForeignKey)
                                 return null;

                             if (coldb.ForeignKey == null || !colModel.ReferenceTable.Name.Equals(ChangeName(coldb.ForeignKey.TargetTable)))
                                 return SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable);

                             var name = SqlBuilder.ForeignKeyName(tab.Name.Name, colModel.Name);
                             return SqlPreCommand.Combine(Spacing.Simple,
                                name != coldb.ForeignKey.Name.Name ? SqlBuilder.RenameForeignKey(coldb.ForeignKey.Name, name) : null,
                                (coldb.ForeignKey.IsDisabled || coldb.ForeignKey.IsNotTrusted) && !replacements.SchemaOnly ? SqlBuilder.EnableForeignKey(tab.Name, name) : null);
                         },
                         Spacing.Simple),
                     Spacing.Double);

                bool? createMissingFreeIndexes = null;

                SqlPreCommand addIndices =
                    Synchronizer.SynchronizeScript(model, database,
                     (tn, tab) => modelIndices[tab].Values.Where(a => !(a is PrimaryClusteredIndex)).Select(SqlBuilder.CreateIndex).Combine(Spacing.Simple),
                     null,
                    (tn, tab, dif) =>
                    {
                        var columnReplacements = replacements.TryGetC(Replacements.KeyColumnsForTable(tn));

                        Func<IColumn, bool> isNew = c => !dif.Columns.ContainsKey(columnReplacements?.TryGetC(c.Name) ?? c.Name);

                        Dictionary<string, Index> modelIxs = modelIndices[tab];

                        var controlledIndexes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                            (i, mix) => mix is UniqueIndex || mix.Columns.Any(isNew) || SafeConsole.Ask(ref createMissingFreeIndexes, "Create missing non-unique index {0} in {1}?".FormatWith(mix.IndexName, tab.Name)) ? SqlBuilder.CreateIndex(mix) : null,
                            null,
                            (i, mix, dix) => !dix.IndexEquals(dif, mix) ? SqlBuilder.CreateIndex(mix) :
                                mix.IndexName != dix.IndexName ? SqlBuilder.RenameIndex(tab, dix.IndexName, mix.IndexName) : null,
                            Spacing.Simple);

                        return SqlPreCommand.Combine(Spacing.Simple, controlledIndexes);
                    }, Spacing.Double);

                SqlPreCommand dropSchemas = Synchronizer.SynchronizeScriptReplacing(replacements, "Schemas",
                  modelSchemas.ToDictionary(a => a.ToString()),
                  databaseSchemas.ToDictionary(a => a.ToString()),
                  null,
                  (_, oldSN) => DropSchema(oldSN) ? SqlBuilder.DropSchema(oldSN) : null,
                  (_, newSN, oldSN) => newSN.Equals(oldSN) ? null : SqlBuilder.DropSchema(oldSN),
                  Spacing.Double);

                return SqlPreCommand.Combine(Spacing.Triple, createSchemas, dropStatistics, dropIndices, dropForeignKeys, tables, syncEnums, addForeingKeys, addIndices, dropSchemas);
            }
        }
Пример #4
0
        public static SqlPreCommand SynchronizeTablesScript(Replacements replacements)
        {
            //Temproal HACK
            if (Database.View<SysIndexes>().Any(a => a.name.StartsWith("FIX")) && SafeConsole.Ask("Old index naming convention...rename first?"))
            {
                return Schema.Current.DatabaseNames().Select(db =>
                {
                    using (Administrator.OverrideDatabaseInViews(db))
                    {
                        var indexes =
                            (from s in Database.View<SysSchemas>()
                             from t in s.Tables()
                             from ix in t.Indices()
                             where !ix.is_primary_key
                             select new { schemaName = s.name, tableName = t.name, ix.is_unique, indexName = ix.name }).ToList();

                        return (from ix in indexes
                                let newName = ix.is_unique ? Regex.Replace(ix.indexName, @"^IX_\w+?_", "UIX_") : Regex.Replace(ix.indexName, @"^F?IX_\w+?_", "IX_")
                                where ix.indexName != newName
                                select new SqlPreCommandSimple("EXEC SP_RENAME '{0}.{1}' , '{2}', 'INDEX' ".Formato(
                                    new ObjectName(new SchemaName(db, ix.schemaName), ix.tableName), ix.indexName, newName))).Combine(Spacing.Simple);
                    }
                }).Combine(Spacing.Double);
            }

            Dictionary<string, ITable> model = Schema.Current.GetDatabaseTables().ToDictionary(a => a.Name.ToString(), "schema tables");

            Dictionary<string, DiffTable> database = DefaultGetDatabaseDescription(Schema.Current.DatabaseNames());

            replacements.AskForReplacements(database.Keys.ToHashSet(), model.Keys.ToHashSet(), Replacements.KeyTables);

            database = replacements.ApplyReplacementsToOld(database, Replacements.KeyTables);

            Dictionary<ITable, Dictionary<string, Index>> modelIndices = model.Values
                .ToDictionary(t => t, t => t.GeneratAllIndexes().ToDictionary(a => a.IndexName, "Indexes for {0}".Formato(t.Name)));

            model.JoinDictionaryForeach(database, (tn, tab, diff) =>
            {
                var key = Replacements.KeyColumnsForTable(tn);

                replacements.AskForReplacements(diff.Colums.Keys.ToHashSet(), tab.Columns.Keys.ToHashSet(), key);

                diff.Colums = replacements.ApplyReplacementsToOld(diff.Colums,  key);

                diff.Indices = ApplyIndexAutoReplacements(diff, tab, modelIndices[tab]);
            });

            Func<ObjectName, ObjectName> ChangeName = (ObjectName objectName) =>
            {
                string name = replacements.Apply(Replacements.KeyTables, objectName.ToString());

                return model.TryGetC(name).Try(a => a.Name) ?? objectName;
            };

            Func<DiffTable, DiffIndex, Index, bool> columnsChanged = (dif, dix, mix) =>
            {
                if (dix.Columns.Count != mix.Columns.Length)
                    return true;

                var dixColumns = dif.Colums.Where(kvp => dix.Columns.Contains(kvp.Value.Name));

                return !dixColumns.All(kvp => dif.Colums.GetOrThrow(kvp.Key).ColumnEquals(mix.Columns.SingleEx(c => c.Name == kvp.Key)));
            };

            //use database without replacements to just remove indexes
            SqlPreCommand dropStatistics =
                Synchronizer.SynchronizeScript(model, database,
                 null,
                (tn, dif) => SqlBuilder.DropStatistics(tn, dif.Stats),
                (tn, tab, dif) =>
                {
                    var removedColums = dif.Colums.Keys.Except(tab.Columns.Keys).ToHashSet();

                    return SqlBuilder.DropStatistics(tn, dif.Stats.Where(a => a.Columns.Any(removedColums.Contains)).ToList());
                },
                 Spacing.Double);


            SqlPreCommand dropIndices =
                Synchronizer.SynchronizeScript(model, database,
                 null,
                (tn, dif) => dif.Indices.Values.Select(ix => SqlBuilder.DropIndex(dif.Name, ix)).Combine(Spacing.Simple),
                (tn, tab, dif) =>
                {
                    Dictionary<string, Index> modelIxs = modelIndices[tab];

                    var removedColums = dif.Colums.Keys.Except(tab.Columns.Keys).ToHashSet();

                    var changes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                        null,
                        (i, dix) => dix.IsControlledIndex || dix.Columns.Any(removedColums.Contains)  ? SqlBuilder.DropIndex(dif.Name, dix) : null,
                        (i, mix, dix) => (mix as UniqueIndex).Try(u => u.ViewName) != dix.ViewName || columnsChanged(dif, dix, mix) ? SqlBuilder.DropIndex(dif.Name, dix) : null,
                        Spacing.Simple);

                    return changes;
                },
                 Spacing.Double);

            SqlPreCommand dropForeignKeys = Synchronizer.SynchronizeScript(
                 model,
                 database,
                 null,
                 (tn, dif) => dif.Colums.Values.Select(c => c.ForeingKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, c.ForeingKey.Name) : null).Combine(Spacing.Simple),
                 (tn, tab, dif) => Synchronizer.SynchronizeScript(
                     tab.Columns,
                     dif.Colums,
                     null,
                     (cn, colDb) => colDb.ForeingKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeingKey.Name) : null,
                     (cn, colModel, colDb) => colDb.ForeingKey == null ? null :
                         colModel.ReferenceTable == null || !colModel.ReferenceTable.Name.Equals(ChangeName(colDb.ForeingKey.TargetTable)) ? 
                         SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeingKey.Name) :
                         null, Spacing.Simple),
                        Spacing.Double);

            SqlPreCommand tables =
                Synchronizer.SynchronizeScript(
                model,
                database,
                (tn, tab) => SqlBuilder.CreateTableSql(tab),
                (tn, dif) => SqlBuilder.DropTable(dif.Name),
                (tn, tab, dif) =>
                    SqlPreCommand.Combine(Spacing.Simple,
                    !object.Equals(dif.Name, tab.Name) ? SqlBuilder.RenameOrMove(dif, tab) : null,
                    Synchronizer.SynchronizeScript(
                        tab.Columns,
                        dif.Colums,
                        (cn, tabCol) => SqlBuilder.AlterTableAddColumn(tab, tabCol),
                        (cn, difCol) => SqlPreCommand.Combine(Spacing.Simple,
                                    difCol.DefaultConstraintName.HasText() ? SqlBuilder.AlterTableDropConstraint(tab.Name, difCol.DefaultConstraintName) : null,
                                    SqlBuilder.AlterTableDropColumn(tab, cn)),
                        (cn, tabCol, difCol) =>SqlPreCommand.Combine(Spacing.Simple,
                            difCol.Name == tabCol.Name ? null : SqlBuilder.RenameColumn(tab, difCol.Name, tabCol.Name),
                            difCol.ColumnEquals(tabCol) ? null : SqlBuilder.AlterTableAlterColumn(tab, tabCol),
                            UpdateByFkChange(tn, difCol, tabCol, ChangeName)),
                        Spacing.Simple)),
                 Spacing.Double);

            var tableReplacements = replacements.TryGetC(Replacements.KeyTables);
            if (tableReplacements != null)
                replacements[Replacements.KeyTablesInverse] = tableReplacements.Inverse();

            SqlPreCommand syncEnums = SynchronizeEnumsScript(replacements);

            SqlPreCommand addForeingKeys = Synchronizer.SynchronizeScript(
                 model,
                 database,
                 (tn, tab) => SqlBuilder.AlterTableForeignKeys(tab),
                 null,
                 (tn, tab, dif) => Synchronizer.SynchronizeScript(
                     tab.Columns,
                     dif.Colums,
                     (cn, colModel) => colModel.ReferenceTable == null ? null:
                         SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable),
                     null,
                     (cn, colModel, coldb) =>
                     {
                         if(colModel.ReferenceTable == null)
                            return null;

                         if(coldb.ForeingKey == null || !colModel.ReferenceTable.Name.Equals(ChangeName(coldb.ForeingKey.TargetTable)))
                            return SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable);
                                                          
                         var name = SqlBuilder.ForeignKeyName(tab.Name.Name, colModel.Name);
                         return SqlPreCommand.Combine(Spacing.Simple,
                            name != coldb.ForeingKey.Name? SqlBuilder.RenameForeignKey(tab.Name.Schema, coldb.ForeingKey.Name, name) : null, 
                            (coldb.ForeingKey.IsDisabled || coldb.ForeingKey.IsNotTrusted) && !ExecutionMode.IsSynchronizeSchemaOnly ? SqlBuilder.EnableForeignKey(tab.Name,  name) : null);
                     },
                     Spacing.Simple),
                 Spacing.Double);

            bool? createMissingFreeIndexes = null;

            SqlPreCommand addIndices =
                Synchronizer.SynchronizeScript(model, database,
                 (tn, tab) => modelIndices[tab].Values.Select(SqlBuilder.CreateIndex).Combine(Spacing.Simple),
                 null,
                (tn, tab, dif) =>
                {
                    var columnReplacements = replacements.TryGetC(Replacements.KeyColumnsForTable(tn));

                    Func<IColumn, bool> isNew = c => !dif.Colums.ContainsKey(columnReplacements.TryGetC(c.Name) ?? c.Name);

                    Dictionary<string, Index> modelIxs = modelIndices[tab];

                    var controlledIndexes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                        (i, mix) => mix is UniqueIndex || mix.Columns.Any(isNew) || SafeConsole.Ask(ref createMissingFreeIndexes, "Create missing non-unique index too?") ? SqlBuilder.CreateIndex(mix) : null,
                        null,
                        (i, mix, dix) => (mix as UniqueIndex).Try(u => u.ViewName) != dix.ViewName || columnsChanged(dif, dix, mix) ? SqlBuilder.CreateIndex(mix) :
                            mix.IndexName != dix.IndexName ? SqlBuilder.RenameIndex(tab, dix.IndexName, mix.IndexName) : null,
                        Spacing.Simple);

                    return SqlPreCommand.Combine(Spacing.Simple, controlledIndexes);
                }, Spacing.Double);

            return SqlPreCommand.Combine(Spacing.Triple, dropStatistics, dropIndices, dropForeignKeys, tables, syncEnums, addForeingKeys, addIndices);
        }
Пример #5
0
        internal SqlPreCommand ImportXml(XElement element, Dictionary <string, Lite <RoleEntity> > roles, Replacements replacements)
        {
            var current = Database.RetrieveAll <RuleTypeEntity>().GroupToDictionary(a => a.Role);
            var xRoles  = (element.Element("Types")?.Elements("Role")).EmptyIfNull();
            var should  = xRoles.ToDictionary(x => roles[x.Attribute("Name").Value]);

            Table table = Schema.Current.Table(typeof(RuleTypeEntity));

            replacements.AskForReplacements(
                xRoles.SelectMany(x => x.Elements("Type")).Select(x => x.Attribute("Resource").Value).ToHashSet(),
                TypeLogic.NameToType.Where(a => !a.Value.IsEnumEntity()).Select(a => a.Key).ToHashSet(), typeReplacementKey);

            replacements.AskForReplacements(
                xRoles.SelectMany(x => x.Elements("Type")).SelectMany(t => t.Elements("Condition")).Select(x => x.Attribute("Name").Value).ToHashSet(),
                SymbolLogic <TypeConditionSymbol> .AllUniqueKeys(),
                typeConditionReplacementKey);

            Func <string, TypeEntity> getResource = s =>
            {
                Type type = TypeLogic.NameToType.TryGetC(replacements.Apply(typeReplacementKey, s));

                if (type == null)
                {
                    return(null);
                }

                return(TypeLogic.TypeToEntity[type]);
            };


            return(Synchronizer.SynchronizeScript(Spacing.Double, should, current,
                                                  createNew: (role, x) =>
            {
                var dic = (from xr in x.Elements("Type")
                           let t = getResource(xr.Attribute("Resource").Value)
                                   where t != null
                                   select KVP.Create(t, new
                {
                    Allowed = xr.Attribute("Allowed").Value.ToEnum <TypeAllowed>(),
                    Condition = Conditions(xr, replacements)
                })).ToDictionaryEx("Type rules for {0}".FormatWith(role));

                SqlPreCommand restSql = dic.Select(kvp => table.InsertSqlSync(new RuleTypeEntity
                {
                    Resource = kvp.Key,
                    Role = role,
                    Allowed = kvp.Value.Allowed,
                    Conditions = kvp.Value.Condition
                }, comment: Comment(role, kvp.Key, kvp.Value.Allowed))).Combine(Spacing.Simple)?.Do(p => p.GoBefore = true);

                return restSql;
            },
                                                  removeOld: (role, list) => list.Select(rt => table.DeleteSqlSync(rt)).Combine(Spacing.Simple)?.Do(p => p.GoBefore = true),
                                                  mergeBoth: (role, x, list) =>
            {
                var dic = (from xr in x.Elements("Type")
                           let t = getResource(xr.Attribute("Resource").Value)
                                   where t != null && !t.ToType().IsEnumEntity()
                                   select KVP.Create(t, xr)).ToDictionaryEx("Type rules for {0}".FormatWith(role));

                SqlPreCommand restSql = Synchronizer.SynchronizeScript(
                    Spacing.Simple,
                    dic,
                    list.Where(a => a.Resource != null).ToDictionary(a => a.Resource),
                    createNew: (r, xr) =>
                {
                    var a = xr.Attribute("Allowed").Value.ToEnum <TypeAllowed>();
                    var conditions = Conditions(xr, replacements);

                    return table.InsertSqlSync(new RuleTypeEntity {
                        Resource = r, Role = role, Allowed = a, Conditions = conditions
                    }, comment: Comment(role, r, a));
                },
                    removeOld: (r, rt) => table.DeleteSqlSync(rt, Comment(role, r, rt.Allowed)),
                    mergeBoth: (r, xr, pr) =>
                {
                    var oldA = pr.Allowed;
                    pr.Allowed = xr.Attribute("Allowed").Value.ToEnum <TypeAllowed>();
                    var conditions = Conditions(xr, replacements);

                    if (!pr.Conditions.SequenceEqual(conditions))
                    {
                        pr.Conditions = conditions;
                    }

                    return table.UpdateSqlSync(pr, comment: Comment(role, r, oldA, pr.Allowed));
                })?.Do(p => p.GoBefore = true);

                return restSql;
            }));
        }