Module: PgActiveRecordEnum

Defined in:
lib/pg_activerecord_enum.rb,
lib/pg_activerecord_enum/schema.rb,
lib/pg_activerecord_enum/version.rb

Defined Under Namespace

Modules: Schema

Constant Summary collapse

VERSION =
'0.1.0'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

._j(values) ⇒ Object



66
67
68
# File 'lib/pg_activerecord_enum.rb', line 66

def self._j(values)
  "'#{values.join("', '")}'"
end

.add_values(name, values) ⇒ Object



38
39
40
41
42
# File 'lib/pg_activerecord_enum.rb', line 38

def self.add_values(name, values)
  values.each do |value|
    ActiveRecord::Base.connection.execute("ALTER TYPE #{name} ADD VALUE '#{value}';")
  end
end

.allow_blank_for(name) ⇒ Object



44
45
46
# File 'lib/pg_activerecord_enum.rb', line 44

def self.allow_blank_for(name)
  add_values(name, [''])
end

.change(name, values, options = {}) ⇒ Object



33
34
35
36
# File 'lib/pg_activerecord_enum.rb', line 33

def self.change(name, values, options = {})
  drop(name)
  define(name, values, options)
end

.define(name, values, options = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/pg_activerecord_enum.rb', line 5

def self.define(name, values, options = {})
  values << '' if options[:allow_blank]
  return if values.blank?
  values.map!(&:to_s)
  previously_defined = values_for(name)
  if previously_defined.present? && previously_defined.sort != values.sort
    raise ArgumentError, "Enum `#{name}` already defined with other values: " +
      "#{_j(previously_defined)} (#{_j(values)} supplied)."
  elsif previously_defined.blank?
    ActiveRecord::Base.connection.execute("CREATE TYPE #{name} AS ENUM (#{_j(values)});")
  else
    ActiveRecord::Base.logger.info "Enum `#{name}` with same values already defined, skip."
  end
end

.dependencies(name) ⇒ Object



59
60
61
62
63
64
# File 'lib/pg_activerecord_enum.rb', line 59

def self.dependencies(name)
  ActiveRecord::Base.connection.execute(
    'SELECT objid::regclass::text FROM pg_depend ' +
      "WHERE classid = 'pg_class'::regclass AND refobjid::regtype::text = '#{name}';"
  ).to_a.map(&:values).flatten
end

.drop(name, options = {}) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/pg_activerecord_enum.rb', line 20

def self.drop(name, options = {})
  enum_dependencies = dependencies(name)
  if enum_dependencies.present?
    if options[:cascade]
      ActiveRecord::Base.connection.execute("DROP TYPE #{name} CASCADE;")
    else
      ActiveRecord::Base.logger.warn "Other objects (#{_j(enum_dependencies)}) depend on enum `#{name}`, skip."
    end
  else
    ActiveRecord::Base.connection.execute("DROP TYPE IF EXISTS #{name};")
  end
end

.values_for(name) ⇒ Object



48
49
50
51
52
53
54
55
56
57
# File 'lib/pg_activerecord_enum.rb', line 48

def self.values_for(name)
  enum_values_sql = "SELECT e.enumlabel AS enum_value\nFROM pg_type t\nJOIN pg_enum e ON t.oid = e.enumtypid\nJOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\nWHERE t.typname = '\#{name}'\n  SQL\n  ActiveRecord::Base.connection.execute(enum_values_sql).map { |row| row['enum_value'] }\nend\n"

Instance Method Details

#pg_enum(name, options = {}) ⇒ Object



70
71
72
73
# File 'lib/pg_activerecord_enum.rb', line 70

def pg_enum(name, options = {})
  enum_values = PgActiveRecordEnum.values_for(name).reject(&:blank?)
  enum({name => enum_values.zip(enum_values).to_h}.merge(options))
end