seed-do 3.1.0 → 4.0.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: a144ca5bdde78bd698bd63b5b7ec5d4538e290d494d6d9feaf3b72c2fabc94bd
4
- data.tar.gz: 05156a89c384563da57269b0850fc21f89b6d3f87fdb1801d83b5743cc286d22
3
+ metadata.gz: c5486ba5dbc636b111be4e69d838b7f317b233ea9cf4b516d611fdf5070f0780
4
+ data.tar.gz: a04c1e585a72163d13184a317aecf059eb4c21f24d9b3e51fd208debf452a574
5
5
  SHA512:
6
- metadata.gz: 22803ec0568fbfe2d89b20cd65f04c331da02673b901724e7fcd48d22c8b764eff73763c14cd197292e9408f7345fe562a4c1ee5b329f3c8e926b7a25413e166
7
- data.tar.gz: '006481304627db4be5b6eb2ebba80c043078b78c1b4e815a9323398a7aa9f7b395ca3971cb0069f942413a957637f8cf839f71c479ebb9feaa8cf6f7b915ba83'
6
+ metadata.gz: a5d0cbf12b3790a33f0c362967c4a7b20a85ef7cdb3e9a0c15b47111d0a4fab0ae5912728c1fbab4be32697669f4ed672d221badc00ea5abca06999117e3a4fb
7
+ data.tar.gz: 0011f72cf7c27fcfef5d8dad96ca74525582eaf9ddc01e66dd0b1b575e255d28c72c49db6b81f0523704991ab12545d7a4ebfc75c83fe46ef8ede8a71448d423
data/README.md CHANGED
@@ -142,6 +142,30 @@ Seed files can be run automatically using `rake db:seed_do`. There are two optio
142
142
 
143
143
  You can also do a similar thing in your code by calling `SeedDo.seed(fixture_paths, filter)`.
144
144
 
145
+ ## Bulk upsert
146
+
147
+ If you load a large amount of seed data, you can enable bulk upsert mode:
148
+
149
+ ```ruby
150
+ SeedDo.seed(bulk: true)
151
+ ```
152
+
153
+ In bulk mode, SeedDo buffers seed data for each file and writes it with `upsert_all`, which can significantly reduce the number of queries.
154
+
155
+ You can also control the batch size per `upsert_all` call. The default is `1000`.
156
+
157
+ ```ruby
158
+ SeedDo.seed(bulk: { batch_size: 100 })
159
+ ```
160
+
161
+ ### Requirements and caveats
162
+
163
+ - Bulk mode relies on Rails `upsert_all`
164
+ - The seed constraints are passed to `unique_by`, so the related columns must have a unique index
165
+ - Bulk mode is supported only on databases that support conflict targets, such as PostgreSQL and SQLite
166
+ - Bulk mode is not available on MySQL
167
+ - `SeedDo.seed` and `SeedDo.seed(bulk: true)` may not always produce the same record order, so verify the behavior carefully before enabling it in an existing production environment
168
+
145
169
  ## Disable output
146
170
 
147
171
  To disable output from Seed Do, set `SeedDo.quiet = true`.
@@ -200,6 +224,22 @@ DB=postgresql bundle exec rspec
200
224
 
201
225
  The connection paramaters for each of these are specified in spec/connections/, which you can edit if necessary (for example to change the username/password).
202
226
 
227
+ ### Dev Container
228
+
229
+ This repository includes a Dev Container setup for running the test suite locally with Ruby, SQLite, MySQL, and PostgreSQL ready to use.
230
+
231
+ 1. Open the repository in a Dev Container.
232
+ 2. Wait for `bundle install` to finish.
233
+ 3. Run the specs you want:
234
+
235
+ ```
236
+ bundle exec rspec
237
+ DB=mysql2 bundle exec rspec
238
+ DB=postgresql bundle exec rspec
239
+ ```
240
+
241
+ The Dev Container config also sets `MYSQL_HOST=mysql` and `POSTGRES_HOST=postgres` automatically, so the database-backed specs work without editing local machine settings.
242
+
203
243
  ## Original Author
