| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- using Invercargill.DataStructures;
- using InvercargillSql.Orm;
- namespace InvercargillSql.Migrations {
-
- /**
- * Builder for configuring foreign key constraints on a column.
- *
- * This builder extends MigrationColumnBuilder to allow method chaining between
- * FK configuration and column configuration. FK-specific methods return this
- * ForeignKeyBuilder, while column methods delegate to the parent and return
- * MigrationColumnBuilder (ending the FK configuration chain).
- *
- * Example usage:
- * {{{
- * t.column<int64?>("user_id")
- * .not_null()
- * .references("users", "id")
- * .name("fk_orders_users")
- * .on_delete_cascade()
- * .indexed(); // Returns to column builder
- * }}}
- */
- public class ForeignKeyBuilder : MigrationColumnBuilder {
- private MigrationColumnBuilder _inner;
- private string _referenced_table;
- private string _referenced_column;
- private string? _constraint_name;
- private ReferentialAction _on_delete = ReferentialAction.NO_ACTION;
- private ReferentialAction _on_update = ReferentialAction.NO_ACTION;
-
- /**
- * Creates a new ForeignKeyBuilder wrapping an existing MigrationColumnBuilder.
- *
- * @param inner the parent MigrationColumnBuilder to wrap and delegate to
- * @param ref_table the referenced table name
- * @param ref_column the referenced column name in the foreign table
- */
- internal ForeignKeyBuilder(MigrationColumnBuilder inner, string ref_table, string ref_column) {
- base.for_subclass();
- _inner = inner;
- _referenced_table = ref_table;
- _referenced_column = ref_column;
- }
-
- /**
- * Sets an explicit name for the foreign key constraint.
- *
- * If not specified, the constraint name will be auto-generated as
- * `fk_{table}_{column}` when the constraint is built.
- *
- * @param constraint_name the explicit constraint name
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder name(string constraint_name) {
- _constraint_name = constraint_name;
- return this;
- }
-
- // ========== ON DELETE actions ==========
-
- /**
- * Sets ON DELETE CASCADE for this foreign key.
- *
- * When a referenced row is deleted, all referencing rows will be deleted automatically.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_delete_cascade() {
- _on_delete = ReferentialAction.CASCADE;
- return this;
- }
-
- /**
- * Sets ON DELETE SET NULL for this foreign key.
- *
- * When a referenced row is deleted, the referencing column will be set to NULL.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_delete_set_null() {
- _on_delete = ReferentialAction.SET_NULL;
- return this;
- }
-
- /**
- * Sets ON DELETE SET DEFAULT for this foreign key.
- *
- * When a referenced row is deleted, the referencing column will be set to its default value.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_delete_set_default() {
- _on_delete = ReferentialAction.SET_DEFAULT;
- return this;
- }
-
- /**
- * Sets ON DELETE NO ACTION for this foreign key.
- *
- * This is the SQL standard default. The database will prevent the delete if
- * referencing rows exist, but the check may be deferred until transaction end.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_delete_no_action() {
- _on_delete = ReferentialAction.NO_ACTION;
- return this;
- }
-
- /**
- * Sets ON DELETE RESTRICT for this foreign key.
- *
- * Similar to NO_ACTION, but the check is immediate and cannot be deferred.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_delete_restrict() {
- _on_delete = ReferentialAction.RESTRICT;
- return this;
- }
-
- // ========== ON UPDATE actions ==========
-
- /**
- * Sets ON UPDATE CASCADE for this foreign key.
- *
- * When a referenced row's key is updated, the referencing column will be updated automatically.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_update_cascade() {
- _on_update = ReferentialAction.CASCADE;
- return this;
- }
-
- /**
- * Sets ON UPDATE SET NULL for this foreign key.
- *
- * When a referenced row's key is updated, the referencing column will be set to NULL.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_update_set_null() {
- _on_update = ReferentialAction.SET_NULL;
- return this;
- }
-
- /**
- * Sets ON UPDATE SET DEFAULT for this foreign key.
- *
- * When a referenced row's key is updated, the referencing column will be set to its default value.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_update_set_default() {
- _on_update = ReferentialAction.SET_DEFAULT;
- return this;
- }
-
- /**
- * Sets ON UPDATE NO ACTION for this foreign key.
- *
- * This is the SQL standard default. The database will prevent the update if
- * referencing rows exist, but the check may be deferred until transaction end.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_update_no_action() {
- _on_update = ReferentialAction.NO_ACTION;
- return this;
- }
-
- /**
- * Sets ON UPDATE RESTRICT for this foreign key.
- *
- * Similar to NO_ACTION, but the check is immediate and cannot be deferred.
- * @return this builder for method chaining
- */
- public ForeignKeyBuilder on_update_restrict() {
- _on_update = ReferentialAction.RESTRICT;
- return this;
- }
-
- // ========== Build methods ==========
-
- /**
- * Gets the referenced table name.
- * @return the name of the referenced table
- */
- internal string referenced_table {
- get { return _referenced_table; }
- }
-
- /**
- * Gets the referenced column name.
- * @return the name of the referenced column
- */
- internal string referenced_column {
- get { return _referenced_column; }
- }
-
- /**
- * Gets the constraint name (explicit or null for auto-generation).
- * @return the explicit constraint name, or null
- */
- internal string? constraint_name {
- get { return _constraint_name; }
- }
-
- /**
- * Gets the ON DELETE referential action.
- * @return the action to take on delete
- */
- internal ReferentialAction on_delete_action {
- get { return _on_delete; }
- }
-
- /**
- * Gets the ON UPDATE referential action.
- * @return the action to take on update
- */
- internal ReferentialAction on_update_action {
- get { return _on_update; }
- }
-
- /**
- * Builds a TableConstraint from this foreign key configuration.
- *
- * @param column_name the name of the column that has this FK
- * @param table_name the table name, used for auto-generating constraint names
- * @return a populated TableConstraint for this FK
- */
- public TableConstraint build_constraint(string column_name, string table_name) {
- var constraint = new TableConstraint();
- constraint.constraint_type = "FOREIGN KEY";
- constraint.columns.add(column_name);
- constraint.reference_table = _referenced_table;
- constraint.reference_columns.add(_referenced_column);
- constraint.on_delete_action = _on_delete;
- constraint.on_update_action = _on_update;
-
- // Auto-generate constraint name if not specified
- constraint.name = _constraint_name ?? @"fk_$(table_name)_$(column_name)";
-
- return constraint;
- }
-
- // ========== Delegate to inner builder ==========
-
- /**
- * Returns to the parent MigrationBuilder.
- *
- * This method navigates through the inner builder to find the MigrationBuilder.
- * @return the parent MigrationBuilder
- */
- internal override MigrationBuilder return_to_migration() {
- return _inner.return_to_migration();
- }
-
- /**
- * Gets the inner MigrationColumnBuilder being wrapped.
- * @return the inner builder
- */
- internal MigrationColumnBuilder inner_builder {
- get { return _inner; }
- }
- }
- }
|