active_record_data_loader 1.2.0 → 1.3.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.
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