204
244
 
205
245
  [Michael Bleigh](http://www.mbleigh.com/) is the original author
@@ -29,7 +29,7 @@ module SeedDo
29
29
  # { :x => 5, :y => 9, :name => "Office" }
30
30
  # )
31
31
  def seed(*args, &block)
32
- SeedDo::Seeder.new(self, *parse_seed_do_args(args, block)).seed
32
+ SeedDo.current_seeder.seed(self, *parse_seed_do_args(args, block))
33
33
  end
34
34
 
35
35
  # Has the same syntax as {#seed}, but if a record already exists with the same values for
@@ -40,26 +40,25 @@ module SeedDo
40
40
  # Person.seed(:id, :id => 1, :name => "Bob") # => Name changed
41
41
  # Person.seed_once(:id, :id => 1, :name => "Harry") # => Name *not* changed
42
42
  def seed_once(*args, &block)
43
- constraints, data = parse_seed_do_args(args, block)
44
- SeedDo::Seeder.new(self, constraints, data, :insert_only => true).seed
43
+ SeedDo.current_seeder.seed_once(self, *parse_seed_do_args(args, block))
45
44
  end
46
45
 
47
46
  private
48
47
 
49
- def parse_seed_do_args(args, block)
50
- if block.nil?
51
- if args.last.is_a?(Array)
52
- # Last arg is an array of data, so assume the rest of the args are constraints
53
- data = args.pop
54
- [args, data]
55
- else
56
- # Partition the args, assuming the first hash is the start of the data
57
- args.partition { |arg| !arg.is_a?(Hash) }
58
- end
48
+ def parse_seed_do_args(args, block)
49
+ if block.nil?
50
+ if args.last.is_a?(Array)
51
+ # Last arg is an array of data, so assume the rest of the args are constraints
52
+ data = args.pop
53
+ [args, data]
59
54
  else
60
- # We have a block, so assume the args are all constraints
61
- [args, [SeedDo::BlockHash.new(block).to_hash]]
55
+ # Partition the args, assuming the first hash is the start of the data
56
+ args.partition { |arg| !arg.is_a?(Hash) }
62
57
  end
58
+ else
59
+ # We have a block, so assume the args are all constraints
60
+ [args, [SeedDo::BlockHash.new(block).to_hash]]
63
61
  end
62
+ end
64
63
  end
65
64
  end
@@ -12,7 +12,7 @@ module SeedDo
12
12
 
13
13
  def method_missing(method_name, *args, &block)
14
14
  if method_name.to_s =~ /^(.*)=$/ && args.length == 1 && block.nil?
15
- @hash[$1] = args.first
15
+ @hash[::Regexp.last_match(1)] = args.first
16
16
  else
17
17
  super
18
18
  end
@@ -0,0 +1,66 @@
1
+ module SeedDo
2
+ # Buffers seeds during a file run and flushes them in bulk.
3
+ class BulkSeeder
4
+ attr_reader :buffer
5
+
6
+ def initialize(batch_size: 1000)
7
+ @batch_size = batch_size
8
+ @buffer = nil
9
+
10
+ validate_support!
11
+ end
12
+
13
+ def seed(model, constraints, data)
14
+ puts " - #{model} #{data.inspect}" unless SeedDo.quiet
15
+ buffer[:seed] << { model: model, constraints: constraints, data: data }
16
+ end
17
+
18
+ def seed_once(model, constraints, data)
19
+ puts " - #{model} #{data.inspect}" unless SeedDo.quiet
20
+ buffer[:seed_once] << { model: model, constraints: constraints, data: data }
21
+ end
22
+
23
+ def with_seed_file
24
+ @buffer = { seed: [], seed_once: [] }
25
+ yield
26
+ process_buffer
27
+ ensure
28
+ @buffer = nil
29
+ end
30
+
31
+ private
32
+
33
+ def validate_support!
34
+ return if ActiveRecord::Base.connection.supports_insert_conflict_target?
35
+
36
+ raise ArgumentError,
37
+ "Bulk mode is not supported for #{ActiveRecord::Base.connection.adapter_name}. " \
38
+ 'The database does not support upsert operations with conflict targets. ' \
39
+ 'Please use SeedDo.seed without the bulk option.'
40
+ end
41
+
42
+ def process_buffer
43
+ return unless buffer
44
+
45
+ buffer.each do |type, operations|
46
+ next if operations.empty?
47
+
48
+ operations.chunk { |operation| [operation[:model], operation[:constraints]] }
49
+ .each do |(model, constraints), chunk|
50
+ flush_chunk(model, constraints, type, chunk)
51
+ end
52
+ end
53
+ end
54
+
55
+ def flush_chunk(model, constraints, type, chunk)
56
+ all_data = chunk.flat_map { |operation| operation[:data] }
57
+
58
+ options = { unique_by: constraints }
59
+ options[:on_duplicate] = :skip if type == :seed_once
60
+
61
+ all_data.each_slice(@batch_size) do |batch|
62
+ model.upsert_all(batch, **options)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,7 +1,7 @@
1
1
  Capistrano::Configuration.instance.load do
2
2
  namespace :db do
3
- desc "Load seed data into database"
4
- task :seed_do, :roles => :db, :only => { :primary => true } do
3
+ desc 'Load seed data into database'
4
+ task :seed_do, roles: :db, only: { primary: true } do
5
5
  run "cd #{release_path} && bundle exec rake RAILS_ENV=#{rails_env} db:seed_do"
6
6
  end
7
7
  end
@@ -1 +1 @@
1
- load File.expand_path('../../tasks/seed_do_capistrano3.rake', __FILE__)
1
+ load File.expand_path('../tasks/seed_do_capistrano3.rake', __dir__)
@@ -1,7 +1,7 @@
1
1
  module SeedDo
2
2
  class Railtie < Rails::Railtie
3
3
  rake_tasks do
4
- load "tasks/seed_do.rake"
4
+ load 'tasks/seed_do.rake'
5
5
  end
6
6
 
7
7
  initializer 'seed_do.set_fixture_paths' do
@@ -3,9 +3,7 @@ require 'active_support/core_ext/array/wrap'
3
3
 
4
4
  module SeedDo
5
5
  # Runs seed files.
6
- #
7
- # It is not recommended to use this class directly. Instead, use {SeedDo.seed SeedDo.seed}, which creates
8
- # an instead of {Runner} and calls {#run #run}.
6
+ # It is not recommended to use this class directly. Instead, use {SeedDo.seed SeedDo.seed}, which creates an instead of {Runner} and calls {#run #run}.
9
7
  #
10
8
  # @see SeedDo.seed SeedDo.seed
11
9
  class Runner
@@ -13,61 +11,80 @@ module SeedDo
13
11
  # `SeedDo.fixture_paths` if {nil}. If the argument is not an array, it will be wrapped by one.
14
12
  # @param [Regexp] filter If given, only seed files with a file name matching this pattern will
15
13
  # be used
16
- def initialize(fixture_paths = nil, filter = nil)
14
+ # @param [Boolean, Hash] bulk If true, use upsert_all to insert/update records in bulk.
15
+ # If a hash, can include :batch_size (default: 1000) to control the number of records
16
+ # per upsert_all call.
17
+ def initialize(fixture_paths = nil, filter = nil, bulk: false)
17
18
  @fixture_paths = Array.wrap(fixture_paths || SeedDo.fixture_paths)
18
19
  @filter = filter
20
+ @seeder = build_seeder(bulk)
19
21
  end
20
22
 
21
23
  # Run the seed files.
22
24
  def run
25
+ SeedDo.current_seeder = @seeder
23
26
  puts "\n== Filtering seed files against regexp: #{@filter.inspect}" if @filter && !SeedDo.quiet
24
27
 
25
- filenames.each do |filename|
26
- run_file(filename)
27
- end
28
+ filenames.each { |filename| run_file(filename) }
29
+ ensure
30
+ SeedDo.current_seeder = nil
31
+ end
32
+
33
+ def seed(model, constraints, data)
34
+ @seeder.seed(model, constraints, data)
35
+ end
36
+
37
+ def seed_once(model, constraints, data)
38
+ @seeder.seed_once(model, constraints, data)
28
39
  end
29
40
 
30
41
  private
31
42
 
32
- def run_file(filename)
33
- puts "\n== Seed from #{filename}" unless SeedDo.quiet
43
+ def run_file(filename)
44
+ puts "\n== Seed from #{filename}" unless SeedDo.quiet
45
+
46
+ ActiveRecord::Base.transaction do
47
+ @seeder.with_seed_file { _run_file(filename) }
48
+ end
49
+ end
50
+
51
+ def build_seeder(bulk)
52
+ return SeedDo::BulkSeeder.new(batch_size: bulk.fetch(:batch_size, 1000)) if bulk.is_a?(Hash)
34
53
 
35
- ActiveRecord::Base.transaction do
36
- open(filename) do |file|
54
+ bulk ? SeedDo::BulkSeeder.new : SeedDo::Seeder.new
55
+ end
56
+
57
+ def _run_file(filename)
58
+ open(filename) do |file|
59
+ chunked_ruby = +''
60
+ file.each_line do |line|
61
+ if line == "# BREAK EVAL\n"
62
+ eval(chunked_ruby)
37
63
  chunked_ruby = +''
38
- file.each_line do |line|
39
- if line == "# BREAK EVAL\n"
40
- eval(chunked_ruby)
41
- chunked_ruby = +''
42
- else
43
- chunked_ruby << line
44
- end
45
- end
46
- eval(chunked_ruby) unless chunked_ruby == ''
64
+ else
65
+ chunked_ruby << line
47
66
  end
48
67
  end
68
+ eval(chunked_ruby) unless chunked_ruby == ''
49
69
  end
70
+ end
50
71
 
51
- def open(filename)
52
- if filename[-3..-1] == '.gz'
53
- Zlib::GzipReader.open(filename) do |file|
54
- yield file
55
- end
56
- else
57
- File.open(filename) do |file|
58
- yield file
59
- end
60
- end
72
+ def open(filename, &)
73
+ if filename[-3..-1] == '.gz'
74
+ Zlib::GzipReader.open(filename, &)
75
+ else
76
+ File.open(filename, &)
61
77
  end
78
+ end
62
79
 
63
- def filenames
64
- filenames = []
65
- @fixture_paths.each do |path|
66
- filenames += (Dir[File.join(path, '*.rb')] + Dir[File.join(path, '*.rb.gz')]).sort
67
- end
68
- filenames.uniq!
69
- filenames = filenames.find_all { |filename| filename =~ @filter } if @filter
70
- filenames
80
+ def filenames
81
+ filenames = []
82
+ @fixture_paths.each do |path|
83
+ filenames += (Dir[File.join(path, '*.rb')] + Dir[File.join(path, '*.rb.gz')]).sort
71
84
  end
85
+ filenames.uniq!
86
+ filenames = filenames.find_all { |filename| filename =~ @filter } if @filter
87
+ filenames
88
+ end
72
89
  end
73
90
  end
@@ -8,30 +8,31 @@ module SeedDo
8
8
  #
9
9
  # @see ActiveRecordExtension
10
10
  class Seeder
11
- # @param [ActiveRecord::Base] model_class The model to be seeded
12
- # @param [Array<Symbol>] constraints A list of attributes which identify a particular seed. If
13
- # a record with these attributes already exists then it will be updated rather than created.
14
- # @param [Array<Hash>] data Each item in this array is a hash containing attributes for a
15
- # particular record.
16
- # @param [Hash] options
17
- # @option options [Boolean] :quiet (SeedDo.quiet) If true, output will be silenced
18
- # @option options [Boolean] :insert_only (false) If true then existing records which match the
19
- # constraints will not be updated, even if the seed data has changed
20
- def initialize(model_class, constraints, data, options = {})
11
+ def seed(model_class, constraints, data)
12
+ seed_records(model_class, constraints, data)
13
+ end
14
+
15
+ def seed_once(model_class, constraints, data)
16
+ seed_records(model_class, constraints, data, insert_only: true)
17
+ end
18
+
19
+ def with_seed_file
20
+ yield
21
+ end
22
+
23
+ private
24
+
25
+ # Insert/update the records as appropriate. Validation is skipped while saving.
26
+ # @return [Array<ActiveRecord::Base>] The records which have been seeded
27
+ def seed_records(model_class, constraints, data, options = {})
21
28
  @model_class = model_class
22
29
  @constraints = constraints.to_a.empty? ? [:id] : constraints
23
30
  @data = data.to_a || []
24
31
  @options = options.symbolize_keys
25
32
 
26
- @options[:quiet] ||= SeedDo.quiet
27
-
28
33
  validate_constraints!
29
34
  validate_data!
30
- end
31
35
 
32
- # Insert/update the records as appropriate. Validation is skipped while saving.
33
- # @return [Array<ActiveRecord::Base>] The records which have been seeded
34
- def seed
35
36
  records = @model_class.transaction do
36
37
  @data.map { |record_data| seed_record(record_data.symbolize_keys) }
37
38
  end
@@ -39,64 +40,61 @@ module SeedDo
39
40
  records
40
41
  end
41
42
 
42
- private
43
+ def validate_constraints!
44
+ unknown_columns = @constraints.map(&:to_s) - @model_class.column_names
45
+ return if unknown_columns.empty?
43
46
 
44
- def validate_constraints!
45
- unknown_columns = @constraints.map(&:to_s) - @model_class.column_names
46
- unless unknown_columns.empty?
47
- raise(ArgumentError,
47
+ raise(ArgumentError,
48
48
  "Your seed constraints contained unknown columns: #{column_list(unknown_columns)}. " +
49
49
  "Valid columns are: #{column_list(@model_class.column_names)}.")
50
- end
51
- end
50
+ end
52
51
 
53
- def validate_data!
54
- raise ArgumentError, "Seed data missing" if @data.empty?
55
- end
52
+ def validate_data!
53
+ raise ArgumentError, 'Seed data missing' if @data.empty?
54
+ end
56
55
 
57
- def column_list(columns)
58
- '`' + columns.join("`, `") + '`'
59
- end
56
+ def column_list(columns)
57
+ '`' + columns.join('`, `') + '`'
58
+ end
60
59
 
61
- def seed_record(data)
62
- record = find_or_initialize_record(data)
63
- return if @options[:insert_only] && !record.new_record?
60
+ def seed_record(data)
61
+ record = find_or_initialize_record(data)
62
+ return if @options[:insert_only] && !record.new_record?
64
63
 
65
- puts " - #{@model_class} #{data.inspect}" unless @options[:quiet]
64
+ puts " - #{@model_class} #{data.inspect}" unless SeedDo.quiet
66
65
 
67
- record.assign_attributes(data)
68
- record.save(:validate => false) || raise(ActiveRecord::RecordNotSaved, 'Record not saved!')
69
- record
70
- end
66
+ record.assign_attributes(data)
67
+ record.save(validate: false) || raise(ActiveRecord::RecordNotSaved, 'Record not saved!')
68
+ record
69
+ end
71
70
 
72
- def find_or_initialize_record(data)
73
- @model_class.where(constraint_conditions(data)).take ||
71
+ def find_or_initialize_record(data)
72
+ @model_class.where(constraint_conditions(data)).take ||
74
73
  @model_class.new
75
- end
74
+ end
76
75
 
77
- def constraint_conditions(data)
78
- Hash[@constraints.map { |c| [c, data[c.to_sym]] }]
79
- end
76
+ def constraint_conditions(data)
77
+ @constraints.to_h { |c| [c, data[c.to_sym]] }
78
+ end
80
79
 
81
- def update_id_sequence
82
- if @model_class.connection.adapter_name == "PostgreSQL" or @model_class.connection.adapter_name == "PostGIS"
83
- return if @model_class.primary_key.nil? || @model_class.sequence_name.nil?
80
+ def update_id_sequence
81
+ return unless %w[PostgreSQL PostGIS].include?(@model_class.connection.adapter_name)
82
+ return if @model_class.primary_key.nil? || @model_class.sequence_name.nil?
84
83
 
85
- quoted_id = @model_class.connection.quote_column_name(@model_class.primary_key)
86
- sequence = @model_class.sequence_name
84
+ quoted_id = @model_class.connection.quote_column_name(@model_class.primary_key)
85
+ sequence = @model_class.sequence_name
87
86
 
88
- if @model_class.connection.postgresql_version >= 100000
89
- sql =<<-EOS
87
+ if @model_class.connection.postgresql_version >= 100_000
88
+ sql = <<-EOS
90
89
  SELECT setval('#{sequence}', (SELECT GREATEST(MAX(#{quoted_id})+(SELECT seqincrement FROM pg_sequence WHERE seqrelid = '#{sequence}'::regclass), (SELECT seqmin FROM pg_sequence WHERE seqrelid = '#{sequence}'::regclass)) FROM #{@model_class.quoted_table_name}), false)
91
- EOS
92
- else
93
- sql =<<-EOS
90
+ EOS
91
+ else
92
+ sql = <<-EOS
94
93
  SELECT setval('#{sequence}', (SELECT GREATEST(MAX(#{quoted_id})+(SELECT increment_by FROM #{sequence}), (SELECT min_value FROM #{sequence})) FROM #{@model_class.quoted_table_name}), false)
95
- EOS
96
- end
97
-
98
- @model_class.connection.execute sql
99
- end
94
+ EOS
100
95
  end
96
+
97
+ @model_class.connection.execute sql
98
+ end
101
99
  end
102
100
  end
@@ -1,3 +1,3 @@
1
1
  module SeedDo
2
- VERSION = '3.1.0'
2
+ VERSION = '4.0.0'
3
3
  end
@@ -18,9 +18,9 @@ module SeedDo
18
18
  class Writer
19
19
  cattr_accessor :default_options
20
20
  @@default_options = {
21
- :chunk_size => 100,
22
- :constraints => [:id],
23
- :seed_type => :seed
21
+ chunk_size: 100,
22
+ constraints: [:id],
23
+ seed_type: :seed
24
24
  }
25
25
 
26
26
  # @param [Hash] options
@@ -33,13 +33,13 @@ module SeedDo
33
33
  # @option options [Array<Symbol>] :constraints ([:id]) The constraining attributes for the seeds
34
34
  def initialize(options = {})
35
35
  @options = self.class.default_options.merge(options)
36
- raise ArgumentError, "missing option :class_name" unless @options[:class_name]
36
+ raise ArgumentError, 'missing option :class_name' unless @options[:class_name]
37
37
  end
38
38
 
39
39
  # Creates a new instance of {Writer} with the `options`, and then calls {#write} with the
40
40
  # `io_or_filename` and `block`
41
- def self.write(io_or_filename, options = {}, &block)
42
- new(options).write(io_or_filename, &block)
41
+ def self.write(io_or_filename, options = {}, &)
42
+ new(options).write(io_or_filename, &)
43
43
  end
44
44
 
45
45
  # Writes the necessary headers and footers, and yields to a block within which the actual
@@ -51,7 +51,7 @@ module SeedDo
51
51
  # closed automatically.)
52
52
  # @yield [self] make calls to `#<<` within the block
53
53
  def write(io_or_filename, &block)
54
- raise ArgumentError, "missing block" unless block_given?
54
+ raise ArgumentError, 'missing block' unless block_given?
55
55
 
56
56
  if io_or_filename.respond_to?(:write)
57
57
  write_to_io(io_or_filename, &block)
@@ -65,7 +65,7 @@ module SeedDo
65
65
  # Add a seed. Must be called within a block passed to {#write}.
66
66
  # @param [Hash] seed The attributes for the seed
67
67
  def <<(seed)
68
- raise "You must add seeds inside a SeedDo::Writer#write block" unless @io
68
+ raise 'You must add seeds inside a SeedDo::Writer#write block' unless @io
69
69
 
70
70
  buffer = +''
71
71
 
@@ -76,57 +76,59 @@ module SeedDo
76
76
  end
77
77
 
78
78
  buffer << ",\n"
79
- buffer << ' ' + seed.inspect
79
+ buffer << (' ' + seed.inspect)
80
80
 
81
81
  @io.write(buffer)
82
82
 
83
83
  @count += 1
84
84
  end
85
- alias_method :add, :<<
85
+ alias add <<
86
86
 
87
87
  private
88
88
 
89
- def write_to_io(io)
90
- @io, @count = io, 0
91
- @io.write(file_header)
92
- @io.write(seed_header)
93
- yield(self)
94
- @io.write(seed_footer)
95
- @io.write(file_footer)
96
- ensure
97
- @io, @count = nil, nil
98
- end
89
+ def write_to_io(io)
90
+ @io = io
91
+ @count = 0
92
+ @io.write(file_header)
93
+ @io.write(seed_header)
94
+ yield(self)
95
+ @io.write(seed_footer)
96
+ @io.write(file_footer)
97
+ ensure
98
+ @io = nil
99
+ @count = nil
100
+ end
99
101
 
100
- def file_header
101
- <<-END
102
- # DO NOT MODIFY THIS FILE, it was auto-generated.
103
- #
104
- # Date: #{Time.now}
105
- # Seeding #{@options[:class_name]}
106
- # Written with the command:
107
- #
108
- # #{$0} #{$*.join}
109
- #
110
- END
111
- end
102
+ def file_header
103
+ <<~END
104
+ # DO NOT MODIFY THIS FILE, it was auto-generated.
105
+ #
106
+ # Date: #{Time.now}
107
+ # Seeding #{@options[:class_name]}
108
+ # Written with the command:
109
+ #
110
+ # #{$0} #{$*.join}
111
+ #
112
+ END
113
+ end
112
114
 
113
- def file_footer
114
- <<-END
115
- # End auto-generated file.
116
- END
117
- end
115
+ def file_footer
116
+ <<~END
117
+ # End auto-generated file.
118
+ END
119
+ end
118
120
 
119
- def seed_header
120
- constraints = @options[:constraints] && @options[:constraints].map(&:inspect).join(', ')
121
- "#{@options[:class_name]}.#{@options[:seed_type]}(#{constraints}"
122
- end
121
+ def seed_header
122
+ constraints = @options[:constraints] && @options[:constraints].map(&:inspect).join(', ')
123
+ "#{@options[:class_name]}.#{@options[:seed_type]}(#{constraints}"
124
+ end
123
125
 
124
- def seed_footer
125
- "\n)\n"
126
- end
126
+ def seed_footer
127
+ "\n)\n"
128
+ end
127
129
 
128
- def chunk_this_seed?
129
- @count != 0 && (@count % @options[:chunk_size]) == 0
130
- end
130
+ def chunk_this_seed?
131
+ @count != 0 && (@count % @options[:chunk_size]) == 0
132
+ end
131
133
  end
132
134
  end
data/lib/seed-do.rb CHANGED
@@ -1,32 +1,37 @@
1
1
  require 'active_record'
2
2
  require 'active_support/core_ext/module/attribute_accessors'
3
- require 'seed-do/railtie' if defined?(Rails) && Rails.version >= "3"
3
+ require 'seed-do/railtie' if defined?(Rails)
4
4
 
5
5
  module SeedDo
6
6
  autoload :VERSION, 'seed-do/version'
7
7
  autoload :Seeder, 'seed-do/seeder'
8
8
  autoload :ActiveRecordExtension, 'seed-do/active_record_extension'
9
9
  autoload :BlockHash, 'seed-do/block_hash'
10
+ autoload :BulkSeeder, 'seed-do/bulk_seeder'
10
11
  autoload :Runner, 'seed-do/runner'
11
12
  autoload :Writer, 'seed-do/writer'
12
13
 
13
- mattr_accessor :quiet
14
-
15
14
  # Set `SeedDo.quiet = true` to silence all output
16
- @@quiet = false
17
-
18
- mattr_accessor :fixture_paths
15
+ mattr_accessor :quiet, default: false
19
16
 
20
17
  # Set this to be an array of paths to directories containing your seed files. If used as a Rails
21
- # plugin, SeedDo will set to to contain `Rails.root/db/fixtures` and
18
+ # plugin, SeedDo will set it to contain `Rails.root/db/fixtures` and
22
19
  # `Rails.root/db/fixtures/Rails.env`
23
- @@fixture_paths = ['db/fixtures']
24
-
20
+ mattr_accessor :fixture_paths, default: ['db/fixtures']
25
21
  # Load seed data from files
26
22
  # @param [Array] fixture_paths The paths to look for seed files in
27
23
  # @param [Regexp] filter If given, only filenames matching this expression will be loaded
28
- def self.seed(fixture_paths = SeedDo.fixture_paths, filter = nil)
29
- Runner.new(fixture_paths, filter).run
24
+ # @param [Boolean] bulk If true, bulk insert/upsert will be used
25
+ def self.seed(fixture_paths = SeedDo.fixture_paths, filter = nil, bulk: false)
26
+ Runner.new(fixture_paths, filter, bulk: bulk).run
27
+ end
28
+
29
+ def self.current_seeder
30
+ @current_seeder || Seeder.new
31
+ end
32
+
33
+ def self.current_seeder=(seeder)
34
+ @current_seeder = seeder
30
35
  end
31
36
  end
32
37
 
@@ -24,14 +24,10 @@ namespace :db do
24
24
  # to load files from RAILS_ROOT/features/fixtures
25
25
  rake db:seed_do FIXTURE_PATH=features/fixtures
26
26
  EOS
27
- task :seed_do => :environment do
28
- if ENV["FILTER"]
29
- filter = /#{ENV["FILTER"].gsub(/,/, "|")}/
30
- end
31
-
32
- if ENV["FIXTURE_PATH"]
33
- fixture_paths = [ENV["FIXTURE_PATH"], ENV["FIXTURE_PATH"] + '/' + Rails.env]
34
- end
27
+ task seed_do: :environment do
28
+ filter = /#{ENV['FILTER'].tr(',', '|')}/ if ENV['FILTER']
29
+
30
+ fixture_paths = [ENV['FIXTURE_PATH'], ENV['FIXTURE_PATH'] + '/' + Rails.env] if ENV['FIXTURE_PATH']
35
31
 
36
32
  SeedDo.seed(fixture_paths, filter)
37
33
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seed-do
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shinichi Maeshima
@@ -66,6 +66,7 @@ files:
66
66
  - lib/seed-do.rb
67
67
  - lib/seed-do/active_record_extension.rb
68
68
  - lib/seed-do/block_hash.rb
69
+ - lib/seed-do/bulk_seeder.rb
69
70
  - lib/seed-do/capistrano.rb
70
71
  - lib/seed-do/capistrano3.rb
71
72
  - lib/seed-do/railtie.rb
@@ -78,7 +79,8 @@ files:
78
79
  homepage: http://github.com/willnet/seed-do
79
80
  licenses:
80
81
  - MIT
81
- metadata: {}
82
+ metadata:
83
+ rubygems_mfa_required: 'true'
82
84
  rdoc_options: []
83
85
  require_paths:
84
86
  - lib
@@ -93,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
95
  - !ruby/object:Gem::Version
94
96
  version: '0'
95
97
  requirements: []
96
- rubygems_version: 3.6.9
98
+ rubygems_version: 4.0.6
97
99
  specification_version: 4
98
100
  summary: Easily manage seed data in your Active Record application
99
101
  test_files: []