# frozen_string_literal: true module ActiveRecord module ConnectionAdapters module PostgreSQL module ColumnMethods extend ActiveSupport::Concern # Defines the primary key field. # Use of the native PostgreSQL UUID type is supported, and can be used # by defining your tables as such: # # create_table :stuffs, id: :uuid do |t| # t.string :content # t.timestamps # end # # By default, this will use the gen_random_uuid() function from the # +pgcrypto+ extension. As that extension is only available in # PostgreSQL 9.4+, for earlier versions an explicit default can be set # to use uuid_generate_v4() from the +uuid-ossp+ extension instead: # # create_table :stuffs, id: false do |t| # t.primary_key :id, :uuid, default: "uuid_generate_v4()" # t.uuid :foo_id # t.timestamps # end # # To enable the appropriate extension, which is a requirement, use # the +enable_extension+ method in your migrations. # # To use a UUID primary key without any of the extensions, set the # +:default+ option to +nil+: # # create_table :stuffs, id: false do |t| # t.primary_key :id, :uuid, default: nil # t.uuid :foo_id # t.timestamps # end # # You may also pass a custom stored procedure that returns a UUID or use a # different UUID generation function from another library. # # Note that setting the UUID primary key default value to +nil+ will # require you to assure that you always provide a UUID value before saving # a record (as primary keys cannot be +nil+). This might be done via the # +SecureRandom.uuid+ method and a +before_save+ callback, for instance. def primary_key(name, type = :primary_key, **options) if type == :uuid options[:default] = options.fetch(:default, "gen_random_uuid()") end super end ## # :method: bigserial # :call-seq: bigserial(*names, **options) ## # :method: bit # :call-seq: bit(*names, **options) ## # :method: bit_varying # :call-seq: bit_varying(*names, **options) ## # :method: cidr # :call-seq: cidr(*names, **options) ## # :method: citext # :call-seq: citext(*names, **options) ## # :method: daterange # :call-seq: daterange(*names, **options) ## # :method: hstore # :call-seq: hstore(*names, **options) ## # :method: inet # :call-seq: inet(*names, **options) ## # :method: interval # :call-seq: interval(*names, **options) ## # :method: int4range # :call-seq: int4range(*names, **options) ## # :method: int8range # :call-seq: int8range(*names, **options) ## # :method: jsonb # :call-seq: jsonb(*names, **options) ## # :method: ltree # :call-seq: ltree(*names, **options) ## # :method: macaddr # :call-seq: macaddr(*names, **options) ## # :method: money # :call-seq: money(*names, **options) ## # :method: numrange # :call-seq: numrange(*names, **options) ## # :method: oid # :call-seq: oid(*names, **options) ## # :method: point # :call-seq: point(*names, **options) ## # :method: line # :call-seq: line(*names, **options) ## # :method: lseg # :call-seq: lseg(*names, **options) ## # :method: box # :call-seq: box(*names, **options) ## # :method: path # :call-seq: path(*names, **options) ## # :method: polygon # :call-seq: polygon(*names, **options) ## # :method: circle # :call-seq: circle(*names, **options) ## # :method: serial # :call-seq: serial(*names, **options) ## # :method: tsrange # :call-seq: tsrange(*names, **options) ## # :method: tstzrange # :call-seq: tstzrange(*names, **options) ## # :method: tsvector # :call-seq: tsvector(*names, **options) ## # :method: uuid # :call-seq: uuid(*names, **options) ## # :method: xml # :call-seq: xml(*names, **options) ## # :method: timestamptz # :call-seq: timestamptz(*names, **options) ## # :method: enum # :call-seq: enum(*names, **options) included do define_column_methods :bigserial, :bit, :bit_varying, :cidr, :citext, :daterange, :hstore, :inet, :interval, :int4range, :int8range, :jsonb, :ltree, :macaddr, :money, :numrange, :oid, :point, :line, :lseg, :box, :path, :polygon, :circle, :serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml, :timestamptz, :enum end end ExclusionConstraintDefinition = Struct.new(:table_name, :expression, :options) do def name options[:name] end def using options[:using] end def where options[:where] end def deferrable options[:deferrable] end def export_name_on_schema_dump? !ActiveRecord::SchemaDumper.excl_ignore_pattern.match?(name) if name end end UniqueKeyDefinition = Struct.new(:table_name, :column, :options) do def name options[:name] end def deferrable options[:deferrable] end def using_index options[:using_index] end def export_name_on_schema_dump? !ActiveRecord::SchemaDumper.unique_ignore_pattern.match?(name) if name end def defined_for?(name: nil, column: nil, **options) (name.nil? || self.name == name.to_s) && (column.nil? || Array(self.column) == Array(column).map(&:to_s)) && options.all? { |k, v| self.options[k].to_s == v.to_s } end end # = Active Record PostgreSQL Adapter \Table Definition class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition include ColumnMethods attr_reader :exclusion_constraints, :unique_keys, :unlogged def initialize(*, **) super @exclusion_constraints = [] @unique_keys = [] @unlogged = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables end def exclusion_constraint(expression, **options) exclusion_constraints << new_exclusion_constraint_definition(expression, options) end def unique_key(column_name, **options) unique_keys << new_unique_key_definition(column_name, options) end def new_exclusion_constraint_definition(expression, options) # :nodoc: options = @conn.exclusion_constraint_options(name, expression, options) ExclusionConstraintDefinition.new(name, expression, options) end def new_unique_key_definition(column_name, options) # :nodoc: options = @conn.unique_key_options(name, column_name, options) UniqueKeyDefinition.new(name, column_name, options) end def new_column_definition(name, type, **options) # :nodoc: case type when :virtual type = options[:type] end super end private def valid_column_definition_options super + [:array, :using, :cast_as, :as, :type, :enum_type, :stored] end def aliased_types(name, fallback) fallback end def integer_like_primary_key_type(type, options) if type == :bigint || options[:limit] == 8 :bigserial else :serial end end end # = Active Record PostgreSQL Adapter \Table class Table < ActiveRecord::ConnectionAdapters::Table include ColumnMethods # Adds an exclusion constraint. # # t.exclusion_constraint("price WITH =, availability_range WITH &&", using: :gist, name: "price_check") # # See {connection.add_exclusion_constraint}[rdoc-ref:SchemaStatements#add_exclusion_constraint] def exclusion_constraint(*args) @base.add_exclusion_constraint(name, *args) end # Removes the given exclusion constraint from the table. # # t.remove_exclusion_constraint(name: "price_check") # # See {connection.remove_exclusion_constraint}[rdoc-ref:SchemaStatements#remove_exclusion_constraint] def remove_exclusion_constraint(*args) @base.remove_exclusion_constraint(name, *args) end # Adds an unique constraint. # # t.unique_key(:position, name: 'unique_position', deferrable: :deferred) # # See {connection.add_unique_key}[rdoc-ref:SchemaStatements#add_unique_key] def unique_key(*args) @base.add_unique_key(name, *args) end # Removes the given unique constraint from the table. # # t.remove_unique_key(name: "unique_position") # # See {connection.remove_unique_key}[rdoc-ref:SchemaStatements#remove_unique_key] def remove_unique_key(*args) @base.remove_unique_key(name, *args) end end # = Active Record PostgreSQL Adapter Alter \Table class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable attr_reader :constraint_validations, :exclusion_constraint_adds, :exclusion_constraint_drops, :unique_key_adds, :unique_key_drops def initialize(td) super @constraint_validations = [] @exclusion_constraint_adds = [] @exclusion_constraint_drops = [] @unique_key_adds = [] @unique_key_drops = [] end def validate_constraint(name) @constraint_validations << name end def add_exclusion_constraint(expression, options) @exclusion_constraint_adds << @td.new_exclusion_constraint_definition(expression, options) end def drop_exclusion_constraint(constraint_name) @exclusion_constraint_drops << constraint_name end def add_unique_key(column_name, options) @unique_key_adds << @td.new_unique_key_definition(column_name, options) end def drop_unique_key(unique_key_name) @unique_key_drops << unique_key_name end end end end end