torque-postgresql 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +31 -0
- data/lib/torque/postgresql/adapter/database_statements.rb +103 -0
- data/lib/torque/postgresql/adapter/oid/array.rb +19 -0
- data/lib/torque/postgresql/adapter/oid/enum.rb +46 -0
- data/lib/torque/postgresql/adapter/oid/interval.rb +94 -0
- data/lib/torque/postgresql/adapter/oid.rb +15 -0
- data/lib/torque/postgresql/adapter/quoting.rb +23 -0
- data/lib/torque/postgresql/adapter/schema_definitions.rb +28 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +31 -0
- data/lib/torque/postgresql/adapter/schema_statements.rb +89 -0
- data/lib/torque/postgresql/adapter.rb +29 -0
- data/lib/torque/postgresql/attributes/builder/enum.rb +151 -0
- data/lib/torque/postgresql/attributes/builder.rb +1 -0
- data/lib/torque/postgresql/attributes/enum.rb +231 -0
- data/lib/torque/postgresql/attributes/lazy.rb +33 -0
- data/lib/torque/postgresql/attributes/type_map.rb +46 -0
- data/lib/torque/postgresql/attributes.rb +32 -0
- data/lib/torque/postgresql/auxiliary_statement.rb +192 -0
- data/lib/torque/postgresql/base.rb +28 -0
- data/lib/torque/postgresql/collector.rb +31 -0
- data/lib/torque/postgresql/config.rb +50 -0
- data/lib/torque/postgresql/migration/command_recorder.rb +31 -0
- data/lib/torque/postgresql/migration.rb +1 -0
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +65 -0
- data/lib/torque/postgresql/relation/distinct_on.rb +43 -0
- data/lib/torque/postgresql/relation.rb +62 -0
- data/lib/torque/postgresql/schema_dumper.rb +37 -0
- data/lib/torque/postgresql/version.rb +5 -0
- data/lib/torque/postgresql.rb +18 -0
- data/lib/torque-postgresql.rb +1 -0
- metadata +236 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d27d24270072d57ca693a53b5fcd29ac72b509e0
|
4
|
+
data.tar.gz: cc63789993cf2817a2857d6cf5c6b8d31c38dabb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b6bd7dc8af51496eecd1c7c7a33f4d3ce8e885e7918668068b8ecf8e7ac9961c1ee4cfe342ecf46c31ccead863b82fe4c3296e523cffd28a5d4ce4c7499be75
|
7
|
+
data.tar.gz: 41141267915f0e8ad1d5b6052cab7cc45c9e2bb37ff4d02fc4e819a4c8cf199ba33ea924884c8732bfd691c354908e330f8390e8836906806bc7e685ce2d7f84
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Carlos Silva
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Torque::Postgresql'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Prints a schema dump of the test database'
|
18
|
+
task :dump do |t|
|
19
|
+
lib = File.expand_path('../lib', __FILE__)
|
20
|
+
spec = File.expand_path('../spec', __FILE__)
|
21
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
22
|
+
$LOAD_PATH.unshift(spec) unless $LOAD_PATH.include?(spec)
|
23
|
+
|
24
|
+
require 'byebug'
|
25
|
+
require 'spec_helper'
|
26
|
+
ActiveRecord::SchemaDumper.dump
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec)
|
31
|
+
task default: :spec
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module DatabaseStatements
|
5
|
+
|
6
|
+
EXTENDED_DATABASE_TYPES = %i(enum interval)
|
7
|
+
|
8
|
+
# Check if a given type is valid.
|
9
|
+
def valid_type?(type)
|
10
|
+
super || extended_types.include?(type)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get the list of extended types
|
14
|
+
def extended_types
|
15
|
+
EXTENDED_DATABASE_TYPES
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns true if type exists.
|
19
|
+
def type_exists?(name)
|
20
|
+
user_defined_types.key? name.to_s
|
21
|
+
end
|
22
|
+
alias data_type_exists? type_exists?
|
23
|
+
|
24
|
+
# Configure the interval format
|
25
|
+
def configure_connection
|
26
|
+
super
|
27
|
+
execute("SET SESSION IntervalStyle TO 'iso_8601'", 'SCHEMA')
|
28
|
+
end
|
29
|
+
|
30
|
+
# Change some of the types being mapped
|
31
|
+
def initialize_type_map(m)
|
32
|
+
super
|
33
|
+
m.register_type 'interval', OID::Interval.new
|
34
|
+
end
|
35
|
+
|
36
|
+
# Add the composite types to be loaded too.
|
37
|
+
def load_additional_types(type_map, oids = nil)
|
38
|
+
super
|
39
|
+
|
40
|
+
filter = "AND a.typelem::integer IN (%s)" % oids.join(", ") if oids
|
41
|
+
|
42
|
+
query = <<-SQL
|
43
|
+
SELECT a.typelem AS oid, t.typname, t.typelem,
|
44
|
+
t.typdelim, t.typbasetype, t.typtype
|
45
|
+
FROM pg_type t
|
46
|
+
INNER JOIN pg_type a ON (a.oid = t.typarray)
|
47
|
+
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
48
|
+
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
|
49
|
+
AND t.typtype IN ( 'c','e' )
|
50
|
+
#{filter}
|
51
|
+
AND NOT EXISTS(
|
52
|
+
SELECT 1 FROM pg_catalog.pg_type el
|
53
|
+
WHERE el.oid = t.typelem AND el.typarray = t.oid
|
54
|
+
)
|
55
|
+
AND (t.typrelid = 0 OR (
|
56
|
+
SELECT c.relkind = 'c' FROM pg_catalog.pg_class c
|
57
|
+
WHERE c.oid = t.typrelid
|
58
|
+
))
|
59
|
+
SQL
|
60
|
+
|
61
|
+
execute_and_clear(query, 'SCHEMA', []) do |records|
|
62
|
+
records.each do |row|
|
63
|
+
typtype = row['typtype']
|
64
|
+
type = begin
|
65
|
+
case
|
66
|
+
when typtype == 'e'.freeze then OID::Enum.create(row)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
type_map.register_type row['oid'].to_i, type
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Gets a list of user defined types.
|
76
|
+
# You can even choose the +typcategory+ filter
|
77
|
+
def user_defined_types(category = nil)
|
78
|
+
category_condition = "AND typtype = '#{category}'" unless category.nil?
|
79
|
+
select_all(<<-SQL).rows.to_h
|
80
|
+
SELECT t.typname AS name,
|
81
|
+
CASE t.typtype
|
82
|
+
WHEN 'e' THEN 'enum'
|
83
|
+
END AS type
|
84
|
+
FROM pg_type t
|
85
|
+
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
86
|
+
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
|
87
|
+
#{category_condition}
|
88
|
+
AND NOT EXISTS(
|
89
|
+
SELECT 1 FROM pg_catalog.pg_type el
|
90
|
+
WHERE el.oid = t.typelem AND el.typarray = t.oid
|
91
|
+
)
|
92
|
+
AND (t.typrelid = 0 OR (
|
93
|
+
SELECT c.relkind = 'c' FROM pg_catalog.pg_class c
|
94
|
+
WHERE c.oid = t.typrelid
|
95
|
+
))
|
96
|
+
ORDER BY t.typtype DESC
|
97
|
+
SQL
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module OID
|
5
|
+
module Array
|
6
|
+
|
7
|
+
def initialize(subtype, delimiter = ',')
|
8
|
+
super
|
9
|
+
@pg_encoder = Coder
|
10
|
+
@pg_decoder = Coder
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.prepend Array
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module OID
|
5
|
+
class Enum < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Enum
|
6
|
+
|
7
|
+
attr_reader :name, :klass
|
8
|
+
|
9
|
+
def self.create(row)
|
10
|
+
new(row['typname'])
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@name = name
|
15
|
+
@klass = Attributes::Enum.lookup(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def hash
|
19
|
+
[self.class, name].hash
|
20
|
+
end
|
21
|
+
|
22
|
+
def serialize(value)
|
23
|
+
return if value.blank?
|
24
|
+
value = cast_value(value)
|
25
|
+
value.to_s unless value.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_valid_value(value)
|
29
|
+
cast_value(value)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def cast_value(value)
|
35
|
+
return if value.blank?
|
36
|
+
return value if value.is_a?(@klass)
|
37
|
+
@klass.new(value)
|
38
|
+
rescue Attributes::Enum::EnumError
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module OID
|
5
|
+
class Interval < ActiveModel::Type::Value
|
6
|
+
|
7
|
+
CAST_PARTS = [:years, :months, :days, :hours, :minutes, :seconds]
|
8
|
+
|
9
|
+
def type
|
10
|
+
:interval
|
11
|
+
end
|
12
|
+
|
13
|
+
# Accepts database-style string, numeric as seconds, array of parts
|
14
|
+
# padded to left, or a hash
|
15
|
+
#
|
16
|
+
# Examples:
|
17
|
+
# [12, 0, 0]
|
18
|
+
# produces: 12 hours, 0 minutes, and 0 seconds
|
19
|
+
#
|
20
|
+
# [nil, nil, 3, 0, 0, 0]
|
21
|
+
# produces: 3 days, 0 hours, 0 minutes, and 0 seconds
|
22
|
+
#
|
23
|
+
# {minutes: 12, seconds: 0}
|
24
|
+
# produces: 12 minutes, and 0 seconds
|
25
|
+
def cast(value)
|
26
|
+
return if value.blank?
|
27
|
+
case value
|
28
|
+
when ::String then deserialize(value)
|
29
|
+
when ::ActiveSupport::Duration then value
|
30
|
+
when ::Numeric
|
31
|
+
parts = CAST_PARTS.map do |part|
|
32
|
+
rest, value = value.divmod(1.send(part))
|
33
|
+
rest == 0 ? nil : [part, rest]
|
34
|
+
end
|
35
|
+
parts_to_duration(parts.compact)
|
36
|
+
when ::Array
|
37
|
+
value.compact!
|
38
|
+
parts = CAST_PARTS.drop(6 - value.size).zip(value).to_h
|
39
|
+
parts_to_duration(parts)
|
40
|
+
when ::Hash
|
41
|
+
parts_to_duration(value)
|
42
|
+
else
|
43
|
+
value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Uses the ActiveSupport::Duration::ISO8601Parser
|
48
|
+
# See ActiveSupport::Duration#parse
|
49
|
+
# The value must be Integer when no precision is given
|
50
|
+
def deserialize(value)
|
51
|
+
return if value.blank?
|
52
|
+
parts = ActiveSupport::Duration::ISO8601Parser.new(value).parse!
|
53
|
+
parts_to_duration(parts)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Uses the ActiveSupport::Duration::ISO8601Serializer
|
57
|
+
# See ActiveSupport::Duration#iso8601
|
58
|
+
def serialize(value)
|
59
|
+
return if value.blank?
|
60
|
+
value = cast(value) unless value.is_a?(ActiveSupport::Duration)
|
61
|
+
value.iso8601(precision: @scale)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Always use the numeric value for schema dumper
|
65
|
+
def type_cast_for_schema(value)
|
66
|
+
cast(value).value.inspect
|
67
|
+
end
|
68
|
+
|
69
|
+
# Check if the user input has the correct format
|
70
|
+
def assert_valid_value(value)
|
71
|
+
# TODO: Implement!
|
72
|
+
end
|
73
|
+
|
74
|
+
# Transform a list of parts into a duration object
|
75
|
+
def parts_to_duration(parts)
|
76
|
+
parts = parts.to_h.with_indifferent_access.slice(*CAST_PARTS)
|
77
|
+
return 0.seconds if parts.blank?
|
78
|
+
|
79
|
+
seconds = 0
|
80
|
+
parts = parts.map do |part, num|
|
81
|
+
num = num.to_i unless num.is_a?(Numeric)
|
82
|
+
if num > 0
|
83
|
+
seconds += num.send(part).value
|
84
|
+
[part, num]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
ActiveSupport::Duration.new(seconds, parts.compact)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'oid/array'
|
2
|
+
require_relative 'oid/enum'
|
3
|
+
require_relative 'oid/interval'
|
4
|
+
|
5
|
+
module Torque
|
6
|
+
module PostgreSQL
|
7
|
+
module Adapter
|
8
|
+
module OID
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
12
|
+
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module Quoting
|
5
|
+
|
6
|
+
Name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name
|
7
|
+
|
8
|
+
# Quotes type names for use in SQL queries.
|
9
|
+
def quote_type_name(string, schema = nil)
|
10
|
+
name_schema, table = string.to_s.scan(/[^".\s]+|"[^"]*"/)
|
11
|
+
if table.nil?
|
12
|
+
table = name_schema
|
13
|
+
name_schema = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
schema = schema || name_schema || 'public'
|
17
|
+
Name.new(schema, table).quoted
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module ColumnMethods
|
5
|
+
|
6
|
+
def interval(*args, **options)
|
7
|
+
args.each { |name| column(name, :interval, options) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def enum(*args, **options)
|
11
|
+
args.each do |name|
|
12
|
+
type = options.fetch(:subtype, name)
|
13
|
+
column(name, type, options)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
module ColumnDefinition
|
20
|
+
attr_accessor :subtype
|
21
|
+
end
|
22
|
+
|
23
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::Table.include ColumnMethods
|
24
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition.include ColumnMethods
|
25
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnDefinition.include ColumnDefinition
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module ColumnDumper
|
5
|
+
|
6
|
+
# Adds +:subtype+ as a valid migration key
|
7
|
+
def migration_keys
|
8
|
+
super + [:subtype]
|
9
|
+
end
|
10
|
+
|
11
|
+
# Adds +:subtype+ option to the default set
|
12
|
+
def prepare_column_options(column)
|
13
|
+
spec = super
|
14
|
+
|
15
|
+
if subtype = schema_subtype(column)
|
16
|
+
spec[:subtype] = subtype
|
17
|
+
end
|
18
|
+
|
19
|
+
spec
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def schema_subtype(column)
|
25
|
+
column.sql_type.to_sym.inspect if [:enum].include? column.type
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module SchemaStatements
|
5
|
+
|
6
|
+
# Drops a type.
|
7
|
+
def drop_type(name, options = {})
|
8
|
+
force = options.fetch(:force, '').upcase
|
9
|
+
check = 'IF EXISTS' if options.fetch(:check, true)
|
10
|
+
execute <<-SQL
|
11
|
+
DROP TYPE #{check}
|
12
|
+
#{quote_type_name(name, options[:schema])} #{force}
|
13
|
+
SQL
|
14
|
+
end
|
15
|
+
|
16
|
+
# Renames a type.
|
17
|
+
def rename_type(type_name, new_name)
|
18
|
+
execute <<-SQL
|
19
|
+
ALTER TYPE #{quote_type_name(type_name)}
|
20
|
+
RENAME TO #{Quoting::Name.new(nil, new_name.to_s).quoted}
|
21
|
+
SQL
|
22
|
+
end
|
23
|
+
|
24
|
+
# Creates a new PostgreSQL enumerator type
|
25
|
+
#
|
26
|
+
# Example:
|
27
|
+
# create_enum 'status', ['foo', 'bar']
|
28
|
+
# create_enum 'status', ['foo', 'bar'], prefix: true
|
29
|
+
# create_enum 'status', ['foo', 'bar'], suffix: 'test'
|
30
|
+
# create_enum 'status', ['foo', 'bar'], force: true
|
31
|
+
def create_enum(name, values, options = {})
|
32
|
+
drop_type(name, options) if options[:force]
|
33
|
+
execute <<-SQL
|
34
|
+
CREATE TYPE #{quote_type_name(name, options[:schema])} AS ENUM
|
35
|
+
(#{quote_enum_values(name, values, options).join(', ')})
|
36
|
+
SQL
|
37
|
+
end
|
38
|
+
|
39
|
+
# Changes the enumerator by adding new values
|
40
|
+
#
|
41
|
+
# Example:
|
42
|
+
# add_enum_values 'status', ['baz']
|
43
|
+
# add_enum_values 'status', ['baz'], before: 'bar'
|
44
|
+
# add_enum_values 'status', ['baz'], after: 'foo'
|
45
|
+
# add_enum_values 'status', ['baz'], prepend: true
|
46
|
+
def add_enum_values(name, values, options = {})
|
47
|
+
before = options.fetch(:before, false)
|
48
|
+
after = options.fetch(:after, false)
|
49
|
+
|
50
|
+
before = enum_values(name).first if options.key? :prepend
|
51
|
+
before = quote(before) unless before == false
|
52
|
+
after = quote(after) unless after == false
|
53
|
+
|
54
|
+
quote_enum_values(name, values, options).each do |value|
|
55
|
+
reference = "BEFORE #{before}" unless before == false
|
56
|
+
reference = "AFTER #{after}" unless after == false
|
57
|
+
execute <<-SQL
|
58
|
+
ALTER TYPE #{quote_type_name(name, options[:schema])}
|
59
|
+
ADD VALUE #{value} #{reference}
|
60
|
+
SQL
|
61
|
+
|
62
|
+
before = false
|
63
|
+
after = value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns all values that an enum type can have.
|
68
|
+
def enum_values(name)
|
69
|
+
select_values("SELECT unnest(enum_range(NULL::#{name}))")
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def quote_enum_values(name, values, options)
|
75
|
+
prefix = options[:prefix]
|
76
|
+
prefix = name if prefix === true
|
77
|
+
|
78
|
+
suffix = options[:suffix]
|
79
|
+
suffix = name if suffix === true
|
80
|
+
|
81
|
+
values.map! do |value|
|
82
|
+
quote([prefix, value, suffix].compact.join('_'))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|