brick 1.0.156 → 1.0.158

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.
@@ -3,354 +3,33 @@
3
3
  require 'rails/generators'
4
4
  require 'rails/generators/active_record'
5
5
  require 'fancy_gets'
6
+ require 'generators/brick/migration_builder'
6
7
 
7
8
  module Brick
8
9
  # Auto-generates migration files
9
10
  class MigrationsGenerator < ::Rails::Generators::Base
10
11
  include FancyGets
11
- # include ::Rails::Generators::Migration
12
-
13
- # Many SQL types are the same as their migration data type name:
14
- # text, integer, bigint, date, boolean, decimal, float
15
- # These however are not:
16
- SQL_TYPES = { 'character varying' => 'string',
17
- 'character' => 'string', # %%% Need to put in "limit: 1"
18
- 'xml' => 'text',
19
- 'bytea' => 'binary',
20
- 'timestamp without time zone' => 'timestamp',
21
- 'timestamp with time zone' => 'timestamp',
22
- 'time without time zone' => 'time',
23
- 'time with time zone' => 'time',
24
- 'double precision' => 'float',
25
- 'smallint' => 'integer', # %%% Need to put in "limit: 2"
26
- 'ARRAY' => 'string', # Note that we'll also add ", array: true"
27
- # Oracle data types
28
- 'VARCHAR2' => 'string',
29
- 'CHAR' => 'string',
30
- ['NUMBER', 22] => 'integer',
31
- /^INTERVAL / => 'string', # Time interval stuff like INTERVAL YEAR(2) TO MONTH, INTERVAL '999' DAY(3), etc
32
- 'XMLTYPE' => 'xml',
33
- 'RAW' => 'binary',
34
- 'SDO_GEOMETRY' => 'geometry',
35
- # MSSQL data types
36
- 'int' => 'integer',
37
- 'nvarchar' => 'string',
38
- 'nchar' => 'string',
39
- 'datetime2' => 'timestamp',
40
- 'bit' => 'boolean',
41
- 'varbinary' => 'binary',
42
- # Sqlite data types
43
- 'TEXT' => 'text',
44
- '' => 'string',
45
- 'INTEGER' => 'integer',
46
- 'REAL' => 'float',
47
- 'BLOB' => 'binary',
48
- 'TIMESTAMP' => 'timestamp',
49
- 'DATETIME' => 'timestamp'
50
- }
51
- # (Still need to find what "inet" and "json" data types map to.)
12
+ include ::Brick::MigrationBuilder
52
13
 
53
14
  desc 'Auto-generates migration files for an existing database.'
54
15
 
55
16
  def brick_migrations
56
17
  # If Apartment is active, see if a default schema to analyse is indicated
57
18
 
58
- # # Load all models
59
- # ::Brick.eager_load_classes
19
+ ::Brick.mode = :on
20
+ ActiveRecord::Base.establish_connection
60
21
 
61
22
  if (tables = ::Brick.relations.reject { |k, v| v.key?(:isView) && v[:isView] == true }.map(&:first).sort).empty?
62
23
  puts "No tables found in database #{ActiveRecord::Base.connection.current_database}."
63
24
  return
64
25
  end
65
26
 
