schema_plus 1.8.9 → 2.0.0.pre1
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 +4 -4
- data/.gitignore +4 -4
- data/.travis.yml +1 -47
- data/CHANGELOG.md +0 -35
- data/README.md +73 -107
- data/Rakefile +7 -10
- data/TODO.md +51 -0
- data/gemfiles/Gemfile.base +2 -0
- data/lib/schema_column_plus.rb +7 -0
- data/lib/{schema_plus → schema_column_plus}/active_record/connection_adapters/column.rb +13 -11
- data/lib/schema_column_plus/middleware/model.rb +22 -0
- data/lib/schema_db_default.rb +13 -0
- data/lib/{schema_plus → schema_db_default}/active_record/attribute.rb +4 -4
- data/lib/schema_db_default/db_default.rb +17 -0
- data/lib/schema_db_default/middleware.rb +30 -0
- data/lib/schema_default_expr.rb +32 -0
- data/lib/schema_default_expr/active_record/connection_adapters/mysql_adapter.rb +17 -0
- data/lib/schema_default_expr/active_record/connection_adapters/postgresql_adapter.rb +18 -0
- data/lib/schema_default_expr/active_record/connection_adapters/sqlite3_adapter.rb +35 -0
- data/lib/schema_default_expr/middleware.rb +54 -0
- data/lib/schema_pg_enums.rb +6 -0
- data/lib/schema_pg_enums/active_record.rb +69 -0
- data/lib/schema_pg_enums/middleware.rb +23 -0
- data/lib/schema_plus.rb +17 -45
- data/lib/schema_plus/active_record/base.rb +6 -23
- data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +80 -181
- data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +78 -99
- data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +34 -114
- data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +16 -370
- data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +1 -67
- data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +18 -112
- data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +14 -116
- data/lib/schema_plus/active_record/migration/command_recorder.rb +8 -59
- data/lib/schema_plus/middleware/dumper.rb +94 -0
- data/lib/schema_plus/middleware/migration.rb +167 -0
- data/lib/schema_plus/middleware/model.rb +17 -0
- data/lib/schema_plus/version.rb +1 -1
- data/lib/schema_plus_tables.rb +15 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/abstract_adapter.rb +20 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/mysql_adapter.rb +25 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/postgresql_adapter.rb +13 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/sqlite3_adapter.rb +12 -0
- data/lib/schema_views.rb +16 -0
- data/lib/schema_views/active_record/connection_adapters/abstract_adapter.rb +41 -0
- data/lib/schema_views/active_record/connection_adapters/mysql_adapter.rb +30 -0
- data/lib/schema_views/active_record/connection_adapters/postgresql_adapter.rb +31 -0
- data/lib/schema_views/active_record/connection_adapters/sqlite3_adapter.rb +18 -0
- data/lib/schema_views/middleware.rb +47 -0
- data/schema_dev.yml +1 -31
- data/schema_plus.gemspec +11 -9
- data/spec/foreign_key_definition_spec.rb +7 -7
- data/spec/foreign_key_spec.rb +63 -48
- data/spec/migration_spec.rb +58 -203
- data/spec/named_schemas_spec.rb +5 -88
- data/spec/{column_spec.rb → schema_column_plus/column_spec.rb} +26 -48
- data/spec/schema_db_default/column_spec.rb +58 -0
- data/spec/{column_default_spec.rb → schema_default_expr/column_default_spec.rb} +1 -2
- data/spec/schema_default_expr/schema_dumper_spec.rb +116 -0
- data/spec/schema_dumper_spec.rb +22 -327
- data/spec/{enum_spec.rb → schema_pg_enums/enum_spec.rb} +1 -1
- data/spec/schema_pg_enums/schema_dumper_spec.rb +37 -0
- data/spec/schema_views/named_schemas_spec.rb +97 -0
- data/spec/{views_spec.rb → schema_views/views_spec.rb} +1 -1
- data/spec/spec_helper.rb +2 -1
- data/spec/support/matchers/reference.rb +11 -12
- metadata +104 -57
- data/gemfiles/rails-3.2/Gemfile.base +0 -3
- data/gemfiles/rails-3.2/Gemfile.mysql +0 -10
- data/gemfiles/rails-3.2/Gemfile.mysql2 +0 -10
- data/gemfiles/rails-3.2/Gemfile.postgresql +0 -10
- data/gemfiles/rails-3.2/Gemfile.sqlite3 +0 -10
- data/gemfiles/rails-4.0/Gemfile.base +0 -3
- data/gemfiles/rails-4.0/Gemfile.mysql2 +0 -10
- data/gemfiles/rails-4.0/Gemfile.postgresql +0 -10
- data/gemfiles/rails-4.0/Gemfile.sqlite3 +0 -10
- data/gemfiles/rails-4.1/Gemfile.base +0 -3
- data/gemfiles/rails-4.1/Gemfile.mysql2 +0 -10
- data/gemfiles/rails-4.1/Gemfile.postgresql +0 -10
- data/gemfiles/rails-4.1/Gemfile.sqlite3 +0 -10
- data/lib/schema_plus/active_record/column_options_handler.rb +0 -117
- data/lib/schema_plus/active_record/connection_adapters/index_definition.rb +0 -70
- data/lib/schema_plus/active_record/db_default.rb +0 -19
- data/lib/schema_plus/active_record/foreign_keys.rb +0 -137
- data/lib/schema_plus/active_record/schema_dumper.rb +0 -171
- data/lib/schema_plus/railtie.rb +0 -20
- data/spec/index_definition_spec.rb +0 -211
- data/spec/index_spec.rb +0 -249
@@ -10,38 +10,21 @@ module SchemaPlus
|
|
10
10
|
end
|
11
11
|
|
12
12
|
module ClassMethods #:nodoc:
|
13
|
-
def self.extended(base) #:nodoc:
|
14
|
-
class << base
|
15
|
-
alias_method_chain :columns, :schema_plus
|
16
|
-
alias_method_chain :reset_column_information, :schema_plus
|
17
|
-
end
|
18
|
-
end
|
19
13
|
|
20
14
|
public
|
21
15
|
|
22
|
-
def columns_with_schema_plus #:nodoc:
|
23
|
-
columns = columns_without_schema_plus
|
24
|
-
columns.each do |column| column.model = self end unless (@schema_plus_extended_columns ||= false)
|
25
|
-
columns
|
26
|
-
end
|
27
|
-
|
28
|
-
def reset_column_information_with_schema_plus #:nodoc:
|
29
|
-
reset_column_information_without_schema_plus
|
30
|
-
@indexes = @foreign_keys = @schema_plus_extended_columns = nil
|
31
|
-
end
|
32
|
-
|
33
|
-
# Returns a list of IndexDefinition objects, for each index
|
34
|
-
# defind on this model's table.
|
35
|
-
def indexes
|
36
|
-
@indexes ||= connection.indexes(table_name, "#{name} Indexes")
|
37
|
-
end
|
38
|
-
|
39
16
|
# Returns a list of ForeignKeyDefinition objects, for each foreign
|
40
17
|
# key constraint defined in this model's table
|
18
|
+
#
|
19
|
+
# (memoized result gets reset in Middleware::Model::ResetColumnInformation)
|
41
20
|
def foreign_keys
|
42
21
|
@foreign_keys ||= connection.foreign_keys(table_name, "#{name} Foreign Keys")
|
43
22
|
end
|
44
23
|
|
24
|
+
def reset_foreign_key_information
|
25
|
+
@foreign_keys = nil
|
26
|
+
end
|
27
|
+
|
45
28
|
# Returns a list of ForeignKeyDefinition objects, for each foreign
|
46
29
|
# key constraint of other tables that refer to this model's table
|
47
30
|
def reverse_foreign_keys
|
@@ -11,59 +11,6 @@ module SchemaPlus
|
|
11
11
|
# things are called by ActiveRecord::Base.
|
12
12
|
#
|
13
13
|
module AbstractAdapter
|
14
|
-
def self.included(base) #:nodoc:
|
15
|
-
base.alias_method_chain :initialize, :schema_plus
|
16
|
-
base.alias_method_chain :remove_index, :schema_plus
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize_with_schema_plus(*args) #:nodoc:
|
20
|
-
initialize_without_schema_plus(*args)
|
21
|
-
adapter = case adapter_name
|
22
|
-
# name of MySQL adapter depends on mysql gem
|
23
|
-
# * with mysql gem adapter is named MySQL
|
24
|
-
# * with mysql2 gem adapter is named Mysql2
|
25
|
-
# Here we handle this and hopefully futher adapter names
|
26
|
-
when /^MySQL/i then 'MysqlAdapter'
|
27
|
-
when 'PostgreSQL', 'PostGIS' then 'PostgresqlAdapter'
|
28
|
-
when 'SQLite' then 'Sqlite3Adapter'
|
29
|
-
end
|
30
|
-
if adapter.nil?
|
31
|
-
unless adapter_name == 'JDBC' # ARJDBC
|
32
|
-
::ActiveRecord::Base.logger.warn "SchemaPlus: Unsupported adapter name #{adapter_name.inspect}. Leaving it alone."
|
33
|
-
end
|
34
|
-
return
|
35
|
-
end
|
36
|
-
adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
|
37
|
-
self.class.send(:include, adapter_module) unless self.class.include?(adapter_module)
|
38
|
-
|
39
|
-
if "#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}".to_r >= "4.1".to_r
|
40
|
-
self.class.const_get(:SchemaCreation).send(:include, adapter_module.const_get(:AddColumnOptions))
|
41
|
-
else
|
42
|
-
self.class.send(:include, adapter_module.const_get(:AddColumnOptions))
|
43
|
-
end
|
44
|
-
|
45
|
-
extend(SchemaPlus::ActiveRecord::ForeignKeys)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Create a view given the SQL definition. Specify :force => true
|
49
|
-
# to first drop the view if it already exists.
|
50
|
-
def create_view(view_name, definition, options={})
|
51
|
-
definition = definition.to_sql if definition.respond_to? :to_sql
|
52
|
-
if options[:force]
|
53
|
-
drop_view(view_name, if_exists: true)
|
54
|
-
end
|
55
|
-
execute "CREATE VIEW #{quote_table_name(view_name)} AS #{definition}"
|
56
|
-
end
|
57
|
-
|
58
|
-
# Drop the named view. Specify :if_exists => true
|
59
|
-
# to fail silently if the view doesn't exist.
|
60
|
-
def drop_view(view_name, options = {})
|
61
|
-
sql = "DROP VIEW"
|
62
|
-
sql += " IF EXISTS" if options[:if_exists]
|
63
|
-
sql += " #{quote_table_name(view_name)}"
|
64
|
-
execute sql
|
65
|
-
end
|
66
|
-
|
67
14
|
|
68
15
|
# Define a foreign key constraint. Valid options are :on_update,
|
69
16
|
# :on_delete, and :deferrable, with values as described at
|
@@ -73,102 +20,118 @@ module SchemaPlus
|
|
73
20
|
# constraints; they must be included in the table specification when
|
74
21
|
# it's created. If you're using Sqlite3, this method will raise an
|
75
22
|
# error.)
|
76
|
-
def add_foreign_key(table_name,
|
77
|
-
|
78
|
-
|
23
|
+
def add_foreign_key(*args) # (table_name, column, to_table, primary_key, options = {})
|
24
|
+
options = args.extract_options!
|
25
|
+
case args.length
|
26
|
+
when 2
|
27
|
+
from_table, to_table = args
|
28
|
+
when 4
|
29
|
+
ActiveSupport::Deprecation.warn "4-argument form of add_foreign_key is deprecated. use add_foreign_key(from_table, to_table, options)"
|
30
|
+
(from_table, column, to_table, primary_key) = args
|
31
|
+
options.merge!(column: column, primary_key: primary_key)
|
32
|
+
end
|
33
|
+
|
34
|
+
options = options.dup
|
35
|
+
options[:column] ||= foreign_key_column_for(to_table)
|
36
|
+
|
37
|
+
foreign_key_sql = add_foreign_key_sql(from_table, to_table, options)
|
38
|
+
execute "ALTER TABLE #{quote_table_name(from_table)} #{foreign_key_sql}"
|
79
39
|
end
|
80
40
|
|
81
41
|
# called directly by AT's bulk_change_table, for migration
|
82
42
|
# change_table :name, :bulk => true { ... }
|
83
|
-
def add_foreign_key_sql(
|
84
|
-
foreign_key =
|
43
|
+
def add_foreign_key_sql(from_table, to_table, options = {}) #:nodoc:
|
44
|
+
foreign_key = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(from_table, AbstractAdapter.proper_table_name(to_table), options)
|
85
45
|
"ADD #{foreign_key.to_sql}"
|
86
46
|
end
|
87
47
|
|
88
|
-
def _build_foreign_key(
|
89
|
-
|
90
|
-
options.reverse_merge!(:name => ForeignKeyDefinition.default_name(table_name, column_names))
|
91
|
-
ForeignKeyDefinition.new(table_name, AbstractAdapter.proper_table_name(references_table_name), options)
|
48
|
+
def _build_foreign_key(from_table, to_table, options = {}) #:nodoc:
|
49
|
+
::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(from_table, AbstractAdapter.proper_table_name(to_table), options)
|
92
50
|
end
|
93
51
|
|
94
52
|
def self.proper_table_name(name)
|
95
|
-
|
96
|
-
proper_name = ::ActiveRecord::Migration.new.proper_table_name(name) # Rails >= 4.1
|
97
|
-
else
|
98
|
-
proper_name = ::ActiveRecord::Migrator.proper_table_name(name) # Rails <= 4.0 ; Deprecated in 4.1
|
99
|
-
end
|
53
|
+
proper_name = ::ActiveRecord::Migration.new.proper_table_name(name)
|
100
54
|
end
|
101
55
|
|
102
56
|
# Remove a foreign key constraint
|
103
57
|
#
|
104
58
|
# Arguments are the same as for add_foreign_key, or by name:
|
105
59
|
#
|
106
|
-
# remove_foreign_key table_name,
|
107
|
-
# remove_foreign_key name: constraint_name
|
60
|
+
# remove_foreign_key table_name, to_table, options
|
61
|
+
# remove_foreign_key table_name, name: constraint_name
|
108
62
|
#
|
109
63
|
# (NOTE: Sqlite3 does not support altering a table to remove
|
110
64
|
# foreign-key constraints. If you're using Sqlite3, this method will
|
111
65
|
# raise an error.)
|
112
|
-
def remove_foreign_key(
|
113
|
-
|
114
|
-
|
66
|
+
def remove_foreign_key(*args)
|
67
|
+
from_table, to_table, options = normalize_remove_foreign_key_args(*args)
|
68
|
+
options[:column] ||= foreign_key_column_for(to_table)
|
69
|
+
if sql = remove_foreign_key_sql(from_table, to_table, options)
|
70
|
+
execute "ALTER TABLE #{quote_table_name(from_table)} #{sql}"
|
115
71
|
end
|
116
72
|
end
|
117
73
|
|
118
|
-
def
|
119
|
-
|
120
|
-
options
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
74
|
+
def normalize_remove_foreign_key_args(*args)
|
75
|
+
options = args.extract_options!
|
76
|
+
if options.has_key? :column_names
|
77
|
+
ActiveSupport::Deprecation.warn ":column_names option is deprecated, use :column"
|
78
|
+
options[:column] = options.delete(:column_names)
|
79
|
+
end
|
80
|
+
if options.has_key? :references_column_names
|
81
|
+
ActiveSupport::Deprecation.warn ":references_column_names option is deprecated, use :primary_key"
|
82
|
+
options[:primary_key] = options.delete(:references_column_names)
|
83
|
+
end
|
84
|
+
if options.has_key? :references_table_name
|
85
|
+
ActiveSupport::Deprecation.warn ":references_table_name option is deprecated, use :to_table"
|
86
|
+
options[:to_table] = options.delete(:references_table_name)
|
87
|
+
end
|
88
|
+
case args.length
|
89
|
+
when 1
|
90
|
+
from_table = args[0]
|
91
|
+
when 2
|
92
|
+
from_table, to_table = args
|
93
|
+
when 3, 4
|
94
|
+
ActiveSupport::Deprecation.warn "3- and 4-argument forms of remove_foreign_key are deprecated. use add_foreign_key(from_table, to_table, options)"
|
95
|
+
(from_table, column, to_table, primary_key) = args
|
96
|
+
options.merge!(column: column, primary_key: primary_key)
|
97
|
+
else
|
98
|
+
raise ArgumentError, "Wrong number of arguments(args.length) to remove_foreign_key"
|
99
|
+
end
|
100
|
+
to_table ||= options.delete(:to_table)
|
101
|
+
[from_table, to_table, options]
|
137
102
|
end
|
138
103
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
104
|
+
def get_foreign_key_name(from_table, to_table, options)
|
105
|
+
return options[:name] if options[:name]
|
106
|
+
|
107
|
+
fks = foreign_keys(from_table)
|
108
|
+
if fks.detect(&its.name == to_table)
|
109
|
+
ActiveSupport::Deprecation.warn "remove_foreign_key(table, name) is deprecated. use remove_foreign_key(table, name: name)"
|
110
|
+
return to_table
|
111
|
+
end
|
112
|
+
test_fk = _build_foreign_key(from_table, to_table, options)
|
113
|
+
if fk = fks.detect { |fk| fk.match(test_fk) }
|
114
|
+
fk.name
|
115
|
+
else
|
116
|
+
raise "SchemaPlus: no foreign key constraint found on #{from_table.inspect} matching #{[to_table, options].inspect}" unless options[:if_exists]
|
117
|
+
nil
|
118
|
+
end
|
149
119
|
end
|
150
120
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
if_exists = options.delete(:if_exists)
|
156
|
-
options.delete(:column) if options[:name] and ::ActiveRecord::VERSION::MAJOR < 4
|
157
|
-
args << options if options.any?
|
158
|
-
return if if_exists and not index_name_exists?(table_name, options[:name] || index_name(table_name, *args), false)
|
159
|
-
remove_index_without_schema_plus(table_name, *args)
|
121
|
+
def remove_foreign_key_sql(from_table, to_table, options)
|
122
|
+
if foreign_key_name = get_foreign_key_name(from_table, to_table, options)
|
123
|
+
"DROP CONSTRAINT #{options[:if_exists] ? "IF EXISTS" : ""} #{foreign_key_name}"
|
124
|
+
end
|
160
125
|
end
|
161
126
|
|
127
|
+
|
162
128
|
# called from individual adpaters, after renaming table from old
|
163
129
|
# name to
|
164
|
-
def
|
165
|
-
indexes(newname).select{|index| index.name == index_name(oldname, index.columns)}.each do |index|
|
166
|
-
rename_index(newname, index.name, index_name(newname, index.columns))
|
167
|
-
end
|
130
|
+
def rename_foreign_keys(oldname, newname) #:nodoc:
|
168
131
|
foreign_keys(newname).each do |fk|
|
169
|
-
index = indexes(newname).find{|index| index.name == ForeignKeyDefinition.auto_index_name(oldname, fk.
|
132
|
+
index = indexes(newname).find{|index| index.name == ForeignKeyDefinition.auto_index_name(oldname, fk.column)}
|
170
133
|
begin
|
171
|
-
remove_foreign_key(newname, fk.name)
|
134
|
+
remove_foreign_key(newname, name: fk.name)
|
172
135
|
rescue NotImplementedError
|
173
136
|
# sqlite3 can't remove foreign keys, so just skip it
|
174
137
|
end
|
@@ -177,69 +140,13 @@ module SchemaPlus
|
|
177
140
|
# if the index is on a foreign key constraint
|
178
141
|
rename_index(newname, index.name, ForeignKeyDefinition.auto_index_name(newname, index.columns)) if index
|
179
142
|
begin
|
180
|
-
add_foreign_key(newname, fk.
|
143
|
+
add_foreign_key(newname, fk.to_table, :column => fk.column, :primary_key => fk.primary_key, :name => fk.name.sub(/#{oldname}/, newname), :on_update => fk.on_update, :on_delete => fk.on_delete, :deferrable => fk.deferrable)
|
181
144
|
rescue NotImplementedError
|
182
145
|
# sqlite3 can't add foreign keys, so just skip it
|
183
146
|
end
|
184
147
|
end
|
185
148
|
end
|
186
149
|
|
187
|
-
# Returns true if the database supports parital indexes (abstract; only
|
188
|
-
# Postgresql returns true)
|
189
|
-
def supports_partial_indexes?
|
190
|
-
false
|
191
|
-
end
|
192
|
-
|
193
|
-
module AddColumnOptions
|
194
|
-
def self.included(base) #:nodoc:
|
195
|
-
base.alias_method_chain :add_column_options!, :schema_plus
|
196
|
-
end
|
197
|
-
|
198
|
-
def add_column_options_with_schema_plus!(sql, options)
|
199
|
-
if options_include_default?(options)
|
200
|
-
default = options[:default]
|
201
|
-
|
202
|
-
if default.is_a? Hash and [[:expr], [:value]].include?(default.keys)
|
203
|
-
value = default[:value]
|
204
|
-
expr = sql_for_function(default[:expr]) || default[:expr] if default[:expr]
|
205
|
-
else
|
206
|
-
value = default
|
207
|
-
expr = sql_for_function(default)
|
208
|
-
end
|
209
|
-
|
210
|
-
if expr
|
211
|
-
raise ArgumentError, "Invalid default expression" unless default_expr_valid?(expr)
|
212
|
-
sql << " DEFAULT #{expr}"
|
213
|
-
# must explicitly check for :null to allow change_column to work on migrations
|
214
|
-
if options[:null] == false
|
215
|
-
sql << " NOT NULL"
|
216
|
-
end
|
217
|
-
else
|
218
|
-
add_column_options_without_schema_plus!(sql, options.merge(default: value))
|
219
|
-
end
|
220
|
-
else
|
221
|
-
add_column_options_without_schema_plus!(sql, options)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
#####################################################################
|
226
|
-
#
|
227
|
-
# The functions below here are abstract; each subclass should
|
228
|
-
# define them all. Defining them here only for reference.
|
229
|
-
|
230
|
-
# (abstract) Return true if the passed expression can be used as a column
|
231
|
-
# default value. (For most databases the specific expression
|
232
|
-
# doesn't matter, and the adapter's function would return a
|
233
|
-
# constant true if default expressions are supported or false if
|
234
|
-
# they're not.)
|
235
|
-
def default_expr_valid?(expr) raise "Internal Error: Connection adapter didn't override abstract function"; end
|
236
|
-
|
237
|
-
# (abstract) Return SQL definition for a given canonical function_name symbol.
|
238
|
-
# Currently, the only function to support is :now, which should
|
239
|
-
# return a DATETIME object for the current time.
|
240
|
-
def sql_for_function(function_name) raise "Internal Error: Connection adapter didn't override abstract function"; end
|
241
|
-
end
|
242
|
-
|
243
150
|
module VisitTableDefinition
|
244
151
|
def self.included(base) #:nodoc:
|
245
152
|
base.alias_method_chain :visit_TableDefinition, :schema_plus
|
@@ -266,14 +173,6 @@ module SchemaPlus
|
|
266
173
|
# define them all. Defining them here only for reference.
|
267
174
|
#
|
268
175
|
|
269
|
-
# (abstract) Returns the names of all views, as an array of strings
|
270
|
-
def views(name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
|
271
|
-
|
272
|
-
# (abstract) Returns the SQL definition of a given view. This is
|
273
|
-
# the literal SQL would come after 'CREATVE VIEW viewname AS ' in
|
274
|
-
# the SQL statement to create a view.
|
275
|
-
def view_definition(view_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; end
|
276
|
-
|
277
176
|
# (abstract) Return the ForeignKeyDefinition objects for foreign key
|
278
177
|
# constraints defined on this table
|
279
178
|
def foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
|
@@ -1,42 +1,4 @@
|
|
1
|
-
|
2
|
-
class ActiveRecord::ConnectionAdapters::ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
|
3
|
-
# The name of the foreign key constraint
|
4
|
-
def name
|
5
|
-
options[:name]
|
6
|
-
end
|
7
|
-
|
8
|
-
def column
|
9
|
-
options[:column]
|
10
|
-
end
|
11
|
-
|
12
|
-
def primary_key
|
13
|
-
options[:primary_key] || default_primary_key
|
14
|
-
end
|
15
|
-
|
16
|
-
# The ON_DELETE behavior for the constraint. See above for the
|
17
|
-
# possible values.
|
18
|
-
def on_delete
|
19
|
-
options[:on_delete]
|
20
|
-
end
|
21
|
-
|
22
|
-
# The ON_UPDATE behavior for the constraint. See above for the
|
23
|
-
# possible values.
|
24
|
-
def on_update
|
25
|
-
options[:on_update]
|
26
|
-
end
|
27
|
-
|
28
|
-
def custom_primary_key?
|
29
|
-
options[:primary_key] != default_primary_key
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
def default_primary_key
|
34
|
-
"id"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
else
|
38
|
-
require 'active_record/connection_adapters/abstract/schema_definitions'
|
39
|
-
end
|
1
|
+
require 'active_record/connection_adapters/abstract/schema_definitions'
|
40
2
|
|
41
3
|
module SchemaPlus
|
42
4
|
module ActiveRecord
|
@@ -46,31 +8,60 @@ module SchemaPlus
|
|
46
8
|
# The on_update and on_delete attributes can take on the following values:
|
47
9
|
# :cascade
|
48
10
|
# :restrict
|
49
|
-
# :
|
11
|
+
# :nullify
|
50
12
|
# :set_default
|
51
13
|
# :no_action
|
52
14
|
#
|
53
15
|
# The deferrable attribute can take on the following values:
|
54
16
|
# true
|
55
17
|
# :initially_deferred
|
56
|
-
|
18
|
+
module ForeignKeyDefinition
|
57
19
|
|
58
|
-
|
59
|
-
|
20
|
+
def self.included(base)
|
21
|
+
base.class_eval do
|
22
|
+
alias_method_chain :initialize, :schema_plus
|
23
|
+
end
|
24
|
+
end
|
60
25
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
26
|
+
def column_names
|
27
|
+
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#column_names is depcreated, use Array.wrap(column)"
|
28
|
+
Array.wrap(column)
|
29
|
+
end
|
65
30
|
|
66
|
-
|
31
|
+
def references_column_names
|
32
|
+
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#references_column_names is depcreated, use Array.wrap(primary_key)"
|
33
|
+
Array.wrap(primary_key)
|
34
|
+
end
|
67
35
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
36
|
+
def references_table_name
|
37
|
+
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#references_table_name is depcreated, use #to_table"
|
38
|
+
to_table
|
39
|
+
end
|
40
|
+
|
41
|
+
def table_name
|
42
|
+
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#table_name is depcreated, use #from_table"
|
43
|
+
from_table
|
44
|
+
end
|
45
|
+
|
46
|
+
ACTIONS = { :cascade => "CASCADE", :restrict => "RESTRICT", :nullify => "SET NULL", :set_default => "SET DEFAULT", :no_action => "NO ACTION" }.freeze
|
47
|
+
ACTION_LOOKUP = ACTIONS.invert.freeze
|
48
|
+
|
49
|
+
def initialize_with_schema_plus(from_table, to_table, options={})
|
50
|
+
[:on_update, :on_delete].each do |key|
|
51
|
+
if options[key] == :set_null
|
52
|
+
require 'byebug' ; byebug
|
53
|
+
ActiveSupport::Deprecation.warn ":set_null value for #{key} is deprecated. use :nullify instead"
|
54
|
+
options[key] = :nullify
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
initialize_without_schema_plus(from_table, to_table, options)
|
59
|
+
if column.is_a?(Array) and column.length == 1
|
60
|
+
options[:column] = column[0]
|
61
|
+
end
|
62
|
+
if primary_key.is_a?(Array) and primary_key.length == 1
|
63
|
+
options[:primary_key] = primary_key[0]
|
64
|
+
end
|
74
65
|
|
75
66
|
ACTIONS.has_key?(on_update) or raise(ArgumentError, "invalid :on_update action: #{on_update.inspect}") if on_update
|
76
67
|
ACTIONS.has_key?(on_delete) or raise(ArgumentError, "invalid :on_delete action: #{on_delete.inspect}") if on_delete
|
@@ -80,35 +71,36 @@ module SchemaPlus
|
|
80
71
|
end
|
81
72
|
end
|
82
73
|
|
83
|
-
|
84
|
-
from_table
|
85
|
-
end
|
86
|
-
|
87
|
-
def references_table_name
|
88
|
-
to_table
|
89
|
-
end
|
90
|
-
|
91
|
-
# True if the constraint is deferrable
|
74
|
+
# Truthy if the constraint is deferrable
|
92
75
|
def deferrable
|
93
76
|
options[:deferrable]
|
94
77
|
end
|
95
78
|
|
96
79
|
# Dumps a definition of foreign key.
|
97
80
|
def to_dump(opts={})
|
98
|
-
|
99
|
-
dump
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
dump << "
|
105
|
-
|
81
|
+
opts = opts.keyword_args(:column, :inline)
|
82
|
+
dump = case
|
83
|
+
when opts.column then "foreign_key: {references:"
|
84
|
+
when opts.inline then "t.foreign_key"
|
85
|
+
else "add_foreign_key #{from_table.inspect},"
|
86
|
+
end
|
87
|
+
dump << " #{to_table.inspect}"
|
88
|
+
|
89
|
+
val_or_array = -> val { val.is_a?(Array) ? "[#{val.map(&:inspect).join(', ')}]" : val.inspect }
|
90
|
+
|
91
|
+
dump << ", column: #{val_or_array.call column}" unless opts.column
|
92
|
+
dump << ", primary_key: #{val_or_array.call column}" if custom_primary_key?
|
93
|
+
dump << ", name: #{name.inspect}" if name
|
94
|
+
dump << ", on_update: #{on_update.inspect}" if on_update
|
95
|
+
dump << ", on_delete: #{on_delete.inspect}" if on_delete
|
96
|
+
dump << ", deferrable: #{deferrable.inspect}" if deferrable
|
97
|
+
dump << "}" if opts.column
|
106
98
|
dump
|
107
99
|
end
|
108
100
|
|
109
101
|
def to_sql
|
110
102
|
sql = name ? "CONSTRAINT #{name} " : ""
|
111
|
-
sql << "FOREIGN KEY (#{quoted_column_names.join(", ")}) REFERENCES #{
|
103
|
+
sql << "FOREIGN KEY (#{quoted_column_names.join(", ")}) REFERENCES #{quoted_to_table} (#{quoted_primary_keys.join(", ")})"
|
112
104
|
sql << " ON UPDATE #{ACTIONS[on_update]}" if on_update
|
113
105
|
sql << " ON DELETE #{ACTIONS[on_delete]}" if on_delete
|
114
106
|
sql << " DEFERRABLE" if deferrable
|
@@ -117,35 +109,23 @@ module SchemaPlus
|
|
117
109
|
end
|
118
110
|
|
119
111
|
def quoted_column_names
|
120
|
-
Array(
|
112
|
+
Array(column).map { |name| ::ActiveRecord::Base.connection.quote_column_name(name) }
|
121
113
|
end
|
122
114
|
|
123
|
-
def
|
124
|
-
Array(
|
125
|
-
end
|
126
|
-
|
127
|
-
def quoted_references_table_name
|
128
|
-
::ActiveRecord::Base.connection.quote_table_name(references_table_name)
|
129
|
-
end
|
130
|
-
|
131
|
-
def unquote(names)
|
132
|
-
if names.is_a?(Array)
|
133
|
-
names.collect { |name| __unquote(name) }
|
134
|
-
else
|
135
|
-
__unquote(names)
|
136
|
-
end
|
115
|
+
def quoted_primary_keys
|
116
|
+
Array(primary_key).map { |name| ::ActiveRecord::Base.connection.quote_column_name(name) }
|
137
117
|
end
|
138
118
|
|
139
|
-
def
|
140
|
-
|
119
|
+
def quoted_to_table
|
120
|
+
::ActiveRecord::Base.connection.quote_table_name(to_table)
|
141
121
|
end
|
142
122
|
|
143
|
-
def self.default_name(
|
144
|
-
"fk_#{fixup_schema_name(
|
123
|
+
def self.default_name(from_table, column)
|
124
|
+
"fk_#{fixup_schema_name(from_table)}_#{Array.wrap(column).join('_and_')}"
|
145
125
|
end
|
146
126
|
|
147
|
-
def self.auto_index_name(
|
148
|
-
"fk__#{fixup_schema_name(
|
127
|
+
def self.auto_index_name(from_table, column_name)
|
128
|
+
"fk__#{fixup_schema_name(from_table)}_#{Array.wrap(column_name).join('_and_')}"
|
149
129
|
end
|
150
130
|
|
151
131
|
def self.fixup_schema_name(table_name)
|
@@ -153,12 +133,11 @@ module SchemaPlus
|
|
153
133
|
table_name.to_s.gsub(/[.]/, '_')
|
154
134
|
end
|
155
135
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
].all? { |attr| self.send(attr) == other.send(attr) }
|
136
|
+
def match(test)
|
137
|
+
return false unless from_table == test.from_table
|
138
|
+
[:to_table, :column].reject{ |attr| test.send(attr).blank? }.all? { |attr|
|
139
|
+
test.send(attr).to_s == self.send(attr).to_s
|
140
|
+
}
|
162
141
|
end
|
163
142
|
end
|
164
143
|
end
|