| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- using Invercargill.DataStructures;
- using InvercargillSql.Dialects;
- using InvercargillSql.Orm;
- namespace InvercargillSql.Migrations {
-
- /**
- * Delegate for configuring table creation within a migration.
- *
- * @param t the TableBuilder to configure
- */
- public delegate void TableConfig(TableBuilder t);
-
- /**
- * Delegate for configuring table alterations within a migration.
- *
- * @param t the AlterTableBuilder to configure
- */
- public delegate void AlterConfig(AlterTableBuilder t);
-
- /**
- * Main builder class providing the fluent API for defining migration operations.
- *
- * MigrationBuilder is the central class used in Migration.up() and Migration.down()
- * methods to define schema changes. It supports creating/dropping tables, altering
- * table structure, and executing raw SQL.
- *
- * Index creation is now handled within TableBuilder and AlterTableBuilder using
- * the fluent index() method.
- *
- * All methods return the builder instance for method chaining.
- *
- * Example usage:
- * {{{
- * public override void up(MigrationBuilder b) {
- * b.create_table("users", t => {
- * t.column<int>("id", c => c.type_int().primary_key().auto_increment());
- * t.column<string>("email", c => c.type_text().not_null().unique());
- * t.column<string>("name", c => c.type_text().not_null());
- * t.index("idx_users_email").on_column("email");
- * });
- * }
- *
- * public override void down(MigrationBuilder b) {
- * b.drop_table("users"); // Indexes are dropped automatically with the table
- * }
- * }}}
- */
- public class MigrationBuilder : Object {
- private SqlDialect _dialect;
- private Vector<SchemaOperation> _operations;
-
- /**
- * Creates a new MigrationBuilder for the specified SQL dialect.
- *
- * @param dialect the SQL dialect to use for generating SQL statements
- */
- public MigrationBuilder(SqlDialect dialect) {
- _dialect = dialect;
- _operations = new Vector<SchemaOperation>();
- }
-
- /**
- * Creates a new table with the specified name and configuration.
- *
- * The configuration delegate receives a TableBuilder that can be used
- * to define columns, constraints, and indexes.
- *
- * Indexes defined within the TableBuilder are emitted after the CREATE TABLE
- * statement in the generated SQL.
- *
- * @param name the name of the table to create
- * @param config a delegate that configures the table structure
- * @return this builder for method chaining
- */
- public MigrationBuilder create_table(string name, owned TableConfig config) {
- var builder = new TableBuilder(this, name);
- config(builder);
-
- // Add the CREATE TABLE operation
- _operations.add(builder.build_operation());
-
- // Add any index operations defined within the table builder
- foreach (var index_op in builder.get_index_operations()) {
- _operations.add(index_op);
- }
-
- return this;
- }
-
- /**
- * Drops the specified table.
- *
- * Note: In most databases, dropping a table automatically drops all
- * associated indexes.
- *
- * @param name the name of the table to drop
- * @return this builder for method chaining
- */
- public MigrationBuilder drop_table(string name) {
- _operations.add(new DropTableOperation() { table_name = name });
- return this;
- }
-
- /**
- * Alters an existing table with the specified configuration.
- *
- * The configuration delegate receives an AlterTableBuilder that can be used
- * to add, drop, or rename columns, and to create or drop indexes.
- *
- * @param name the name of the table to alter
- * @param config a delegate that configures the alterations
- * @return this builder for method chaining
- */
- public MigrationBuilder alter_table(string name, owned AlterConfig config) {
- var builder = new AlterTableBuilder(this, name);
- config(builder);
- foreach (var op in builder.get_operations()) {
- _operations.add(op);
- }
- return this;
- }
-
- /**
- * Executes raw SQL directly.
- *
- * Use with caution as this bypasses the dialect abstraction.
- *
- * @param sql the raw SQL to execute
- * @return this builder for method chaining
- */
- public MigrationBuilder execute_sql(string sql) {
- _operations.add(new RawSqlOperation() { sql = sql });
- return this;
- }
-
- /**
- * Adds a column operation from a column builder.
- *
- * This is used internally by MigrationColumnBuilder to add configured
- * columns directly to the operations list.
- *
- * @param table_name the name of the table
- * @param col the column definition to add
- */
- internal void add_column_from_builder(string table_name, ColumnDefinition col) {
- _operations.add(new AddColumnOperation() {
- table_name = table_name,
- column = col
- });
- }
-
- /**
- * Gets all schema operations collected by this builder.
- *
- * @return a Vector of SchemaOperation objects
- */
- public Vector<SchemaOperation> get_operations() {
- return _operations;
- }
-
- /**
- * Executes all collected operations against the specified connection.
- *
- * Each operation is converted to SQL using the dialect and executed
- * in the order they were added.
- *
- * @param conn the database connection to execute against
- * @throws SqlError if any operation fails
- */
- public void execute(Connection conn) throws SqlError {
- foreach (var op in _operations) {
- var sql = op.to_sql(_dialect);
- conn.execute(sql);
- }
- }
- }
- }
|