66
- is_sqlite = ActiveRecord::Base.connection.adapter_name == 'SQLite'
67
- key_type = ((is_sqlite || ActiveRecord.version < ::Gem::Version.new('5.1')) ? 'integer' : 'bigint')
68
- is_4x_rails = ActiveRecord.version < ::Gem::Version.new('5.0')
69
- ar_version = "[#{ActiveRecord.version.segments[0..1].join('.')}]" unless is_4x_rails
70
- is_insert_versions = true
71
- is_delete_versions = false
72
- versions_to_delete_or_append = nil
73
- if Dir.exist?(mig_path = ActiveRecord::Migrator.migrations_paths.first || "#{::Rails.root}/db/migrate")
74
- if Dir["#{mig_path}/**/*.rb"].present?
75
- puts "WARNING: migrations folder #{mig_path} appears to already have ruby files present."
76
- mig_path2 = "#{::Rails.root}/tmp/brick_migrations"
77
- is_insert_versions = false unless mig_path == mig_path2
78
- if Dir.exist?(mig_path2)
79
- if Dir["#{mig_path2}/**/*.rb"].present?
80
- puts "As well, temporary folder #{mig_path2} also has ruby files present."
81
- puts "Choose a destination -- all existing .rb files will be removed:"
82
- mig_path2 = gets_list(list: ['Cancel operation!', "Append migration files into #{mig_path} anyway", mig_path, mig_path2])
83
- return if mig_path2.start_with?('Cancel')
84
-
85
- existing_mig_files = Dir["#{mig_path2}/**/*.rb"]
86
- if (is_insert_versions = mig_path == mig_path2)
87
- versions_to_delete_or_append = existing_mig_files.map { |ver| ver.split('/').last.split('_').first }
88
- end
89
- if mig_path2.start_with?('Append migration files into ')
90
- mig_path2 = mig_path
91
- else
92
- is_delete_versions = true
93
- existing_mig_files.each { |rb| File.delete(rb) }
94
- end
95
- else
96
- puts "Using temporary folder #{mig_path2} for created migration files.\n\n"
97
- end
98
- else
99
- puts "Creating the temporary folder #{mig_path2} for created migration files.\n\n"
100
- Dir.mkdir(mig_path2)
101
- end
102
- mig_path = mig_path2
103
- else
104
- puts "Using standard migration folder #{mig_path} for created migration files.\n\n"
105
- end
106
- else
107
- puts "Creating standard ActiveRecord migration folder #{mig_path} to hold new migration files.\n\n"
108
- Dir.mkdir(mig_path)
109
- end
27
+ mig_path, is_insert_versions, is_delete_versions = ::Brick::MigrationBuilder.check_folder
110
28
 
111
29
  # Generate a list of tables that can be chosen
112
30
  chosen = gets_list(list: tables, chosen: tables.dup)
113
- schemas = chosen.each_with_object({}) do |v, s|
114
- if (v_parts = v.split('.')).length > 1
115
- s[v_parts.first] = nil unless [::Brick.default_schema, 'public'].include?(v_parts.first)
116
- end
117
- end
118
- # Start the timestamps back the same number of minutes from now as expected number of migrations to create
119
- current_mig_time = Time.now - (schemas.length + chosen.length).minutes
120
- done = []
121
- fks = {}
122
- stuck = {}
123
- indexes = {} # Track index names to make sure things are unique
124
- built_schemas = {} # Track all built schemas so we can place an appropriate drop_schema command only in the first
125
- # migration in which that schema is referenced, thereby allowing rollbacks to function properly.
126
- versions_to_create = [] # Resulting versions to be used when updating the schema_migrations table
127
- ar_base = Object.const_defined?(:ApplicationRecord) ? ApplicationRecord : Class.new(ActiveRecord::Base)
128
- # Start by making migrations for fringe tables (those with no foreign keys).
129
- # Continue layer by layer, creating migrations for tables that reference ones already done, until
130
- # no more migrations can be created. (At that point hopefully all tables are accounted for.)
131
- while (fringe = chosen.reject do |tbl|
132
- snag_fks = []
133
- snags = ::Brick.relations.fetch(tbl, nil)&.fetch(:fks, nil)&.select do |_k, v|
134
- v[:is_bt] && !v[:polymorphic] &&
135
- tbl != v[:inverse_table] && # Ignore self-referencing associations (stuff like "parent_id")
136
- !done.include?(v[:inverse_table]) &&
137
- ::Brick.config.ignore_migration_fks.exclude?(snag_fk = "#{tbl}.#{v[:fk]}") &&
138
- snag_fks << snag_fk
139
- end
140
- if snags&.present?
141
- # puts snag_fks.inspect
142
- stuck[tbl] = snags
143
- end
144
- end).present?
145
- fringe.each do |tbl|
146
- next unless (relation = ::Brick.relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present?
147
-
148
- pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ar_base.primary_key].flatten.sort)
149
- # In case things aren't as standard
150
- if pkey_cols.empty?
151
- pkey_cols = if rpk.empty? && relation[:cols][arpk.first]&.first == key_type
152
- arpk
153
- elsif rpk.first
154
- rpk
155
- end
156
- end
157
- schema = if (tbl_parts = tbl.split('.')).length > 1
158
- if tbl_parts.first == (::Brick.default_schema || 'public')
159
- tbl_parts.shift
160
- nil
161
- else
162
- tbl_parts.first
163
- end
164
- end
165
- unless schema.blank? || built_schemas.key?(schema)
166
- mig = +" def change\n create_schema(:#{schema}) unless schema_exists?(:#{schema})\n end\n"
167
- migration_file_write(mig_path, "create_db_schema_#{schema.underscore}", current_mig_time += 1.minute, ar_version, mig)
168
- built_schemas[schema] = nil
169
- end
170
31
 
