square-activerecord 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6140 -0
- data/README.rdoc +222 -0
- data/examples/associations.png +0 -0
- data/examples/performance.rb +179 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +124 -0
- data/lib/active_record/aggregations.rb +277 -0
- data/lib/active_record/association_preload.rb +430 -0
- data/lib/active_record/associations.rb +2307 -0
- data/lib/active_record/associations/association_collection.rb +572 -0
- data/lib/active_record/associations/association_proxy.rb +299 -0
- data/lib/active_record/associations/belongs_to_association.rb +91 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +82 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
- data/lib/active_record/associations/has_many_association.rb +128 -0
- data/lib/active_record/associations/has_many_through_association.rb +115 -0
- data/lib/active_record/associations/has_one_association.rb +143 -0
- data/lib/active_record/associations/has_one_through_association.rb +40 -0
- data/lib/active_record/associations/through_association_scope.rb +154 -0
- data/lib/active_record/attribute_methods.rb +60 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +30 -0
- data/lib/active_record/attribute_methods/dirty.rb +95 -0
- data/lib/active_record/attribute_methods/primary_key.rb +56 -0
- data/lib/active_record/attribute_methods/query.rb +39 -0
- data/lib/active_record/attribute_methods/read.rb +145 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +64 -0
- data/lib/active_record/attribute_methods/write.rb +43 -0
- data/lib/active_record/autosave_association.rb +369 -0
- data/lib/active_record/base.rb +1904 -0
- data/lib/active_record/callbacks.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +364 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +333 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +73 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +539 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +217 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +657 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1031 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +401 -0
- data/lib/active_record/counter_cache.rb +115 -0
- data/lib/active_record/dynamic_finder_match.rb +56 -0
- data/lib/active_record/dynamic_scope_match.rb +23 -0
- data/lib/active_record/errors.rb +172 -0
- data/lib/active_record/fixtures.rb +1006 -0
- data/lib/active_record/locale/en.yml +40 -0
- data/lib/active_record/locking/optimistic.rb +172 -0
- data/lib/active_record/locking/pessimistic.rb +55 -0
- data/lib/active_record/log_subscriber.rb +48 -0
- data/lib/active_record/migration.rb +617 -0
- data/lib/active_record/named_scope.rb +138 -0
- data/lib/active_record/nested_attributes.rb +419 -0
- data/lib/active_record/observer.rb +125 -0
- data/lib/active_record/persistence.rb +290 -0
- data/lib/active_record/query_cache.rb +36 -0
- data/lib/active_record/railtie.rb +91 -0
- data/lib/active_record/railties/controller_runtime.rb +38 -0
- data/lib/active_record/railties/databases.rake +512 -0
- data/lib/active_record/reflection.rb +411 -0
- data/lib/active_record/relation.rb +394 -0
- data/lib/active_record/relation/batches.rb +89 -0
- data/lib/active_record/relation/calculations.rb +295 -0
- data/lib/active_record/relation/finder_methods.rb +363 -0
- data/lib/active_record/relation/predicate_builder.rb +48 -0
- data/lib/active_record/relation/query_methods.rb +303 -0
- data/lib/active_record/relation/spawn_methods.rb +132 -0
- data/lib/active_record/schema.rb +59 -0
- data/lib/active_record/schema_dumper.rb +195 -0
- data/lib/active_record/serialization.rb +60 -0
- data/lib/active_record/serializers/xml_serializer.rb +244 -0
- data/lib/active_record/session_store.rb +340 -0
- data/lib/active_record/test_case.rb +67 -0
- data/lib/active_record/timestamp.rb +88 -0
- data/lib/active_record/transactions.rb +359 -0
- data/lib/active_record/validations.rb +84 -0
- data/lib/active_record/validations/associated.rb +48 -0
- data/lib/active_record/validations/uniqueness.rb +190 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/rails/generators/active_record.rb +19 -0
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
- data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
- data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
- metadata +223 -0
@@ -0,0 +1,539 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters # :nodoc:
|
5
|
+
module SchemaStatements
|
6
|
+
# Returns a Hash of mappings from the abstract data types to the native
|
7
|
+
# database types. See TableDefinition#column for details on the recognized
|
8
|
+
# abstract data types.
|
9
|
+
def native_database_types
|
10
|
+
{}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Truncates a table alias according to the limits of the current adapter.
|
14
|
+
def table_alias_for(table_name)
|
15
|
+
table_name[0..table_alias_length-1].gsub(/\./, '_')
|
16
|
+
end
|
17
|
+
|
18
|
+
# def tables(name = nil) end
|
19
|
+
|
20
|
+
def table_exists?(table_name)
|
21
|
+
tables.include?(table_name.to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns an array of indexes for the given table.
|
25
|
+
# def indexes(table_name, name = nil) end
|
26
|
+
|
27
|
+
# Checks to see if an index exists on a table for a given index definition
|
28
|
+
#
|
29
|
+
# === Examples
|
30
|
+
# # Check an index exists
|
31
|
+
# index_exists?(:suppliers, :company_id)
|
32
|
+
#
|
33
|
+
# # Check an index on multiple columns exists
|
34
|
+
# index_exists?(:suppliers, [:company_id, :company_type])
|
35
|
+
#
|
36
|
+
# # Check a unique index exists
|
37
|
+
# index_exists?(:suppliers, :company_id, :unique => true)
|
38
|
+
#
|
39
|
+
# # Check an index with a custom name exists
|
40
|
+
# index_exists?(:suppliers, :company_id, :name => "idx_company_id"
|
41
|
+
def index_exists?(table_name, column_name, options = {})
|
42
|
+
column_names = Array.wrap(column_name)
|
43
|
+
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names)
|
44
|
+
if options[:unique]
|
45
|
+
indexes(table_name).any?{ |i| i.unique && i.name == index_name }
|
46
|
+
else
|
47
|
+
indexes(table_name).any?{ |i| i.name == index_name }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns an array of Column objects for the table specified by +table_name+.
|
52
|
+
# See the concrete implementation for details on the expected parameter values.
|
53
|
+
def columns(table_name, name = nil) end
|
54
|
+
|
55
|
+
# Checks to see if a column exists in a given table.
|
56
|
+
#
|
57
|
+
# === Examples
|
58
|
+
# # Check a column exists
|
59
|
+
# column_exists?(:suppliers, :name)
|
60
|
+
#
|
61
|
+
# # Check a column exists of a particular type
|
62
|
+
# column_exists?(:suppliers, :name, :string)
|
63
|
+
#
|
64
|
+
# # Check a column exists with a specific definition
|
65
|
+
# column_exists?(:suppliers, :name, :string, :limit => 100)
|
66
|
+
def column_exists?(table_name, column_name, type = nil, options = {})
|
67
|
+
columns(table_name).any?{ |c| c.name == column_name.to_s &&
|
68
|
+
(!type || c.type == type) &&
|
69
|
+
(!options[:limit] || c.limit == options[:limit]) &&
|
70
|
+
(!options[:precision] || c.precision == options[:precision]) &&
|
71
|
+
(!options[:scale] || c.scale == options[:scale]) }
|
72
|
+
end
|
73
|
+
|
74
|
+
# Creates a new table with the name +table_name+. +table_name+ may either
|
75
|
+
# be a String or a Symbol.
|
76
|
+
#
|
77
|
+
# There are two ways to work with +create_table+. You can use the block
|
78
|
+
# form or the regular form, like this:
|
79
|
+
#
|
80
|
+
# === Block form
|
81
|
+
# # create_table() passes a TableDefinition object to the block.
|
82
|
+
# # This form will not only create the table, but also columns for the
|
83
|
+
# # table.
|
84
|
+
#
|
85
|
+
# create_table(:suppliers) do |t|
|
86
|
+
# t.column :name, :string, :limit => 60
|
87
|
+
# # Other fields here
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# === Block form, with shorthand
|
91
|
+
# # You can also use the column types as method calls, rather than calling the column method.
|
92
|
+
# create_table(:suppliers) do |t|
|
93
|
+
# t.string :name, :limit => 60
|
94
|
+
# # Other fields here
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# === Regular form
|
98
|
+
# # Creates a table called 'suppliers' with no columns.
|
99
|
+
# create_table(:suppliers)
|
100
|
+
# # Add a column to 'suppliers'.
|
101
|
+
# add_column(:suppliers, :name, :string, {:limit => 60})
|
102
|
+
#
|
103
|
+
# The +options+ hash can include the following keys:
|
104
|
+
# [<tt>:id</tt>]
|
105
|
+
# Whether to automatically add a primary key column. Defaults to true.
|
106
|
+
# Join tables for +has_and_belongs_to_many+ should set it to false.
|
107
|
+
# [<tt>:primary_key</tt>]
|
108
|
+
# The name of the primary key, if one is to be added automatically.
|
109
|
+
# Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
|
110
|
+
#
|
111
|
+
# Also note that this just sets the primary key in the table. You additionally
|
112
|
+
# need to configure the primary key in the model via the +set_primary_key+ macro.
|
113
|
+
# Models do NOT auto-detect the primary key from their table definition.
|
114
|
+
#
|
115
|
+
# [<tt>:options</tt>]
|
116
|
+
# Any extra options you want appended to the table definition.
|
117
|
+
# [<tt>:temporary</tt>]
|
118
|
+
# Make a temporary table.
|
119
|
+
# [<tt>:force</tt>]
|
120
|
+
# Set to true to drop the table before creating it.
|
121
|
+
# Defaults to false.
|
122
|
+
#
|
123
|
+
# ===== Examples
|
124
|
+
# ====== Add a backend specific option to the generated SQL (MySQL)
|
125
|
+
# create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
126
|
+
# generates:
|
127
|
+
# CREATE TABLE suppliers (
|
128
|
+
# id int(11) DEFAULT NULL auto_increment PRIMARY KEY
|
129
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
130
|
+
#
|
131
|
+
# ====== Rename the primary key column
|
132
|
+
# create_table(:objects, :primary_key => 'guid') do |t|
|
133
|
+
# t.column :name, :string, :limit => 80
|
134
|
+
# end
|
135
|
+
# generates:
|
136
|
+
# CREATE TABLE objects (
|
137
|
+
# guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
|
138
|
+
# name varchar(80)
|
139
|
+
# )
|
140
|
+
#
|
141
|
+
# ====== Do not add a primary key column
|
142
|
+
# create_table(:categories_suppliers, :id => false) do |t|
|
143
|
+
# t.column :category_id, :integer
|
144
|
+
# t.column :supplier_id, :integer
|
145
|
+
# end
|
146
|
+
# generates:
|
147
|
+
# CREATE TABLE categories_suppliers (
|
148
|
+
# category_id int,
|
149
|
+
# supplier_id int
|
150
|
+
# )
|
151
|
+
#
|
152
|
+
# See also TableDefinition#column for details on how to create columns.
|
153
|
+
def create_table(table_name, options = {})
|
154
|
+
table_definition = TableDefinition.new(self)
|
155
|
+
table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
|
156
|
+
|
157
|
+
yield table_definition if block_given?
|
158
|
+
|
159
|
+
if options[:force] && table_exists?(table_name)
|
160
|
+
drop_table(table_name, options)
|
161
|
+
end
|
162
|
+
|
163
|
+
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
|
164
|
+
create_sql << "#{quote_table_name(table_name)} ("
|
165
|
+
create_sql << table_definition.to_sql
|
166
|
+
create_sql << ") #{options[:options]}"
|
167
|
+
execute create_sql
|
168
|
+
end
|
169
|
+
|
170
|
+
# A block for changing columns in +table+.
|
171
|
+
#
|
172
|
+
# === Example
|
173
|
+
# # change_table() yields a Table instance
|
174
|
+
# change_table(:suppliers) do |t|
|
175
|
+
# t.column :name, :string, :limit => 60
|
176
|
+
# # Other column alterations here
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# ===== Examples
|
180
|
+
# ====== Add a column
|
181
|
+
# change_table(:suppliers) do |t|
|
182
|
+
# t.column :name, :string, :limit => 60
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# ====== Add 2 integer columns
|
186
|
+
# change_table(:suppliers) do |t|
|
187
|
+
# t.integer :width, :height, :null => false, :default => 0
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# ====== Add created_at/updated_at columns
|
191
|
+
# change_table(:suppliers) do |t|
|
192
|
+
# t.timestamps
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# ====== Add a foreign key column
|
196
|
+
# change_table(:suppliers) do |t|
|
197
|
+
# t.references :company
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# Creates a <tt>company_id(integer)</tt> column
|
201
|
+
#
|
202
|
+
# ====== Add a polymorphic foreign key column
|
203
|
+
# change_table(:suppliers) do |t|
|
204
|
+
# t.belongs_to :company, :polymorphic => true
|
205
|
+
# end
|
206
|
+
#
|
207
|
+
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns
|
208
|
+
#
|
209
|
+
# ====== Remove a column
|
210
|
+
# change_table(:suppliers) do |t|
|
211
|
+
# t.remove :company
|
212
|
+
# end
|
213
|
+
#
|
214
|
+
# ====== Remove several columns
|
215
|
+
# change_table(:suppliers) do |t|
|
216
|
+
# t.remove :company_id
|
217
|
+
# t.remove :width, :height
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# ====== Remove an index
|
221
|
+
# change_table(:suppliers) do |t|
|
222
|
+
# t.remove_index :company_id
|
223
|
+
# end
|
224
|
+
#
|
225
|
+
# See also Table for details on
|
226
|
+
# all of the various column transformation
|
227
|
+
def change_table(table_name)
|
228
|
+
yield Table.new(table_name, self)
|
229
|
+
end
|
230
|
+
|
231
|
+
# Renames a table.
|
232
|
+
# ===== Example
|
233
|
+
# rename_table('octopuses', 'octopi')
|
234
|
+
def rename_table(table_name, new_name)
|
235
|
+
raise NotImplementedError, "rename_table is not implemented"
|
236
|
+
end
|
237
|
+
|
238
|
+
# Drops a table from the database.
|
239
|
+
def drop_table(table_name, options = {})
|
240
|
+
execute "DROP TABLE #{quote_table_name(table_name)}"
|
241
|
+
end
|
242
|
+
|
243
|
+
# Adds a new column to the named table.
|
244
|
+
# See TableDefinition#column for details of the options you can use.
|
245
|
+
def add_column(table_name, column_name, type, options = {})
|
246
|
+
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
247
|
+
add_column_options!(add_column_sql, options)
|
248
|
+
execute(add_column_sql)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Removes the column(s) from the table definition.
|
252
|
+
# ===== Examples
|
253
|
+
# remove_column(:suppliers, :qualification)
|
254
|
+
# remove_columns(:suppliers, :qualification, :experience)
|
255
|
+
def remove_column(table_name, *column_names)
|
256
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
257
|
+
column_names.flatten.each do |column_name|
|
258
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
alias :remove_columns :remove_column
|
262
|
+
|
263
|
+
# Changes the column's definition according to the new options.
|
264
|
+
# See TableDefinition#column for details of the options you can use.
|
265
|
+
# ===== Examples
|
266
|
+
# change_column(:suppliers, :name, :string, :limit => 80)
|
267
|
+
# change_column(:accounts, :description, :text)
|
268
|
+
def change_column(table_name, column_name, type, options = {})
|
269
|
+
raise NotImplementedError, "change_column is not implemented"
|
270
|
+
end
|
271
|
+
|
272
|
+
# Sets a new default value for a column. If you want to set the default
|
273
|
+
# value to +NULL+, you are out of luck. You need to
|
274
|
+
# DatabaseStatements#execute the appropriate SQL statement yourself.
|
275
|
+
# ===== Examples
|
276
|
+
# change_column_default(:suppliers, :qualification, 'new')
|
277
|
+
# change_column_default(:accounts, :authorized, 1)
|
278
|
+
def change_column_default(table_name, column_name, default)
|
279
|
+
raise NotImplementedError, "change_column_default is not implemented"
|
280
|
+
end
|
281
|
+
|
282
|
+
# Renames a column.
|
283
|
+
# ===== Example
|
284
|
+
# rename_column(:suppliers, :description, :name)
|
285
|
+
def rename_column(table_name, column_name, new_column_name)
|
286
|
+
raise NotImplementedError, "rename_column is not implemented"
|
287
|
+
end
|
288
|
+
|
289
|
+
# Adds a new index to the table. +column_name+ can be a single Symbol, or
|
290
|
+
# an Array of Symbols.
|
291
|
+
#
|
292
|
+
# The index will be named after the table and the first column name,
|
293
|
+
# unless you pass <tt>:name</tt> as an option.
|
294
|
+
#
|
295
|
+
# When creating an index on multiple columns, the first column is used as a name
|
296
|
+
# for the index. For example, when you specify an index on two columns
|
297
|
+
# [<tt>:first</tt>, <tt>:last</tt>], the DBMS creates an index for both columns as well as an
|
298
|
+
# index for the first column <tt>:first</tt>. Using just the first name for this index
|
299
|
+
# makes sense, because you will never have to create a singular index with this
|
300
|
+
# name.
|
301
|
+
#
|
302
|
+
# ===== Examples
|
303
|
+
#
|
304
|
+
# ====== Creating a simple index
|
305
|
+
# add_index(:suppliers, :name)
|
306
|
+
# generates
|
307
|
+
# CREATE INDEX suppliers_name_index ON suppliers(name)
|
308
|
+
#
|
309
|
+
# ====== Creating a unique index
|
310
|
+
# add_index(:accounts, [:branch_id, :party_id], :unique => true)
|
311
|
+
# generates
|
312
|
+
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
|
313
|
+
#
|
314
|
+
# ====== Creating a named index
|
315
|
+
# add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
|
316
|
+
# generates
|
317
|
+
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
318
|
+
#
|
319
|
+
# ====== Creating an index with specific key length
|
320
|
+
# add_index(:accounts, :name, :name => 'by_name', :length => 10)
|
321
|
+
# generates
|
322
|
+
# CREATE INDEX by_name ON accounts(name(10))
|
323
|
+
#
|
324
|
+
# add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15})
|
325
|
+
# generates
|
326
|
+
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
327
|
+
#
|
328
|
+
# Note: SQLite doesn't support index length
|
329
|
+
def add_index(table_name, column_name, options = {})
|
330
|
+
column_names = Array.wrap(column_name)
|
331
|
+
index_name = index_name(table_name, :column => column_names)
|
332
|
+
|
333
|
+
if Hash === options # legacy support, since this param was a string
|
334
|
+
index_type = options[:unique] ? "UNIQUE" : ""
|
335
|
+
index_name = options[:name].to_s if options.key?(:name)
|
336
|
+
else
|
337
|
+
index_type = options
|
338
|
+
end
|
339
|
+
|
340
|
+
if index_name.length > index_name_length
|
341
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters"
|
342
|
+
end
|
343
|
+
if index_name_exists?(table_name, index_name, false)
|
344
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
345
|
+
end
|
346
|
+
quoted_column_names = quoted_columns_for_index(column_names, options).join(", ")
|
347
|
+
|
348
|
+
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
|
349
|
+
end
|
350
|
+
|
351
|
+
# Remove the given index from the table.
|
352
|
+
#
|
353
|
+
# Remove the suppliers_name_index in the suppliers table.
|
354
|
+
# remove_index :suppliers, :name
|
355
|
+
# Remove the index named accounts_branch_id_index in the accounts table.
|
356
|
+
# remove_index :accounts, :column => :branch_id
|
357
|
+
# Remove the index named accounts_branch_id_party_id_index in the accounts table.
|
358
|
+
# remove_index :accounts, :column => [:branch_id, :party_id]
|
359
|
+
# Remove the index named by_branch_party in the accounts table.
|
360
|
+
# remove_index :accounts, :name => :by_branch_party
|
361
|
+
def remove_index(table_name, options = {})
|
362
|
+
index_name = index_name(table_name, options)
|
363
|
+
unless index_name_exists?(table_name, index_name, true)
|
364
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
365
|
+
end
|
366
|
+
remove_index!(table_name, index_name)
|
367
|
+
end
|
368
|
+
|
369
|
+
def remove_index!(table_name, index_name) #:nodoc:
|
370
|
+
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
371
|
+
end
|
372
|
+
|
373
|
+
# Rename an index.
|
374
|
+
#
|
375
|
+
# Rename the index_people_on_last_name index to index_users_on_last_name
|
376
|
+
# rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
|
377
|
+
def rename_index(table_name, old_name, new_name)
|
378
|
+
# this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
|
379
|
+
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
380
|
+
return unless old_index_def
|
381
|
+
remove_index(table_name, :name => old_name)
|
382
|
+
add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique)
|
383
|
+
end
|
384
|
+
|
385
|
+
def index_name(table_name, options) #:nodoc:
|
386
|
+
if Hash === options # legacy support
|
387
|
+
if options[:column]
|
388
|
+
"index_#{table_name}_on_#{Array.wrap(options[:column]) * '_and_'}"
|
389
|
+
elsif options[:name]
|
390
|
+
options[:name]
|
391
|
+
else
|
392
|
+
raise ArgumentError, "You must specify the index name"
|
393
|
+
end
|
394
|
+
else
|
395
|
+
index_name(table_name, :column => options)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Verify the existence of an index with a given name.
|
400
|
+
#
|
401
|
+
# The default argument is returned if the underlying implementation does not define the indexes method,
|
402
|
+
# as there's no way to determine the correct answer in that case.
|
403
|
+
def index_name_exists?(table_name, index_name, default)
|
404
|
+
return default unless respond_to?(:indexes)
|
405
|
+
index_name = index_name.to_s
|
406
|
+
indexes(table_name).detect { |i| i.name == index_name }
|
407
|
+
end
|
408
|
+
|
409
|
+
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
|
410
|
+
# entire structure of the database.
|
411
|
+
def structure_dump
|
412
|
+
end
|
413
|
+
|
414
|
+
def dump_schema_information #:nodoc:
|
415
|
+
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
416
|
+
migrated = select_values("SELECT version FROM #{sm_table}")
|
417
|
+
migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n")
|
418
|
+
end
|
419
|
+
|
420
|
+
# Should not be called normally, but this operation is non-destructive.
|
421
|
+
# The migrations module handles this automatically.
|
422
|
+
def initialize_schema_migrations_table
|
423
|
+
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
424
|
+
|
425
|
+
unless table_exists?(sm_table)
|
426
|
+
create_table(sm_table, :id => false) do |schema_migrations_table|
|
427
|
+
schema_migrations_table.column :version, :string, :null => false
|
428
|
+
end
|
429
|
+
add_index sm_table, :version, :unique => true,
|
430
|
+
:name => "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
|
431
|
+
|
432
|
+
# Backwards-compatibility: if we find schema_info, assume we've
|
433
|
+
# migrated up to that point:
|
434
|
+
si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
|
435
|
+
|
436
|
+
if table_exists?(si_table)
|
437
|
+
|
438
|
+
old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
|
439
|
+
assume_migrated_upto_version(old_version)
|
440
|
+
drop_table(si_table)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def assume_migrated_upto_version(version, migrations_path = ActiveRecord::Migrator.migrations_path)
|
446
|
+
version = version.to_i
|
447
|
+
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
448
|
+
|
449
|
+
migrated = select_values("SELECT version FROM #{sm_table}").map { |v| v.to_i }
|
450
|
+
versions = Dir["#{migrations_path}/[0-9]*_*.rb"].map do |filename|
|
451
|
+
filename.split('/').last.split('_').first.to_i
|
452
|
+
end
|
453
|
+
|
454
|
+
unless migrated.include?(version)
|
455
|
+
execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
|
456
|
+
end
|
457
|
+
|
458
|
+
inserted = Set.new
|
459
|
+
(versions - migrated).each do |v|
|
460
|
+
if inserted.include?(v)
|
461
|
+
raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict."
|
462
|
+
elsif v < version
|
463
|
+
execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
|
464
|
+
inserted << v
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
470
|
+
if native = native_database_types[type]
|
471
|
+
column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
|
472
|
+
|
473
|
+
if type == :decimal # ignore limit, use precision and scale
|
474
|
+
scale ||= native[:scale]
|
475
|
+
|
476
|
+
if precision ||= native[:precision]
|
477
|
+
if scale
|
478
|
+
column_type_sql << "(#{precision},#{scale})"
|
479
|
+
else
|
480
|
+
column_type_sql << "(#{precision})"
|
481
|
+
end
|
482
|
+
elsif scale
|
483
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
|
484
|
+
end
|
485
|
+
|
486
|
+
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
487
|
+
column_type_sql << "(#{limit})"
|
488
|
+
end
|
489
|
+
|
490
|
+
column_type_sql
|
491
|
+
else
|
492
|
+
type
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def add_column_options!(sql, options) #:nodoc:
|
497
|
+
sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
|
498
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
499
|
+
if options[:null] == false
|
500
|
+
sql << " NOT NULL"
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
|
505
|
+
# Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.
|
506
|
+
#
|
507
|
+
# distinct("posts.id", "posts.created_at desc")
|
508
|
+
def distinct(columns, order_by)
|
509
|
+
"DISTINCT #{columns}"
|
510
|
+
end
|
511
|
+
|
512
|
+
# Adds timestamps (created_at and updated_at) columns to the named table.
|
513
|
+
# ===== Examples
|
514
|
+
# add_timestamps(:suppliers)
|
515
|
+
def add_timestamps(table_name)
|
516
|
+
add_column table_name, :created_at, :datetime
|
517
|
+
add_column table_name, :updated_at, :datetime
|
518
|
+
end
|
519
|
+
|
520
|
+
# Removes the timestamp columns (created_at and updated_at) from the table definition.
|
521
|
+
# ===== Examples
|
522
|
+
# remove_timestamps(:suppliers)
|
523
|
+
def remove_timestamps(table_name)
|
524
|
+
remove_column table_name, :updated_at
|
525
|
+
remove_column table_name, :created_at
|
526
|
+
end
|
527
|
+
|
528
|
+
protected
|
529
|
+
# Overridden by the mysql adapter for supporting index lengths
|
530
|
+
def quoted_columns_for_index(column_names, options = {})
|
531
|
+
column_names.map {|name| quote_column_name(name) }
|
532
|
+
end
|
533
|
+
|
534
|
+
def options_include_default?(options)
|
535
|
+
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|