using Invercargill.DataStructures; using InvercargillSql.Dialects; using InvercargillSql.Orm; namespace InvercargillSql.Migrations { /** * Represents the referential action to take when a referenced row is deleted or updated. * These actions correspond to SQL standard foreign key actions. */ public enum ReferentialAction { NO_ACTION, // default - restricts the action but check is deferred CASCADE, // cascade the change to dependent rows SET_NULL, // set referencing column to NULL SET_DEFAULT, // set referencing column to its default value RESTRICT; // restricts the action, check is immediate /** * Converts the referential action to its SQL string representation. * @return The SQL keyword(s) for this action */ public string to_sql() { switch (this) { case CASCADE: return "CASCADE"; case SET_NULL: return "SET NULL"; case SET_DEFAULT: return "SET DEFAULT"; case RESTRICT: return "RESTRICT"; default: return "NO ACTION"; } } } public interface SchemaOperation : Object { public abstract string to_sql(SqlDialect dialect); } public class CreateTableOperation : Object, SchemaOperation { public string table_name { get; set; } public Vector columns { get; set; } public Vector constraints { get; set; } public CreateTableOperation() { columns = new Vector(); constraints = new Vector(); } public string to_sql(SqlDialect dialect) { return dialect.create_table_sql(this); } } public class DropTableOperation : Object, SchemaOperation { public string table_name { get; set; } public string to_sql(SqlDialect dialect) { return dialect.drop_table_sql(this); } } public class AddColumnOperation : Object, SchemaOperation { public string table_name { get; set; } public ColumnDefinition column { get; set; } /** * Optional foreign key constraint for the column being added. * When set, the dialect should include REFERENCES clause in the ADD COLUMN SQL. */ public TableConstraint? foreign_key_constraint { get; set; } public string to_sql(SqlDialect dialect) { return dialect.add_column_sql(this); } } public class DropColumnOperation : Object, SchemaOperation { public string table_name { get; set; } public string column_name { get; set; } public string to_sql(SqlDialect dialect) { return dialect.drop_column_sql(this); } } public class RenameColumnOperation : Object, SchemaOperation { public string table_name { get; set; } public string old_name { get; set; } public string new_name { get; set; } public string to_sql(SqlDialect dialect) { return dialect.rename_column_sql(this); } } public class CreateIndexOperation : Object, SchemaOperation { public string index_name { get; set; } public string table_name { get; set; } public Vector columns { get; set; } public bool is_unique { get; set; } public CreateIndexOperation() { columns = new Vector(); } public string to_sql(SqlDialect dialect) { return dialect.create_index_sql(this); } } public class DropIndexOperation : Object, SchemaOperation { public string index_name { get; set; } public string table_name { get; set; } public string to_sql(SqlDialect dialect) { return dialect.drop_index_sql(this); } } public class RawSqlOperation : Object, SchemaOperation { public string sql { get; set; } public string to_sql(SqlDialect dialect) { return sql; } } public class TableConstraint : Object { public string name { get; set; } public string constraint_type { get; set; } // PRIMARY KEY, UNIQUE, FOREIGN KEY, etc. public Vector columns { get; set; } public string? reference_table { get; set; } public Vector reference_columns { get; set; } /** * The action to take when a referenced row is deleted. * Default is NO_ACTION per SQL standard. */ public ReferentialAction on_delete_action { get; set; default = ReferentialAction.NO_ACTION; } /** * The action to take when a referenced row is updated. * Default is NO_ACTION per SQL standard. */ public ReferentialAction on_update_action { get; set; default = ReferentialAction.NO_ACTION; } public TableConstraint() { columns = new Vector(); reference_columns = new Vector(); } } /** * Schema operation for dropping a foreign key constraint. * Can identify the constraint by name or by column (for auto-generated names). */ public class DropForeignKeyOperation : Object, SchemaOperation { /** * The name of the table containing the foreign key constraint. */ public string table_name { get; construct set; } /** * The name of the constraint to drop (optional). * Use this when the constraint name is known. */ public string? constraint_name { get; construct set; } /** * The column name to find and drop the FK for (optional). * Use this for auto-generated constraint names. */ public string? column_name { get; construct set; } /** * Creates a new drop foreign key operation. * @param table_name The table containing the FK constraint */ public DropForeignKeyOperation(string table_name) { Object(table_name: table_name); } /** * Generates the SQL to drop the foreign key constraint. * Note: SQLite requires table recreation, handled by the dialect. */ public string to_sql(SqlDialect dialect) { return dialect.drop_foreign_key_sql(this); } } }