171
- # %%% For the moment we're skipping polymorphics
172
- fkey_cols = relation[:fks].values.select { |assoc| assoc[:is_bt] && !assoc[:polymorphic] }
173
- # If the primary key is also used as a foreign key, will need to do id: false and then build out
174
- # a column definition which includes :primary_key -- %%% also using a data type of bigserial or serial
175
- # if this one has come in as bigint or integer.
176
- pk_is_also_fk = fkey_cols.any? { |assoc| pkey_cols&.first == assoc[:fk] } ? pkey_cols&.first : nil
177
- # Support missing primary key (by adding: , id: false)
178
- id_option = if pk_is_also_fk || !pkey_cols&.present?
179
- needs_serial_col = true
180
- +', id: false'
181
- elsif ((pkey_col_first = (col_def = relation[:cols][pkey_cols&.first])&.first) &&
182
- (pkey_col_first = SQL_TYPES[pkey_col_first] || SQL_TYPES[col_def&.[](0..1)] ||
183
- SQL_TYPES.find { |r| r.first.is_a?(Regexp) && pkey_col_first =~ r.first }&.last ||
184
- pkey_col_first
185
- ) != key_type
186
- )
187
- case pkey_col_first
188
- when 'integer'
189
- +', id: :serial'
190
- when 'bigint'
191
- +', id: :bigserial'
192
- else
193
- +", id: :#{pkey_col_first}" # Something like: id: :integer, primary_key: :businessentityid
194
- end +
195
- (pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '')
196
- end
197
- if !id_option && pkey_cols.sort != arpk
198
- id_option = +", primary_key: :#{pkey_cols.first}"
199
- end
200
- if !is_4x_rails && (comment = relation&.fetch(:description, nil))&.present?
201
- (id_option ||= +'') << ", comment: #{comment.inspect}"
202
- end
203
- # Find the ActiveRecord class in order to see if the columns have comments
204
- unless is_4x_rails
205
- klass = begin
206
- tbl.tr('.', '/').singularize.camelize.constantize
207
- rescue StandardError
208
- end
209
- if klass
210
- unless ActiveRecord::Migration.table_exists?(klass.table_name)
211
- puts "WARNING: Unable to locate table #{klass.table_name} (for #{klass.name})."
212
- klass = nil
213
- end
214
- end
215
- end
216
- # Refer to this table name as a symbol or dotted string as appropriate
217
- tbl_code = tbl_parts.length == 1 ? ":#{tbl_parts.first}" : "'#{tbl}'"
218
- mig = +" def change\n return unless reverting? || !table_exists?(#{tbl_code})\n\n"
219
- mig << " create_table #{tbl_code}#{id_option} do |t|\n"
220
- possible_ts = [] # Track possible generic timestamps
221
- add_fks = [] # Track foreign keys to add after table creation
222
- relation[:cols].each do |col, col_type|
223
- sql_type = SQL_TYPES[col_type.first] || SQL_TYPES[col_type[0..1]] ||
224
- SQL_TYPES.find { |r| r.first.is_a?(Regexp) && col_type.first =~ r.first }&.last ||
225
- col_type.first
226
- suffix = col_type[3] || pkey_cols&.include?(col) ? +', null: false' : +''
227
- suffix << ', array: true' if (col_type.first == 'ARRAY')
228
- if !is_4x_rails && klass && (comment = klass.columns_hash.fetch(col, nil)&.comment)&.present?
229
- suffix << ", comment: #{comment.inspect}"
230
- end
231
- # Determine if this column is used as part of a foreign key
232
- if (fk = fkey_cols.find { |assoc| col == assoc[:fk] })
233
- to_table = fk[:inverse_table].split('.')
234
- to_table = to_table.length == 1 ? ":#{to_table.first}" : "'#{fk[:inverse_table]}'"
235
- if needs_serial_col && pkey_cols&.include?(col) && (new_serial_type = {'integer' => 'serial', 'bigint' => 'bigserial'}[sql_type])
236
- sql_type = new_serial_type
237
- needs_serial_col = false
238
- end
239
- if fk[:fk] != "#{fk[:assoc_name].singularize}_id" # Need to do our own foreign_key tricks, not use references?
240
- column = fk[:fk]
241
- mig << emit_column(sql_type, column, suffix)
242
- add_fks << [to_table, column, ::Brick.relations[fk[:inverse_table]]]
243
- else
244
- suffix << ", type: :#{sql_type}" unless sql_type == key_type
245
- # Will the resulting default index name be longer than what Postgres allows? (63 characters)
246
- if (idx_name = ActiveRecord::Base.connection.index_name(tbl, {column: col})).length > 63
247
- # Try to find a shorter name that hasn't been used yet
248
- unless indexes.key?(shorter = idx_name[0..62]) ||
249
- indexes.key?(shorter = idx_name.tr('_', '')[0..62]) ||
250
- indexes.key?(shorter = idx_name.tr('aeio', '')[0..62])
251
- puts "Unable to easily find unique name for index #{idx_name} that is shorter than 64 characters,"
252
- puts "so have resorted to this GUID-based identifier: #{shorter = "#{tbl[0..25]}_#{::SecureRandom.uuid}"}."
253
- end
254
- suffix << ", index: { name: '#{shorter || idx_name}' }"
255
- indexes[shorter || idx_name] = nil
256
- end
257
- primary_key = ::Brick.relations[fk[:inverse_table]][:class_name]&.constantize&.primary_key
258
- mig << " t.references :#{fk[:assoc_name]}#{suffix}, foreign_key: { to_table: #{to_table}#{", primary_key: :#{primary_key}" if primary_key != ar_base.primary_key} }\n"
259
- end
260
- else
261
- next if !id_option&.end_with?('id: false') && pkey_cols&.include?(col)
262
-
263
- # See if there are generic timestamps
264
- if sql_type == 'timestamp' && ['created_at','updated_at'].include?(col)
265
- possible_ts << [col, !col_type[3]]
266
- else
267
- mig << emit_column(sql_type, col, suffix)
268
- end
269
- end
270
- end
271
- if possible_ts.length == 2 && # Both created_at and updated_at
272
- # Rails 5 and later timestamps default to NOT NULL
273
- (possible_ts.first.last == is_4x_rails && possible_ts.last.last == is_4x_rails)
274
- mig << "\n t.timestamps\n"
275
- else # Just one or the other, or a nullability mismatch
276
- possible_ts.each { |ts| emit_column('timestamp', ts.first, nil) }
277
- end
278
- mig << " end\n"
279
- if pk_is_also_fk
280
- mig << " reversible do |dir|\n"
281
- mig << " dir.up { execute('ALTER TABLE #{tbl} ADD PRIMARY KEY (#{pk_is_also_fk})') }\n"
282
- mig << " end\n"
283
- end
284
- add_fks.each do |add_fk|
285
- is_commented = false
286
- # add_fk[2] holds the inverse relation
287
- unless (pk = add_fk[2][:pkey].values.flatten&.first)
288
- is_commented = true
289
- mig << " # (Unable to create relationship because primary key is missing on table #{add_fk[0]})\n"
290
- # No official PK, but if coincidentally there's a column of the same name, take a chance on it
291
- pk = (add_fk[2][:cols].key?(add_fk[1]) && add_fk[1]) || '???'
292
- end
293
- # to_table column
294
- mig << " #{'# ' if is_commented}add_foreign_key #{tbl_code}, #{add_fk[0]}, column: :#{add_fk[1]}, primary_key: :#{pk}\n"
295
- end
296
- mig << " end\n"
297
- versions_to_create << migration_file_write(mig_path, "create_#{tbl_parts.map(&:underscore).join('_')}", current_mig_time += 1.minute, ar_version, mig)
298
- end
299
- done.concat(fringe)
300
- chosen -= done
301
- end
302
-
303
- stuck_counts = Hash.new { |h, k| h[k] = 0 }
304
- chosen.each do |leftover|
305
- puts "Can't do #{leftover} because:\n #{stuck[leftover].map do |snag|
306
- stuck_counts[snag.last[:inverse_table]] += 1
307
- snag.last[:assoc_name]
308
- end.join(', ')}"
309
- end
310
- if mig_path.start_with?(cur_path = ::Rails.root.to_s)
311
- pretty_mig_path = mig_path[cur_path.length..-1]
312
- end
313
- puts "\n*** Created #{done.length} migration files under #{pretty_mig_path || mig_path} ***"
314
- if (stuck_sorted = stuck_counts.to_a.sort { |a, b| b.last <=> a.last }).length.positive?
315
- puts "-----------------------------------------"
316
- puts "Unable to create migrations for #{stuck_sorted.length} tables#{
317
- ". Here's the top 5 blockers" if stuck_sorted.length > 5
318
- }:"
319
- pp stuck_sorted[0..4]
320
- else # Successful, and now we can update the schema_migrations table accordingly
321
- unless ActiveRecord::Migration.table_exists?(ActiveRecord::Base.schema_migrations_table_name)
322
- ActiveRecord::SchemaMigration.create_table
323
- end
324
- # Remove to_delete - to_create
325
- if ((versions_to_delete_or_append ||= []) - versions_to_create).present? && is_delete_versions
326
- ActiveRecord::Base.execute_sql("DELETE FROM #{
327
- ActiveRecord::Base.schema_migrations_table_name} WHERE version IN (#{
328
- (versions_to_delete_or_append - versions_to_create).map { |vtd| "'#{vtd}'" }.join(', ')}
329
- )")
330
- end
331
- # Add to_create - to_delete
332
- if is_insert_versions && ((versions_to_create ||= []) - versions_to_delete_or_append).present?
333
- ActiveRecord::Base.execute_sql("INSERT INTO #{
334
- ActiveRecord::Base.schema_migrations_table_name} (version) VALUES #{
335
- (versions_to_create - versions_to_delete_or_append).map { |vtc| "('#{vtc}')" }.join(', ')
336
- }")
337
- end
338
- end
339
- end
340
-
341
- private
342
-
343
- def emit_column(type, name, suffix)
344
- " t.#{type.start_with?('numeric') ? 'decimal' : type} :#{name}#{suffix}\n"
345
- end
346
-
347
- def migration_file_write(mig_path, name, current_mig_time, ar_version, mig)
348
- File.open("#{mig_path}/#{version = current_mig_time.strftime('%Y%m%d%H%M00')}_#{name}.rb", "w") do |f|
349
- f.write "class #{name.camelize} < ActiveRecord::Migration#{ar_version}\n"
350
- f.write mig
351
- f.write "end\n"
352
- end
353
- version
32
+ ::Brick::MigrationBuilder.generate_migrations(chosen, mig_path, is_insert_versions, is_delete_versions)
354
33
  end
