# frozen_string_literal: false

# @!parse
#   class ActiveRecord::Migration
#     # Drops a foreign key constraint
#     #
#     # @param [#to_s] table (nil) The qualified name of the table
#     # @param [#to_s] reference (nil) The qualified name of the reference table
#     # @option options [#to_s] :name (nil) The current name of the foreign key
#     # @option options [Boolean] :if_exists (false) Suppress the error when the constraint is absent
#     # @option options [#to_s] :to (nil) The new name for the foreign key
#     # @option options [Array<#to_s>] :columns ([]) The list of columns of the table
#     # @option options [#to_s] :column (nil) An alias for :columns for the case of single-column keys
#     # @option options [Array<#to_s>] :primary_key ([]) The list of columns of the reference table
#     # @option options [Symbol] :match (:full) Define how to match rows
#     #   Supported values: :full (default), :partial, :simple
#     # @option options [Symbol] :on_delete (:restrict)
#     #   Define how to handle the deletion of the referred row.
#     #   Supported values: :restrict (default), :cascade, :nullify, :reset
#     # @option options [Symbol] :on_update (:restrict)
#     #   Define how to handle the update of the referred row.
#     #   Supported values: :restrict (default), :cascade, :nullify, :reset
#     # @yield [k] the block with the key's definition
#     # @yieldparam Object receiver of methods specifying the foreign key
#     # @return [void]
#     #
#     # The key can be identified by table/name (not invertible):
#     #
#     # ```ruby
#     # drop_foreign_key "users", name: "user_roles_fk"
#     # ```
#     #
#     # To make it invertible use the same options like
#     # in the `add_foreign_key` operation.
#     #
#     # ```ruby
#     # drop_foreign_key do |k|
#     #   k.table "users"
#     #   k.reference "roles"
#     #   k.column "role_id"
#     #   k.primary_key "id"
#     #   k.on_update :cascade
#     #   k.on_delete :cascade
#     #   k.comment "Phone is 10+ chars long"
#     # end
#     # ```
#     #
#     # Notice that the name can be skipped, in this case we would
#     # find it in the database.
#     #
#     # The operation can be called with `if_exists` option.
#     #
#     # ```ruby
#     # drop_foreign_key "users", name: "user_roles_fk", if_exists: true
#     # ```
#     #
#     # In this case the operation is always irreversible due to
#     # uncertainty of the previous state of the database.
#     def drop_foreign_key(table, reference, **options, &block); end
#   end
module PGTrunk::Operations::ForeignKeys
  # @private
  class DropForeignKey < Base
    # The name can be looked for in the database.
    # This is necessary because the name generated by `rails` inside the table
    # is different from the name generated by the `add_foreign_key`.
    after_initialize { self.name = current_name if name.blank? }
    # This prevents a validation error in case there's no fk found in the db
    # by reference, columns and primary key.
    after_initialize { self.name = generated_name if if_exists }

    validates :if_not_exists, absence: true

    def to_sql(_version)
      sql = "ALTER TABLE #{table.to_sql} DROP CONSTRAINT"
      sql << " IF EXISTS" if if_exists
      sql << " #{name.lean.inspect};"
    end

    def invert
      irreversible!("if_exists: true") if if_exists
      AddForeignKey.new(**to_h)
    end
  end
end
