active_record_data_loader 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codeql-analysis.yml +70 -0
  3. data/.rubocop.yml +8 -2
  4. data/CHANGELOG.md +9 -0
  5. data/CODE_OF_CONDUCT.md +2 -2
  6. data/Gemfile.lock +24 -24
  7. data/README.md +88 -18
  8. data/active_record_data_loader.gemspec +1 -1
  9. data/lib/active_record_data_loader/active_record/{belongs_to_configuration.rb → belongs_to_data_provider.rb} +7 -6
  10. data/lib/active_record_data_loader/active_record/{column_configuration.rb → column_data_provider.rb} +2 -2
  11. data/lib/active_record_data_loader/active_record/list.rb +35 -0
  12. data/lib/active_record_data_loader/active_record/model_data_generator.rb +60 -5
  13. data/lib/active_record_data_loader/active_record/{polymorphic_belongs_to_configuration.rb → polymorphic_belongs_to_data_provider.rb} +11 -6
  14. data/lib/active_record_data_loader/active_record/unique_index_tracker.rb +67 -0
  15. data/lib/active_record_data_loader/bulk_insert_strategy.rb +16 -9
  16. data/lib/active_record_data_loader/configuration.rb +13 -30
  17. data/lib/active_record_data_loader/connection_handler.rb +23 -45
  18. data/lib/active_record_data_loader/copy_strategy.rb +21 -7
  19. data/lib/active_record_data_loader/data_faker.rb +12 -4
  20. data/lib/active_record_data_loader/dsl/model.rb +19 -2
  21. data/lib/active_record_data_loader/errors.rb +5 -0
  22. data/lib/active_record_data_loader/file_output_adapter.rb +20 -12
  23. data/lib/active_record_data_loader/loader.rb +61 -55
  24. data/lib/active_record_data_loader/null_output_adapter.rb +15 -0
  25. data/lib/active_record_data_loader/table_loader.rb +59 -0
  26. data/lib/active_record_data_loader/version.rb +1 -1
  27. data/lib/active_record_data_loader.rb +9 -41
  28. metadata +12 -7
  29. data/lib/active_record_data_loader/connection_output_adapter.rb +0 -20
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecordDataLoader
4
+ class NullOutputAdapter
5
+ def self.with_output_options(_options)
6
+ yield new
7
+ end
8
+
9
+ def copy(table:, columns:, data:, row_numbers:); end
10
+
11
+ def insert(command); end
12
+
13
+ def write_command(command); end
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark"
4
+
5
+ module ActiveRecordDataLoader
6
+ class TableLoader
7
+ def self.load_data(
8
+ total_rows:,
9
+ batch_size:,
10
+ logger:,
11
+ connection_handler:,
12
+ strategy:
13
+ )
14
+ new(logger: logger, connection_handler: connection_handler, strategy: strategy)
15
+ .load_data(batch_size, total_rows)
16
+ end
17
+
18
+ def initialize(logger:, connection_handler:, strategy:)
19
+ @logger = logger
20
+ @connection_handler = connection_handler
21
+ @strategy = strategy
22
+ end
23
+
24
+ def load_data(batch_size, total_rows)
25
+ batch_count = (total_rows / batch_size.to_f).ceil
26
+
27
+ logger.info(
28
+ "[ActiveRecordDataLoader] "\
29
+ "Loading #{total_rows} row(s) into '#{strategy.table_name}' via #{strategy.name}. "\
30
+ "#{batch_size} row(s) per batch, #{batch_count} batch(es)."
31
+ )
32
+ total_time = Benchmark.realtime do
33
+ load_in_batches(batch_size, total_rows, batch_count)
34
+ end
35
+ logger.info(
36
+ "[ActiveRecordDataLoader] "\
37
+ "Completed loading #{total_rows} row(s) into '#{strategy.table_name}' "\
38
+ "in #{total_time} seconds."
39
+ )
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :strategy, :connection_handler, :logger
45
+
46
+ def load_in_batches(batch_size, total_rows, batch_count)
47
+ connection_handler.with_connection do |connection|
48
+ total_rows.times.each_slice(batch_size).with_index do |row_numbers, i|
49
+ time = Benchmark.realtime { strategy.load_batch(row_numbers, connection) }
50
+
51
+ logger.debug(
52
+ "[ActiveRecordDataLoader] "\
53
+ "Completed batch #{i + 1}/#{batch_count}, #{row_numbers.count} row(s) in #{time} seconds"
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordDataLoader
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.0"
5
5
  end
@@ -2,31 +2,35 @@
2
2
 
3
3
  require "active_record_data_loader/version"
4
4
  require "active_record"
5
+ require "active_record_data_loader/errors"
5
6
  require "active_record_data_loader/configuration"
6
7
  require "active_record_data_loader/connection_handler"
7
8
  require "active_record_data_loader/data_faker"
9
+ require "active_record_data_loader/active_record/list"
8
10
  require "active_record_data_loader/active_record/per_row_value_cache"
9
11
  require "active_record_data_loader/active_record/integer_value_generator"
10
12
  require "active_record_data_loader/active_record/text_value_generator"
11
13
  require "active_record_data_loader/active_record/enum_value_generator"
12
14
  require "active_record_data_loader/active_record/datetime_value_generator"
13
- require "active_record_data_loader/active_record/column_configuration"
14
- require "active_record_data_loader/active_record/belongs_to_configuration"
15
- require "active_record_data_loader/active_record/polymorphic_belongs_to_configuration"
15
+ require "active_record_data_loader/active_record/column_data_provider"
16
+ require "active_record_data_loader/active_record/belongs_to_data_provider"
17
+ require "active_record_data_loader/active_record/polymorphic_belongs_to_data_provider"
18
+ require "active_record_data_loader/active_record/unique_index_tracker"
16
19
  require "active_record_data_loader/active_record/model_data_generator"
17
20
  require "active_record_data_loader/dsl/belongs_to_association"
18
21
  require "active_record_data_loader/dsl/polymorphic_association"
19
22
  require "active_record_data_loader/dsl/model"
20
23
  require "active_record_data_loader/dsl/definition"
21
- require "active_record_data_loader/connection_output_adapter"
22
24
  require "active_record_data_loader/file_output_adapter"
25
+ require "active_record_data_loader/null_output_adapter"
23
26
  require "active_record_data_loader/copy_strategy"
24
27
  require "active_record_data_loader/bulk_insert_strategy"
28
+ require "active_record_data_loader/table_loader"
25
29
  require "active_record_data_loader/loader"
26
30
 
27
31
  module ActiveRecordDataLoader
28
32
  def self.define(config = ActiveRecordDataLoader.configuration, &block)
29
- LoaderProxy.new(
33
+ ActiveRecordDataLoader::Loader.new(
30
34
  config,
31
35
  ActiveRecordDataLoader::Dsl::Definition.new(config).tap { |l| l.instance_eval(&block) }
32
36
  )
@@ -39,40 +43,4 @@ module ActiveRecordDataLoader
39
43
  def self.configuration
40
44
  @configuration ||= ActiveRecordDataLoader::Configuration.new
41
45
  end
42
-
43
- class LoaderProxy
44
- def initialize(configuration, definition)
45
- @configuration = configuration
46
- @definition = definition
47
- end
48
-
49
- def load_data
50
- ActiveRecordDataLoader::ActiveRecord::PerRowValueCache.clear
51
-
52
- configuration.connection_handler.with_statement_timeout_for_output do
53
- definition.models.map { |m| load_model(m) }
54
- end
55
- end
56
-
57
- private
58
-
59
- attr_reader :definition, :configuration
60
-
61
- def load_model(model)
62
- generator = ActiveRecordDataLoader::ActiveRecord::ModelDataGenerator.new(
63
- model: model.klass,
64
- column_settings: model.columns,
65
- polymorphic_settings: model.polymorphic_associations,
66
- belongs_to_settings: model.belongs_to_associations,
67
- connection_factory: configuration.connection_factory
68
- )
69
-
70
- ActiveRecordDataLoader::Loader.load_data(
71
- data_generator: generator,
72
- batch_size: model.batch_size,
73
- total_rows: model.row_count,
74
- configuration: configuration
75
- )
76
- end
77
- end
78
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_data_loader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Beiderman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-14 00:00:00.000000000 Z
11
+ date: 2021-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -208,7 +208,7 @@ dependencies:
208
208
  version: '0'
209
209
  description: A utility to bulk load test data for performance testing.
210
210
  email:
211
- - abeiderman@gmail.com
211
+ - active_record_data_loader@ossprojects.dev
212
212
  executables:
213
213
  - console
214
214
  - setup
@@ -216,6 +216,7 @@ extensions: []
216
216
  extra_rdoc_files: []
217
217
  files:
218
218
  - ".github/workflows/build.yml"
219
+ - ".github/workflows/codeql-analysis.yml"
219
220
  - ".github/workflows/gem-push.yml"
220
221
  - ".gitignore"
221
222
  - ".rspec"
@@ -240,27 +241,31 @@ files:
240
241
  - gemfiles/ffaker.gemfile
241
242
  - gemfiles/rails.gemfile
242
243
  - lib/active_record_data_loader.rb
243
- - lib/active_record_data_loader/active_record/belongs_to_configuration.rb
244
- - lib/active_record_data_loader/active_record/column_configuration.rb
244
+ - lib/active_record_data_loader/active_record/belongs_to_data_provider.rb
245
+ - lib/active_record_data_loader/active_record/column_data_provider.rb
245
246
  - lib/active_record_data_loader/active_record/datetime_value_generator.rb
246
247
  - lib/active_record_data_loader/active_record/enum_value_generator.rb
247
248
  - lib/active_record_data_loader/active_record/integer_value_generator.rb
249
+ - lib/active_record_data_loader/active_record/list.rb
248
250
  - lib/active_record_data_loader/active_record/model_data_generator.rb
249
251
  - lib/active_record_data_loader/active_record/per_row_value_cache.rb
250
- - lib/active_record_data_loader/active_record/polymorphic_belongs_to_configuration.rb
252
+ - lib/active_record_data_loader/active_record/polymorphic_belongs_to_data_provider.rb
251
253
  - lib/active_record_data_loader/active_record/text_value_generator.rb
254
+ - lib/active_record_data_loader/active_record/unique_index_tracker.rb
252
255
  - lib/active_record_data_loader/bulk_insert_strategy.rb
253
256
  - lib/active_record_data_loader/configuration.rb
254
257
  - lib/active_record_data_loader/connection_handler.rb
255
- - lib/active_record_data_loader/connection_output_adapter.rb
256
258
  - lib/active_record_data_loader/copy_strategy.rb
257
259
  - lib/active_record_data_loader/data_faker.rb
258
260
  - lib/active_record_data_loader/dsl/belongs_to_association.rb
259
261
  - lib/active_record_data_loader/dsl/definition.rb
260
262
  - lib/active_record_data_loader/dsl/model.rb
261
263
  - lib/active_record_data_loader/dsl/polymorphic_association.rb
264
+ - lib/active_record_data_loader/errors.rb
262
265
  - lib/active_record_data_loader/file_output_adapter.rb
263
266
  - lib/active_record_data_loader/loader.rb
267
+ - lib/active_record_data_loader/null_output_adapter.rb
268
+ - lib/active_record_data_loader/table_loader.rb
264
269
  - lib/active_record_data_loader/version.rb
265
270
  - log/.keep
266
271
  homepage:
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveRecordDataLoader
4
- class ConnectionOutputAdapter
5
- def needs_timeout_output?
6
- false
7
- end
8
-
9
- def copy(connection:, table:, columns:, data:, row_numbers:)
10
- raw_connection = connection.raw_connection
11
- raw_connection.copy_data("COPY #{table} (#{columns}) FROM STDIN WITH (FORMAT CSV)") do
12
- raw_connection.put_copy_data(data.join("\n"))
13
- end
14
- end
15
-
16
- def insert(connection:, command:)
17
- connection.insert(command)
18
- end
19
- end
20
- end