355
34
  end
356
35
  end
@@ -15,6 +15,9 @@ module Brick
15
15
  def brick_models
16
16
  # %%% If Apartment is active and there's no schema_to_analyse, ask which schema they want
17
17
 
18
+ ::Brick.mode = :on
19
+ ActiveRecord::Base.establish_connection
20
+
18
21
  # Load all models
19
22
  ::Brick.eager_load_classes
20
23
 
@@ -9,25 +9,46 @@ module Brick
9
9
 
10
10
  desc 'Auto-generates a seeds file from existing data.'
11
11
 
12
+ SeedModel = Struct.new(:table_name, :klass, :is_brick)
13
+ SeedModel.define_method(:to_s) do
14
+ "#{klass.name}#{' (brick-generated)' if is_brick}"
15
+ end
16
+
12
17
  def brick_seeds
13
18
  # %%% If Apartment is active and there's no schema_to_analyse, ask which schema they want
14
19
 
15
20
  ::Brick.mode = :on
16
21
  ActiveRecord::Base.establish_connection
17
22
 
18
- if (tables = ::Brick.relations.reject { |k, v| v.key?(:isView) && v[:isView] == true }.map(&:first).sort).empty?
19
- puts "No tables found in database #{ActiveRecord::Base.connection.current_database}."
23
+ # Load all models
24
+ ::Brick.eager_load_classes
25
+
26
+ # Generate a list of viable models that can be chosen
27
+ # First start with any existing models that have been defined ...
28
+ existing_models = ActiveRecord::Base.descendants.each_with_object({}) do |m, s|
29
+ s[m.table_name] = SeedModel.new(m.table_name, m, false) if !m.abstract_class? && m.table_exists?
30
+ end
31
+ models = (existing_models.values +
32
+ # ... then add models which can be auto-built by Brick
33
+ ::Brick.relations.reject do |k, v|
34
+ (v.key?(:isView) && v[:isView] == true) || existing_models.key?(k)
35
+ end.map { |k, v| SeedModel.new(k, v[:class_name].constantize, true) }
36
+ ).sort { |a, b| a.to_s <=> b.to_s }
37
+ if models.empty?
38
+ puts "No viable models found for database #{ActiveRecord::Base.connection.current_database}."
20
39
  return
