diff --git a/src/Umbraco.Core/Persistence/Migrations/IMigration.cs b/src/Umbraco.Core/Persistence/Migrations/IMigration.cs new file mode 100644 index 0000000000..2769400e44 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/IMigration.cs @@ -0,0 +1,11 @@ +namespace Umbraco.Core.Persistence.Migrations +{ + /// + /// Marker interface for database migrations + /// + public interface IMigration + { + void Up(); + void Down(); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs new file mode 100644 index 0000000000..70484942fc --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs @@ -0,0 +1,28 @@ +using System; + +namespace Umbraco.Core.Persistence.Migrations +{ + /// + /// Represents the Migration attribute, which is used to mark classes as + /// database migrations with Up/Down methods for pushing changes UP or pulling them DOWN. + /// + [AttributeUsage(AttributeTargets.Class)] + public class MigrationAttribute : Attribute + { + public MigrationAttribute(string targetVersion, int sortOrder) + { + TargetVersion = new Version(targetVersion); + SortOrder = sortOrder; + } + + /// + /// Gets or sets the target version of this migration. + /// + public Version TargetVersion { get; private set; } + + /// + /// Gets or sets the sort order, which is the order this migration will be run in. + /// + public int SortOrder { get; private set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs new file mode 100644 index 0000000000..88103e7d2d --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs @@ -0,0 +1,65 @@ +using Umbraco.Core.Persistence.Migrations.Syntax.Alter; +using Umbraco.Core.Persistence.Migrations.Syntax.Create; +using Umbraco.Core.Persistence.Migrations.Syntax.Delete; +using Umbraco.Core.Persistence.Migrations.Syntax.Insert; +using Umbraco.Core.Persistence.Migrations.Syntax.Rename; +using Umbraco.Core.Persistence.Migrations.Syntax.Schema; +using Umbraco.Core.Persistence.Migrations.Syntax.Update; + +namespace Umbraco.Core.Persistence.Migrations +{ + public abstract class MigrationBase : IMigration + { + internal IMigrationContext _context; + + public abstract void Up(); + public abstract void Down(); + + public virtual void GetUpExpressions(IMigrationContext context) + { + _context = context; + Up(); + } + + public virtual void GetDownExpressions(IMigrationContext context) + { + _context = context; + Down(); + } + + public IAlterSyntaxBuilder Alter + { + get { return new AlterSyntaxBuilder(_context); } + } + + public ICreateBuilder Create + { + get { return new CreateBuilder(_context); } + } + + public IDeleteBuilder Delete + { + get { return new DeleteBuilder(_context); } + } + + public IInsertBuilder Insert + { + get { return new InsertBuilder(_context); } + } + + public IRenameBuilder Rename + { + get { return new RenameBuilder(_context); } + } + + public ISchemaBuilder Schema + { + get { return new SchemaBuilder(_context); } + } + + public IUpdateBuilder Update + { + get { return new UpdateBuilder(_context); } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationContext.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationContext.cs new file mode 100644 index 0000000000..8fac51a11b --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationContext.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Umbraco.Core.Persistence.Migrations +{ + internal class MigrationContext : IMigrationContext + { + public MigrationContext() + { + Expressions = new Collection(); + } + + public virtual ICollection Expressions { get; set; } + } + + public interface IMigrationContext + { + ICollection Expressions { get; set; } + } + + /// + /// Marker interface for migration expressions + /// + public interface IMigrationExpression + {} +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/ColumnDefinition.cs b/src/Umbraco.Core/Persistence/Migrations/Model/ColumnDefinition.cs new file mode 100644 index 0000000000..c41aebf0ab --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Model/ColumnDefinition.cs @@ -0,0 +1,29 @@ +using System.Data; + +namespace Umbraco.Core.Persistence.Migrations.Model +{ + public class ColumnDefinition + { + public virtual string Name { get; set; } + public virtual DbType? Type { get; set; } + public virtual int Size { get; set; } + public virtual int Precision { get; set; } + public virtual string CustomType { get; set; } + public virtual object DefaultValue { get; set; } + public virtual bool IsForeignKey { get; set; } + public virtual bool IsIdentity { get; set; } + public virtual bool IsIndexed { get; set; } + public virtual bool IsPrimaryKey { get; set; } + public virtual string PrimaryKeyName { get; set; } + public virtual bool IsNullable { get; set; } + public virtual bool IsUnique { get; set; } + public virtual string TableName { get; set; } + public virtual ColumnModificationType ModificationType { get; set; } + } + + public enum ColumnModificationType + { + Create, + Alter + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/ForeignKeyDefinition.cs b/src/Umbraco.Core/Persistence/Migrations/Model/ForeignKeyDefinition.cs new file mode 100644 index 0000000000..b688f230d5 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Model/ForeignKeyDefinition.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Data; + +namespace Umbraco.Core.Persistence.Migrations.Model +{ + public class ForeignKeyDefinition + { + public ForeignKeyDefinition() + { + ForeignColumns = new List(); + PrimaryColumns = new List(); + } + + public virtual string Name { get; set; } + public virtual string ForeignTable { get; set; } + public virtual string ForeignTableSchema { get; set; } + public virtual string PrimaryTable { get; set; } + public virtual string PrimaryTableSchema { get; set; } + public virtual Rule OnDelete { get; set; } + public virtual Rule OnUpdate { get; set; } + public virtual ICollection ForeignColumns { get; set; } + public virtual ICollection PrimaryColumns { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/IndexColumnDefinition.cs b/src/Umbraco.Core/Persistence/Migrations/Model/IndexColumnDefinition.cs new file mode 100644 index 0000000000..1f30bf3381 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Model/IndexColumnDefinition.cs @@ -0,0 +1,14 @@ +namespace Umbraco.Core.Persistence.Migrations.Model +{ + public class IndexColumnDefinition + { + public virtual string Name { get; set; } + public virtual Direction Direction { get; set; } + } + + public enum Direction + { + Ascending = 0, + Descending = 1 + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/IndexDefinition.cs b/src/Umbraco.Core/Persistence/Migrations/Model/IndexDefinition.cs new file mode 100644 index 0000000000..0ba9c5f9ca --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Model/IndexDefinition.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Persistence.Migrations.Model +{ + public class IndexDefinition + { + public IndexDefinition() + { + Columns = new List(); + } + + public virtual string Name { get; set; } + public virtual string SchemaName { get; set; } + public virtual string TableName { get; set; } + public virtual bool IsUnique { get; set; } + public bool IsClustered { get; set; } + public virtual ICollection Columns { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/SystemMethods.cs b/src/Umbraco.Core/Persistence/Migrations/Model/SystemMethods.cs new file mode 100644 index 0000000000..2bd0591494 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Model/SystemMethods.cs @@ -0,0 +1,10 @@ +namespace Umbraco.Core.Persistence.Migrations.Model +{ + public enum SystemMethods + { + NewGuid, + NewSequentialId, + CurrentDateTime, + CurrentUTCDateTime + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/TableDefinition.cs b/src/Umbraco.Core/Persistence/Migrations/Model/TableDefinition.cs new file mode 100644 index 0000000000..a305875b7c --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Model/TableDefinition.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Persistence.Migrations.Model +{ + public class TableDefinition + { + public TableDefinition() + { + Columns = new List(); + ForeignKeys = new List(); + Indexes = new List(); + } + + public virtual string Name { get; set; } + public virtual string SchemaName { get; set; } + public virtual ICollection Columns { get; set; } + public virtual ICollection ForeignKeys { get; set; } + public virtual ICollection Indexes { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs new file mode 100644 index 0000000000..44b3c8c828 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs @@ -0,0 +1,30 @@ +using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column; +using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions; +using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter +{ + public class AlterSyntaxBuilder : IAlterSyntaxBuilder + { + private readonly IMigrationContext _context; + + public AlterSyntaxBuilder(IMigrationContext context) + { + _context = context; + } + + public IAlterTableSyntax Table(string tableName) + { + var expression = new AlterTableExpression { TableName = tableName }; + //_context.Expressions.Add(expression); + return new AlterTableSyntaxBuilder(expression, _context); + } + + public IAlterColumnSyntax Column(string columnName) + { + var expression = new AlterColumnExpression { Column = { Name = columnName } }; + //_context.Expressions.Add(expression); + return new AlterColumnSyntaxBuilder(expression, _context); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnSyntaxBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnSyntaxBuilder.cs new file mode 100644 index 0000000000..b0ef9144f8 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnSyntaxBuilder.cs @@ -0,0 +1,229 @@ +using System.Data; +using Umbraco.Core.Persistence.Migrations.Model; +using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions; +using Umbraco.Core.Persistence.Migrations.Syntax.Expressions; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column +{ + public class AlterColumnSyntaxBuilder : ExpressionBuilder, + IAlterColumnSyntax, + IAlterColumnOptionForeignKeyCascadeSyntax + { + private readonly IMigrationContext _context; + + public AlterColumnSyntaxBuilder(AlterColumnExpression expression, IMigrationContext context) + : base(expression) + { + _context = context; + } + + public ForeignKeyDefinition CurrentForeignKey { get; set; } + + public override ColumnDefinition GetColumnForType() + { + return Expression.Column; + } + + public IAlterColumnOptionSyntax WithDefaultValue(object value) + { + var dc = new AlterDefaultConstraintExpression + { + TableName = Expression.TableName, + SchemaName = Expression.SchemaName, + ColumnName = Expression.Column.Name, + DefaultValue = value + }; + + _context.Expressions.Add(dc); + + Expression.Column.DefaultValue = value; + + return this; + } + + public IAlterColumnOptionSyntax Identity() + { + Expression.Column.IsIdentity = true; + return this; + } + + public IAlterColumnOptionSyntax Indexed() + { + return Indexed(null); + } + + public IAlterColumnOptionSyntax Indexed(string indexName) + { + Expression.Column.IsIndexed = true; + + var index = new CreateIndexExpression + { + Index = new IndexDefinition + { + Name = indexName, + SchemaName = Expression.SchemaName, + TableName = Expression.TableName + } + }; + + index.Index.Columns.Add(new IndexColumnDefinition + { + Name = Expression.Column.Name + }); + + _context.Expressions.Add(index); + + return this; + } + + public IAlterColumnOptionSyntax PrimaryKey() + { + Expression.Column.IsPrimaryKey = true; + return this; + } + + public IAlterColumnOptionSyntax PrimaryKey(string primaryKeyName) + { + Expression.Column.IsPrimaryKey = true; + Expression.Column.PrimaryKeyName = primaryKeyName; + return this; + } + + public IAlterColumnOptionSyntax Nullable() + { + Expression.Column.IsNullable = true; + return this; + } + + public IAlterColumnOptionSyntax NotNullable() + { + Expression.Column.IsNullable = false; + return this; + } + + public IAlterColumnOptionSyntax Unique() + { + return Unique(null); + } + + public IAlterColumnOptionSyntax Unique(string indexName) + { + Expression.Column.IsUnique = true; + + var index = new CreateIndexExpression + { + Index = new IndexDefinition + { + Name = indexName, + SchemaName = Expression.SchemaName, + TableName = Expression.TableName, + IsUnique = true + } + }; + + index.Index.Columns.Add(new IndexColumnDefinition + { + Name = Expression.Column.Name + }); + + _context.Expressions.Add(index); + + return this; + } + + public IAlterColumnOptionForeignKeyCascadeSyntax ForeignKey(string primaryTableName, string primaryColumnName) + { + return ForeignKey(null, null, primaryTableName, primaryColumnName); + } + + public IAlterColumnOptionForeignKeyCascadeSyntax ForeignKey(string foreignKeyName, string primaryTableName, + string primaryColumnName) + { + return ForeignKey(foreignKeyName, null, primaryTableName, primaryColumnName); + } + + public IAlterColumnOptionForeignKeyCascadeSyntax ForeignKey(string foreignKeyName, string primaryTableSchema, + string primaryTableName, string primaryColumnName) + { + Expression.Column.IsForeignKey = true; + + var fk = new CreateForeignKeyExpression + { + ForeignKey = new ForeignKeyDefinition + { + Name = foreignKeyName, + PrimaryTable = primaryTableName, + PrimaryTableSchema = primaryTableSchema, + ForeignTable = Expression.TableName, + ForeignTableSchema = Expression.SchemaName + } + }; + + fk.ForeignKey.PrimaryColumns.Add(primaryColumnName); + fk.ForeignKey.ForeignColumns.Add(Expression.Column.Name); + + _context.Expressions.Add(fk); + CurrentForeignKey = fk.ForeignKey; + return this; + } + + public IAlterColumnOptionForeignKeyCascadeSyntax ForeignKey() + { + Expression.Column.IsForeignKey = true; + return this; + } + + public IAlterColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignTableName, string foreignColumnName) + { + return ReferencedBy(null, null, foreignTableName, foreignColumnName); + } + + public IAlterColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableName, + string foreignColumnName) + { + return ReferencedBy(foreignKeyName, null, foreignTableName, foreignColumnName); + } + + public IAlterColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableSchema, + string foreignTableName, string foreignColumnName) + { + var fk = new CreateForeignKeyExpression + { + ForeignKey = new ForeignKeyDefinition + { + Name = foreignKeyName, + PrimaryTable = Expression.TableName, + PrimaryTableSchema = Expression.SchemaName, + ForeignTable = foreignTableName, + ForeignTableSchema = foreignTableSchema + } + }; + + fk.ForeignKey.PrimaryColumns.Add(Expression.Column.Name); + fk.ForeignKey.ForeignColumns.Add(foreignColumnName); + + _context.Expressions.Add(fk); + CurrentForeignKey = fk.ForeignKey; + return this; + } + + public IAlterColumnOptionForeignKeyCascadeSyntax OnDelete(Rule rule) + { + CurrentForeignKey.OnDelete = rule; + return this; + } + + public IAlterColumnOptionForeignKeyCascadeSyntax OnUpdate(Rule rule) + { + CurrentForeignKey.OnUpdate = rule; + return this; + } + + public IAlterColumnOptionSyntax OnDeleteOrUpdate(Rule rule) + { + OnDelete(rule); + OnUpdate(rule); + return this; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnOptionForeignKeyCascadeSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnOptionForeignKeyCascadeSyntax.cs new file mode 100644 index 0000000000..c6c3aae29e --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnOptionForeignKeyCascadeSyntax.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column +{ + public interface IAlterColumnOptionForeignKeyCascadeSyntax : + IAlterColumnOptionSyntax, + IForeignKeyCascadeSyntax + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnOptionSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnOptionSyntax.cs new file mode 100644 index 0000000000..2dd4578f1d --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnOptionSyntax.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column +{ + public interface IAlterColumnOptionSyntax : IColumnOptionSyntax + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnSyntax.cs new file mode 100644 index 0000000000..846b4857f2 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/IAlterColumnSyntax.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column +{ + public interface IAlterColumnSyntax : IFluentSyntax + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs new file mode 100644 index 0000000000..32eaf9da71 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs @@ -0,0 +1,22 @@ +using Umbraco.Core.Persistence.Migrations.Model; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions +{ + public class AlterColumnExpression : IMigrationExpression + { + public AlterColumnExpression() + { + Column = new ColumnDefinition() { ModificationType = ColumnModificationType.Alter }; + } + + public virtual string SchemaName { get; set; } + public virtual string TableName { get; set; } + public virtual ColumnDefinition Column { get; set; } + + public override string ToString() + { + //TODO Implement usage of the SqlSyntax provider here to generate the sql statement for this expression. + return TableName + " " + Column.Name + " " + Column.Type ?? Column.CustomType; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs new file mode 100644 index 0000000000..bcff2fbc25 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs @@ -0,0 +1,17 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions +{ + public class AlterTableExpression : IMigrationExpression + { + public AlterTableExpression() + { + } + + public virtual string SchemaName { get; set; } + public virtual string TableName { get; set; } + + public override string ToString() + { + return base.ToString() + TableName; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/IAlterSyntaxBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/IAlterSyntaxBuilder.cs new file mode 100644 index 0000000000..479c2eadce --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/IAlterSyntaxBuilder.cs @@ -0,0 +1,11 @@ +using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column; +using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter +{ + public interface IAlterSyntaxBuilder : IFluentSyntax + { + IAlterTableSyntax Table(string tableName); + IAlterColumnSyntax Column(string columnName); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableSyntaxBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableSyntaxBuilder.cs new file mode 100644 index 0000000000..79d5ba3630 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableSyntaxBuilder.cs @@ -0,0 +1,265 @@ +using System.Data; +using Umbraco.Core.Persistence.Migrations.Model; +using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions; +using Umbraco.Core.Persistence.Migrations.Syntax.Expressions; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table +{ + public class AlterTableSyntaxBuilder : ExpressionBuilder, + IAlterTableColumnSyntax, + IAlterTableColumnOptionForeignKeyCascadeSyntax + { + private readonly IMigrationContext _context; + + public AlterTableSyntaxBuilder(AlterTableExpression expression, IMigrationContext context) + : base(expression) + { + _context = context; + } + + public ColumnDefinition CurrentColumn { get; set; } + + public ForeignKeyDefinition CurrentForeignKey { get; set; } + + public override ColumnDefinition GetColumnForType() + { + return CurrentColumn; + } + + public IAlterTableColumnOptionSyntax WithDefaultValue(object value) + { + if (CurrentColumn.ModificationType == ColumnModificationType.Alter) + { + var dc = new AlterDefaultConstraintExpression + { + TableName = Expression.TableName, + SchemaName = Expression.SchemaName, + ColumnName = CurrentColumn.Name, + DefaultValue = value + }; + + _context.Expressions.Add(dc); + } + + CurrentColumn.DefaultValue = value; + return this; + } + + public IAlterTableColumnOptionSyntax Identity() + { + CurrentColumn.IsIdentity = true; + return this; + } + + public IAlterTableColumnOptionSyntax Indexed() + { + return Indexed(null); + } + + public IAlterTableColumnOptionSyntax Indexed(string indexName) + { + CurrentColumn.IsIndexed = true; + + var index = new CreateIndexExpression + { + Index = new IndexDefinition + { + Name = indexName, + SchemaName = Expression.SchemaName, + TableName = Expression.TableName + } + }; + + index.Index.Columns.Add(new IndexColumnDefinition + { + Name = CurrentColumn.Name + }); + + _context.Expressions.Add(index); + + return this; + } + + public IAlterTableColumnOptionSyntax PrimaryKey() + { + CurrentColumn.IsPrimaryKey = true; + return this; + } + + public IAlterTableColumnOptionSyntax PrimaryKey(string primaryKeyName) + { + CurrentColumn.IsPrimaryKey = true; + CurrentColumn.PrimaryKeyName = primaryKeyName; + return this; + } + + public IAlterTableColumnOptionSyntax Nullable() + { + CurrentColumn.IsNullable = true; + return this; + } + + public IAlterTableColumnOptionSyntax NotNullable() + { + CurrentColumn.IsNullable = false; + return this; + } + + public IAlterTableColumnOptionSyntax Unique() + { + return Unique(null); + } + + public IAlterTableColumnOptionSyntax Unique(string indexName) + { + CurrentColumn.IsUnique = true; + + var index = new CreateIndexExpression + { + Index = new IndexDefinition + { + Name = indexName, + SchemaName = Expression.SchemaName, + TableName = Expression.TableName, + IsUnique = true + } + }; + + index.Index.Columns.Add(new IndexColumnDefinition + { + Name = CurrentColumn.Name + }); + + _context.Expressions.Add(index); + + return this; + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax ForeignKey(string primaryTableName, string primaryColumnName) + { + return ForeignKey(null, null, primaryTableName, primaryColumnName); + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax ForeignKey(string foreignKeyName, string primaryTableName, + string primaryColumnName) + { + return ForeignKey(foreignKeyName, null, primaryTableName, primaryColumnName); + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax ForeignKey(string foreignKeyName, string primaryTableSchema, + string primaryTableName, string primaryColumnName) + { + CurrentColumn.IsForeignKey = true; + + var fk = new CreateForeignKeyExpression + { + ForeignKey = new ForeignKeyDefinition + { + Name = foreignKeyName, + PrimaryTable = primaryTableName, + PrimaryTableSchema = primaryTableSchema, + ForeignTable = Expression.TableName, + ForeignTableSchema = Expression.SchemaName + } + }; + + fk.ForeignKey.PrimaryColumns.Add(primaryColumnName); + fk.ForeignKey.ForeignColumns.Add(CurrentColumn.Name); + + _context.Expressions.Add(fk); + CurrentForeignKey = fk.ForeignKey; + return this; + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax ForeignKey() + { + CurrentColumn.IsForeignKey = true; + return this; + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignTableName, string foreignColumnName) + { + return ReferencedBy(null, null, foreignTableName, foreignColumnName); + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableName, + string foreignColumnName) + { + return ReferencedBy(foreignKeyName, null, foreignTableName, foreignColumnName); + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax ReferencedBy(string foreignKeyName, string foreignTableSchema, + string foreignTableName, string foreignColumnName) + { + var fk = new CreateForeignKeyExpression + { + ForeignKey = new ForeignKeyDefinition + { + Name = foreignKeyName, + PrimaryTable = Expression.TableName, + PrimaryTableSchema = Expression.SchemaName, + ForeignTable = foreignTableName, + ForeignTableSchema = foreignTableSchema + } + }; + + fk.ForeignKey.PrimaryColumns.Add(CurrentColumn.Name); + fk.ForeignKey.ForeignColumns.Add(foreignColumnName); + + _context.Expressions.Add(fk); + CurrentForeignKey = fk.ForeignKey; + return this; + } + + public IAlterTableColumnSyntax AddColumn(string name) + { + var column = new ColumnDefinition { Name = name, ModificationType = ColumnModificationType.Create }; + var createColumn = new CreateColumnExpression + { + Column = column, + SchemaName = Expression.SchemaName, + TableName = Expression.TableName + }; + + CurrentColumn = column; + + _context.Expressions.Add(createColumn); + return this; + } + + public IAlterTableColumnSyntax AlterColumn(string name) + { + var column = new ColumnDefinition { Name = name, ModificationType = ColumnModificationType.Alter }; + var alterColumn = new AlterColumnExpression + { + Column = column, + SchemaName = Expression.SchemaName, + TableName = Expression.TableName + }; + + CurrentColumn = column; + + _context.Expressions.Add(alterColumn); + return this; + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax OnDelete(Rule rule) + { + CurrentForeignKey.OnDelete = rule; + return this; + } + + public IAlterTableColumnOptionForeignKeyCascadeSyntax OnUpdate(Rule rule) + { + CurrentForeignKey.OnUpdate = rule; + return this; + } + + public IAlterTableColumnOptionSyntax OnDeleteOrUpdate(Rule rule) + { + OnDelete(rule); + OnUpdate(rule); + return this; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnOptionForeignKeyCascadeSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnOptionForeignKeyCascadeSyntax.cs new file mode 100644 index 0000000000..e9035c195c --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnOptionForeignKeyCascadeSyntax.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table +{ + public interface IAlterTableColumnOptionForeignKeyCascadeSyntax : + IAlterTableColumnOptionSyntax, + IForeignKeyCascadeSyntax + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnOptionSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnOptionSyntax.cs new file mode 100644 index 0000000000..956f9ee999 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnOptionSyntax.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table +{ + public interface IAlterTableColumnOptionSyntax : + IColumnOptionSyntax, + IAlterTableSyntax + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnSyntax.cs new file mode 100644 index 0000000000..44dc72de6c --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableColumnSyntax.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table +{ + public interface IAlterTableColumnSyntax : IColumnTypeSyntax + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableSyntax.cs new file mode 100644 index 0000000000..d761c80565 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/IAlterTableSyntax.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table +{ + public interface IAlterTableSyntax : IFluentSyntax + { + IAlterTableColumnSyntax AddColumn(string name); + IAlterTableColumnSyntax AlterColumn(string name); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs new file mode 100644 index 0000000000..af1a2284c0 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Create +{ + public class CreateBuilder : ICreateBuilder + { + private readonly IMigrationContext _context; + + public CreateBuilder(IMigrationContext context) + { + _context = context; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/ICreateBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/ICreateBuilder.cs new file mode 100644 index 0000000000..1a7e451f0b --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/ICreateBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Create +{ + public interface ICreateBuilder + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs new file mode 100644 index 0000000000..8013869854 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete +{ + public class DeleteBuilder : IDeleteBuilder + { + private readonly IMigrationContext _context; + + public DeleteBuilder(IMigrationContext context) + { + _context = context; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/IDeleteBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/IDeleteBuilder.cs new file mode 100644 index 0000000000..2989156022 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/IDeleteBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete +{ + public interface IDeleteBuilder + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/ExpressionBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/ExpressionBuilder.cs new file mode 100644 index 0000000000..28be42d739 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/ExpressionBuilder.cs @@ -0,0 +1,181 @@ +using System.Data; +using Umbraco.Core.Persistence.Migrations.Model; + +namespace Umbraco.Core.Persistence.Migrations.Syntax +{ + public abstract class ExpressionBuilder : ExpressionBuilderBase + where ExpressionT : IMigrationExpression + where NextT : IFluentSyntax + { + protected ExpressionBuilder(ExpressionT expression) + : base(expression) + { + } + + public abstract ColumnDefinition GetColumnForType(); + + private ColumnDefinition Column + { + get { return GetColumnForType(); } + } + + public NextT AsAnsiString() + { + Column.Type = DbType.AnsiString; + return (NextT)(object)this; + } + + public NextT AsAnsiString(int size) + { + Column.Type = DbType.AnsiString; + Column.Size = size; + return (NextT)(object)this; + } + + public NextT AsBinary() + { + Column.Type = DbType.Binary; + return (NextT)(object)this; + } + + public NextT AsBinary(int size) + { + Column.Type = DbType.Binary; + Column.Size = size; + return (NextT)(object)this; + } + + public NextT AsBoolean() + { + Column.Type = DbType.Boolean; + return (NextT)(object)this; + } + + public NextT AsByte() + { + Column.Type = DbType.Byte; + return (NextT)(object)this; + } + + public NextT AsCurrency() + { + Column.Type = DbType.Currency; + return (NextT)(object)this; + } + + public NextT AsDate() + { + Column.Type = DbType.Date; + return (NextT)(object)this; + } + + public NextT AsDateTime() + { + Column.Type = DbType.DateTime; + return (NextT)(object)this; + } + + public NextT AsDecimal() + { + Column.Type = DbType.Decimal; + return (NextT)(object)this; + } + + public NextT AsDecimal(int size, int precision) + { + Column.Type = DbType.Decimal; + Column.Size = size; + Column.Precision = precision; + return (NextT)(object)this; + } + + public NextT AsDouble() + { + Column.Type = DbType.Double; + return (NextT)(object)this; + } + + public NextT AsFixedLengthString(int size) + { + Column.Type = DbType.StringFixedLength; + Column.Size = size; + return (NextT)(object)this; + } + + public NextT AsFixedLengthAnsiString(int size) + { + Column.Type = DbType.AnsiStringFixedLength; + Column.Size = size; + return (NextT)(object)this; + } + + public NextT AsFloat() + { + Column.Type = DbType.Single; + return (NextT)(object)this; + } + + public NextT AsGuid() + { + Column.Type = DbType.Guid; + return (NextT)(object)this; + } + + public NextT AsInt16() + { + Column.Type = DbType.Int16; + return (NextT)(object)this; + } + + public NextT AsInt32() + { + Column.Type = DbType.Int32; + return (NextT)(object)this; + } + + public NextT AsInt64() + { + Column.Type = DbType.Int64; + return (NextT)(object)this; + } + + public NextT AsString() + { + Column.Type = DbType.String; + return (NextT)(object)this; + } + + public NextT AsString(int size) + { + Column.Type = DbType.String; + Column.Size = size; + return (NextT)(object)this; + } + + public NextT AsTime() + { + Column.Type = DbType.Time; + return (NextT)(object)this; + } + + public NextT AsXml() + { + Column.Type = DbType.Xml; + return (NextT)(object)this; + } + + public NextT AsXml(int size) + { + Column.Type = DbType.Xml; + Column.Size = size; + return (NextT)(object)this; + } + + public NextT AsCustom(string customType) + { + Column.Type = null; + Column.CustomType = customType; + return (NextT)(object)this; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/ExpressionBuilderBase.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/ExpressionBuilderBase.cs new file mode 100644 index 0000000000..da75ab8541 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/ExpressionBuilderBase.cs @@ -0,0 +1,13 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax +{ + public abstract class ExpressionBuilderBase + where T : IMigrationExpression + { + public T Expression { get; private set; } + + protected ExpressionBuilderBase(T expression) + { + Expression = expression; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/AlterDefaultConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/AlterDefaultConstraintExpression.cs new file mode 100644 index 0000000000..d50df9b0fe --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/AlterDefaultConstraintExpression.cs @@ -0,0 +1,20 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions +{ + public class AlterDefaultConstraintExpression : IMigrationExpression + { + public virtual string SchemaName { get; set; } + public virtual string TableName { get; set; } + public virtual string ColumnName { get; set; } + public virtual object DefaultValue { get; set; } + + public override string ToString() + { + return base.ToString() + + string.Format("{0}.{1} {2} {3}", + SchemaName, + TableName, + ColumnName, + DefaultValue); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs new file mode 100644 index 0000000000..592eac3e85 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs @@ -0,0 +1,27 @@ +using System; +using Umbraco.Core.Persistence.Migrations.Model; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions +{ + public class CreateColumnExpression : IMigrationExpression + { + public CreateColumnExpression() + { + Column = new ColumnDefinition { ModificationType = ColumnModificationType.Create }; + } + + public virtual string SchemaName { get; set; } + public virtual string TableName { get; set; } + public virtual ColumnDefinition Column { get; set; } + + public override string ToString() + { + + var output = String.Format(SyntaxConfig.SqlSyntaxProvider.AddColumn, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + SyntaxConfig.SqlSyntaxProvider.Format(Column)); + return output; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs new file mode 100644 index 0000000000..08ca98befa --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs @@ -0,0 +1,26 @@ +using System.Linq; +using Umbraco.Core.Persistence.Migrations.Model; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions +{ + public class CreateForeignKeyExpression : IMigrationExpression + { + public CreateForeignKeyExpression() + { + ForeignKey = new ForeignKeyDefinition(); + } + + public virtual ForeignKeyDefinition ForeignKey { get; set; } + + public override string ToString() + { + return base.ToString() + + string.Format("{0} {1}({2}) {3}({4})", + ForeignKey.Name, + ForeignKey.ForeignTable, + string.Join(", ", ForeignKey.ForeignColumns.ToArray()), + ForeignKey.PrimaryTable, + string.Join(", ", ForeignKey.PrimaryColumns.ToArray())); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs new file mode 100644 index 0000000000..854acd7e3d --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs @@ -0,0 +1,20 @@ +using System.Linq; +using Umbraco.Core.Persistence.Migrations.Model; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions +{ + public class CreateIndexExpression : IMigrationExpression + { + public CreateIndexExpression() + { + Index = new IndexDefinition(); + } + + public virtual IndexDefinition Index { get; set; } + + public override string ToString() + { + return base.ToString() + Index.TableName + " (" + string.Join(", ", Index.Columns.Select(x => x.Name).ToArray()) + ")"; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/IColumnOptionSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/IColumnOptionSyntax.cs new file mode 100644 index 0000000000..e18a68eda7 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/IColumnOptionSyntax.cs @@ -0,0 +1,28 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax +{ + public interface IColumnOptionSyntax : IFluentSyntax + where TNext : IFluentSyntax + where TNextFk : IFluentSyntax + { + TNext WithDefaultValue(object value); + TNext Identity(); + TNext Indexed(); + TNext Indexed(string indexName); + + TNext PrimaryKey(); + TNext PrimaryKey(string primaryKeyName); + TNext Nullable(); + TNext NotNullable(); + TNext Unique(); + TNext Unique(string indexName); + + TNextFk ForeignKey(string primaryTableName, string primaryColumnName); + TNextFk ForeignKey(string foreignKeyName, string primaryTableName, string primaryColumnName); + TNextFk ForeignKey(string foreignKeyName, string primaryTableSchema, string primaryTableName, string primaryColumnName); + TNextFk ForeignKey(); + + TNextFk ReferencedBy(string foreignTableName, string foreignColumnName); + TNextFk ReferencedBy(string foreignKeyName, string foreignTableName, string foreignColumnName); + TNextFk ReferencedBy(string foreignKeyName, string foreignTableSchema, string foreignTableName, string foreignColumnName); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/IColumnTypeSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/IColumnTypeSyntax.cs new file mode 100644 index 0000000000..406e6962bb --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/IColumnTypeSyntax.cs @@ -0,0 +1,32 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax +{ + public interface IColumnTypeSyntax : IFluentSyntax + where TNext : IFluentSyntax + { + TNext AsAnsiString(); + TNext AsAnsiString(int size); + TNext AsBinary(); + TNext AsBinary(int size); + TNext AsBoolean(); + TNext AsByte(); + TNext AsCurrency(); + TNext AsDate(); + TNext AsDateTime(); + TNext AsDecimal(); + TNext AsDecimal(int size, int precision); + TNext AsDouble(); + TNext AsGuid(); + TNext AsFixedLengthString(int size); + TNext AsFixedLengthAnsiString(int size); + TNext AsFloat(); + TNext AsInt16(); + TNext AsInt32(); + TNext AsInt64(); + TNext AsString(); + TNext AsString(int size); + TNext AsTime(); + TNext AsXml(); + TNext AsXml(int size); + TNext AsCustom(string customType); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/IFluentSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/IFluentSyntax.cs new file mode 100644 index 0000000000..f6d1f67f2b --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/IFluentSyntax.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax +{ + public interface IFluentSyntax + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/IForeignKeyCascadeSyntax.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/IForeignKeyCascadeSyntax.cs new file mode 100644 index 0000000000..eb75ef7c3d --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/IForeignKeyCascadeSyntax.cs @@ -0,0 +1,13 @@ +using System.Data; + +namespace Umbraco.Core.Persistence.Migrations.Syntax +{ + public interface IForeignKeyCascadeSyntax : IFluentSyntax + where TNext : IFluentSyntax + where TNextFk : IFluentSyntax + { + TNextFk OnDelete(Rule rule); + TNextFk OnUpdate(Rule rule); + TNext OnDeleteOrUpdate(Rule rule); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/IInsertBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/IInsertBuilder.cs new file mode 100644 index 0000000000..7a8eeeb8ba --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/IInsertBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert +{ + public interface IInsertBuilder + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs new file mode 100644 index 0000000000..12f046e56b --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert +{ + public class InsertBuilder : IInsertBuilder + { + private readonly IMigrationContext _context; + + public InsertBuilder(IMigrationContext context) + { + _context = context; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/IRenameBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/IRenameBuilder.cs new file mode 100644 index 0000000000..6a54c32863 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/IRenameBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename +{ + public interface IRenameBuilder + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs new file mode 100644 index 0000000000..4e04f87554 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename +{ + public class RenameBuilder : IRenameBuilder + { + private readonly IMigrationContext _context; + + public RenameBuilder(IMigrationContext context) + { + _context = context; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Schema/ISchemaBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Schema/ISchemaBuilder.cs new file mode 100644 index 0000000000..b22c92ed07 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Schema/ISchemaBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Schema +{ + public interface ISchemaBuilder + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Schema/SchemaBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Schema/SchemaBuilder.cs new file mode 100644 index 0000000000..327102d520 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Schema/SchemaBuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Schema +{ + public class SchemaBuilder : ISchemaBuilder + { + private readonly IMigrationContext _context; + + public SchemaBuilder(IMigrationContext context) + { + _context = context; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/IUpdateBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/IUpdateBuilder.cs new file mode 100644 index 0000000000..fce9bfe18f --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/IUpdateBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Update +{ + public interface IUpdateBuilder + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs new file mode 100644 index 0000000000..5866a3b8b9 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Persistence.Migrations.Syntax.Update +{ + public class UpdateBuilder : IUpdateBuilder + { + private readonly IMigrationContext _context; + + public UpdateBuilder(IMigrationContext context) + { + _context = context; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs index c5e117459f..6431b43347 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs @@ -26,5 +26,24 @@ namespace Umbraco.Core.Persistence.SqlSyntax string GetSpecialDbType(SpecialDbTypes dbTypes); string GetConstraintDefinition(ColumnDefinition column, string tableName); List ToAlterIdentitySeedStatements(TableDefinition table); + string CreateTable { get; } + string DropTable { get; } + string AddColumn { get; } + string DropColumn { get; } + string AlterColumn { get; } + string RenameColumn { get; } + string RenameTable { get; } + string CreateSchema { get; } + string AlterSchema { get; } + string DropSchema { get; } + string CreateIndex { get; } + string DropIndex { get; } + string InsertData { get; } + string UpdateData { get; } + string DeleteData { get; } + string CreateConstraint { get; } + string DeleteConstraint { get; } + string CreateForeignKeyConstraint { get; } + string Format(Migrations.Model.ColumnDefinition column); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs index 2beec2bd1d..d9914f2e86 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using System.Text; using Umbraco.Core.Persistence.DatabaseAnnotations; -using Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions; +using Umbraco.Core.Persistence.Migrations.Model; +using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; +using TableDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.TableDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -166,5 +168,33 @@ namespace Umbraco.Core.Persistence.SqlSyntax return result > 0; } + + protected override string FormatIdentity(Migrations.Model.ColumnDefinition column) + { + return column.IsIdentity ? AutoIncrementDefinition : string.Empty; + } + + protected override string FormatSystemMethods(SystemMethods systemMethod) + { + switch (systemMethod) + { + case SystemMethods.NewGuid: + return "NEWID()"; + case SystemMethods.NewSequentialId: + return "NEWSEQUENTIALID()"; + case SystemMethods.CurrentDateTime: + return "GETDATE()"; + case SystemMethods.CurrentUTCDateTime: + return "GETUTCDATE()"; + } + + return null; + } + + public override string AlterColumn { get { return "ALTER TABLE {0} MODIFY COLUMN {1}"; } } + + public override string DeleteConstraint { get { return "ALTER TABLE {0} DROP {1}{2}"; } } + + public override string CreateTable { get { return "CREATE TABLE {0} ({1}) ENGINE = INNODB"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs index 8a644ddd43..07fdd0a790 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions; +using Umbraco.Core.Persistence.Migrations.Model; +using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -75,5 +76,34 @@ namespace Umbraco.Core.Persistence.SqlSyntax return result > 0; } + + protected override string FormatIdentity(Migrations.Model.ColumnDefinition column) + { + return column.IsIdentity ? GetIdentityString(column) : string.Empty; + } + + private static string GetIdentityString(Migrations.Model.ColumnDefinition column) + { + return "IDENTITY(1,1)"; + } + + protected override string FormatSystemMethods(SystemMethods systemMethod) + { + switch (systemMethod) + { + case SystemMethods.NewGuid: + return "NEWID()"; + case SystemMethods.NewSequentialId: + return "NEWSEQUENTIALID()"; + case SystemMethods.CurrentDateTime: + return "GETDATE()"; + case SystemMethods.CurrentUTCDateTime: + return "GETUTCDATE()"; + } + + return null; + } + + public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs index ca6a5f1a13..5784fff530 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Persistence.SqlSyntax +using Umbraco.Core.Persistence.Migrations.Model; + +namespace Umbraco.Core.Persistence.SqlSyntax { /// /// Static class that provides simple access to the Sql Server SqlSyntax Providers singleton @@ -40,5 +42,34 @@ return result > 0; } + + protected override string FormatIdentity(Migrations.Model.ColumnDefinition column) + { + return column.IsIdentity ? GetIdentityString(column) : string.Empty; + } + + private static string GetIdentityString(Migrations.Model.ColumnDefinition column) + { + return "IDENTITY(1,1)"; + } + + protected override string FormatSystemMethods(SystemMethods systemMethod) + { + switch (systemMethod) + { + case SystemMethods.NewGuid: + return "NEWID()"; + case SystemMethods.NewSequentialId: + return "NEWSEQUENTIALID()"; + case SystemMethods.CurrentDateTime: + return "GETDATE()"; + case SystemMethods.CurrentUTCDateTime: + return "GETUTCDATE()"; + } + + return null; + } + + public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index ec0337d293..da129c7aca 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -4,7 +4,9 @@ using System.Data; using System.Linq; using System.Text; using Umbraco.Core.Persistence.DatabaseAnnotations; -using Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions; +using Umbraco.Core.Persistence.Migrations.Model; +using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; +using TableDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.TableDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -18,6 +20,19 @@ namespace Umbraco.Core.Persistence.SqlSyntax internal abstract class SqlSyntaxProviderBase : ISqlSyntaxProvider where TSyntax : ISqlSyntaxProvider { + protected SqlSyntaxProviderBase() + { + ClauseOrder = new List> + { + FormatString, + FormatType, + FormatNullable, + FormatDefaultValue, + FormatPrimaryKey, + FormatIdentity + }; + } + public string StringLengthNonUnicodeColumnDefinitionFormat = "VARCHAR({0})"; public string StringLengthUnicodeColumnDefinitionFormat = "NVARCHAR({0})"; @@ -39,6 +54,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax public string DateTimeColumnDefinition = "DATETIME"; public string TimeColumnDefinition = "DATETIME"; + protected IList> ClauseOrder { get; set; } + protected DbTypes DbTypeMap = new DbTypes(); protected void InitColumnTypeMap() { @@ -317,5 +334,96 @@ namespace Umbraco.Core.Persistence.SqlSyntax return DbTypeMap.ColumnDbTypeMap[valueType]; } + + public virtual string Format(Migrations.Model.ColumnDefinition column) + { + var clauses = new List(); + + foreach (var action in ClauseOrder) + { + string clause = action(column); + if (!string.IsNullOrEmpty(clause)) + clauses.Add(clause); + } + + return string.Join(" ", clauses.ToArray()); + } + + public virtual string FormatString(Migrations.Model.ColumnDefinition column) + { + return GetQuotedColumnName(column.Name); + } + + protected virtual string FormatType(Migrations.Model.ColumnDefinition column) + { + if (!column.Type.HasValue) + return column.CustomType; + + var dbType = DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key; + var definition = DbTypeMap.ColumnDbTypeMap.First(x => x.Key == dbType).Value; + + string dbTypeDefinition = column.Size != default(int) + ? string.Format("{0}({1})", definition, column.Size) + : definition.ToString(); + //NOTE Percision is left out + return dbTypeDefinition; + } + + protected virtual string FormatNullable(Migrations.Model.ColumnDefinition column) + { + return !column.IsNullable ? "NOT NULL" : string.Empty; + } + + protected virtual string FormatDefaultValue(Migrations.Model.ColumnDefinition column) + { + if (column.DefaultValue == null) + return string.Empty; + + // see if this is for a system method + if (column.DefaultValue is SystemMethods) + { + string method = FormatSystemMethods((SystemMethods)column.DefaultValue); + if (string.IsNullOrEmpty(method)) + return string.Empty; + + return "DEFAULT " + method; + } + + return "DEFAULT " + GetQuotedValue(column.DefaultValue.ToString()); + } + + protected virtual string FormatPrimaryKey(Migrations.Model.ColumnDefinition column) + { + return string.Empty; + } + + protected abstract string FormatSystemMethods(SystemMethods systemMethod); + + protected abstract string FormatIdentity(Migrations.Model.ColumnDefinition column); + + public virtual string CreateTable { get { return "CREATE TABLE {0} ({1})"; } } + public virtual string DropTable { get { return "DROP TABLE {0}"; } } + + public virtual string AddColumn { get { return "ALTER TABLE {0} ADD COLUMN {1}"; } } + public virtual string DropColumn { get { return "ALTER TABLE {0} DROP COLUMN {1}"; } } + public virtual string AlterColumn { get { return "ALTER TABLE {0} ALTER COLUMN {1}"; } } + public virtual string RenameColumn { get { return "ALTER TABLE {0} RENAME COLUMN {1} TO {2}"; } } + + public virtual string RenameTable { get { return "RENAME TABLE {0} TO {1}"; } } + + public virtual string CreateSchema { get { return "CREATE SCHEMA {0}"; } } + public virtual string AlterSchema { get { return "ALTER SCHEMA {0} TRANSFER {1}.{2}"; } } + public virtual string DropSchema { get { return "DROP SCHEMA {0}"; } } + + public virtual string CreateIndex { get { return "CREATE {0}{1}INDEX {2} ON {3} ({4})"; } } + public virtual string DropIndex { get { return "DROP INDEX {0}"; } } + + public virtual string InsertData { get { return "INSERT INTO {0} ({1}) VALUES ({2})"; } } + public virtual string UpdateData { get { return "UPDATE {0} SET {1} WHERE {2}"; } } + public virtual string DeleteData { get { return "DELETE FROM {0} WHERE {1}"; } } + + public virtual string CreateConstraint { get { return "ALTER TABLE {0} ADD CONSTRAINT {1} {2} ({3})"; } } + public virtual string DeleteConstraint { get { return "ALTER TABLE {0} DROP CONSTRAINT {1}"; } } + public virtual string CreateForeignKeyConstraint { get { return "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}){5}{6}"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index e5fe961a5a..1e4474c7ba 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -190,8 +190,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -488,7 +533,9 @@ umbraco.interfaces - + + +