rails_steroids 0.5.0 → 0.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 575fafaef4cda7385ace12ae8c8c6ba3469ca6a8720eb54692240a79739ca6c1
4
- data.tar.gz: 764ba190e5246e78820af6bae9598ab498258133b513f0cc26f7767bd90bb2ee
3
+ metadata.gz: 9e8022f4d9c1864d8fb7886a799f32b7f8d0f7db85152a7f29db9810ce104367
4
+ data.tar.gz: 04571a62c83ac2d43d3294189265a9563e351fd43350dea47c413e2738d1b76e
5
5
  SHA512:
6
- metadata.gz: 73d18703d85c492632f3348941505cd748ff34855f4b293a8127128a5c278b07e7716b1e5f9754d296560846f0ce0304b23e7d0452a71b60b2f119d375a3453b
7
- data.tar.gz: c9e6807f7f94a24e956ba7f1e7c8d0348495168c761f149cb8b573a7882f6bbfd823b90dcde840ffc4fa5ea4a8fea2c801f01d398936b60a5a8a9776fcb06492
6
+ metadata.gz: 30fb811636d668a114df763e0f0eb50dffae19cef6ab6e2246a12772cfbabd8e6f3f4d8b66e948bbcd80f646d9233aca061259456b39712c16ecec78b91f36bd
7
+ data.tar.gz: 902918a36f478d5da29a785da787ab4eaf19896354f6c24fe2ca3143aba778b07535f6a689902fea8042085220f22b5e270a846f7f0c50cf37d9d42799e8dbb9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.7.0] - 2024-02-08
4
+
5
+ - Improvement in steroid recipe: migration
6
+ - Create new migration interactively for modify table with
7
+ * add_column, remove_column
8
+ * add_index, remove_index
9
+ * add_remove, remove_reference
10
+
11
+ ## [0.6.0] - 2024-02-07
12
+
13
+ - New steroid recipe: migration
14
+ - Create new migration interactively for
15
+ * Create table
16
+ * Create join table
17
+ * Drop table
18
+
3
19
  ## [0.5.0] - 2024-02-06
4
20
 
5
21
  - New steroid recipe: model (Create new model interactively)
data/README.md CHANGED
@@ -49,6 +49,7 @@ and then enjoy easily entering or selecting options interactively to the questio
49
49
 
50
50
  | Functionality | Command |
51
51
  |---|---|
52
+ |migration|`rails_steroids inject steroid:migration`|
52
53
  |model|`rails_steroids inject steroid:model`|
53
54
  |controller|`rails_steroids inject steroid:controller`|
54
55
  |new_project|`rails_steroids inject steroid:new_project`|