21
40
  end
22
41
 
23
42
  if File.exist?(seed_file_path = "#{::Rails.root}/db/seeds.rb")
24
- puts "WARNING: seeds file #{seed_file_path} appears to already be present."
43
+ puts "WARNING: seeds file #{seed_file_path} appears to already be present.\nOverwrite?"
44
+ return unless gets_list(list: ['No', 'Yes']) == 'Yes'
45
+
46
+ puts "\n"
25
47
  end
26
48
 
27
- # Generate a list of tables that can be chosen
28
- chosen = gets_list(list: tables, chosen: tables.dup)
49
+ chosen = gets_list(list: models, chosen: models.dup)
29
50
  schemas = chosen.each_with_object({}) do |v, s|
30
- if (v_parts = v.split('.')).length > 1
51
+ if (v_parts = v.table_name.split('.')).length > 1
31
52
  s[v_parts.first] = nil unless [::Brick.default_schema, 'public'].include?(v_parts.first)
32
53
  end
33
54
  end
@@ -40,12 +61,13 @@ module Brick
40
61
  # Start by making entries for fringe models (those with no foreign keys).
41
62
  # Continue layer by layer, creating entries for models that reference ones already done, until
42
63
  # no more entries can be created. (At that point hopefully all models are accounted for.)
43
- while (fringe = chosen.reject do |tbl|
64
+ while (fringe = chosen.reject do |seed_model|
65
+ tbl = seed_model.table_name
44
66
  snag_fks = []
45
67
  snags = ::Brick.relations.fetch(tbl, nil)&.fetch(:fks, nil)&.select do |_k, v|
46
68
  v[:is_bt] && !v[:polymorphic] &&
47
69
  tbl != v[:inverse_table] && # Ignore self-referencing associations (stuff like "parent_id")
48
- !done.include?(v[:inverse_table]) &&
70
+ !done.any? { |done_seed_model| done_seed_model.table_name == v[:inverse_table] } &&
49
71
  ::Brick.config.ignore_migration_fks.exclude?(snag_fk = "#{tbl}.#{v[:fk]}") &&
50
72
  snag_fks << snag_fk
51
73
  end
@@ -53,12 +75,14 @@ module Brick
53
75
  # puts snag_fks.inspect
54
76
  stuck[tbl] = snags
55
77
  end
56
- end).present?
78
+ end
79
+ ).present?
57
80
  seeds << "\n"
