pry-helper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,550 @@
1
+ require 'active_support/concern'
2
+
3
+ module PryHelper
4
+ module Concerns
5
+ module TableDataDefinition
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+
10
+ # Add a new +type+ column named +column_name+ to +table_name+.
11
+ #
12
+ # The +type+ parameter is normally one of the migrations native types,
13
+ # which is one of the following:
14
+ # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
15
+ # <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
16
+ # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
17
+ # <tt>:binary</tt>, <tt>:boolean</tt>.
18
+ #
19
+ # You may use a type not in this list as long as it is supported by your
20
+ # database (for example, "polygon" in MySQL), but this will not be database
21
+ # agnostic and should usually be avoided.
22
+ #
23
+ # Available options are (none of these exists by default):
24
+ # * <tt>:limit</tt> -
25
+ # Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
26
+ # and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
27
+ # This option is ignored by some backends.
28
+ # * <tt>:default</tt> -
29
+ # The column's default value. Use +nil+ for +NULL+.
30
+ # * <tt>:null</tt> -
31
+ # Allows or disallows +NULL+ values in the column.
32
+ # * <tt>:precision</tt> -
33
+ # Specifies the precision for the <tt>:decimal</tt>, <tt>:numeric</tt>,
34
+ # <tt>:datetime</tt>, and <tt>:time</tt> columns.
35
+ # * <tt>:scale</tt> -
36
+ # Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
37
+ # * <tt>:collation</tt> -
38
+ # Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column. If not specified, the
39
+ # column will have the same collation as the table.
40
+ # * <tt>:comment</tt> -
41
+ # Specifies the comment for the column. This option is ignored by some backends.
42
+ #
43
+ # Note: The precision is the total number of significant digits,
44
+ # and the scale is the number of digits that can be stored following
45
+ # the decimal point. For example, the number 123.45 has a precision of 5
46
+ # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
47
+ # range from -999.99 to 999.99.
48
+ #
49
+ # Please be aware of different RDBMS implementations behavior with
50
+ # <tt>:decimal</tt> columns:
51
+ # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
52
+ # <tt>:precision</tt>, and makes no comments about the requirements of
53
+ # <tt>:precision</tt>.
54
+ # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
55
+ # Default is (10,0).
56
+ # * PostgreSQL: <tt>:precision</tt> [1..infinity],
57
+ # <tt>:scale</tt> [0..infinity]. No default.
58
+ # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
59
+ # but the maximum supported <tt>:precision</tt> is 16. No default.
60
+ # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
61
+ # Default is (38,0).
62
+ # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
63
+ # Default unknown.
64
+ # * SqlServer: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
65
+ # Default (38,0).
66
+ #
67
+ # == Examples
68
+ #
69
+ # User.add_column(:picture, :binary, limit: 2.megabytes)
70
+ # # ALTER TABLE "users" ADD "picture" blob(2097152)
71
+ #
72
+ # Article.add_column(:status, :string, limit: 20, default: 'draft', null: false)
73
+ # # ALTER TABLE "articles" ADD "status" varchar(20) DEFAULT 'draft' NOT NULL
74
+ #
75
+ # Answer.add_column(:bill_gates_money, :decimal, precision: 15, scale: 2)
76
+ # # ALTER TABLE "answers" ADD "bill_gates_money" decimal(15,2)
77
+ #
78
+ # Measurement.add_column(:sensor_reading, :decimal, precision: 30, scale: 20)
79
+ # # ALTER TABLE "measurements" ADD "sensor_reading" decimal(30,20)
80
+ #
81
+ # # While :scale defaults to zero on most databases, it
82
+ # # probably wouldn't hurt to include it.
83
+ # Measurement.add_column(:huge_integer, :decimal, precision: 30)
84
+ # # ALTER TABLE "measurements" ADD "huge_integer" decimal(30)
85
+ #
86
+ # # Defines a column that stores an array of a type.
87
+ # User.add_column(:skills, :text, array: true)
88
+ # # ALTER TABLE "users" ADD "skills" text[]
89
+ #
90
+ # # Defines a column with a database-specific type.
91
+ # Shape.add_column(:triangle, 'polygon')
92
+ # # ALTER TABLE "shapes" ADD "triangle" polygon
93
+ def add_column(column_name, type, **options)
94
+ ActiveRecord::Base.connection.add_column(table_name, column_name, type, **options)
95
+ end
96
+
97
+ # Changes the column's definition according to the new options.
98
+ # See TableDefinition#column for details of the options you can use.
99
+ #
100
+ # Supplier.change_column(:name, :string, limit: 80)
101
+ # Post.change_column(:description, :text)
102
+ #
103
+ def change_column(column_name, type, options = {})
104
+ ActiveRecord::Base.connection.change_column(table_name, column_name, type, options)
105
+ end
106
+
107
+ # Removes the column from the table definition.
108
+ #
109
+ # Supplier.remove_column(:qualification)
110
+ #
111
+ # The +type+ and +options+ parameters will be ignored if present. It can be helpful
112
+ # to provide these in a migration's +change+ method so it can be reverted.
113
+ # In that case, +type+ and +options+ will be used by #add_column.
114
+ # Indexes on the column are automatically removed.
115
+ def remove_column(column_name, type = nil, **options)
116
+ ActiveRecord::Base.connection.remove_column(table_name, column_name, type, **options)
117
+ end
118
+
119
+ # Adds a new index to the table. +column_name+ can be a single Symbol, or
120
+ # an Array of Symbols.
121
+ #
122
+ # The index will be named after the table and the column name(s), unless
123
+ # you pass <tt>:name</tt> as an option.
124
+ #
125
+ # ====== Creating a simple index
126
+ #
127
+ # Supplier.add_index(:name)
128
+ #
129
+ # generates:
130
+ #
131
+ # CREATE INDEX suppliers_name_index ON suppliers(name)
132
+ #
133
+ # ====== Creating a unique index
134
+ #
135
+ # Account.add_index([:branch_id, :party_id], unique: true)
136
+ #
137
+ # generates:
138
+ #
139
+ # CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
140
+ #
141
+ # ====== Creating a named index
142
+ #
143
+ # Account.add_index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
144
+ #
145
+ # generates:
146
+ #
147
+ # CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
148
+ #
149
+ # ====== Creating an index with specific key length
150
+ #
151
+ # Account.add_index(:name, name: 'by_name', length: 10)
152
+ #
153
+ # generates:
154
+ #
155
+ # CREATE INDEX by_name ON accounts(name(10))
156
+ #
157
+ # ====== Creating an index with specific key lengths for multiple keys
158
+ #
159
+ # Account.add_index([:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
160
+ #
161
+ # generates:
162
+ #
163
+ # CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
164
+ #
165
+ # Note: SQLite doesn't support index length.
166
+ #
167
+ # ====== Creating an index with a sort order (desc or asc, asc is the default)
168
+ #
169
+ # Account.add_index([:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
170
+ #
171
+ # generates:
172
+ #
173
+ # CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
174
+ #
175
+ # Note: MySQL only supports index order from 8.0.1 onwards (earlier versions accepted the syntax but ignored it).
176
+ #
177
+ # ====== Creating a partial index
178
+ #
179
+ # Account.add_index([:branch_id, :party_id], unique: true, where: "active")
180
+ #
181
+ # generates:
182
+ #
183
+ # CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
184
+ #
185
+ # Note: Partial indexes are only supported for PostgreSQL and SQLite 3.8.0+.
186
+ #
187
+ # ====== Creating an index with a specific method
188
+ #
189
+ # Developer.add_index(:name, using: 'btree')
190
+ #
191
+ # generates:
192
+ #
193
+ # CREATE INDEX index_developers_on_name ON developers USING btree (name) -- PostgreSQL
194
+ # CREATE INDEX index_developers_on_name USING btree ON developers (name) -- MySQL
195
+ #
196
+ # Note: only supported by PostgreSQL and MySQL
197
+ #
198
+ # ====== Creating an index with a specific operator class
199
+ #
200
+ # Developer.add_index(:name, using: 'gist', opclass: :gist_trgm_ops)
201
+ # # CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
202
+ #
203
+ # Developer.add_index([:name, :city], using: 'gist', opclass: { city: :gist_trgm_ops })
204
+ # # CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
205
+ #
206
+ # Developer.add_index([:name, :city], using: 'gist', opclass: :gist_trgm_ops)
207
+ # # CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
208
+ #
209
+ # Note: only supported by PostgreSQL
210
+ #
211
+ # ====== Creating an index with a specific type
212
+ #
213
+ # Developer.add_index(:name, type: :fulltext)
214
+ #
215
+ # generates:
216
+ #
217
+ # CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
218
+ #
219
+ # Note: only supported by MySQL.
220
+ #
221
+ # ====== Creating an index with a specific algorithm
222
+ #
223
+ # Developer.add_index(:name, algorithm: :concurrently)
224
+ # # CREATE INDEX CONCURRENTLY developers_on_name on developers (name)
225
+ #
226
+ # Note: only supported by PostgreSQL.
227
+ #
228
+ # Concurrently adding an index is not supported in a transaction.
229
+ #
230
+ # For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
231
+ def add_index(column_name, options = {})
232
+ ActiveRecord::Base.connection.add_index(table_name, column_name, options)
233
+ end
234
+
235
+ # Adds a new foreign key.
236
+ # +to_table+ contains the referenced primary key.
237
+ #
238
+ # The foreign key will be named after the following pattern: <tt>fk_rails_<identifier></tt>.
239
+ # +identifier+ is a 10 character long string which is deterministically generated from this
240
+ # table and +column+. A custom name can be specified with the <tt>:name</tt> option.
241
+ #
242
+ # ====== Creating a simple foreign key
243
+ #
244
+ # Article.add_foreign_key :authors
245
+ #
246
+ # generates:
247
+ #
248
+ # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
249
+ #
250
+ # ====== Creating a foreign key on a specific column
251
+ #
252
+ # Article.add_foreign_key :users, column: :author_id, primary_key: "lng_id"
253
+ #
254
+ # generates:
255
+ #
256
+ # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id")
257
+ #
258
+ # ====== Creating a cascading foreign key
259
+ #
260
+ # Article.add_foreign_key :authors, on_delete: :cascade
261
+ #
262
+ # generates:
263
+ #
264
+ # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
265
+ #
266
+ # The +options+ hash can include the following keys:
267
+ # [<tt>:column</tt>]
268
+ # The foreign key column name on +from_table+. Defaults to <tt>to_table.singularize + "_id"</tt>
269
+ # [<tt>:primary_key</tt>]
270
+ # The primary key column name on +to_table+. Defaults to +id+.
271
+ # [<tt>:name</tt>]
272
+ # The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
273
+ # [<tt>:on_delete</tt>]
274
+ # Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
275
+ # [<tt>:on_update</tt>]
276
+ # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
277
+ # [<tt>:validate</tt>]
278
+ # (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
279
+ def add_foreign_key(to_table, **options)
280
+ ActiveRecord::Base.connection.add_foreign_key(table_name, to_table, **options)
281
+ end
282
+
283
+ # Adds timestamps (+created_at+ and +updated_at+) columns to this table.
284
+ # Additional options (like +:null+) are forwarded to #add_column.
285
+ #
286
+ # Supplier.add_timestamps(null: true)
287
+ #
288
+ def add_timestamps(**options)
289
+ ActiveRecord::Base.connection.add_timestamps(table_name, **options)
290
+ end
291
+
292
+ # Changes the comment for a column or removes it if +nil+.
293
+ #
294
+ # Passing a hash containing +:from+ and +:to+ will make this change
295
+ # reversible in migration:
296
+ #
297
+ # Post.change_column_comment(:state, from: "old_comment", to: "new_comment")
298
+ def change_column_comment(column_name, comment_or_changes)
299
+ ActiveRecord::Base.connection.change_column_comment(table_name, column_name, comment_or_changes)
300
+ end
301
+
302
+ # Sets a new default value for a column:
303
+ #
304
+ # Supplier.change_column_default(:qualification, 'new')
305
+ # change_column_default(:accounts, :authorized, 1)
306
+ #
307
+ # Setting the default to +nil+ effectively drops the default:
308
+ #
309
+ # User.change_column_default(:email, nil)
310
+ #
311
+ # Passing a hash containing +:from+ and +:to+ will make this change
312
+ # reversible in migration:
313
+ #
314
+ # Post.change_column_default(:state, from: nil, to: "draft")
315
+ #
316
+ def change_column_default(column_name, default_or_changes)
317
+ ActiveRecord::Base.connection.change_column_default(table_name, column_name, default_or_changes)
318
+ end
319
+
320
+ # Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag
321
+ # indicates whether the value can be +NULL+. For example
322
+ #
323
+ # User.change_column_null(:nickname, false)
324
+ #
325
+ # says nicknames cannot be +NULL+ (adds the constraint), whereas
326
+ #
327
+ # User.change_column_null(:nickname, true)
328
+ #
329
+ # allows them to be +NULL+ (drops the constraint).
330
+ #
331
+ # The method accepts an optional fourth argument to replace existing
332
+ # <tt>NULL</tt>s with some other value. Use that one when enabling the
333
+ # constraint if needed, since otherwise those rows would not be valid.
334
+ #
335
+ # Please note the fourth argument does not set a column's default.
336
+ def change_column_null(column_name, null, default = nil)
337
+ ActiveRecord::Base.connection.change_column_null(table_name, column_name, null, default)
338
+ end
339
+
340
+ # Renames a column.
341
+ #
342
+ # Supplier.rename_column(:description, :name)
343
+ #
344
+ def rename_column(column_name, new_column_name)
345
+ ActiveRecord::Base.connection.rename_column(table_name, column_name, new_column_name)
346
+ end
347
+
348
+ # A block for changing columns in +table+.
349
+ #
350
+ # # change_table() yields a Table instance
351
+ # Supplier.change_table do |t|
352
+ # t.column :name, :string, limit: 60
353
+ # # Other column alterations here
354
+ # end
355
+ #
356
+ # The +options+ hash can include the following keys:
357
+ # [<tt>:bulk</tt>]
358
+ # Set this to true to make this a bulk alter query, such as
359
+ #
360
+ # ALTER TABLE `users` ADD COLUMN age INT, ADD COLUMN birthdate DATETIME ...
361
+ #
362
+ # Defaults to false.
363
+ #
364
+ # Only supported on the MySQL and PostgreSQL adapter, ignored elsewhere.
365
+ #
366
+ # ====== Add a column
367
+ #
368
+ # Supplier.change_table do |t|
369
+ # t.column :name, :string, limit: 60
370
+ # end
371
+ #
372
+ # ====== Add 2 integer columns
373
+ #
374
+ # Supplier.change_table do |t|
375
+ # t.integer :width, :height, null: false, default: 0
376
+ # end
377
+ #
378
+ # ====== Add created_at/updated_at columns
379
+ #
380
+ # Supplier.change_table do |t|
381
+ # t.timestamps
382
+ # end
383
+ #
384
+ # ====== Add a foreign key column
385
+ #
386
+ # Supplier.change_table do |t|
387
+ # t.references :company
388
+ # end
389
+ #
390
+ # Creates a <tt>company_id(bigint)</tt> column.
391
+ #
392
+ # ====== Add a polymorphic foreign key column
393
+ #
394
+ # Supplier.change_table do |t|
395
+ # t.belongs_to :company, polymorphic: true
396
+ # end
397
+ #
398
+ # Creates <tt>company_type(varchar)</tt> and <tt>company_id(bigint)</tt> columns.
399
+ #
400
+ # ====== Remove a column
401
+ #
402
+ # Supplier.change_table do |t|
403
+ # t.remove :company
404
+ # end
405
+ #
406
+ # ====== Remove several columns
407
+ #
408
+ # Supplier.change_table do |t|
409
+ # t.remove :company_id
410
+ # t.remove :width, :height
411
+ # end
412
+ #
413
+ # ====== Remove an index
414
+ #
415
+ # Supplier.change_table do |t|
416
+ # t.remove_index :company_id
417
+ # end
418
+ #
419
+ # See also Table for details on all of the various column transformations.
420
+ def change_table(**options)
421
+ ActiveRecord::Base.connection.change_table(table_name, **options)
422
+ end
423
+
424
+ # Renames a table.
425
+ #
426
+ # rename_table('octopi')
427
+ #
428
+ def rename_table(new_name)
429
+ ActiveRecord::Base.connection.rename_table(table_name, new_name)
430
+ end
431
+
432
+ # Changes the comment for a table or removes it if +nil+.
433
+ #
434
+ # Passing a hash containing +:from+ and +:to+ will make this change
435
+ # reversible in migration:
436
+ #
437
+ # Post.change_table_comment(from: "old_comment", to: "new_comment")
438
+ def change_table_comment(comment_or_changes)
439
+ ActiveRecord::Base.connection.change_table_comment(table_name, comment_or_changes)
440
+ end
441
+
442
+ # Drops a table from the database.
443
+ #
444
+ # [<tt>:force</tt>]
445
+ # Set to +:cascade+ to drop dependent objects as well.
446
+ # Defaults to false.
447
+ # [<tt>:if_exists</tt>]
448
+ # Set to +true+ to only drop the table if it exists.
449
+ # Defaults to false.
450
+ #
451
+ # Although this command ignores most +options+ and the block if one is given,
452
+ # it can be helpful to provide these in a migration's +change+ method so it can be reverted.
453
+ # In that case, +options+ and the block will be used by #create_table.
454
+ def drop_table(**options)
455
+ ActiveRecord::Base.connection.drop_table(table_name, **options)
456
+ end
457
+
458
+ # Returns an array of foreign keys for the given table.
459
+ # The foreign keys are represented as ForeignKeyDefinition objects.
460
+ def foreign_keys
461
+ ActiveRecord::Base.connection.foreign_keys(table_name)
462
+ end
463
+
464
+ # Removes the given foreign key from the table. Any option parameters provided
465
+ # will be used to re-add the foreign key in case of a migration rollback.
466
+ # It is recommended that you provide any options used when creating the foreign
467
+ # key so that the migration can be reverted properly.
468
+ #
469
+ # Removes the foreign key on +accounts.branch_id+.
470
+ #
471
+ # Account.remove_foreign_key :branches
472
+ #
473
+ # Removes the foreign key on +accounts.owner_id+.
474
+ #
475
+ # Account.remove_foreign_key column: :owner_id
476
+ #
477
+ # Removes the foreign key on +accounts.owner_id+.
478
+ #
479
+ # Account.remove_foreign_key to_table: :owners
480
+ #
481
+ # Removes the foreign key named +special_fk_name+ on the +accounts+ table.
482
+ #
483
+ # Account.remove_foreign_key name: :special_fk_name
484
+ #
485
+ # The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
486
+ # with an addition of
487
+ # [<tt>:to_table</tt>]
488
+ # The name of the table that contains the referenced primary key.
489
+ def remove_foreign_key(to_table = nil, **options)
490
+ ActiveRecord::Base.connection.remove_foreign_key(table_name, to_table, **options)
491
+ end
492
+
493
+ # Removes the given index from the table.
494
+ #
495
+ # Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
496
+ #
497
+ # Account.remove_index :branch_id
498
+ #
499
+ # Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
500
+ #
501
+ # Account.remove_index column: :branch_id
502
+ #
503
+ # Removes the index on +branch_id+ and +party_id+ in the +accounts+ table if exactly one such index exists.
504
+ #
505
+ # Account.remove_index column: [:branch_id, :party_id]
506
+ #
507
+ # Removes the index named +by_branch_party+ in the +accounts+ table.
508
+ #
509
+ # Account.remove_index name: :by_branch_party
510
+ #
511
+ # Removes the index named +by_branch_party+ in the +accounts+ table +concurrently+.
512
+ #
513
+ # Account.remove_index name: :by_branch_party, algorithm: :concurrently
514
+ #
515
+ # Note: only supported by PostgreSQL.
516
+ #
517
+ # Concurrently removing an index is not supported in a transaction.
518
+ #
519
+ # For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
520
+ def remove_index(options = {})
521
+ ActiveRecord::Base.connection.remove_index(table_name, options)
522
+ end
523
+
524
+ # Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
525
+ #
526
+ # Supplier.remove_timestamps
527
+ #
528
+ def remove_timestamps(**options)
529
+ ActiveRecord::Base.connection.remove_timestamps(**options)
530
+ end
531
+
532
+ # Renames an index.
533
+ #
534
+ # Rename the +index_people_on_last_name+ index to +index_users_on_last_name+:
535
+ #
536
+ # Person.rename_index 'index_people_on_last_name', 'index_users_on_last_name'
537
+ #
538
+ def rename_index(old_name, new_name)
539
+ ActiveRecord::Base.connection.rename_index(table_name, old_name, new_name)
540
+ end
541
+
542
+ # Returns the table comment that's stored in database metadata.
543
+ def table_comment
544
+ ActiveRecord::Base.connection.table_comment(table_name)
545
+ end
546
+
547
+ end
548
+ end
549
+ end
550
+ end
@@ -0,0 +1,2 @@
1
+ require 'pry-helper/concerns/global_data_definition'
2
+ require 'pry-helper/concerns/table_data_definition'