module PGTrunk::Operations::Domains

@private Namespace for operations with functions

@!parse

class ActiveRecord::Migration
  # Modify a domain type
  #
  # @param [#to_s] name (nil) The qualified name of the type
  # @yield [d] the block with the type's definition
  # @yieldparam Object receiver of methods specifying the type
  # @return [void]
  #
  # The operation can be used to add or remove constraints,
  # modify the default_sql value, or the description of the domain type.
  # Neither the underlying type nor the collation can be changed.
  #
  # ```ruby
  # change_domain "dict.us_postal_code" do |d|
  #   d.null true # from: false
  #   # check is added for inversion
  #   d.drop_constraint "postal_code_length", check: <<~SQL
  #     length(VALUE) > 3 AND length(VALUE) < 6
  #   SQL
  #   d.add_constraint <<~SQL, name: "postal_code_valid"
  #     VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$'
  #   SQL
  #   d.default_sql "'00000'::text", from: "'0000'::text"
  #   d.comment <<~COMMENT, from: <<~COMMENT
  #     Supported currencies
  #   COMMENT
  #     Currencies
  #   COMMENT
  # end
  # ```
  #
  # Use blank string (not a `nil` value) to reset either a default_sql,
  # or the comment. `nil`-s here will be ignored.
  #
  # When dropping a constraint you can use a `check` expression.
  # In the same manner, use `from` option with `comment` or `default_sql`
  # to make the operation invertible.
  #
  # It is irreversible in case any `drop_constraint` clause
  # has `if_exists: true` or `force: :cascade` option -- due to
  # uncertainty of the previous state of the database:
  #
  # ```ruby
  # change_domain "dict.us_postal_code", force: :cascade do |d|
  #   d.drop_constraint "postal_code_valid" # missed `:check` option
  #   d.drop_constraint "postal_code_length"
  #   d.drop_constraint "postal_code_format", if_exists: true
  #   d.default_sql "'0000'::text" # missed `:from` option
  #   d.comment "New comment" # missed `:from` option
  # end
  # ```
  def change_domain(name, &block); end
end

@!parse

class ActiveRecord::Migration
  # Create a domain type
  #
  # @param [#to_s] name (nil) The qualified name of the type
  # @option options [#to_s] :as (nil) The base type for the domain (alias: :type)
  # @option options [#to_s] :collation (nil) The collation
  # @option options [Boolean] :null (true) If a value of this type can be NULL
  # @option options [#to_s] :default_sql (nil) The snippet for the default value of the domain
  # @option options [#to_s] :comment (nil) The comment describing the constraint
  # @yield [d] the block with the type's definition
  # @yieldparam Object receiver of methods specifying the type
  # @return [void]
  #
  # ```ruby
  # create_domain "dict.us_postal_code", as: "text" do |d|
  #   d.collation "en_US"
  #   d.default_sql "'0000'::text"
  #   d.null false
  #   d.constraint <<~SQL, name: "code_valid"
  #     VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$'
  #   SQL
  #   d.comment "US postal code"
  # end
  # ```
  #
  # It is always reversible.
  def create_domain(name, **options, &block); end
end

@!parse

class ActiveRecord::Migration
  # Drop a domain type by qualified name
  #
  # @param [#to_s] name (nil) The qualified name of the type
  # @option options [Boolean] :if_exists (false) Suppress the error when the type is absent
  # @option options [Symbol] :force (:restrict) How to process dependent objects (`:cascade` or `:restrict`)
  # @option options [#to_s] :as (nil) The base type for the domain (alias: :type)
  # @option options [#to_s] :collation (nil) The collation
  # @option options [#to_s] :default_sql (nil) The snippet for the default value of the domain
  # @option options [#to_s] :comment (nil) The comment describing the constraint
  # @yield [d] the block with the type's definition
  # @yieldparam Object receiver of methods specifying the type
  # @return [void]
  #
  # ```ruby
  # drop_domain "dict.us_postal_code"
  # ```
  #
  # To make the operation invertible, use the same options
  # as in the `create_domain` operation.
  #
  # ```ruby
  # drop_domain "dict.us_postal_code", as: "string" do |d|
  #   d.constraint <<~SQL, name: "code_valid"
  #     VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$'
  #   SQL
  #   d.comment <<~COMMENT
  #     US postal code
  #   COMMENT
  # end
  # ```
  #
  # With the `force: :cascade` option the operation would remove
  # all the objects that use the type.
  #
  # ```ruby
  # drop_domain "dict.us_postal_code", force: :cascade
  # ```
  #
  # With the `if_exists: true` option the operation won't fail
  # even when the view was absent in the database.
  #
  # ```ruby
  # drop_domain "dict.us_postal_code", if_exists: true
  # ```
  #
  # Both options make a migration irreversible due to uncertainty
  # of the previous state of the database.
  def drop_domain(name, **options, &block); end
end

@!parse

class ActiveRecord::Migration
  # Change the name and/or schema of a domain type
  #
  # @param [#to_s] :name (nil) The qualified name of the type
  # @option options [#to_s] :to (nil) The new qualified name for the type
  # @return [void]
  #
  # A domain type can be both renamed and moved to another schema.
  #
  # ```ruby
  # rename_domain "us_code", to: "dict.us_postal_code"
  # ```
  #
  # The operation is always reversible.
  def rename_domain(name, to:); end
end