@@ -0,0 +1,25 @@
1
+ Description:
2
+ `steroid:migration` will create Migration interactively.
3
+
4
+ Usage Example:
5
+ # with installed gem
6
+ rails_steroids inject steroid:migration
7
+ # with bundler
8
+ bin/rails g steroid:migration
9
+
10
+ What will this do?:
11
+ Create new Rails migration with configurations selected interactively.
12
+ Current options available to customize are:
13
+ * Create table, Create join table and Drop table
14
+ * Specify columns with column type and some other metadata
15
+ * Column metadata includes:
16
+ - limit for integer, string, text, binary
17
+ - precision and scale for decimal
18
+ - polymorphic for references
19
+ - index and unique index
20
+ - id column, custom join table name for join table creation
21
+ - Addition to original migration generator is we can set default value as well
22
+ * Modify table with
23
+ - add_column, remove_column
24
+ - add_index, remove_index
25
+ - add_remove, remove_reference
@@ -0,0 +1,253 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tty/prompt'
4
+ require 'rails/version'
5
+ require 'rails/generators/active_record'
6
+ require 'rails/generators/active_record/migration'
7
+
8
+ module Steroid
9
+ class MigrationGenerator < Rails::Generators::Base
10
+ desc "Adds Migration to the application"
11
+ source_root File.expand_path("templates", __dir__)
12
+ include ActiveRecord::Generators::Migration
13
+ include ActiveRecord::Migration::JoinTable
14
+
15
+ def add_migration
16
+ say "Injecting steroid: Migration", :green
17
+ cmd = ["rails generate migration"]
18
+
19
+ action_choices = [
20
+ {name: 'Create table', value: 'create_table'},
21
+ {name: 'Create join table', value: 'create_join_table'},
22
+ {name: 'Drop table', value: 'drop_table'},
23
+ {name: 'Modify table columns/index', value: 'modify_table'},
24
+ ]
25
+ @action = prompt.select("What would you like to do?", action_choices)
26
+
27
+ case @action
28
+ when 'create_table'
29
+ table_name = prompt.ask("What is the name of table to be created?", required: true) { |q| q.modify :remove }
30
+ @content = content_for_create_table(table_name, collect_columns_data)
31
+ migration_template "migration.rb", "#{db_migrate_path}/create_#{table_name}.rb"
32
+ when 'create_join_table'
33
+ table1_name = prompt.ask("What is the name of first table to be joined?", required: true) { |q| q.modify :remove }
34
+ table2_name = prompt.ask("What is the name of second table to be joined?", required: true) { |q| q.modify :remove }
35
+ table_name = prompt.ask("What is the custom name for join table?", default: find_join_table_name(table1_name, table2_name), required: true) { |q| q.modify :remove }
36
+ columns_data = []
37
+ if prompt.select("Add `id` column?", boolean_choices)
38
+ columns_data << {name: 'id', type: 'primary_key'}
39
+ end
40
+ if prompt.select("Add index for #{table1_name} foreign_key?", boolean_choices)
41
+ columns_data << {name: "#{table1_name.singularize}_id", type: 'index'}
42
+ end
43
+ if prompt.select("Add index for #{table2_name} foreign_key?", boolean_choices)
44
+ columns_data << {name: "#{table2_name.singularize}_id", type: 'index'}
45
+ end
46
+ if prompt.select("Add composite index for #{table1_name} and #{table2_name} foreign_key?", boolean_choices)
47
+ uniq_index_option = prompt.select("Unique combination index?", boolean_choices) ? {meta: {unique: true}} : {}
48
+ columns_data << {name: ["#{table2_name.singularize}_id", "#{table2_name.singularize}_id"], type: 'index'}.merge(uniq_index_option)
49
+ end
50
+ @content = content_for_create_join_table(table1_name, table2_name, table_name, (columns_data + collect_columns_data))
51
+ migration_template "migration.rb", "#{db_migrate_path}/create_join_table_#{table_name}.rb"
52
+ when 'drop_table'
53
+ table_name = prompt.ask("What is the name of table to be dropped?", required: true) { |q| q.modify :remove }
54
+ @content = content_for_drop_table(table_name)
55
+ migration_template "migration.rb", "#{db_migrate_path}/drop_#{table_name}.rb"
56
+ when 'modify_table'
57
+ table_name = prompt.ask("What is the name of table to add/remove columns/index?", required: true) { |q| q.modify :remove }
58
+ modify_table_choices = [
59
+ {name: 'Add column', value: 'add_column'}, {name: 'Remove column', value: 'remove_column'},
60
+ {name: 'Add index', value: 'add_index'}, {name: 'Remove index', value: 'remove_index'},
61
+ {name: 'Add reference', value: 'add_reference'}, {name: 'Remove reference', value: 'remove_reference'},
62
+ # {name: 'Add timestamps', value: 'add_timestamps'}, {name: 'Remove timestamps', value: 'remove_timestamps'},
63
+ {name: 'Exit', value: 'exit'}
64
+ ]
65
+ @content = []
66
+ file_name = []
67
+ while (modify_table_action = prompt.select("What would you like to do?", modify_table_choices)) != 'exit'
68
+ for_removal = modify_table_action.start_with?('remove_')
69
+ if modify_table_action.end_with?('_index') || modify_table_action.end_with?('_reference')
70
+ data = modify_table_action.end_with?('_index') ? ask_index_data(for_removal: for_removal) : ask_reference_data(for_removal: for_removal)
71
+ file_name << modify_table_action << data[:name]
72
+ else
73
+ data = ask_column_data(for_removal: for_removal)
74
+ file_name << (for_removal ? 'remove' : 'add') << data[:name]
75
+ end
76
+ @content << format_statement_for_modify_table(modify_table_action, table_name, data)
77
+ end
78
+ @content = content_for_modify_table(@content.join("\n "))
79
+ migration_template "migration.rb", "#{db_migrate_path}/#{file_name.join('_')}_in_#{table_name}.rb"
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def prompt
86
+ TTY::Prompt.new
87
+ end
88
+
89
+ def boolean_choices
90
+ [{name: "yes", value: true}, {name: "no", value: false}]
91
+ end
92
+
93
+ def collect_columns_data
94
+ columns_data = []
95
+ while prompt.select("Would you like to add model attributes(columns)?", boolean_choices)
96
+ columns_data << ask_column_data
97
+ end
98
+ timestamps_data = ask_timestamps_data
99
+ columns_data << timestamps_data if timestamps_data
100
+ columns_data
101
+ end
102
+
103
+ def ask_column_data(for_removal: false)
104
+ column_data = { meta: {} }
105
+ column_name = prompt.ask("Specify name of column:", required: true) { |q| q.modify :remove }
106
+
107
+ column_type_choices = %w(boolean string text integer decimal float binary date time datetime primary_key digest token)
108
+ column_type_choices << 'references' unless @action == 'modify_table'
109
+ column_type = prompt.select("Choose type of column:", column_type_choices)
110
+
111
+ if column_type == 'references'
112
+ column_data[:meta][:foreign_key] = true if prompt.select("Foreign_key to be #{for_removal ? 'removed' : 'added'}?", boolean_choices)
113
+ column_data[:meta][:polymorphic] = true if prompt.select("Polymorphic association?", boolean_choices)
114
+ end
115
+ unless for_removal
116
+ if %w(integer string text binary).include?(column_type)
117
+ if prompt.select("Set limit?", boolean_choices)
118
+ limit = prompt.ask("Specify limit:", required: true) do |q|
119
+ q.modify :remove
120
+ q.convert(:int, "Invalid input! Please provide integer value.")
121
+ end
122
+ column_data[:meta][:limit] = limit
123
+ end
124
+ end
125
+ if column_type == 'decimal'
126
+ if prompt.select("Set precision & scale?", boolean_choices)
127
+ precision = prompt.ask("Specify precision:", required: true) do |q|
128
+ q.modify :remove
129
+ q.convert(:int, "Invalid input! Please provide integer value.")
130
+ end
131
+ column_data[:meta][:precision] = precision
132
+ scale = prompt.ask("Specify scale:", required: true) do |q|
133
+ q.modify :remove
134
+ q.convert(:int, "Invalid input! Please provide integer value.")
135
+ end
136
+ column_data[:meta][:scale] = scale
137
+ end
138
+ end
139
+
140
+ if %w(references primary_key digest token).exclude?(column_type) && prompt.select("Add default value?", boolean_choices)
141
+ acceptable_value_type = { 'text' => :string }[column_type] || column_type.to_sym
142
+ column_data[:meta][:default] = prompt.ask("Specify default value:", required: true) do |q|
143
+ q.modify :remove
144
+ q.convert(acceptable_value_type, "Invalid input! Please provide %{type} value.")
145
+ end
146
+ end
147
+
148
+ if prompt.select("Add index?", boolean_choices)
149
+ column_data[:meta][:index] = prompt.select("Unique index?", boolean_choices) ? :unique : true
150
+ end
151
+ end
152
+
153
+ column_data.merge!(name: column_name, type: column_type)
154
+ column_data
155
+ end
156
+
157
+ def ask_reference_data(for_removal: false)
158
+ column_data = { meta: {} }
159
+ column_data[:name] = prompt.ask("Specify name of reference:", required: true) { |q| q.modify :remove }
160
+ column_data[:meta][:foreign_key] = true if prompt.select("Foreign_key to be #{for_removal ? 'removed' : 'added'}?", boolean_choices)
161
+ column_data[:meta][:polymorphic] = true if prompt.select("Polymorphic association?", boolean_choices)
162
+ column_data
163
+ end
164
+
165
+ def ask_index_data(for_removal: false)
166
+ column_data = { meta: {} }
167
+ names = []
168
+ names << prompt.ask("Specify name of column:", required: true) { |q| q.modify :remove }
169
+ while prompt.select("Add more columns for Composite index?", boolean_choices)
170
+ names << prompt.ask("Specify name of another column:", required: true) { |q| q.modify :remove }
171
+ end
172
+ column_data[:name] = names
173
+ unless for_removal
174
+ column_data[:meta][:unique] = true if prompt.select("Unique index?", boolean_choices)
175
+ end
176
+ custom_name = prompt.ask("Specify custom name for index (optional):") { |q| q.modify :remove }
177
+ column_data[:meta][:name] = custom_name if custom_name.present?
178
+ column_data
179
+ end
180
+
181
+ def ask_timestamps_data
182
+ if prompt.select("Add timestamps?", boolean_choices)
183
+ { type: 'timestamps' }
184
+ end
185
+ end
186
+
187
+ def format_statement_for_modify_table(modify_table_action, table_name, column_data)
188
+ statement_data = ["#{modify_table_action} :#{table_name}"]
189
+ statement_data << if column_data[:name].is_a?(Array)
190
+ col_name = column_data[:name].size > 1 ? "[#{column_data[:name].map { |n| ":#{n}" }.join(', ')}]" : ":#{column_data[:name].first}"
191
+ "column: #{col_name}" if modify_table_action == 'remove_index'
192
+ else
193
+ ":#{column_data[:name]}"
194
+ end
195
+ statement_data << ":#{column_data[:type]}" if column_data[:type]
196
+ column_data[:meta].each { |key, value| statement_data << "#{key}: #{value.inspect}" }
197
+ statement_data = statement_data.join(', ')
198
+ end
199
+
200
+ def format_statement_for_create_table(columns_data)
201
+ columns_data.map do |c|
202
+ column_row = if c[:name].is_a?(Array)
203
+ ["t.#{c[:type]} [#{c[:name].map { |n| ":#{n}" }.join(', ')}]"]
204
+ elsif c[:name].nil?
205
+ ["t.#{c[:type]}"]
206
+ else
207
+ ["t.#{c[:type]} :#{c[:name]}"]
208
+ end
209
+ c[:meta].each { |key, value| column_row << "#{key}: #{value.inspect}" } if c[:meta]
210
+ column_row.join(', ')
211
+ end.join("\n ")
212
+ end
213
+
214
+ def content_for_create_table(table_name, columns_data)
215
+ columns_data_content = format_statement_for_create_table(columns_data)
216
+ <<-CONTENT
217
+ def change
218
+ create_table :#{table_name}#{primary_key_type} do |t|
219
+ #{columns_data_content}
220
+ end
221
+ end
222
+ CONTENT
223
+ end
224
+
225
+ def content_for_create_join_table(table1_name, table2_name, table_name, columns_data)
226
+ columns_data_content = format_statement_for_create_table(columns_data)
227
+ <<-CONTENT
228
+ def change
229
+ create_join_table :#{table1_name}, :#{table2_name}, table_name: :#{table_name} do |t|
230
+ #{columns_data_content}
231
+ end
232
+ end
233
+ CONTENT
234
+ end
235
+
236
+ def content_for_drop_table(table_name)
237
+ <<-CONTENT
238
+ def change
239
+ drop_table :#{table_name}
240
+ end
241
+ CONTENT
242
+ end
243
+
244
+ def content_for_modify_table(statements)
245
+ <<-CONTENT
246
+ def change
247
+ #{statements}
248
+ end
249
+ CONTENT
250
+ end
251
+
252
+ end
253
+ end
@@ -0,0 +1,3 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ <%= @content -%>
3
+ end
@@ -25,6 +25,7 @@ module RailsSteroids
25
25
  puts "| Functionality | Command |"
26
26
  puts "|---|---|"
27
27
  steroid_names = [
28
+ 'migration',
28
29
  'model',
29
30
  'controller',
30
31
  'new_project',
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsSteroids
4
- VERSION = "0.5.0"
4
+ VERSION = "0.7.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_steroids
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anand Bait
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-06 00:00:00.000000000 Z
11
+ date: 2024-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -106,6 +106,9 @@ files:
106
106
  - bin/setup
107
107
  - lib/generators/steroid/controller/USAGE
108
108
  - lib/generators/steroid/controller/controller_generator.rb
109
+ - lib/generators/steroid/migration/USAGE
110
+ - lib/generators/steroid/migration/migration_generator.rb
111
+ - lib/generators/steroid/migration/templates/migration.rb.tt
109
112
  - lib/generators/steroid/model/USAGE
110
113
  - lib/generators/steroid/model/model_generator.rb
111
114
  - lib/generators/steroid/new_project/USAGE