using System; using System.Collections.Generic; using System.Linq; using System.Net.NetworkInformation; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; using Oqtane.Databases.Interfaces; using Oqtane.Interfaces; // ReSharper disable BuiltInTypeReferenceStyleForMemberAccess namespace Oqtane.Migrations.EntityBuilders { public abstract class BaseEntityBuilder where TEntityBuilder : BaseEntityBuilder { private readonly MigrationBuilder _migrationBuilder; protected BaseEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) { _migrationBuilder = migrationBuilder; ActiveDatabase = database; ForeignKeys = new List>(); } protected IDatabase ActiveDatabase { get; } protected abstract TEntityBuilder BuildTable(ColumnsBuilder table); protected string EntityTableName { get; init; } protected PrimaryKey PrimaryKey { get; init; } protected List> ForeignKeys { get; } private string RewriteName(string name) { return ActiveDatabase.RewriteName(name); } // Column Operations protected OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name) { return ActiveDatabase.AddAutoIncrementColumn(table, RewriteName(name)); } public void AddBooleanColumn(string name, bool nullable = false) { _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), nullable: nullable); } protected OperationBuilder AddBooleanColumn(ColumnsBuilder table, string name, bool nullable = false) { return table.Column(name: RewriteName(name), nullable: nullable); } public void AddDateTimeColumn(string name, bool nullable = false) { _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), nullable: nullable); } protected OperationBuilder AddDateTimeColumn(ColumnsBuilder table, string name, bool nullable = false) { return table.Column(name: RewriteName(name), nullable: nullable); } public void AddDateTimeOffsetColumn(string name, bool nullable = false) { _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), nullable: nullable); } protected OperationBuilder AddDateTimeOffsetColumn(ColumnsBuilder table, string name, bool nullable = false) { return table.Column(name: RewriteName(name), nullable: nullable); } public void AddIntegerColumn(string name, bool nullable = false) { _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), nullable: nullable); } protected OperationBuilder AddIntegerColumn(ColumnsBuilder table, string name, bool nullable = false) { return table.Column(name: RewriteName(name), nullable: nullable); } public void AddMaxStringColumn(string name, bool nullable = false, bool unicode = true) { _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), nullable: nullable, unicode: unicode); } protected OperationBuilder AddMaxStringColumn(ColumnsBuilder table, string name, bool nullable = false, bool unicode = true) { return table.Column(name: RewriteName(name), nullable: nullable, unicode: unicode); } public void AddStringColumn(string name, int length, bool nullable = false, bool unicode = true) { _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), maxLength: length, nullable: nullable, unicode: unicode); } protected OperationBuilder AddStringColumn(ColumnsBuilder table, string name, int length, bool nullable = false, bool unicode = true) { return table.Column(name: RewriteName(name), maxLength: length, nullable: nullable, unicode: unicode); } public void AlterStringColumn(string name, int length, bool nullable = false, bool unicode = true) { _migrationBuilder.AlterColumn(RewriteName(name), RewriteName(EntityTableName), maxLength: length, nullable: nullable, unicode: unicode); } public void AddDecimalColumn(string name, int precision, int scale, bool nullable = false) { _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), nullable: nullable, precision: precision, scale: scale); } protected OperationBuilder AddDecimalColumn(ColumnsBuilder table, string name, int precision, int scale, bool nullable = false) { return table.Column(name: RewriteName(name), nullable: nullable, precision: precision, scale: scale); } public void DropColumn(string name) { _migrationBuilder.DropColumn(RewriteName(name), RewriteName(EntityTableName)); } //Index Operations /// /// Creates a Migration to add an Index to the Entity (table) /// /// The name of the Index to create /// The name of the column to add to the index /// A flag that determines if the Index should be Unique public virtual void AddIndex(string indexName, string columnName, bool isUnique = false) { _migrationBuilder.CreateIndex( name: RewriteName(indexName), table: RewriteName(EntityTableName), column: RewriteName(columnName), unique: isUnique); } public virtual void AddForeignKey(string foreignKeyName, string columnName, string principalTable, string principalColumn, ReferentialAction onDelete) { _migrationBuilder.AddForeignKey( name: RewriteName(foreignKeyName), table: RewriteName(EntityTableName), column: RewriteName(columnName), principalTable: RewriteName(principalTable), principalColumn: RewriteName(principalColumn), onDelete: onDelete ); } /// /// Creates a Migration to add an Index to the Entity (table) /// /// The name of the Index to create /// The names of the columns to add to the index /// A flag that determines if the Index should be Unique public virtual void AddIndex(string indexName, string[] columnNames, bool isUnique = false) { _migrationBuilder.CreateIndex( name: RewriteName(indexName), table: RewriteName(EntityTableName), columns: columnNames.Select(RewriteName).ToArray(), unique: isUnique); } /// /// Creates a Migration to drop an Index from the Entity (table) /// /// The name of the Index to drop public virtual void DropIndex(string indexName) { _migrationBuilder.DropIndex(RewriteName(indexName), RewriteName(EntityTableName)); } // Key Operations private void AddKeys(CreateTableBuilder table) { AddPrimaryKey(table, PrimaryKey); foreach (var foreignKey in ForeignKeys) { AddForeignKey(table, foreignKey); } } public void AddPrimaryKey(CreateTableBuilder table, PrimaryKey primaryKey) { table.PrimaryKey(RewriteName(primaryKey.Name), primaryKey.Columns); } public void AddForeignKey(CreateTableBuilder table, ForeignKey foreignKey) { table.ForeignKey( name: RewriteName(foreignKey.Name), column: foreignKey.Column, principalTable: RewriteName(foreignKey.PrincipalTable), principalColumn: RewriteName(foreignKey.PrincipalColumn), onDelete: foreignKey.OnDeleteAction); } public void AddForeignKey(string name) { var foreignKey = ForeignKeys.Single(k => k.Name == name); _migrationBuilder.AddForeignKey( name: RewriteName(foreignKey.Name), table: RewriteName(EntityTableName), column: RewriteName(foreignKey.ColumnName), principalTable: RewriteName(foreignKey.PrincipalTable), principalColumn: RewriteName(foreignKey.PrincipalColumn), onDelete: foreignKey.OnDeleteAction); } public void DropForeignKey(ForeignKey foreignKey) { DropForeignKey(RewriteName(foreignKey.Name)); } public void DropForeignKey(string keyName) { _migrationBuilder.DropForeignKey(RewriteName(keyName), RewriteName(EntityTableName)); } // Table Operations /// /// Creates a Migration to Create the Entity (table) /// public void Create() { _migrationBuilder.CreateTable(RewriteName(EntityTableName), BuildTable, null, AddKeys); } /// /// Creates a Migration to Drop the Entity (table) /// public void Drop() { _migrationBuilder.DropTable(RewriteName(EntityTableName)); } //Sql Operations public void DeleteFromTable(string condition = "") { var deleteSql = $"DELETE FROM {RewriteName(EntityTableName)} "; if(!string.IsNullOrEmpty(condition)) { deleteSql += $"WHERE {condition}"; } _migrationBuilder.Sql(deleteSql); } public void UpdateColumn(string columnName, string value, string condition = "") { var updateSql = $"UPDATE {RewriteName(EntityTableName)} SET {RewriteName(columnName)} = {value} "; if (!string.IsNullOrEmpty(condition)) { updateSql += $"WHERE {condition}"; } _migrationBuilder.Sql(updateSql); } } }