activerecord-cipherstash-pg-adapter 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.tool-versions +2 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +15 -0
- data/LICENSE +124 -0
- data/README.md +29 -0
- data/Rakefile +8 -0
- data/activerecord-cipherstash-pg-adapter.gemspec +35 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/column.rb +69 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/database_extensions.rb +31 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/database_tasks.rb +15 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/array.rb +91 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/bit.rb +53 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/cidr.rb +48 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/date.rb +31 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/enum.rb +20 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/hstore.rb +109 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/point.rb +64 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/range.rb +115 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/type_map_initializer.rb +125 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/uuid.rb +35 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/oid.rb +38 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/quoting.rb +231 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/referential_integrity.rb +77 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/schema_creation.rb +100 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/schema_definitions.rb +243 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/schema_dumper.rb +74 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/schema_statements.rb +812 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/cipherstash_pg/utils.rb +80 -0
- data/lib/active_record/connection_adapters/cipherstash_pg_adapter.rb +1100 -0
- data/lib/active_record/connection_adapters/postgres_cipherstash_adapter.rb +13 -0
- data/lib/activerecord-cipherstash-pg-adapter.rb +33 -0
- data/lib/version.rb +3 -0
- metadata +126 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module CipherStashPG
|
6
|
+
module ReferentialIntegrity # :nodoc:
|
7
|
+
def disable_referential_integrity # :nodoc:
|
8
|
+
original_exception = nil
|
9
|
+
|
10
|
+
begin
|
11
|
+
transaction(requires_new: true) do
|
12
|
+
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
|
13
|
+
end
|
14
|
+
rescue ActiveRecord::ActiveRecordError => e
|
15
|
+
original_exception = e
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
yield
|
20
|
+
rescue ActiveRecord::InvalidForeignKey => e
|
21
|
+
warn <<-WARNING
|
22
|
+
WARNING: Rails was not able to disable referential integrity.
|
23
|
+
|
24
|
+
This is most likely caused due to missing permissions.
|
25
|
+
Rails needs superuser privileges to disable referential integrity.
|
26
|
+
|
27
|
+
cause: #{original_exception&.message}
|
28
|
+
|
29
|
+
WARNING
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
transaction(requires_new: true) do
|
35
|
+
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
|
36
|
+
end
|
37
|
+
rescue ActiveRecord::ActiveRecordError
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def all_foreign_keys_valid? # :nodoc:
|
42
|
+
sql = <<~SQL
|
43
|
+
do $$
|
44
|
+
declare r record;
|
45
|
+
BEGIN
|
46
|
+
FOR r IN (
|
47
|
+
SELECT FORMAT(
|
48
|
+
'UPDATE pg_constraint SET convalidated=false WHERE conname = ''%I'' AND connamespace::regnamespace = ''%I''::regnamespace; ALTER TABLE %I.%I VALIDATE CONSTRAINT %I;',
|
49
|
+
constraint_name,
|
50
|
+
table_schema,
|
51
|
+
table_schema,
|
52
|
+
table_name,
|
53
|
+
constraint_name
|
54
|
+
) AS constraint_check
|
55
|
+
FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'
|
56
|
+
)
|
57
|
+
LOOP
|
58
|
+
EXECUTE (r.constraint_check);
|
59
|
+
END LOOP;
|
60
|
+
END;
|
61
|
+
$$;
|
62
|
+
SQL
|
63
|
+
|
64
|
+
begin
|
65
|
+
transaction(requires_new: true) do
|
66
|
+
execute(sql)
|
67
|
+
end
|
68
|
+
|
69
|
+
true
|
70
|
+
rescue ActiveRecord::StatementInvalid
|
71
|
+
false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module CipherStashPG
|
6
|
+
class SchemaCreation < SchemaCreation # :nodoc:
|
7
|
+
private
|
8
|
+
def visit_AlterTable(o)
|
9
|
+
super << o.constraint_validations.map { |fk| visit_ValidateConstraint fk }.join(" ")
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit_AddForeignKey(o)
|
13
|
+
super.dup.tap do |sql|
|
14
|
+
if o.deferrable
|
15
|
+
sql << " DEFERRABLE"
|
16
|
+
sql << " INITIALLY #{o.deferrable.to_s.upcase}" unless o.deferrable == true
|
17
|
+
end
|
18
|
+
|
19
|
+
sql << " NOT VALID" unless o.validate?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_CheckConstraintDefinition(o)
|
24
|
+
super.dup.tap { |sql| sql << " NOT VALID" unless o.validate? }
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_ValidateConstraint(name)
|
28
|
+
"VALIDATE CONSTRAINT #{quote_column_name(name)}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_ChangeColumnDefinition(o)
|
32
|
+
column = o.column
|
33
|
+
column.sql_type = type_to_sql(column.type, **column.options)
|
34
|
+
quoted_column_name = quote_column_name(o.name)
|
35
|
+
|
36
|
+
change_column_sql = +"ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}"
|
37
|
+
|
38
|
+
options = column_options(column)
|
39
|
+
|
40
|
+
if options[:collation]
|
41
|
+
change_column_sql << " COLLATE \"#{options[:collation]}\""
|
42
|
+
end
|
43
|
+
|
44
|
+
if options[:using]
|
45
|
+
change_column_sql << " USING #{options[:using]}"
|
46
|
+
elsif options[:cast_as]
|
47
|
+
cast_as_type = type_to_sql(options[:cast_as], **options)
|
48
|
+
change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
|
49
|
+
end
|
50
|
+
|
51
|
+
if options.key?(:default)
|
52
|
+
if options[:default].nil?
|
53
|
+
change_column_sql << ", ALTER COLUMN #{quoted_column_name} DROP DEFAULT"
|
54
|
+
else
|
55
|
+
quoted_default = quote_default_expression(options[:default], column)
|
56
|
+
change_column_sql << ", ALTER COLUMN #{quoted_column_name} SET DEFAULT #{quoted_default}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if options.key?(:null)
|
61
|
+
change_column_sql << ", ALTER COLUMN #{quoted_column_name} #{options[:null] ? 'DROP' : 'SET'} NOT NULL"
|
62
|
+
end
|
63
|
+
|
64
|
+
change_column_sql
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_column_options!(sql, options)
|
68
|
+
if options[:collation]
|
69
|
+
sql << " COLLATE \"#{options[:collation]}\""
|
70
|
+
end
|
71
|
+
|
72
|
+
if as = options[:as]
|
73
|
+
sql << " GENERATED ALWAYS AS (#{as})"
|
74
|
+
|
75
|
+
if options[:stored]
|
76
|
+
sql << " STORED"
|
77
|
+
else
|
78
|
+
raise ArgumentError, <<~MSG
|
79
|
+
PostgreSQL currently does not support VIRTUAL (not persisted) generated columns.
|
80
|
+
Specify 'stored: true' option for '#{options[:column].name}'
|
81
|
+
MSG
|
82
|
+
end
|
83
|
+
end
|
84
|
+
super
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
88
|
+
def table_modifier_in_create(o)
|
89
|
+
# A table cannot be both TEMPORARY and UNLOGGED, since all TEMPORARY
|
90
|
+
# tables are already UNLOGGED.
|
91
|
+
if o.temporary
|
92
|
+
" TEMPORARY"
|
93
|
+
elsif o.unlogged
|
94
|
+
" UNLOGGED"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module CipherStashPG
|
6
|
+
module ColumnMethods
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
# Defines the primary key field.
|
10
|
+
# Use of the native PostgreSQL UUID type is supported, and can be used
|
11
|
+
# by defining your tables as such:
|
12
|
+
#
|
13
|
+
# create_table :stuffs, id: :uuid do |t|
|
14
|
+
# t.string :content
|
15
|
+
# t.timestamps
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# By default, this will use the <tt>gen_random_uuid()</tt> function from the
|
19
|
+
# +pgcrypto+ extension. As that extension is only available in
|
20
|
+
# PostgreSQL 9.4+, for earlier versions an explicit default can be set
|
21
|
+
# to use <tt>uuid_generate_v4()</tt> from the +uuid-ossp+ extension instead:
|
22
|
+
#
|
23
|
+
# create_table :stuffs, id: false do |t|
|
24
|
+
# t.primary_key :id, :uuid, default: "uuid_generate_v4()"
|
25
|
+
# t.uuid :foo_id
|
26
|
+
# t.timestamps
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# To enable the appropriate extension, which is a requirement, use
|
30
|
+
# the +enable_extension+ method in your migrations.
|
31
|
+
#
|
32
|
+
# To use a UUID primary key without any of the extensions, set the
|
33
|
+
# +:default+ option to +nil+:
|
34
|
+
#
|
35
|
+
# create_table :stuffs, id: false do |t|
|
36
|
+
# t.primary_key :id, :uuid, default: nil
|
37
|
+
# t.uuid :foo_id
|
38
|
+
# t.timestamps
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# You may also pass a custom stored procedure that returns a UUID or use a
|
42
|
+
# different UUID generation function from another library.
|
43
|
+
#
|
44
|
+
# Note that setting the UUID primary key default value to +nil+ will
|
45
|
+
# require you to assure that you always provide a UUID value before saving
|
46
|
+
# a record (as primary keys cannot be +nil+). This might be done via the
|
47
|
+
# +SecureRandom.uuid+ method and a +before_save+ callback, for instance.
|
48
|
+
def primary_key(name, type = :primary_key, **options)
|
49
|
+
if type == :uuid
|
50
|
+
options[:default] = options.fetch(:default, "gen_random_uuid()")
|
51
|
+
end
|
52
|
+
|
53
|
+
super
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# :method: bigserial
|
58
|
+
# :call-seq: bigserial(*names, **options)
|
59
|
+
|
60
|
+
##
|
61
|
+
# :method: bit
|
62
|
+
# :call-seq: bit(*names, **options)
|
63
|
+
|
64
|
+
##
|
65
|
+
# :method: bit_varying
|
66
|
+
# :call-seq: bit_varying(*names, **options)
|
67
|
+
|
68
|
+
##
|
69
|
+
# :method: cidr
|
70
|
+
# :call-seq: cidr(*names, **options)
|
71
|
+
|
72
|
+
##
|
73
|
+
# :method: citext
|
74
|
+
# :call-seq: citext(*names, **options)
|
75
|
+
|
76
|
+
##
|
77
|
+
# :method: daterange
|
78
|
+
# :call-seq: daterange(*names, **options)
|
79
|
+
|
80
|
+
##
|
81
|
+
# :method: hstore
|
82
|
+
# :call-seq: hstore(*names, **options)
|
83
|
+
|
84
|
+
##
|
85
|
+
# :method: inet
|
86
|
+
# :call-seq: inet(*names, **options)
|
87
|
+
|
88
|
+
##
|
89
|
+
# :method: interval
|
90
|
+
# :call-seq: interval(*names, **options)
|
91
|
+
|
92
|
+
##
|
93
|
+
# :method: int4range
|
94
|
+
# :call-seq: int4range(*names, **options)
|
95
|
+
|
96
|
+
##
|
97
|
+
# :method: int8range
|
98
|
+
# :call-seq: int8range(*names, **options)
|
99
|
+
|
100
|
+
##
|
101
|
+
# :method: jsonb
|
102
|
+
# :call-seq: jsonb(*names, **options)
|
103
|
+
|
104
|
+
##
|
105
|
+
# :method: ltree
|
106
|
+
# :call-seq: ltree(*names, **options)
|
107
|
+
|
108
|
+
##
|
109
|
+
# :method: macaddr
|
110
|
+
# :call-seq: macaddr(*names, **options)
|
111
|
+
|
112
|
+
##
|
113
|
+
# :method: money
|
114
|
+
# :call-seq: money(*names, **options)
|
115
|
+
|
116
|
+
##
|
117
|
+
# :method: numrange
|
118
|
+
# :call-seq: numrange(*names, **options)
|
119
|
+
|
120
|
+
##
|
121
|
+
# :method: oid
|
122
|
+
# :call-seq: oid(*names, **options)
|
123
|
+
|
124
|
+
##
|
125
|
+
# :method: point
|
126
|
+
# :call-seq: point(*names, **options)
|
127
|
+
|
128
|
+
##
|
129
|
+
# :method: line
|
130
|
+
# :call-seq: line(*names, **options)
|
131
|
+
|
132
|
+
##
|
133
|
+
# :method: lseg
|
134
|
+
# :call-seq: lseg(*names, **options)
|
135
|
+
|
136
|
+
##
|
137
|
+
# :method: box
|
138
|
+
# :call-seq: box(*names, **options)
|
139
|
+
|
140
|
+
##
|
141
|
+
# :method: path
|
142
|
+
# :call-seq: path(*names, **options)
|
143
|
+
|
144
|
+
##
|
145
|
+
# :method: polygon
|
146
|
+
# :call-seq: polygon(*names, **options)
|
147
|
+
|
148
|
+
##
|
149
|
+
# :method: circle
|
150
|
+
# :call-seq: circle(*names, **options)
|
151
|
+
|
152
|
+
##
|
153
|
+
# :method: serial
|
154
|
+
# :call-seq: serial(*names, **options)
|
155
|
+
|
156
|
+
##
|
157
|
+
# :method: tsrange
|
158
|
+
# :call-seq: tsrange(*names, **options)
|
159
|
+
|
160
|
+
##
|
161
|
+
# :method: tstzrange
|
162
|
+
# :call-seq: tstzrange(*names, **options)
|
163
|
+
|
164
|
+
##
|
165
|
+
# :method: tsvector
|
166
|
+
# :call-seq: tsvector(*names, **options)
|
167
|
+
|
168
|
+
##
|
169
|
+
# :method: uuid
|
170
|
+
# :call-seq: uuid(*names, **options)
|
171
|
+
|
172
|
+
##
|
173
|
+
# :method: xml
|
174
|
+
# :call-seq: xml(*names, **options)
|
175
|
+
|
176
|
+
##
|
177
|
+
# :method: timestamptz
|
178
|
+
# :call-seq: timestamptz(*names, **options)
|
179
|
+
|
180
|
+
##
|
181
|
+
# :method: enum
|
182
|
+
# :call-seq: enum(*names, **options)
|
183
|
+
|
184
|
+
included do
|
185
|
+
define_column_methods :bigserial, :bit, :bit_varying, :cidr, :citext, :daterange,
|
186
|
+
:hstore, :inet, :interval, :int4range, :int8range, :jsonb, :ltree, :macaddr,
|
187
|
+
:money, :numrange, :oid, :point, :line, :lseg, :box, :path, :polygon, :circle,
|
188
|
+
:serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml, :timestamptz, :enum
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
193
|
+
include ColumnMethods
|
194
|
+
|
195
|
+
attr_reader :unlogged
|
196
|
+
|
197
|
+
def initialize(*, **)
|
198
|
+
super
|
199
|
+
@unlogged = ActiveRecord::ConnectionAdapters::CipherStashPGAdapter.create_unlogged_tables
|
200
|
+
end
|
201
|
+
|
202
|
+
def new_column_definition(name, type, **options) # :nodoc:
|
203
|
+
case type
|
204
|
+
when :virtual
|
205
|
+
type = options[:type]
|
206
|
+
end
|
207
|
+
|
208
|
+
super
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
def aliased_types(name, fallback)
|
213
|
+
fallback
|
214
|
+
end
|
215
|
+
|
216
|
+
def integer_like_primary_key_type(type, options)
|
217
|
+
if type == :bigint || options[:limit] == 8
|
218
|
+
:bigserial
|
219
|
+
else
|
220
|
+
:serial
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
class Table < ActiveRecord::ConnectionAdapters::Table
|
226
|
+
include ColumnMethods
|
227
|
+
end
|
228
|
+
|
229
|
+
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
|
230
|
+
attr_reader :constraint_validations
|
231
|
+
|
232
|
+
def initialize(td)
|
233
|
+
super
|
234
|
+
@constraint_validations = []
|
235
|
+
end
|
236
|
+
|
237
|
+
def validate_constraint(name)
|
238
|
+
@constraint_validations << name
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module CipherStashPG
|
6
|
+
class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
|
7
|
+
private
|
8
|
+
def extensions(stream)
|
9
|
+
extensions = @connection.extensions
|
10
|
+
if extensions.any?
|
11
|
+
stream.puts " # These are extensions that must be enabled in order to support this database"
|
12
|
+
extensions.sort.each do |extension|
|
13
|
+
stream.puts " enable_extension #{extension.inspect}"
|
14
|
+
end
|
15
|
+
stream.puts
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def types(stream)
|
20
|
+
types = @connection.enum_types
|
21
|
+
if types.any?
|
22
|
+
stream.puts " # Custom types defined in this database."
|
23
|
+
stream.puts " # Note that some types may not work with other database engines. Be careful if changing database."
|
24
|
+
types.sort.each do |name, values|
|
25
|
+
stream.puts " create_enum #{name.inspect}, #{values.split(",").inspect}"
|
26
|
+
end
|
27
|
+
stream.puts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare_column_options(column)
|
32
|
+
spec = super
|
33
|
+
spec[:array] = "true" if column.array?
|
34
|
+
|
35
|
+
if @connection.supports_virtual_columns? && column.virtual?
|
36
|
+
spec[:as] = extract_expression_for_virtual_column(column)
|
37
|
+
spec[:stored] = true
|
38
|
+
spec = { type: schema_type(column).inspect }.merge!(spec)
|
39
|
+
end
|
40
|
+
|
41
|
+
spec[:enum_type] = "\"#{column.sql_type}\"" if column.enum?
|
42
|
+
|
43
|
+
spec
|
44
|
+
end
|
45
|
+
|
46
|
+
def default_primary_key?(column)
|
47
|
+
schema_type(column) == :bigserial
|
48
|
+
end
|
49
|
+
|
50
|
+
def explicit_primary_key_default?(column)
|
51
|
+
column.type == :uuid || (column.type == :integer && !column.serial?)
|
52
|
+
end
|
53
|
+
|
54
|
+
def schema_type(column)
|
55
|
+
return super unless column.serial?
|
56
|
+
|
57
|
+
if column.bigint?
|
58
|
+
:bigserial
|
59
|
+
else
|
60
|
+
:serial
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def schema_expression(column)
|
65
|
+
super unless column.serial?
|
66
|
+
end
|
67
|
+
|
68
|
+
def extract_expression_for_virtual_column(column)
|
69
|
+
column.default_function.inspect
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|