58
- fringe.each do |tbl|
81
+ fringe.each do |seed_model|
82
+ tbl = seed_model.table_name
59
83
  next unless ::Brick.config.exclude_tables.exclude?(tbl) &&
60
84
  (relation = ::Brick.relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present? &&
61
- (klass = Object.const_get(class_name = relation[:class_name])).table_exists?
85
+ (klass = seed_model.klass).table_exists?
62
86
 
63
87
  pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ar_base.primary_key].flatten.sort)
64
88
  # In case things aren't as standard
@@ -88,7 +112,7 @@ module Brick
88
112
  klass.order(*pkey_cols).each do |obj|
89
113
  unless has_rows
90
114
  has_rows = true
91
- seeds << " puts 'Seeding: #{class_name}'\n"
115
+ seeds << " puts 'Seeding: #{seed_model.klass.name}'\n"
92
116
  end
93
117
  is_empty = false
94
118
  pk_val = obj.send(pkey_cols.first)
@@ -108,9 +132,9 @@ module Brick
108
132
  data << "#{col}: #{val.inspect}"
109
133
  end
110
134
  end
111
- seeds << "#{tbl.gsub('.', '__')}_#{brick_escape(pk_val)} = #{class_name}.create(#{(fk_vals + data).join(', ')})\n"
135
+ seeds << "#{tbl.gsub('.', '__')}_#{brick_escape(pk_val)} = #{seed_model.klass.name}.create(#{(fk_vals + data).join(', ')})\n"
112
136
  end
