brick 1.0.156 → 1.0.158

Sign up to get free protection for your applications and to get access to all the features.
@@ -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