forked from datamapper/dm-migrations
/
dm-postgres-adapter.rb
157 lines (130 loc) · 4.21 KB
/
dm-postgres-adapter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
require 'dm-migrations/auto_migration'
require 'dm-migrations/adapters/dm-do-adapter'
module DataMapper
module Migrations
module PostgresAdapter
include DataObjectsAdapter
# @api private
def self.included(base)
base.extend DataObjectsAdapter::ClassMethods
base.extend ClassMethods
end
# @api semipublic
def upgrade_model_storage(model)
without_notices { super }
end
# @api semipublic
def create_model_storage(model)
without_notices { super }
end
# @api semipublic
def destroy_model_storage(model)
if supports_drop_table_if_exists?
without_notices { super }
else
super
end
end
module SQL #:nodoc:
# private ## This cannot be private for current migrations
# @api private
def supports_drop_table_if_exists?
@supports_drop_table_if_exists ||= postgres_version >= '8.2'
end
# @api private
def schema_name
@schema_name ||= select('SELECT current_schema()').first.freeze
end
# @api private
def postgres_version
@postgres_version ||= select('SELECT version()').first.split[1].freeze
end
# @api private
def without_notices
# execute the block with NOTICE messages disabled
begin
execute('SET client_min_messages = warning')
yield
ensure
execute('RESET client_min_messages')
end
end
# @api private
def property_schema_hash(property)
schema = super
# Postgres does not support precision and scale for Float
if property.kind_of?(Property::Float)
schema.delete(:precision)
schema.delete(:scale)
end
if property.kind_of?(Property::Integer)
min = property.min
max = property.max
schema[:primitive] = integer_column_statement(min..max) if min && max
end
if schema[:serial]
schema[:primitive] = serial_column_statement(min..max)
end
schema
end
private
# Return SQL statement for the integer column
#
# @param [Range] range
# the min/max allowed integers
#
# @return [String]
# the statement to create the integer column
#
# @api private
def integer_column_statement(range)
min = range.first
max = range.last
smallint = 2**15
integer = 2**31
bigint = 2**63
if min >= -smallint && max < smallint then 'SMALLINT'
elsif min >= -integer && max < integer then 'INTEGER'
elsif min >= -bigint && max < bigint then 'BIGINT'
else
raise ArgumentError, "min #{min} and max #{max} exceeds supported range"
end
end
# Return SQL statement for the serial column
#
# @param [Integer] max
# the max allowed integer
#
# @return [String]
# the statement to create the serial column
#
# @api private
def serial_column_statement(range)
max = range.last
if max.nil? || max < 2**31 then 'SERIAL'
elsif max < 2**63 then 'BIGSERIAL'
else
raise ArgumentError, "min #{range.first} and max #{max} exceeds supported range"
end
end
end # module SQL
include SQL
module ClassMethods
# Types for PostgreSQL databases.
#
# @return [Hash] types for PostgreSQL databases.
#
# @api private
def type_map
precision = Property::Numeric.precision
scale = Property::Decimal.scale
super.merge(
Property::Binary => { :primitive => 'BYTEA' },
BigDecimal => { :primitive => 'NUMERIC', :precision => precision, :scale => scale },
Float => { :primitive => 'DOUBLE PRECISION' }
).freeze
end
end
end
end
end