113
- seeds << " # (Skipping #{class_name} as it has no rows)\n" unless has_rows
137
+ seeds << " # (Skipping #{seed_model.klass.name} as it has no rows)\n" unless has_rows
114
138
  File.open(seed_file_path, "w") { |f| f.write seeds }
115
139
  end
116
140
  done.concat(fringe)
@@ -118,7 +142,7 @@ module Brick
118
142
  end
119
143
  stuck_counts = Hash.new { |h, k| h[k] = 0 }
120
144
  chosen.each do |leftover|
121
- puts "Can't do #{leftover} because:\n #{stuck[leftover].map do |snag|
145
+ puts "Can't do #{leftover.klass.name} because:\n #{stuck[leftover.table_name].map do |snag|
122
146
  stuck_counts[snag.last[:inverse_table]] += 1
123
147
  snag.last[:assoc_name]
124
148
  end.join(', ')}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brick
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.156
4
+ version: 1.0.158
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-11 00:00:00.000000000 Z
11
+ date: 2023-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -255,6 +255,7 @@ files:
255
255
  - lib/brick/version_number.rb
256
256
  - lib/generators/brick/USAGE
257
257
  - lib/generators/brick/install_generator.rb
258
+ - lib/generators/brick/migration_builder.rb
258
259
  - lib/generators/brick/migrations_generator.rb
259
260
  - lib/generators/brick/models_generator.rb
260
261
  - lib/generators/brick/seeds_generator.rb