module PGTrunk::Operations::Triggers

@private Namespace for operations with triggers

@!parse

class ActiveRecord::Migration
  # Create a trigger for a table
  #
  # @param [#to_s] table (nil) The qualified name of the table
  # @param [#to_s] name (nil) The name of the trigger
  # @option options [Boolean] :if_exists (false) Suppress the error when the trigger is absent
  # @yield [t] the block with the trigger's definition
  # @yieldparam Object receiver of methods specifying the trigger
  # @return [void]
  #
  # The trigger can be changed using `CREATE OR REPLACE TRIGGER` command:
  #
  # ```ruby
  # change_trigger "users", "do_something" do |t|
  #   t.function "do_something()", from: "do_something_different()"
  #   t.for_each :row # from: :statement
  #   t.type :after, from: :before
  #   t.events %i[insert update], from: %i[insert]
  #   t.comment "Does something useful", from: ""
  # end
  # ```
  def create_trigger(table, name = nil, **options, &block); end
end

@!parse

class ActiveRecord::Migration
  # Create a trigger for a table
  #
  # @param [#to_s] table (nil) The qualified name of the table
  # @param [#to_s] name (nil) The name of the trigger
  # @option options [Boolean] :replace_existing (false) If the trigger should overwrite an existing one
  # @option options [#to_s] :function (nil) The qualified name of the function to be called
  # @option options [Symbol] :type (nil) When the trigger should be run
  #   Supported values: :before, :after, :instead_of
  # @option options [Array<Symbol>] :events List of events running the trigger
  #   Supported values in the array: :insert, :update, :delete, :truncate
  # @option options [Boolean] :constraint (false) If the trigger is a constraint
  # @option options [Symbol] :initially (:immediate) If the constraint check should be deferred
  #   Supported values: :immediate (default), :deferred
  # @option options [#to_s] :when (nil) The SQL snippet definiing a condition for the trigger
  # @option options [Symbol] :for_each (:statement) Define if a trigger should be run for every row
  #   Supported values: :statement (default), :row
  # @option options [#to_s] :comment (nil) The commend describing the trigger
  # @yield [t] the block with the trigger's definition
  # @yieldparam Object receiver of methods specifying the trigger
  # @return [void]
  #
  # The trigger can be created either using inline syntax
  #
  # ```ruby
  # create_trigger "users", "do_something",
  #                 function: "do_something()",
  #                 for_each: :row,
  #                 type: :after,
  #                 events: %i[insert update],
  #                 comment: "Does something useful"
  # ```
  #
  # or using a block:
  #
  # ```ruby
  # create_trigger do |t|
  #   t.table "users"
  #   t.name "do_something"
  #   t.function "do_something()"
  #   t.for_each :row
  #   t.type :after
  #   t.events %i[insert update]
  #   t.comment "Does something useful"
  # end
  # ```
  #
  # With a `replace_existing: true` option,
  # it will be created using the `CREATE OR REPLACE` clause.
  # (Available in PostgreSQL v14+).
  #
  # ```ruby
  #  create_trigger "users", "do_something",
  #                 function: "do_something()",
  #                 type: :after,
  #                 events: %i[insert update],
  #                 replace_previous: true
  # ```
  #
  # In this case the migration is irreversible because we
  # don't know if and how to restore its previous definition.
  def create_trigger(table, name = nil, **options, &block); end
end

@!parse

class ActiveRecord::Migration
  # Drop a trigger for a table
  #
  # @param [#to_s] table (nil) The qualified name of the table
  # @param [#to_s] name (nil) The name of the trigger
  # @option options [Boolean] :if_exists (false) Suppress the error when the trigger is absent
  # @option options [#to_s] :function (nil) The qualified name of the function to be called
  # @option options [Symbol] :type (nil) When the trigger should be run
  #   Supported values: :before, :after, :instead_of
  # @option options [Array<Symbol>] :events List of events running the trigger
  #   Supported values in the array: :insert, :update, :delete, :truncate
  # @option options [Boolean] :constraint (false) If the trigger is a constraint
  # @option options [Symbol] :initially (:immediate) If the constraint check should be deferred
  #   Supported values: :immediate (default), :deferred
  # @option options [#to_s] :when (nil) The SQL snippet definiing a condition for the trigger
  # @option options [Symbol] :for_each (:statement) Define if a trigger should be run for every row
  #   Supported values: :statement (default), :row
  # @option options [#to_s] :comment (nil) The commend describing the trigger
  # @yield [t] the block with the trigger's definition
  # @yieldparam Object receiver of methods specifying the trigger
  # @return [void]
  #
  # A trigger can be dropped by a table and name:
  #
  # ```ruby
  # drop_trigger "users", "do_something"
  # ```
  #
  # the default name can be restored from its attributes as well.
  #
  # ```ruby
  # drop_trigger "users" do |t|
  #   t.function "send_notifications()"
  #   t.for_each :row
  #   t.type :after
  #   t.events %i[update]
  #   t.columns %w[email phone]
  #   t.comment "Does something"
  # end
  # ```
  #
  # Notice, that you have to specify all attributes to make
  # the operation reversible.
  #
  # The operation can be called with `if_exists` option. In this case
  # it would do nothing when no trigger existed.
  #
  # ```ruby
  # drop_trigger "users", "unknown_trigger", if_exists: true
  # ```
  #
  # This option, though, makes the operation irreversible because of
  # uncertainty of the previous state of the database.
  def drop_trigger(table, name = nil, **options, &block); end
end

@!parse

class ActiveRecord::Migration
  # Rename a trigger
  #
  # @param [#to_s] table (nil) The qualified name of the table
  # @param [#to_s] name (nil) The name of the trigger
  # @option options [#to_s] :to (nil) The new name of the trigger
  # @param [#to_s] table (nil) The qualified name of the table
  # @param [#to_s] name (nil) The current name of the trigger
  # @option options [#to_s] :to (nil) The new name for the trigger
  # @option options [#to_s] :function (nil) The qualified name of the function to be called
  # @option options [Symbol] :type (nil) When the trigger should be run
  #   Supported values: :before, :after, :instead_of
  # @option options [Array<Symbol>] :events List of events running the trigger
  #   Supported values in the array: :insert, :update, :delete, :truncate
  # @option options [Symbol] :for_each (:statement) Define if a trigger should be run for every row
  #   Supported values: :statement (default), :row
  # @yield [t] the block with the trigger's definition
  # @yieldparam Object receiver of methods specifying the trigger
  # @return [void]
  #
  # A trigger can be renamed by either setting a new name explicitly
  #
  #   rename_trigger "users", "do_something", to: "do_something_different"
  #
  # or resetting it to the default (generated) value.
  #
  #   rename_trigger "users", "do_something"
  #
  # The previously generated name of the trigger can be get
  # from its parameters. In this case all the essentials
  # parameters must be specified:
  #
  #   rename_trigger "users", to: "do_something_different" do |t|
  #     t.function "do_something()"
  #     t.for_each :row
  #     t.type :after
  #     t.events %i[insert update]
  #   end
  #
  # In the same way, when you reset the name to default,
  # all the essential parameters must be got to make the trigger
  # invertible.
  #
  #   rename_trigger "users", "do_something" do |t|
  #     t.function "do_something()"
  #     t.for_each :row
  #     t.type :after
  #     t.events %i[insert update]
  #   end
  def rename_trigger(table, name = nil, **options, &block); end
end